Hi, I submitted this a few weeks ago but here it is again since I got no response. If there is somewhere else I should send this, please tell me. This patch implements SSH2_FXF_APPEND in the sftp server. It is a fairly trivial patch and applies against the proper OpenSSH and the Portable edition. I would argue that it is important for OpenSSH to implement SSH2_FXF_APPEND since it is in the spec and clients who expect it to work find that their files are overwritten rather than appended to. I opened a bug for it: https://bugzilla.mindrot.org/show_bug.cgi?id=2159 Some relevant links: http://marc.info/?l=openssh-unix-dev&m=138053388830753&w=2 http://marc.info/?l=openssh-unix-dev&m=123798287811788 http://marc.info/?l=openssh-unix-dev&m=111093206900604 https://bugzilla.gnome.org/show_bug.cgi?id=608910 Thanks -- Ross Lagerwall -------------- next part -------------- Index: sftp-server.c ==================================================================RCS file: /cvs/openssh/sftp-server.c,v retrieving revision 1.114 diff -u -p -r1.114 sftp-server.c --- sftp-server.c 1 Jun 2013 21:31:19 -0000 1.114 +++ sftp-server.c 30 Sep 2013 08:16:57 -0000 @@ -130,6 +130,8 @@ flags_from_portable(int pflags) } else if (pflags & SSH2_FXF_WRITE) { flags = O_WRONLY; } + if (pflags & SSH2_FXF_APPEND) + flags |= O_APPEND; if (pflags & SSH2_FXF_CREAT) flags |= O_CREAT; if (pflags & SSH2_FXF_TRUNC) @@ -156,6 +158,8 @@ string_from_portable(int pflags) PAPPEND("READ") if (pflags & SSH2_FXF_WRITE) PAPPEND("WRITE") + if (pflags & SSH2_FXF_APPEND) + PAPPEND("APPEND") if (pflags & SSH2_FXF_CREAT) PAPPEND("CREATE") if (pflags & SSH2_FXF_TRUNC) @@ -179,6 +183,7 @@ struct Handle { int use; DIR *dirp; int fd; + int flags; char *name; u_int64_t bytes_read, bytes_write; int next_unused; @@ -202,7 +207,7 @@ static void handle_unused(int i) } static int -handle_new(int use, const char *name, int fd, DIR *dirp) +handle_new(int use, const char *name, int fd, int flags, DIR *dirp) { int i; @@ -220,6 +225,7 @@ handle_new(int use, const char *name, in handles[i].use = use; handles[i].dirp = dirp; handles[i].fd = fd; + handles[i].flags = flags; handles[i].name = xstrdup(name); handles[i].bytes_read = handles[i].bytes_write = 0; @@ -282,6 +288,14 @@ handle_to_fd(int handle) return -1; } +static int +handle_to_flags(int handle) +{ + if (handle_is_ok(handle, HANDLE_FILE)) + return handles[handle].flags; + return -1; +} + static void handle_update_read(int handle, ssize_t bytes) { @@ -567,7 +581,7 @@ process_open(void) if (fd < 0) { status = errno_to_portable(errno); } else { - handle = handle_new(HANDLE_FILE, name, fd, NULL); + handle = handle_new(HANDLE_FILE, name, fd, flags, NULL); if (handle < 0) { close(fd); } else { @@ -660,7 +674,8 @@ process_write(void) else if (readonly) status = SSH2_FX_PERMISSION_DENIED; else { - if (lseek(fd, off, SEEK_SET) < 0) { + if (!(handle_to_flags(handle) & O_APPEND) && + lseek(fd, off, SEEK_SET) < 0) { status = errno_to_portable(errno); error("process_write: seek failed"); } else { @@ -893,7 +908,7 @@ process_opendir(void) if (dirp == NULL) { status = errno_to_portable(errno); } else { - handle = handle_new(HANDLE_DIR, path, 0, dirp); + handle = handle_new(HANDLE_DIR, path, 0, 0, dirp); if (handle < 0) { closedir(dirp); } else {