if (version <= 4) {
String path = buffer.getString();
int pflags = buffer.getInt();
// attrs
try {
SshFile file = resolveFile(path);
if (file.doesExist()) {
if (((pflags & SSH_FXF_CREAT) != 0) && ((pflags & SSH_FXF_EXCL) != 0)) {
sendStatus(id, SSH_FX_FILE_ALREADY_EXISTS, path);
return;
}
} else {
if (((pflags & SSH_FXF_CREAT) != 0)) {
if (!file.isWritable()) {
sendStatus(id, SSH_FX_FAILURE, "Can not create " + path);
return;
}
file.create();
}
}
String acc = ((pflags & (SSH_FXF_READ | SSH_FXF_WRITE)) != 0 ? "r" : "") +
((pflags & SSH_FXF_WRITE) != 0 ? "w" : "");
if ((pflags & SSH_FXF_TRUNC) != 0) {
file.truncate();
}
String handle = UUID.randomUUID().toString();
handles.put(handle, new FileHandle(file, pflags)); // handle flags conversion
sendHandle(id, handle);
} catch (IOException e) {
sendStatus(id, SSH_FX_FAILURE, e.getMessage());
}
} else {
String path = buffer.getString();
int acc = buffer.getInt();
int flags = buffer.getInt();
// attrs
try {
SshFile file = resolveFile(path);
switch (flags & SSH_FXF_ACCESS_DISPOSITION) {
case SSH_FXF_CREATE_NEW: {
if (file.doesExist()) {
sendStatus(id, SSH_FX_FILE_ALREADY_EXISTS, path);
return;
} else if (!file.isWritable()) {
sendStatus(id, SSH_FX_FAILURE, "Can not create " + path);
}
file.create();
break;
}
case SSH_FXF_CREATE_TRUNCATE: {
if (file.doesExist()) {
sendStatus(id, SSH_FX_FILE_ALREADY_EXISTS, path);
return;
} else if (!file.isWritable()) {
sendStatus(id, SSH_FX_FAILURE, "Can not create " + path);
}
file.truncate();
break;
}
case SSH_FXF_OPEN_EXISTING: {
if (!file.doesExist()) {
if (!file.getParentFile().doesExist()) {
sendStatus(id, SSH_FX_NO_SUCH_PATH, path);
} else {
sendStatus(id, SSH_FX_NO_SUCH_FILE, path);
}
return;
}
break;
}
case SSH_FXF_OPEN_OR_CREATE: {
if (!file.doesExist()) {
file.create();
}
break;
}
case SSH_FXF_TRUNCATE_EXISTING: {
if (!file.doesExist()) {
if (!file.getParentFile().doesExist()) {
sendStatus(id, SSH_FX_NO_SUCH_PATH, path);
} else {
sendStatus(id, SSH_FX_NO_SUCH_FILE, path);
}
return;
}
file.truncate();
break;
}
default:
throw new IllegalArgumentException("Unsupported open mode: " + flags);
}
String handle = UUID.randomUUID().toString();
handles.put(handle, new FileHandle(file, flags));
sendHandle(id, handle);
} catch (IOException e) {
sendStatus(id, SSH_FX_FAILURE, e.getMessage());
}
}
break;
}
case SSH_FXP_CLOSE: {
String handle = buffer.getString();
try {
Handle h = handles.get(handle);
if (h == null) {
sendStatus(id, SSH_FX_INVALID_HANDLE, handle, "");
} else {
handles.remove(handle);
h.close();
sendStatus(id, SSH_FX_OK, "", "");
}
} catch (IOException e) {
sendStatus(id, SSH_FX_FAILURE, e.getMessage());
}
break;
}
case SSH_FXP_READ: {
String handle = buffer.getString();
long offset = buffer.getLong();
int len = buffer.getInt();
try {
Handle p = handles.get(handle);
if (!(p instanceof FileHandle)) {
sendStatus(id, SSH_FX_INVALID_HANDLE, handle);
} else {
FileHandle fh = (FileHandle) p;
byte[] b = new byte[Math.min(len, 1024 * 32)];
len = fh.read(b, offset);
if (len >= 0) {
Buffer buf = new Buffer(len + 5);
buf.putByte((byte) SSH_FXP_DATA);
buf.putInt(id);
buf.putBytes(b, 0, len);
if (version >= 6) {
buf.putBoolean(len == 0);
}
send(buf);
} else {
sendStatus(id, SSH_FX_EOF, "");
}
}
} catch (IOException e) {
sendStatus(id, SSH_FX_FAILURE, e.getMessage());
}
break;
}
case SSH_FXP_WRITE: {
String handle = buffer.getString();
long offset = buffer.getLong();
byte[] data = buffer.getBytes();
try {
Handle p = handles.get(handle);
if (!(p instanceof FileHandle)) {
sendStatus(id, SSH_FX_INVALID_HANDLE, handle);
} else {
FileHandle fh = (FileHandle) p;
fh.write(data, offset);
SshFile sshFile = fh.getFile();
sshFile.setLastModified(new Date().getTime());
sendStatus(id, SSH_FX_OK, "");
}
} catch (IOException e) {
sendStatus(id, SSH_FX_FAILURE, e.getMessage());
}
break;
}
case SSH_FXP_LSTAT:
case SSH_FXP_STAT: {
String path = buffer.getString();
try {
SshFile p = resolveFile(path);
sendAttrs(id, p);
} catch (FileNotFoundException e) {
sendStatus(id, SSH_FX_NO_SUCH_FILE, e.getMessage());
} catch (IOException e) {
sendStatus(id, SSH_FX_FAILURE, e.getMessage());
}
break;
}
case SSH_FXP_FSTAT: {
String handle = buffer.getString();
try {
Handle p = handles.get(handle);
if (p == null) {
sendStatus(id, SSH_FX_INVALID_HANDLE, handle);
} else {
sendAttrs(id, p.getFile());
}
} catch (FileNotFoundException e) {
sendStatus(id, SSH_FX_NO_SUCH_FILE, e.getMessage());
} catch (IOException e) {
sendStatus(id, SSH_FX_FAILURE, e.getMessage());
}
break;
}
case SSH_FXP_OPENDIR: {
String path = buffer.getString();
try {
SshFile p = resolveFile(path);
if (!p.doesExist()) {
sendStatus(id, SSH_FX_NO_SUCH_FILE, path);
} else if (!p.isDirectory()) {
sendStatus(id, SSH_FX_NOT_A_DIRECTORY, path);
} else if (!p.isReadable()) {
sendStatus(id, SSH_FX_PERMISSION_DENIED, path);
} else {
String handle = UUID.randomUUID().toString();
handles.put(handle, new DirectoryHandle(p));
sendHandle(id, handle);
}
} catch (IOException e) {
sendStatus(id, SSH_FX_FAILURE, e.getMessage());
}
break;
}
case SSH_FXP_READDIR: {
String handle = buffer.getString();
try {
Handle p = handles.get(handle);
if (!(p instanceof DirectoryHandle)) {
sendStatus(id, SSH_FX_INVALID_HANDLE, handle);
} else if (((DirectoryHandle) p).isDone()) {
sendStatus(id, SSH_FX_EOF, "", "");
} else if (!p.getFile().doesExist()) {
sendStatus(id, SSH_FX_NO_SUCH_FILE, p.getFile().getAbsolutePath());
} else if (!p.getFile().isDirectory()) {
sendStatus(id, SSH_FX_NOT_A_DIRECTORY, p.getFile().getAbsolutePath());
} else if (!p.getFile().isReadable()) {
sendStatus(id, SSH_FX_PERMISSION_DENIED, p.getFile().getAbsolutePath());
} else {
DirectoryHandle dh = (DirectoryHandle) p;
if (dh.hasNext()) {
// There is at least one file in the directory.
// Send only a few files at a time to not create packets of a too
// large size or have a timeout to occur.
sendName(id, dh);
if (!dh.hasNext()) {
// if no more files to send
dh.setDone(true);
dh.clearFileList();
}
} else {
// empty directory
dh.setDone(true);
dh.clearFileList();
sendStatus(id, SSH_FX_EOF, "", "");
}
}
} catch (IOException e) {
sendStatus(id, SSH_FX_FAILURE, e.getMessage());
}
break;
}
case SSH_FXP_REMOVE: {
String path = buffer.getString();
try {
SshFile p = resolveFile(path);
if (!p.doesExist()) {
sendStatus(id, SSH_FX_NO_SUCH_FILE, p.getAbsolutePath());
} else if (p.isDirectory()) {
sendStatus(id, SSH_FX_FILE_IS_A_DIRECTORY, p.getAbsolutePath());
} else if (!p.delete()) {
sendStatus(id, SSH_FX_FAILURE, "Failed to delete file");
} else {
sendStatus(id, SSH_FX_OK, "");
}
} catch (IOException e) {
sendStatus(id, SSH_FX_FAILURE, e.getMessage());
}
break;
}
case SSH_FXP_MKDIR: {
String path = buffer.getString();
// attrs
try {
SshFile p = resolveFile(path);
if (p.doesExist()) {
if (p.isDirectory()) {
sendStatus(id, SSH_FX_FILE_ALREADY_EXISTS, p.getAbsolutePath());
} else {
sendStatus(id, SSH_FX_NOT_A_DIRECTORY, p.getAbsolutePath());
}
} else if (!p.isWritable()) {
sendStatus(id, SSH_FX_PERMISSION_DENIED, p.getAbsolutePath());
} else if (!p.mkdir()) {
throw new IOException("Error creating dir " + path);
} else {
sendStatus(id, SSH_FX_OK, "");
}
} catch (IOException e) {
sendStatus(id, SSH_FX_FAILURE, e.getMessage());
}
break;
}
case SSH_FXP_RMDIR: {
String path = buffer.getString();
// attrs
try {
SshFile p = resolveFile(path);
if (p.isDirectory()) {
if (p.doesExist()) {
if (p.listSshFiles().size() == 0) {
if (p.delete()) {
sendStatus(id, SSH_FX_OK, "");
} else {
sendStatus(id, SSH_FX_FAILURE, "Unable to delete directory " + path);
}
} else {
sendStatus(id, SSH_FX_DIR_NOT_EMPTY, path);
}
} else {
sendStatus(id, SSH_FX_NO_SUCH_PATH, path);
}
} else {
sendStatus(id, SSH_FX_NOT_A_DIRECTORY, p.getAbsolutePath());
}
} catch (IOException e) {
sendStatus(id, SSH_FX_FAILURE, e.getMessage());
}
break;
}
case SSH_FXP_REALPATH: {
String path = buffer.getString();
if (path.trim().length() == 0) {
path = ".";
}
// TODO: handle optional args
try {
SshFile p = resolveFile(path);
sendPath(id, p);
} catch (FileNotFoundException e) {
e.printStackTrace();
sendStatus(id, SSH_FX_NO_SUCH_FILE, e.getMessage());
} catch (IOException e) {
e.printStackTrace();
sendStatus(id, SSH_FX_FAILURE, e.getMessage());
}
break;
}
case SSH_FXP_RENAME: {
String oldPath = buffer.getString();
String newPath = buffer.getString();
try {
SshFile o = resolveFile(oldPath);
SshFile n = resolveFile(newPath);
if (!o.doesExist()) {
sendStatus(id, SSH_FX_NO_SUCH_FILE, o.getAbsolutePath());
} else if (n.doesExist()) {
sendStatus(id, SSH_FX_FILE_ALREADY_EXISTS, n.getAbsolutePath());
} else if (!o.move(n)) {
sendStatus(id, SSH_FX_FAILURE, "Failed to rename file");
} else {
sendStatus(id, SSH_FX_OK, "");
}