/*
* This file is part of DrFTPD, Distributed FTP Daemon.
*
* DrFTPD is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* DrFTPD is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with DrFTPD; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.drftpd.commands.dir;
import java.io.FileNotFoundException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.StringTokenizer;
import org.apache.log4j.Logger;
import org.drftpd.Bytes;
import org.drftpd.Checksum;
import org.drftpd.GlobalContext;
import org.drftpd.commandmanager.CommandInterface;
import org.drftpd.commandmanager.CommandRequest;
import org.drftpd.commandmanager.CommandResponse;
import org.drftpd.commandmanager.ImproperUsageException;
import org.drftpd.commandmanager.StandardCommandManager;
import org.drftpd.dynamicdata.Key;
import org.drftpd.event.DirectoryFtpEvent;
import org.drftpd.exceptions.FileExistsException;
import org.drftpd.exceptions.NoAvailableSlaveException;
import org.drftpd.io.PermissionDeniedException;
import org.drftpd.master.Session;
import org.drftpd.usermanager.User;
import org.drftpd.vfs.DirectoryHandle;
import org.drftpd.vfs.FileHandle;
import org.drftpd.vfs.InodeHandle;
import org.drftpd.vfs.LinkHandle;
import org.drftpd.vfs.ListUtils;
import org.drftpd.vfs.ObjectNotValidException;
import org.drftpd.vfs.VirtualFileSystem;
/**
* @author mog
* @author djb61
* @version $Id: Dir.java 2466 2011-06-13 20:02:29Z djb61 $
*/
public class Dir extends CommandInterface {
private final static SimpleDateFormat DATE_FMT = new SimpleDateFormat(
"yyyyMMddHHmmss.SSS");
private static final Logger logger = Logger.getLogger(Dir.class);
public static final Key<InodeHandle> RENAMEFROM = new Key<InodeHandle>(Dir.class, "renamefrom");
public static final Key<InodeHandle> RENAMETO = new Key<InodeHandle>(Dir.class, "renameto");
// This Keys are place holders for usefull information that gets removed during
// deletion operations but are need to process hooks.
public static final Key<String> USERNAME = new Key<String>(Dir.class, "username");
public static final Key<Long> FILESIZE = new Key<Long>(Dir.class, "fileSize");
public static final Key<String> FILENAME = new Key<String>(Dir.class, "fileName");
public static final Key<Boolean> ISFILE = new Key<Boolean>(Dir.class, "isFile");
public static final Key<Long> XFERTIME = new Key<Long>(Dir.class, "xferTime");
public static final Key<Boolean> WIPE_RECURSIVE = new Key<Boolean>(Dir.class, "wipe_recursive");
public static final Key<String> WIPE_PATH = new Key<String>(Dir.class, "wipe_path");
/**
* <code>CDUP <CRLF></code><br>
*
* This command is a special case of CWD, and is included to
* simplify the implementation of programs for transferring
* directory trees between operating systems having different
* syntaxes for naming the parent directory. The reply codes
* shall be identical to the reply codes of CWD.
*/
public CommandResponse doCDUP(CommandRequest request) {
// change directory
if (request.getCurrentDirectory().isRoot()) {
return new CommandResponse(250,
"Directory remains " + request.getCurrentDirectory().getPath());
}
DirectoryHandle newCurrentDirectory = request.getCurrentDirectory().getParent();
return new CommandResponse(250,
"Directory changed to " + newCurrentDirectory.getPath(),
newCurrentDirectory, request.getUser());
}
/**
* <code>CWD <SP> <pathname> <CRLF></code><br>
*
* This command allows the user to work with a different
* directory for file storage or retrieval without
* altering his login or accounting information. Transfer
* parameters are similarly unchanged. The argument is a
* pathname specifying a directory.
*/
public CommandResponse doCWD(CommandRequest request) {
if (!request.hasArgument()) {
return StandardCommandManager.genericResponse("RESPONSE_501_SYNTAX_ERROR");
}
DirectoryHandle newCurrentDirectory;
User user = request.getSession().getUserNull(request.getUser());
try {
newCurrentDirectory = request.getCurrentDirectory().getDirectory(request.getArgument(), user);
} catch (FileNotFoundException ex) {
return new CommandResponse(550, ex.getMessage());
} catch (ObjectNotValidException e) {
return new CommandResponse(550, request.getArgument() + ": is not a directory");
}
return new CommandResponse(250,
"Directory changed to " + newCurrentDirectory.getPath(),
newCurrentDirectory, request.getUser());
}
private void addVictimInformationToResponse(InodeHandle victim,
CommandResponse response) throws FileNotFoundException {
response.setObject(FILENAME, victim.getName());
response.setObject(FILESIZE, victim.getSize());
response.setObject(USERNAME, victim.getUsername());
response.setObject(ISFILE, victim.isFile());
response.setObject(XFERTIME, victim.isFile() ? ((FileHandle)victim).getXfertime() : 0L);
}
/**
* <code>DELE <SP> <pathname> <CRLF></code><br>
*
* This command causes the file specified in the pathname to be
* deleted at the server site.
*/
public CommandResponse doDELE(CommandRequest request) {
// argument check
if (!request.hasArgument()) {
// out.print(FtpResponse.RESPONSE_501_SYNTAX_ERROR);
return StandardCommandManager
.genericResponse("RESPONSE_501_SYNTAX_ERROR");
}
// get filenames
String fileName = request.getArgument();
CommandResponse response = StandardCommandManager
.genericResponse("RESPONSE_250_ACTION_OKAY");
User user = request.getSession().getUserNull(request.getUser());
InodeHandle victim;
try {
victim = request.getCurrentDirectory().getInodeHandle(fileName,
user);
addVictimInformationToResponse(victim, response);
if (victim.isDirectory()) {
DirectoryHandle victimDir = (DirectoryHandle) victim;
if (!victimDir.isEmpty(user)) {
return new CommandResponse(550, victim.getPath()
+ ": Directory not empty");
}
}
victim.delete(user); // the file is only deleted here.
} catch (FileNotFoundException e) {
// this isn't good or bad, there could have easily been a race in
// another thread to delete this file
return new CommandResponse(550, e.getMessage());
} catch (PermissionDeniedException e) {
return StandardCommandManager
.genericResponse("RESPONSE_530_ACCESS_DENIED");
}
if (victim.isFile() || victim.isLink()) { // link or file
GlobalContext.getEventService().publishAsync(
new DirectoryFtpEvent(request.getSession().getUserNull(
request.getUser()), "DELE", victim.getParent()));
// strange that we're sending the parent directory of the file being
// deleted without mentioning the file that was deleted...
} else { // if (requestedFile.isDirectory()) {
GlobalContext.getEventService()
.publishAsync(
new DirectoryFtpEvent(request.getSession()
.getUserNull(request.getUser()), "RMD",
(DirectoryHandle) victim));
}
return response;
}
/**
* <code>MDTM <SP> <pathname> <CRLF></code><br>
*
* Returns the date and time of when a file was modified.
*/
public CommandResponse doMDTM(CommandRequest request) {
// argument check
if (!request.hasArgument()) {
return StandardCommandManager.genericResponse("RESPONSE_501_SYNTAX_ERROR");
}
// get filenames
String fileName = request.getArgument();
InodeHandle reqFile;
User user = request.getSession().getUserNull(request.getUser());
try {
reqFile = request.getCurrentDirectory().getInodeHandle(fileName, user);
} catch (FileNotFoundException ex) {
return StandardCommandManager.genericResponse("RESPONSE_550_REQUESTED_ACTION_NOT_TAKEN");
}
try {
synchronized(DATE_FMT) {
return new CommandResponse(213,
DATE_FMT.format(new Date(reqFile.lastModified())));
}
} catch (FileNotFoundException e) {
return new CommandResponse(550, e.getMessage());
}
//out.print(ftpStatus.getResponse(213, request, user, args));
//} else {
// out.write(ftpStatus.getResponse(550, request, user, null));
//}
}
/**
* <code>MKD <SP> <pathname> <CRLF></code><br>
*
* This command causes the directory specified in the pathname
* to be created as a directory (if the pathname is absolute)
* or as a subdirectory of the current working directory (if
* the pathname is relative).
*
*
* MKD
* 257
* 500, 501, 502, 421, 530, 550
*/
public CommandResponse doMKD(CommandRequest request) {
// argument check
if (!request.hasArgument()) {
return StandardCommandManager.genericResponse("RESPONSE_501_SYNTAX_ERROR");
}
Session session = request.getSession();
String path = VirtualFileSystem.fixPath(request.getArgument());
DirectoryHandle fakeDirectory = request.getCurrentDirectory().getNonExistentDirectoryHandle(path);
String dirName = fakeDirectory.getName();
if (!ListUtils.isLegalFileName(dirName)) {
return StandardCommandManager.genericResponse("RESPONSE_553_REQUESTED_ACTION_NOT_TAKEN");
}
try {
try {
if (!fakeDirectory.getParent().equals(request.getCurrentDirectory()) &&
InodeHandle.isLink(fakeDirectory.getParent().getPath())) {
fakeDirectory = new LinkHandle(fakeDirectory.getParent().getPath())
.getTargetDirectory(session.getUserNull(request.getUser()))
.getNonExistentDirectoryHandle(dirName);
}
} catch (FileNotFoundException e1) {
return new CommandResponse(550, "Parent directory does not exist");
} catch (ObjectNotValidException e) {
return new CommandResponse(550, "Parent directory does not exist");
}
DirectoryHandle newDir;
try {
newDir = fakeDirectory.getParent().createDirectory(session.getUserNull(request.getUser()), dirName);
} catch (FileNotFoundException e) {
return new CommandResponse(550, "Parent directory does not exist");
} catch (PermissionDeniedException e) {
return StandardCommandManager.genericResponse("RESPONSE_530_ACCESS_DENIED");
}
GlobalContext.getEventService().publishAsync(new DirectoryFtpEvent(
session.getUserNull(request.getUser()), "MKD", newDir));
return new CommandResponse(257, "\"" + newDir.getPath() +
"\" created.");
} catch (FileExistsException ex) {
return new CommandResponse(550,
"directory " + dirName + " already exists");
}
}
/**
* <code>PWD <CRLF></code><br>
*
* This command causes the name of the current working
* directory to be returned in the reply.
*/
public CommandResponse doPWD(CommandRequest request) {
return new CommandResponse(257,
"\"" + request.getCurrentDirectory().getPath() +
"\" is current directory");
}
/**
* <code>RMD <SP> <pathname> <CRLF></code><br>
*
* This command causes the directory specified in the pathname
* to be removed as a directory (if the pathname is absolute)
* or as a subdirectory of the current working directory (if
* the pathname is relative).
*/
public CommandResponse doRMD(CommandRequest request) {
return doDELE(request);
}
/**
* <code>RNFR <SP> <pathname> <CRLF></code><br>
*
* This command specifies the old pathname of the file which is
* to be renamed. This command must be immediately followed by
* a "rename to" command specifying the new file pathname.
*
* RNFR
450, 550
500, 501, 502, 421, 530
350
*/
public CommandResponse doRNFR(CommandRequest request) {
// argument check
if (!request.hasArgument()) {
return StandardCommandManager.genericResponse("RESPONSE_501_SYNTAX_ERROR");
}
User user = request.getSession().getUserNull(request.getUser());
try {
request.getSession().setObject(RENAMEFROM, request.getCurrentDirectory().getInodeHandle(request.getArgument(), user));
} catch (FileNotFoundException e) {
return StandardCommandManager.genericResponse("RESPONSE_550_REQUESTED_ACTION_NOT_TAKEN");
}
return new CommandResponse(350, "File exists, ready for destination name");
}
/**
* <code>RNTO <SP> <pathname> <CRLF></code><br>
*
* This command specifies the new pathname of the file
* specified in the immediately preceding "rename from"
* command. Together the two commands cause a file to be
* renamed.
*/
public CommandResponse doRNTO(CommandRequest request) {
// argument check
if (!request.hasArgument()) {
return StandardCommandManager.genericResponse("RESPONSE_501_SYNTAX_ERROR");
}
// set state variables
InodeHandle fromInode = request.getSession().getObject(RENAMEFROM, null);
if (fromInode == null) {
return StandardCommandManager.genericResponse("RESPONSE_503_BAD_SEQUENCE_OF_COMMANDS");
}
String argument = VirtualFileSystem.fixPath(request.getArgument());
if (!(argument.startsWith(VirtualFileSystem.separator))) {
// Not a full path, let's make it one
if (request.getCurrentDirectory().isRoot()) {
argument = VirtualFileSystem.separator + argument;
} else {
argument = request.getCurrentDirectory().getPath() + VirtualFileSystem.separator + argument;
}
}
DirectoryHandle toDir;
String newName;
User user = request.getSession().getUserNull(request.getUser());
try {
toDir = request.getCurrentDirectory().getDirectory(argument, user);
// toDir exists and is a directory, so we're just changing the parent directory and not the name
// unless toInode and fromInode are the same (i.e. a case change)
if (fromInode.isDirectory() && fromInode.equals(toDir)) {
toDir = request.getCurrentDirectory().getDirectory(VirtualFileSystem.stripLast(argument), user);
newName = VirtualFileSystem.getLast(argument);
} else {
// There are two possibilites here, the target is an existing link or a directory
// Check to see if a link with the target name exists
newName = fromInode.getName();
boolean linkRename = false;
DirectoryHandle argParentDir = null;
try {
argParentDir = request.getCurrentDirectory().getDirectory(VirtualFileSystem.stripLast(argument), user);
String linkName = VirtualFileSystem.getLast(argument);
// If a link exists and is the same link as the from inode this is valid
try {
InodeHandle linkHandle = argParentDir.getLink(linkName, user);
if (fromInode.isLink() && fromInode.equals(linkHandle)) {
// Changing case of existing link
toDir = argParentDir;
newName = linkName;
linkRename = true;
}
} catch (FileNotFoundException e2) {
// No link exists so we are moving an inode to a new parent without changing its name
} catch (ObjectNotValidException e2) {
// Target is an existing directory
}
} catch (FileNotFoundException e1) {
// Destination doesn't exist, shouldn't be possible as the full argument does exist
logger.warn("Destination doesn't exist, this shouldn't happen", e1);
return StandardCommandManager.genericResponse("RESPONSE_550_REQUESTED_ACTION_NOT_TAKEN");
} catch (ObjectNotValidException e1) {
// Destination isn't a Directory, shouldn't be possible as the full argument is a dir
logger.warn("Destination isn't a Directory, this shouldn't happen", e1);
return StandardCommandManager.genericResponse("RESPONSE_550_REQUESTED_ACTION_NOT_TAKEN");
}
if (!linkRename && fromInode.isDirectory() && newName.equalsIgnoreCase(VirtualFileSystem.getLast(argument))) {
// Source is a directory and a directory with the same name already exists in the target, the move
// should not be allowed. Rather than returning an error here we will allow the VFS to reject this so that
// permissions can be checked otherwise this could leak knowledge of the contents of parts of the VFS the
// user does not have access to.
toDir = argParentDir;
newName = VirtualFileSystem.getLast(argument);
}
}
} catch (FileNotFoundException e) {
// Directory does not exist, that means they may have specified _renameFrom's new name
// as the last part of the argument
try {
toDir = request.getCurrentDirectory().getDirectory(VirtualFileSystem.stripLast(argument), user);
newName = VirtualFileSystem.getLast(argument);
} catch (FileNotFoundException e1) {
// Destination doesn't exist
logger.debug("Destination doesn't exist", e1);
return StandardCommandManager.genericResponse("RESPONSE_550_REQUESTED_ACTION_NOT_TAKEN");
} catch (ObjectNotValidException e1) {
// Destination isn't a Directory
logger.debug("Destination isn't a Directory", e1);
return StandardCommandManager.genericResponse("RESPONSE_550_REQUESTED_ACTION_NOT_TAKEN");
}
} catch (ObjectNotValidException e) {
// Target exists but is not a dir, this is invalid unless the target is a file and the same
// file as the source (i.e. a case change)
try {
toDir = request.getCurrentDirectory().getDirectory(VirtualFileSystem.stripLast(argument), user);
newName = VirtualFileSystem.getLast(argument);
if (!toDir.equals(fromInode.getParent()) || !newName.equalsIgnoreCase(fromInode.getName())) {
return StandardCommandManager.genericResponse("RESPONSE_553_REQUESTED_ACTION_NOT_TAKEN_FILE_EXISTS");
}
} catch (FileNotFoundException e1) {
// Destination doesn't exist, shouldn't be possible as the full argument does exist
logger.warn("Destination doesn't exist, this shouldn't happen", e1);
return StandardCommandManager.genericResponse("RESPONSE_550_REQUESTED_ACTION_NOT_TAKEN");
} catch (ObjectNotValidException e1) {
// Destination isn't a Directory, shouldn't be possible as the full argument is a dir
logger.warn("Destination isn't a Directory, this shouldn't happen", e1);
return StandardCommandManager.genericResponse("RESPONSE_550_REQUESTED_ACTION_NOT_TAKEN");
}
}
InodeHandle toInode;
if (fromInode.isDirectory()) {
toInode = new DirectoryHandle(toDir.getPath() + VirtualFileSystem.separator + newName);
} else if (fromInode.isFile()) {
toInode = new FileHandle(toDir.getPath() + VirtualFileSystem.separator + newName);
} else if (fromInode.isLink()) {
toInode = new LinkHandle(toDir.getPath() + VirtualFileSystem.separator + newName);
} else {
return new CommandResponse(500, "Someone has extended the VFS beyond File/Directory/Link");
}
try {
/*logger.debug("before rename toInode-" +toInode);
logger.debug("before rename toInode.getPath()-" + toInode.getPath());
logger.debug("before rename toInode.getParent()-" + toInode.getParent());
logger.debug("before rename toInode.getParent().getPath()-" + toInode.getParent().getPath());*/
fromInode.renameTo(request.getSession().getUserNull(request.getUser()), toInode);
} catch (PermissionDeniedException e) {
return StandardCommandManager.genericResponse("RESPONSE_530_ACCESS_DENIED");
} catch (FileNotFoundException e) {
logger.info("FileNotFoundException on renameTo()", e);
return new CommandResponse(500, "FileNotFound - " + e.getMessage());
} catch (FileExistsException e) {
return StandardCommandManager.genericResponse("RESPONSE_553_REQUESTED_ACTION_NOT_TAKEN_FILE_EXISTS");
}
request.getSession().setObject(RENAMETO, toInode);
/*logger.debug("after rename toInode-" +toInode);
logger.debug("after rename toInode.getPath()-" + toInode.getPath());
logger.debug("after rename toInode.getParent()-" + toInode.getParent());
logger.debug("after rename toInode.getParent().getPath()-" + toInode.getParent().getPath());*/
return new CommandResponse(250, request.getCommand().toUpperCase() + " command successful.");
}
public CommandResponse doSITE_CHOWN(CommandRequest request) throws ImproperUsageException {
if (!request.hasArgument()) {
throw new ImproperUsageException();
}
StringTokenizer st = new StringTokenizer(request.getArgument());
if (st.countTokens() < 2) {
throw new ImproperUsageException();
}
String owner = st.nextToken();
String group = null;
boolean recursive = false;
if (owner.equalsIgnoreCase("-r")) {
recursive = true;
owner = st.nextToken();
}
int pos = owner.indexOf(':');
if (pos > 0) {
// Both user and group specified
group = owner.substring(pos + 1);
owner = owner.substring(0, pos);
} else if (pos == 0) {
// First char is ':', only change group
group = owner.substring(1);
owner = null;
}
CommandResponse response = StandardCommandManager.genericResponse("RESPONSE_200_COMMAND_OK");
User user = request.getSession().getUserNull(request.getUser());
if (!st.hasMoreTokens()) {
throw new ImproperUsageException();
}
while (st.hasMoreTokens()) {
try {
InodeHandle file = request.getCurrentDirectory().getInodeHandle(st.nextToken(), user);
if (owner != null) {
file.setUsername(owner);
}
if (group != null) {
file.setGroup(group);
}
if (file.isDirectory() && recursive) {
recursiveCHOWN((DirectoryHandle)file, owner, group, user, response);
}
} catch (FileNotFoundException e) {
response.addComment(e.getMessage());
}
}
return response;
}
private void recursiveCHOWN(DirectoryHandle dir, String owner, String group, User user, CommandResponse response) {
try {
for (InodeHandle inode : dir.getInodeHandles(user)) {
if (owner != null) {
inode.setUsername(owner);
}
if (group != null) {
inode.setGroup(group);
}
if (inode.isDirectory()) {
recursiveCHOWN((DirectoryHandle)inode, owner, group, user, response);
}
}
} catch (FileNotFoundException e) {
response.addComment(e.getMessage());
}
}
public CommandResponse doSITE_LINK(CommandRequest request) throws ImproperUsageException {
if (!request.hasArgument()) {
throw new ImproperUsageException();
}
StringTokenizer st = new StringTokenizer(request.getArgument(),
" ");
if (st.countTokens() != 2) {
return StandardCommandManager.genericResponse("RESPONSE_501_SYNTAX_ERROR");
}
String targetName = st.nextToken();
String linkName = st.nextToken();
User user = request.getSession().getUserNull(request.getUser());
try {
request.getCurrentDirectory().getInodeHandleUnchecked(targetName); // checks if the inode exists.
request.getCurrentDirectory().createLink(user, linkName, targetName); // create the link
} catch (FileExistsException e) {
return StandardCommandManager.genericResponse("RESPONSE_553_REQUESTED_ACTION_NOT_TAKEN_FILE_EXISTS");
} catch (FileNotFoundException e) {
return StandardCommandManager.genericResponse("RESPONSE_550_REQUESTED_ACTION_NOT_TAKEN");
} catch (PermissionDeniedException e) {
return StandardCommandManager.genericResponse("RESPONSE_530_ACCESS_DENIED");
}
return StandardCommandManager.genericResponse("RESPONSE_200_COMMAND_OK");
}
/**
* USAGE: site wipe [-r] <file/directory>
*
* This is similar to the UNIX rm command.
* In glftpd, if you just delete a file, the uploader loses credits and
* upload stats for it. There are many people who didn't like that and
* were unable/too lazy to write a shell script to do it for them, so I
* wrote this command to get them off my back.
*
* If the argument is a file, it will simply be deleted. If it's a
* directory, it and the files it contains will be deleted. If the
* directory contains other directories, the deletion will be aborted.
*
* To remove a directory containing subdirectories, you need to use
* "site wipe -r dirname". BE CAREFUL WHO YOU GIVE ACCESS TO THIS COMMAND.
* Glftpd will check if the parent directory of the file/directory you're
* trying to delete is writable by its owner. If not, wipe will not
* execute, so to protect directories from being wiped, make their parent
* 555.
*
* Also, wipe will only work where you have the right to delete (in
* glftpd.conf). Delete right and parent directory's mode of 755/777/etc
* will cause glftpd to SWITCH TO ROOT UID and wipe the file/directory.
* "site wipe -r /" will not work, but "site wipe -r /incoming" WILL, SO
* BE CAREFUL.
*
* This command will remove the deleted files/directories from the dirlog
* and dupefile databases.
*
* To give access to this command, add "-wipe -user flag =group" to the
* config file (similar to other site commands).
*
* @param request
* @param out
*/
public CommandResponse doSITE_WIPE(CommandRequest request) {
if (!request.hasArgument()) {
return StandardCommandManager.genericResponse("RESPONSE_501_SYNTAX_ERROR");
}
String arg = request.getArgument();
boolean recursive;
CommandResponse response = StandardCommandManager.genericResponse("RESPONSE_200_COMMAND_OK");
if (arg.startsWith("-r ")) {
arg = arg.substring(3);
response.setObject(WIPE_RECURSIVE,true);
recursive = true;
} else {
response.setObject(WIPE_RECURSIVE,false);
recursive = false;
}
response.setObject(WIPE_PATH,VirtualFileSystem.fixPath(arg));
InodeHandle wipeFile;
User user = request.getSession().getUserNull(request.getUser());
try {
wipeFile = request.getCurrentDirectory().getInodeHandle(arg, user);
if (wipeFile.isDirectory() && !recursive) {
if (!((DirectoryHandle) wipeFile).isEmpty(user)) {
return new CommandResponse(550, "Can't wipe, directory not empty");
}
}
if (wipeFile.isLink()) {
InodeHandle linkFile = wipeFile;
wipeFile = ((LinkHandle) wipeFile).getTargetInodeUnchecked();
linkFile.delete(request.getSession().getUserNull(request.getUser()));
}
wipeFile.delete(request.getSession().getUserNull(request.getUser()));
if (wipeFile.isDirectory()) {
GlobalContext.getEventService().publishAsync(
new DirectoryFtpEvent(request.getSession().getUserNull(request.getUser()), "WIPE", (DirectoryHandle)wipeFile));
}
} catch (FileNotFoundException e) {
return StandardCommandManager.genericResponse("RESPONSE_550_REQUESTED_ACTION_NOT_TAKEN");
} catch (PermissionDeniedException e) {
return StandardCommandManager.genericResponse("RESPONSE_550_REQUESTED_ACTION_NOT_TAKEN");
}
return response;
}
/**
* <code>SIZE <SP> <pathname> <CRLF></code><br>
*
* Returns the size of the file in bytes.
*/
public CommandResponse doSIZE(CommandRequest request) {
if (!request.hasArgument()) {
return StandardCommandManager.genericResponse("RESPONSE_501_SYNTAX_ERROR");
}
InodeHandle file;
User user = request.getSession().getUserNull(request.getUser());
try {
file = request.getCurrentDirectory().getInodeHandle(request.getArgument(), user);
return new CommandResponse(213, Long.toString(file.getSize()));
} catch (FileNotFoundException ex) {
return StandardCommandManager.genericResponse("RESPONSE_550_REQUESTED_ACTION_NOT_TAKEN");
}
}
/**
* http://www.southrivertech.com/support/titanftp/webhelp/xcrc.htm
*
* Originally implemented by CuteFTP Pro and Globalscape FTP Server
*/
public CommandResponse doXCRC(CommandRequest request) {
if (!request.hasArgument()) {
return StandardCommandManager.genericResponse("RESPONSE_501_SYNTAX_ERROR");
}
StringTokenizer st = new StringTokenizer(request.getArgument());
FileHandle myFile;
User user = request.getSession().getUserNull(request.getUser());
try {
myFile = request.getCurrentDirectory().getFile(st.nextToken(), user);
} catch (FileNotFoundException e) {
return StandardCommandManager.genericResponse("RESPONSE_550_REQUESTED_ACTION_NOT_TAKEN");
} catch (ObjectNotValidException e) {
return StandardCommandManager.genericResponse("RESPONSE_504_COMMAND_NOT_IMPLEMENTED_FOR_PARM");
}
try {
if (st.hasMoreTokens()) {
if (!st.nextToken().equals("0")
|| !st.nextToken().equals(
Long.toString(myFile.getSize()))) {
return StandardCommandManager.genericResponse("RESPONSE_504_COMMAND_NOT_IMPLEMENTED_FOR_PARM");
}
}
return new CommandResponse(250, "XCRC Successful. "
+ Checksum.formatChecksum(myFile.getCheckSum()));
} catch (NoAvailableSlaveException e1) {
logger.warn("", e1);
return new CommandResponse(550, "NoAvailableSlaveException: "
+ e1.getMessage());
} catch (FileNotFoundException e) {
return StandardCommandManager.genericResponse("RESPONSE_550_REQUESTED_ACTION_NOT_TAKEN");
}
}
public CommandResponse doSITE_FIXSIZE(CommandRequest request) {
long difference = 0;
try {
difference = request.getCurrentDirectory().validateSizeRecursive();
} catch (FileNotFoundException e) {
return new CommandResponse(500, e.getMessage());
}
CommandResponse response = StandardCommandManager.genericResponse("RESPONSE_200_COMMAND_OK");
response.addComment("Difference was " + Bytes.formatBytes(difference));
return response;
}
public CommandResponse doSITE_FIXSLAVECOUNT(CommandRequest request) {
try {
request.getCurrentDirectory().recalcSlaveRefCounts();
} catch (FileNotFoundException e) {
return new CommandResponse(500, e.getMessage());
}
CommandResponse response = StandardCommandManager.genericResponse("RESPONSE_200_COMMAND_OK");
return response;
}
}