Bugzilla – Attachment 2351 Details for
Bug 1798
Add fsync() support to sftp/sftp-server
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Updated to -current
fsync.diff (text/plain), 17.44 KB, created by
Damien Miller
on 2013-10-11 14:23:14 AEDT
(
hide
)
Description:
Updated to -current
Filename:
MIME Type:
Creator:
Damien Miller
Created:
2013-10-11 14:23:14 AEDT
Size:
17.44 KB
patch
obsolete
>Index: PROTOCOL >=================================================================== >RCS file: /cvs/src/usr.bin/ssh/PROTOCOL,v >retrieving revision 1.20 >diff -u -p -r1.20 PROTOCOL >--- PROTOCOL 8 Jan 2013 18:49:04 -0000 1.20 >+++ PROTOCOL 11 Oct 2013 03:20:48 -0000 >@@ -331,4 +331,18 @@ link(oldpath, newpath) and will respond > This extension is advertised in the SSH_FXP_VERSION hello with version > "1". > >+10. sftp: Extension request "fsync@openssh.com" >+ >+This request asks the server to call fsync(2) on an open file handle. >+ >+ uint32 id >+ string "hardlink@openssh.com" >+ string handle >+ >+One receiving this request, a server will call fsync(handle_fd) and will >+respond with a SSH_FXP_STATUS message. >+ >+This extension is advertised in the SSH_FXP_VERSION hello with version >+"1". >+ > $OpenBSD: PROTOCOL,v 1.20 2013/01/08 18:49:04 markus Exp $ >Index: sftp-client.c >=================================================================== >RCS file: /cvs/src/usr.bin/ssh/sftp-client.c,v >retrieving revision 1.106 >diff -u -p -r1.106 sftp-client.c >--- sftp-client.c 11 Oct 2013 02:52:23 -0000 1.106 >+++ sftp-client.c 11 Oct 2013 03:20:48 -0000 >@@ -69,6 +69,7 @@ struct sftp_conn { > #define SFTP_EXT_STATVFS 0x00000002 > #define SFTP_EXT_FSTATVFS 0x00000004 > #define SFTP_EXT_HARDLINK 0x00000008 >+#define SFTP_EXT_FSYNC 0x00000010 > u_int exts; > u_int64_t limit_kbps; > struct bwlimit bwlimit_in, bwlimit_out; >@@ -381,6 +382,10 @@ do_init(int fd_in, int fd_out, u_int tra > strcmp(value, "1") == 0) { > ret->exts |= SFTP_EXT_HARDLINK; > known = 1; >+ } else if (strcmp(name, "fsync@openssh.com") == 0 && >+ strcmp(value, "1") == 0) { >+ ret->exts |= SFTP_EXT_FSYNC; >+ known = 1; > } > if (known) { > debug2("Server supports extension \"%s\" revision %s", >@@ -862,6 +867,36 @@ do_symlink(struct sftp_conn *conn, char > return(status); > } > >+int >+do_fsync(struct sftp_conn *conn, char *handle, u_int handle_len) >+{ >+ Buffer msg; >+ u_int status, id; >+ >+ /* Silently return if the extension is not supported */ >+ if ((conn->exts & SFTP_EXT_FSYNC) == 0) >+ return -1; >+ >+ buffer_init(&msg); >+ >+ /* Send fsync request */ >+ id = conn->msg_id++; >+ >+ buffer_put_char(&msg, SSH2_FXP_EXTENDED); >+ buffer_put_int(&msg, id); >+ buffer_put_cstring(&msg, "fsync@openssh.com"); >+ buffer_put_string(&msg, handle, handle_len); >+ send_msg(conn, &msg); >+ debug3("Sent message fsync@openssh.com I:%u", id); >+ buffer_free(&msg); >+ >+ status = get_status(conn, id); >+ if (status != SSH2_FX_OK) >+ error("Couldn't sync file: %s", fx2txt(status)); >+ >+ return status; >+} >+ > #ifdef notyet > char * > do_readlink(struct sftp_conn *conn, char *path) >@@ -984,7 +1019,7 @@ send_read_request(struct sftp_conn *conn > > int > do_download(struct sftp_conn *conn, char *remote_path, char *local_path, >- Attrib *a, int preserve_flag, int resume_flag) >+ Attrib *a, int preserve_flag, int resume_flag, int fsync_flag) > { > Attrib junk; > Buffer msg; >@@ -1240,6 +1275,12 @@ do_download(struct sftp_conn *conn, char > error("Can't set times on \"%s\": %s", > local_path, strerror(errno)); > } >+ if (fsync_flag) { >+ debug("syncing \"%s\"", local_path); >+ if (fsync(local_fd) == -1) >+ error("Couldn't sync file \"%s\": %s", >+ local_path, strerror(errno)); >+ } > } > close(local_fd); > buffer_free(&msg); >@@ -1250,7 +1291,8 @@ do_download(struct sftp_conn *conn, char > > static int > download_dir_internal(struct sftp_conn *conn, char *src, char *dst, int depth, >- Attrib *dirattrib, int preserve_flag, int print_flag, int resume_flag) >+ Attrib *dirattrib, int preserve_flag, int print_flag, int resume_flag, >+ int fsync_flag) > { > int i, ret = 0; > SFTP_DIRENT **dir_entries; >@@ -1303,11 +1345,12 @@ download_dir_internal(struct sftp_conn * > continue; > if (download_dir_internal(conn, new_src, new_dst, > depth + 1, &(dir_entries[i]->a), preserve_flag, >- print_flag, resume_flag) == -1) >+ print_flag, resume_flag, fsync_flag) == -1) > ret = -1; > } else if (S_ISREG(dir_entries[i]->a.perm) ) { > if (do_download(conn, new_src, new_dst, >- &(dir_entries[i]->a), preserve_flag, resume_flag) == -1) { >+ &(dir_entries[i]->a), preserve_flag, >+ resume_flag, fsync_flag) == -1) { > error("Download of file %s to %s failed", > new_src, new_dst); > ret = -1; >@@ -1340,7 +1383,8 @@ download_dir_internal(struct sftp_conn * > > int > download_dir(struct sftp_conn *conn, char *src, char *dst, >- Attrib *dirattrib, int preserve_flag, int print_flag, int resume_flag) >+ Attrib *dirattrib, int preserve_flag, int print_flag, >+ int resume_flag, int fsync_flag) > { > char *src_canon; > int ret; >@@ -1351,14 +1395,14 @@ download_dir(struct sftp_conn *conn, cha > } > > ret = download_dir_internal(conn, src_canon, dst, 0, >- dirattrib, preserve_flag, print_flag, resume_flag); >+ dirattrib, preserve_flag, print_flag, resume_flag, fsync_flag); > free(src_canon); > return ret; > } > > int > do_upload(struct sftp_conn *conn, char *local_path, char *remote_path, >- int preserve_flag) >+ int preserve_flag, int fsync_flag) > { > int local_fd; > int status = SSH2_FX_OK; >@@ -1533,6 +1577,9 @@ do_upload(struct sftp_conn *conn, char * > if (preserve_flag) > do_fsetstat(conn, handle, handle_len, &a); > >+ if (fsync_flag) >+ (void)do_fsync(conn, handle, handle_len); >+ > if (do_close(conn, handle, handle_len) != SSH2_FX_OK) > status = -1; > free(handle); >@@ -1542,7 +1589,7 @@ do_upload(struct sftp_conn *conn, char * > > static int > upload_dir_internal(struct sftp_conn *conn, char *src, char *dst, int depth, >- int preserve_flag, int print_flag) >+ int preserve_flag, int print_flag, int fsync_flag) > { > int ret = 0, status; > DIR *dirp; >@@ -1611,11 +1658,12 @@ upload_dir_internal(struct sftp_conn *co > continue; > > if (upload_dir_internal(conn, new_src, new_dst, >- depth + 1, preserve_flag, print_flag) == -1) >+ depth + 1, preserve_flag, print_flag, >+ fsync_flag) == -1) > ret = -1; > } else if (S_ISREG(sb.st_mode)) { > if (do_upload(conn, new_src, new_dst, >- preserve_flag) == -1) { >+ preserve_flag, fsync_flag) == -1) { > error("Uploading of file %s to %s failed!", > new_src, new_dst); > ret = -1; >@@ -1634,7 +1682,7 @@ upload_dir_internal(struct sftp_conn *co > > int > upload_dir(struct sftp_conn *conn, char *src, char *dst, int preserve_flag, >- int print_flag) >+ int print_flag, int fsync_flag) > { > char *dst_canon; > int ret; >@@ -1645,7 +1693,8 @@ upload_dir(struct sftp_conn *conn, char > } > > ret = upload_dir_internal(conn, src, dst_canon, 0, preserve_flag, >- print_flag); >+ print_flag, fsync_flag); >+ > free(dst_canon); > return ret; > } >Index: sftp-client.h >=================================================================== >RCS file: /cvs/src/usr.bin/ssh/sftp-client.h,v >retrieving revision 1.23 >diff -u -p -r1.23 sftp-client.h >--- sftp-client.h 11 Oct 2013 02:53:45 -0000 1.23 >+++ sftp-client.h 11 Oct 2013 03:20:48 -0000 >@@ -100,29 +100,33 @@ int do_hardlink(struct sftp_conn *, char > /* Rename 'oldpath' to 'newpath' */ > int do_symlink(struct sftp_conn *, char *, char *); > >+/* Call fsync() on open file 'handle' */ >+int do_fsync(struct sftp_conn *conn, char *, u_int); >+ > /* > * Download 'remote_path' to 'local_path'. Preserve permissions and times > * if 'pflag' is set > */ >-int do_download(struct sftp_conn *, char *, char *, Attrib *, int, int); >+int do_download(struct sftp_conn *, char *, char *, Attrib *, int, int, int); > > /* > * Recursively download 'remote_directory' to 'local_directory'. Preserve > * times if 'pflag' is set > */ >-int download_dir(struct sftp_conn *, char *, char *, Attrib *, int, int, int); >+int download_dir(struct sftp_conn *, char *, char *, Attrib *, int, >+ int, int, int); > > /* > * Upload 'local_path' to 'remote_path'. Preserve permissions and times > * if 'pflag' is set > */ >-int do_upload(struct sftp_conn *, char *, char *, int); >+int do_upload(struct sftp_conn *, char *, char *, int, int); > > /* > * Recursively upload 'local_directory' to 'remote_directory'. Preserve > * times if 'pflag' is set > */ >-int upload_dir(struct sftp_conn *, char *, char *, int, int); >+int upload_dir(struct sftp_conn *, char *, char *, int, int, int); > > /* Concatenate paths, taking care of slashes. Caller must free result. */ > char *path_append(char *, char *); >Index: sftp-server.c >=================================================================== >RCS file: /cvs/src/usr.bin/ssh/sftp-server.c,v >retrieving revision 1.99 >diff -u -p -r1.99 sftp-server.c >--- sftp-server.c 10 Oct 2013 00:53:25 -0000 1.99 >+++ sftp-server.c 11 Oct 2013 03:20:48 -0000 >@@ -103,6 +103,7 @@ static void process_extended_posix_renam > static void process_extended_statvfs(u_int32_t id); > static void process_extended_fstatvfs(u_int32_t id); > static void process_extended_hardlink(u_int32_t id); >+static void process_extended_fsync(u_int32_t id); > static void process_extended(u_int32_t id); > > struct sftp_handler { >@@ -143,6 +144,7 @@ struct sftp_handler extended_handlers[] > { "statvfs", "statvfs@openssh.com", 0, process_extended_statvfs, 0 }, > { "fstatvfs", "fstatvfs@openssh.com", 0, process_extended_fstatvfs, 0 }, > { "hardlink", "hardlink@openssh.com", 0, process_extended_hardlink, 1 }, >+ { "fsync", "fsync@openssh.com", 0, process_extended_fsync, 1 }, > { NULL, NULL, 0, NULL, 0 } > }; > >@@ -629,6 +631,9 @@ process_init(void) > /* hardlink extension */ > buffer_put_cstring(&msg, "hardlink@openssh.com"); > buffer_put_cstring(&msg, "1"); /* version */ >+ /* fsync extension */ >+ buffer_put_cstring(&msg, "fsync@openssh.com"); >+ buffer_put_cstring(&msg, "1"); /* version */ > send_msg(&msg); > buffer_free(&msg); > } >@@ -1252,6 +1257,23 @@ process_extended_hardlink(u_int32_t id) > send_status(id, status); > free(oldpath); > free(newpath); >+} >+ >+static void >+process_extended_fsync(u_int32_t id) >+{ >+ int handle, fd, ret, status = SSH2_FX_OP_UNSUPPORTED; >+ >+ handle = get_handle(); >+ debug3("request %u: fsync (handle %u)", id, handle); >+ verbose("fsync \"%s\"", handle_to_name(handle)); >+ if ((fd = handle_to_fd(handle)) < 0) >+ status = SSH2_FX_NO_SUCH_FILE; >+ else if (handle_is_ok(handle, HANDLE_FILE)) { >+ ret = fsync(fd); >+ status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK; >+ } >+ send_status(id, status); > } > > static void >Index: sftp.1 >=================================================================== >RCS file: /cvs/src/usr.bin/ssh/sftp.1,v >retrieving revision 1.94 >diff -u -p -r1.94 sftp.1 >--- sftp.1 7 Aug 2013 06:24:51 -0000 1.94 >+++ sftp.1 11 Oct 2013 03:20:48 -0000 >@@ -31,7 +31,7 @@ > .Sh SYNOPSIS > .Nm sftp > .Bk -words >-.Op Fl 1246aCpqrv >+.Op Fl 1246aCfpqrv > .Op Fl B Ar buffer_size > .Op Fl b Ar batchfile > .Op Fl c Ar cipher >@@ -164,6 +164,10 @@ per-user configuration file for > .Xr ssh 1 . > This option is directly passed to > .Xr ssh 1 . >+.It Fl f >+Requests that files be flushed to disk immediately after transfer. >+When uploading files, this feature is only enabled if the server >+implements the "fsync@openssh.com" extension. > .It Fl i Ar identity_file > Selects the file from which the identity (private key) for public key > authentication is read. >@@ -348,7 +352,7 @@ extension. > Quit > .Nm sftp . > .It Xo Ic get >-.Op Fl aPpr >+.Op Fl afPpr > .Ar remote-path > .Op Ar local-path > .Xc >@@ -376,6 +380,13 @@ the remote copy. > If the remote file contents differ from the partial local copy then the > resultant file is likely to be corrupt. > .Pp >+If the >+.Fl f >+flag is specified, then >+.Xr fsync 2 >+will ba called after the file transfer has completed to flush the file >+to disk. >+.Pp > If either the > .Fl P > or >@@ -479,7 +490,7 @@ Create remote directory specified by > .It Ic progress > Toggle display of progress meter. > .It Xo Ic put >-.Op Fl Ppr >+.Op Fl fPpr > .Ar local-path > .Op Ar remote-path > .Xc >@@ -497,6 +508,14 @@ If it does and > is specified, then > .Ar remote-path > must specify a directory. >+.Pp >+If the >+.Fl f >+flag is specified, then a request will be sent to the server to call >+.Xr fsync 2 >+after the file has been transferred. >+Note that this is only supported by servers that implement >+the "fsync@openssh.com" extension. > .Pp > If either the > .Fl P >Index: sftp.c >=================================================================== >RCS file: /cvs/src/usr.bin/ssh/sftp.c,v >retrieving revision 1.155 >diff -u -p -r1.155 sftp.c >--- sftp.c 31 Aug 2013 00:13:54 -0000 1.155 >+++ sftp.c 11 Oct 2013 03:20:49 -0000 >@@ -75,6 +75,9 @@ int global_aflag = 0; > /* When this option is set, the file transfers will always preserve times */ > int global_pflag = 0; > >+/* When this option is set, transfers will have fsync() called on each file */ >+int global_fflag = 0; >+ > /* SIGINT received during command processing */ > volatile sig_atomic_t interrupted = 0; > >@@ -338,7 +341,7 @@ make_absolute(char *p, char *pwd) > > static int > parse_getput_flags(const char *cmd, char **argv, int argc, >- int *aflag, int *pflag, int *rflag) >+ int *aflag, int *fflag, int *pflag, int *rflag) > { > extern int opterr, optind, optopt, optreset; > int ch; >@@ -346,12 +349,15 @@ parse_getput_flags(const char *cmd, char > optind = optreset = 1; > opterr = 0; > >- *aflag = *rflag = *pflag = 0; >- while ((ch = getopt(argc, argv, "aPpRr")) != -1) { >+ *aflag = *fflag = *rflag = *pflag = 0; >+ while ((ch = getopt(argc, argv, "afPpRr")) != -1) { > switch (ch) { > case 'a': > *aflag = 1; > break; >+ case 'f': >+ *fflag = 1; >+ break; > case 'p': > case 'P': > *pflag = 1; >@@ -553,7 +559,7 @@ pathname_is_dir(char *pathname) > > static int > process_get(struct sftp_conn *conn, char *src, char *dst, char *pwd, >- int pflag, int rflag, int resume) >+ int pflag, int rflag, int resume, int fflag) > { > char *abs_src = NULL; > char *abs_dst = NULL; >@@ -612,11 +618,13 @@ process_get(struct sftp_conn *conn, char > printf("Fetching %s to %s\n", g.gl_pathv[i], abs_dst); > if (pathname_is_dir(g.gl_pathv[i]) && (rflag || global_rflag)) { > if (download_dir(conn, g.gl_pathv[i], abs_dst, NULL, >- pflag || global_pflag, 1, resume) == -1) >+ pflag || global_pflag, 1, resume, >+ fflag || global_fflag) == -1) > err = -1; > } else { > if (do_download(conn, g.gl_pathv[i], abs_dst, NULL, >- pflag || global_pflag, resume) == -1) >+ pflag || global_pflag, resume, >+ fflag || global_fflag) == -1) > err = -1; > } > free(abs_dst); >@@ -631,7 +639,7 @@ out: > > static int > process_put(struct sftp_conn *conn, char *src, char *dst, char *pwd, >- int pflag, int rflag) >+ int pflag, int rflag, int fflag) > { > char *tmp_dst = NULL; > char *abs_dst = NULL; >@@ -698,11 +706,13 @@ process_put(struct sftp_conn *conn, char > printf("Uploading %s to %s\n", g.gl_pathv[i], abs_dst); > if (pathname_is_dir(g.gl_pathv[i]) && (rflag || global_rflag)) { > if (upload_dir(conn, g.gl_pathv[i], abs_dst, >- pflag || global_pflag, 1) == -1) >+ pflag || global_pflag, 1, >+ fflag || global_fflag) == -1) > err = -1; > } else { > if (do_upload(conn, g.gl_pathv[i], abs_dst, >- pflag || global_pflag) == -1) >+ pflag || global_pflag, >+ fflag || global_fflag) == -1) > err = -1; > } > } >@@ -1155,8 +1165,8 @@ makeargv(const char *arg, int *argcp, in > } > > static int >-parse_args(const char **cpp, int *aflag, int *hflag, int *iflag, int *lflag, >- int *pflag, int *rflag, int *sflag, unsigned long *n_arg, >+parse_args(const char **cpp, int *aflag, int *fflag, int *hflag, int *iflag, >+ int *lflag, int *pflag, int *rflag, int *sflag, unsigned long *n_arg, > char **path1, char **path2) > { > const char *cmd, *cp = *cpp; >@@ -1201,7 +1211,8 @@ parse_args(const char **cpp, int *aflag, > } > > /* Get arguments and parse flags */ >- *aflag = *lflag = *pflag = *rflag = *hflag = *n_arg = 0; >+ *aflag = *fflag = *hflag = *iflag = *lflag = *pflag = 0; >+ *rflag = *sflag = 0; > *path1 = *path2 = NULL; > optidx = 1; > switch (cmdnum) { >@@ -1209,7 +1220,7 @@ parse_args(const char **cpp, int *aflag, > case I_REGET: > case I_PUT: > if ((optidx = parse_getput_flags(cmd, argv, argc, >- aflag, pflag, rflag)) == -1) >+ aflag, fflag, pflag, rflag)) == -1) > return -1; > /* Get first pathname (mandatory) */ > if (argc - optidx < 1) { >@@ -1350,7 +1361,7 @@ parse_dispatch_command(struct sftp_conn > int err_abort) > { > char *path1, *path2, *tmp; >- int aflag = 0, hflag = 0, iflag = 0, lflag = 0, pflag = 0; >+ int aflag = 0, fflag = 0, hflag = 0, iflag = 0, lflag = 0, pflag = 0; > int rflag = 0, sflag = 0; > int cmdnum, i; > unsigned long n_arg = 0; >@@ -1360,8 +1371,8 @@ parse_dispatch_command(struct sftp_conn > glob_t g; > > path1 = path2 = NULL; >- cmdnum = parse_args(&cmd, &aflag, &hflag, &iflag, &lflag, &pflag, >- &rflag, &sflag, &n_arg, &path1, &path2); >+ cmdnum = parse_args(&cmd, &aflag, &fflag, &hflag, &iflag, &lflag, >+ &pflag, &rflag, &sflag, &n_arg, &path1, &path2); > if (iflag != 0) > err_abort = 0; > >@@ -1381,10 +1392,11 @@ parse_dispatch_command(struct sftp_conn > /* FALLTHROUGH */ > case I_GET: > err = process_get(conn, path1, path2, *pwd, pflag, >- rflag, aflag); >+ rflag, aflag, fflag); > break; > case I_PUT: >- err = process_put(conn, path1, path2, *pwd, pflag, rflag); >+ err = process_put(conn, path1, path2, *pwd, pflag, >+ rflag, fflag); > break; > case I_RENAME: > path1 = make_absolute(path1, *pwd); >@@ -2189,7 +2201,7 @@ main(int argc, char **argv) > infile = stdin; > > while ((ch = getopt(argc, argv, >- "1246ahpqrvCc:D:i:l:o:s:S:b:B:F:P:R:")) != -1) { >+ "1246afhpqrvCc:D:i:l:o:s:S:b:B:F:P:R:")) != -1) { > switch (ch) { > /* Passed through to ssh(1) */ > case '4': >@@ -2248,6 +2260,9 @@ main(int argc, char **argv) > showprogress = 0; > quiet = batchmode = 1; > addargs(&args, "-obatchmode yes"); >+ break; >+ case 'f': >+ global_fflag = 1; > break; > case 'p': > global_pflag = 1;
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 1798
:
1898
|
1905
|
2065
| 2351