/* This code is part of Freenet. It is distributed under the GNU General
* Public License, version 2 (or at your option any later version). See
* http://www.gnu.org/ for further details of the GPL. */
package freenet.clients.fcp;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashMap;
import freenet.client.DefaultMIMETypes;
import freenet.node.Node;
import freenet.support.LogThresholdCallback;
import freenet.support.Logger;
import freenet.support.Logger.LogLevel;
import freenet.support.SimpleFieldSet;
import freenet.support.api.BucketFactory;
import freenet.support.api.ManifestElement;
import freenet.support.io.FileBucket;
/**
* Insert a directory from disk as a manifest.
*
* ClientPutDiskDirMessage
* < generic fields from ClientPutDirMessage >
* Filename=<filename>
* AllowUnreadableFiles=<unless true, any unreadable files cause the whole request to fail>
* End
*
* FIXME this should use the same code as makeDiskDirManifest does for internal
* directory inserts.
*/
public class ClientPutDiskDirMessage extends ClientPutDirMessage {
public final static String NAME = "ClientPutDiskDir";
final File dirname;
final boolean allowUnreadableFiles;
final boolean includeHiddenFiles;
private static volatile boolean logMINOR;
static {
Logger.registerLogThresholdCallback(new LogThresholdCallback(){
@Override
public void shouldUpdate(){
logMINOR = Logger.shouldLog(LogLevel.MINOR, this);
}
});
}
public ClientPutDiskDirMessage(SimpleFieldSet fs) throws MessageInvalidException {
super(fs);
allowUnreadableFiles = fs.getBoolean("AllowUnreadableFiles", false);
includeHiddenFiles = fs.getBoolean("includeHiddenFiles", false);
String fnam = fs.get("Filename");
if(fnam == null)
throw new MessageInvalidException(ProtocolErrorMessage.MISSING_FIELD, "Filename missing", identifier, global);
dirname = new File(fnam);
}
@Override
public String getName() {
return NAME;
}
@Override
public void run(FCPConnectionHandler handler, Node node)
throws MessageInvalidException {
if(!handler.server.core.allowUploadFrom(dirname))
throw new MessageInvalidException(ProtocolErrorMessage.ACCESS_DENIED, "Not allowed to upload from "+dirname, identifier, global);
// Create a directory listing of Buckets of data, mapped to ManifestElement's.
// Directories are sub-HashMap's.
HashMap<String, Object> buckets = makeBucketsByName(dirname, "");
handler.startClientPutDir(this, buckets, true);
}
/**
* Create a map of String -> Bucket for every file in a directory
* and its subdirs.
* @throws MessageInvalidException
*/
private HashMap<String, Object> makeBucketsByName(File thisdir, String prefix) throws MessageInvalidException {
if(logMINOR)
Logger.minor(this, "Listing directory: "+thisdir);
HashMap<String, Object> ret = new HashMap<String, Object>();
File filelist[] = thisdir.listFiles();
if(filelist == null)
throw new MessageInvalidException(ProtocolErrorMessage.FILE_NOT_FOUND, "No such directory!", identifier, global);
for(int i = 0 ; i < filelist.length ; i++) {
if(filelist[i].isHidden() && !includeHiddenFiles) continue;
// Skip unreadable files and dirs
// Skip files nonexistant (dangling symlinks) - check last
if (filelist[i].canRead() && filelist[i].exists()) {
if (filelist[i].isFile()) {
File f = filelist[i];
FileBucket bucket = new FileBucket(f, true, false, false, false);
ret.put(f.getName(), new ManifestElement(f.getName(), prefix + f.getName(), bucket, DefaultMIMETypes.guessMIMEType(f.getName(), true), f.length()));
} else if(filelist[i].isDirectory()) {
HashMap<String, Object> subdir = makeBucketsByName(new File(thisdir, filelist[i].getName()), prefix
+ filelist[i].getName() + '/');
ret.put(filelist[i].getName(), subdir);
} else if(!allowUnreadableFiles) {
throw new MessageInvalidException(ProtocolErrorMessage.FILE_NOT_FOUND, "Not directory and not file: "+filelist[i], identifier, global);
}
} else {
if(!allowUnreadableFiles)
throw new MessageInvalidException(ProtocolErrorMessage.FILE_NOT_FOUND, "Not readable or doesn't exist: "+filelist[i], identifier, global);
}
}
return ret;
}
@Override
long dataLength() {
return 0;
}
String getIdentifier() {
return identifier;
}
@Override
public void readFrom(InputStream is, BucketFactory bf, FCPServer server) throws IOException, MessageInvalidException {
// Do nothing
}
@Override
protected void writeData(OutputStream os) throws IOException {
// Do nothing
}
}