String path = buffer.getString();
int pflags = buffer.getInt();
Map<SshFile.Attribute, Object> attrs = readAttrs(buffer);
log.debug("Received SSH_FXP_OPEN (path={}, pflags={}, attrs={})", new Object[] { path, pflags, attrs });
try {
SshFile file = resolveFile(path);
if (file.doesExist()) {
if (((pflags & SSH_FXF_CREAT) != 0) && ((pflags & SSH_FXF_EXCL) != 0)) {
sendStatus(id, SSH_FX_FAILURE, path);
return;
}
} else {
if (((pflags & SSH_FXF_CREAT) != 0)) {
if (!file.isWritable()) {
sendStatus(id, SSH_FX_PERMISSION_DENIED, "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();
}
if ((pflags & SSH_FXF_CREAT) != 0) {
file.setAttributes(attrs);
}
String handle = UUID.randomUUID().toString();
handles.put(handle, new FileHandle(file));
sendHandle(id, handle);
} catch (IOException e) {
sendStatus(id, SSH_FX_FAILURE, e.getMessage() == null ? "" : e.getMessage());
}
break;
}
case SSH_FXP_CLOSE: {
String handle = buffer.getString();
log.debug("Received SSH_FXP_CLOSE (handle={})", handle);
try {
Handle h = handles.get(handle);
if (h == null) {
sendStatus(id, SSH_FX_FAILURE, 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();
log.debug("Received SSH_FXP_READ (handle={}, offset={}, length={})", new Object[] { handle, offset, len });
try {
Handle p = handles.get(handle);
if (!(p instanceof FileHandle)) {
sendStatus(id, SSH_FX_FAILURE, handle);
} else {
FileHandle fh = (FileHandle) p;
byte[] b = new byte[Math.min(len, Buffer.MAX_LEN)];
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);
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();
log.debug("Received SSH_FXP_WRITE (handle={}, offset={}, data=byte[{}])", new Object[] { handle, offset, data.length });
try {
Handle p = handles.get(handle);
if (!(p instanceof FileHandle)) {
sendStatus(id, SSH_FX_FAILURE, 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: {
String path = buffer.getString();
log.debug("Received SSH_FXP_LSTAT (path={})", path);
try {
SshFile p = resolveFile(path);
sendAttrs(id, p, false);
} 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();
log.debug("Received SSH_FXP_FSTAT (handle={})", handle);
try {
Handle p = handles.get(handle);
if (p == null) {
sendStatus(id, SSH_FX_FAILURE, handle);
} else {
sendAttrs(id, p.getFile(), true);
}
} 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_SETSTAT: {
String path = buffer.getString();
Map<SshFile.Attribute, Object> attrs = readAttrs(buffer);
log.debug("Received SSH_FXP_SETSTAT (path={}, attrs={})", path, attrs);
try {
SshFile p = resolveFile(path);
p.setAttributes(attrs);
sendStatus(id, SSH_FX_OK, "");
} catch (FileNotFoundException e) {
sendStatus(id, SSH_FX_NO_SUCH_FILE, e.getMessage());
} catch (IOException e) {
sendStatus(id, SSH_FX_FAILURE, e.getMessage());
} catch (UnsupportedOperationException e) {
sendStatus(id, SSH_FX_FAILURE, "");
}
break;
}
case SSH_FXP_FSETSTAT: {
String handle = buffer.getString();
Map<SshFile.Attribute, Object> attrs = readAttrs(buffer);
log.debug("Received SSH_FXP_FSETSTAT (handle={}, attrs={})", handle, attrs);
try {
Handle p = handles.get(handle);
if (p == null) {
sendStatus(id, SSH_FX_FAILURE, handle);
} else {
p.getFile().setAttributes(attrs);
sendStatus(id, SSH_FX_OK, "");
}
} catch (FileNotFoundException e) {
sendStatus(id, SSH_FX_NO_SUCH_FILE, e.getMessage());
} catch (IOException e) {
sendStatus(id, SSH_FX_FAILURE, e.getMessage());
} catch (UnsupportedOperationException e) {
sendStatus(id, SSH_FX_FAILURE, e.getMessage());
}
break;
}
case SSH_FXP_OPENDIR: {
String path = buffer.getString();
log.debug("Received SSH_FXP_OPENDIR (path={})", path);
try {
SshFile p = resolveFile(path);
if (!p.doesExist()) {
sendStatus(id, SSH_FX_NO_SUCH_FILE, path);
} else if (!p.isDirectory()) {
sendStatus(id, SSH_FX_NO_SUCH_FILE, 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();
log.debug("Received SSH_FXP_READDIR (handle={})", handle);
try {
Handle p = handles.get(handle);
if (!(p instanceof DirectoryHandle)) {
sendStatus(id, SSH_FX_FAILURE, 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_NO_SUCH_FILE, 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();
log.debug("Received SSH_FXP_REMOVE (path={})", path);
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_NO_SUCH_FILE, 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();
log.debug("Received SSH_FXP_MKDIR (path={})", path);
// attrs
try {
SshFile p = resolveFile(path);
if (p.doesExist()) {
if (p.isDirectory()) {
sendStatus(id, SSH_FX_FAILURE, p.getAbsolutePath());
} else {
sendStatus(id, SSH_FX_NO_SUCH_FILE, 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();
log.debug("Received SSH_FXP_RMDIR (path={})", path);
// 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_FAILURE, path);
}
} else {
sendStatus(id, SSH_FX_NO_SUCH_FILE, path);
}
} else {
sendStatus(id, SSH_FX_NO_SUCH_FILE, p.getAbsolutePath());
}
} catch (IOException e) {
sendStatus(id, SSH_FX_FAILURE, e.getMessage());
}
break;
}
case SSH_FXP_REALPATH: {
String path = buffer.getString();
log.debug("Received SSH_FXP_REALPATH (path={})", path);
if (path.trim().length() == 0) {
path = ".";
}
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_STAT: {
String path = buffer.getString();
log.debug("Received SSH_FXP_STAT (path={})", path);
try {
SshFile p = resolveFile(path);
sendAttrs(id, p, true);
} 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_RENAME: {
String oldPath = buffer.getString();
String newPath = buffer.getString();
log.debug("Received SSH_FXP_RENAME (oldPath={}, newPath={})", oldPath, newPath);
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_FAILURE, n.getAbsolutePath());
} else if (!o.move(n)) {
sendStatus(id, SSH_FX_FAILURE, "Failed to rename file");
} else {
sendStatus(id, SSH_FX_OK, "");
}
} catch (IOException e) {
sendStatus(id, SSH_FX_FAILURE, e.getMessage());
}
break;
}
case SSH_FXP_READLINK: {
String path = buffer.getString();
log.debug("Received SSH_FXP_READLINK (path={})", path);
try {
SshFile f = resolveFile(path);
String l = f.readSymbolicLink();
sendLink(id, l);
} catch (UnsupportedOperationException e) {
sendStatus(id, SSH_FX_OP_UNSUPPORTED, "Command " + type + " is unsupported or not implemented");
} catch (IOException e) {
sendStatus(id, SSH_FX_FAILURE, e.getMessage());