From fe8b55ff64258c7dea0d9e180096b4e26e51c1a1 Mon Sep 17 00:00:00 2001 From: Richard W.M. Jones Date: Apr 09 2013 15:01:28 +0000 Subject: Add three patches from upstream git required for qemu ssh block driver. --- diff --git a/0001-sftp-seek-Don-t-flush-buffers-on-same-offset.patch b/0001-sftp-seek-Don-t-flush-buffers-on-same-offset.patch new file mode 100644 index 0000000..9acbd6d --- /dev/null +++ b/0001-sftp-seek-Don-t-flush-buffers-on-same-offset.patch @@ -0,0 +1,54 @@ +From 486bb376218a37fe15318d7724d6eada36b81e6c Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Tue, 26 Mar 2013 17:58:04 +0100 +Subject: [PATCH 1/3] sftp: seek: Don't flush buffers on same offset + +Signed-off-by: Richard W.M. Jones +--- + src/sftp.c | 27 +++++++++++++++------------ + 1 file changed, 15 insertions(+), 12 deletions(-) + +diff --git a/src/sftp.c b/src/sftp.c +index d0536dd..3760025 100644 +--- a/src/sftp.c ++++ b/src/sftp.c +@@ -2132,21 +2132,24 @@ libssh2_sftp_fstat_ex(LIBSSH2_SFTP_HANDLE *hnd, + LIBSSH2_API void + libssh2_sftp_seek64(LIBSSH2_SFTP_HANDLE *handle, libssh2_uint64_t offset) + { +- if(handle) { +- handle->u.file.offset = handle->u.file.offset_sent = offset; +- /* discard all pending requests and currently read data */ +- sftp_packetlist_flush(handle); ++ if(!handle) ++ return; ++ if(handle->u.file.offset == offset && handle->u.file.offset_sent == offset) ++ return; + +- /* free the left received buffered data */ +- if (handle->u.file.data_left) { +- LIBSSH2_FREE(handle->sftp->channel->session, handle->u.file.data); +- handle->u.file.data_left = handle->u.file.data_len = 0; +- handle->u.file.data = NULL; +- } ++ handle->u.file.offset = handle->u.file.offset_sent = offset; ++ /* discard all pending requests and currently read data */ ++ sftp_packetlist_flush(handle); + +- /* reset EOF to False */ +- handle->u.file.eof = FALSE; ++ /* free the left received buffered data */ ++ if (handle->u.file.data_left) { ++ LIBSSH2_FREE(handle->sftp->channel->session, handle->u.file.data); ++ handle->u.file.data_left = handle->u.file.data_len = 0; ++ handle->u.file.data = NULL; + } ++ ++ /* reset EOF to False */ ++ handle->u.file.eof = FALSE; + } + + /* libssh2_sftp_seek +-- +1.8.1.4 + diff --git a/0002-sftp-statvfs-Along-error-path-reset-the-correct-stat.patch b/0002-sftp-statvfs-Along-error-path-reset-the-correct-stat.patch new file mode 100644 index 0000000..83ca15e --- /dev/null +++ b/0002-sftp-statvfs-Along-error-path-reset-the-correct-stat.patch @@ -0,0 +1,26 @@ +From a12f3ffab579b514eeb7fdfaca0ade271961cdb4 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Mon, 8 Apr 2013 17:30:10 +0100 +Subject: [PATCH 2/3] sftp: statvfs: Along error path, reset the correct + 'state' variable. + +--- + src/sftp.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/sftp.c b/src/sftp.c +index 3760025..65fa77a 100644 +--- a/src/sftp.c ++++ b/src/sftp.c +@@ -2752,7 +2752,7 @@ static int sftp_statvfs(LIBSSH2_SFTP *sftp, const char *path, + "Error waiting for FXP EXTENDED REPLY"); + } else if (data_len < 93) { + LIBSSH2_FREE(session, data); +- sftp->fstatvfs_state = libssh2_NB_state_idle; ++ sftp->statvfs_state = libssh2_NB_state_idle; + return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, + "SFTP Protocol Error: short response"); + } +-- +1.8.1.4 + diff --git a/0003-sftp-Add-support-for-fsync-OpenSSH-extension.patch b/0003-sftp-Add-support-for-fsync-OpenSSH-extension.patch new file mode 100644 index 0000000..cc1cbb4 --- /dev/null +++ b/0003-sftp-Add-support-for-fsync-OpenSSH-extension.patch @@ -0,0 +1,223 @@ +From 6e0d757f24a45252c4cae9ea09732eda2562c767 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Tue, 9 Apr 2013 11:42:09 +0200 +Subject: [PATCH 3/3] sftp: Add support for fsync (OpenSSH extension). + +The new libssh2_sftp_fsync API causes data and metadata in the +currently open file to be committed to disk at the server. + +This is an OpenSSH extension to the SFTP protocol. See: + +https://bugzilla.mindrot.org/show_bug.cgi?id=1798 +--- + docs/Makefile.am | 1 + + docs/libssh2_sftp_fsync.3 | 39 +++++++++++++++++++ + include/libssh2_sftp.h | 1 + + src/sftp.c | 97 +++++++++++++++++++++++++++++++++++++++++++++++ + src/sftp.h | 5 +++ + 5 files changed, 143 insertions(+) + create mode 100644 docs/libssh2_sftp_fsync.3 + +diff --git a/docs/Makefile.am b/docs/Makefile.am +index e4cf487..e6ab394 100644 +--- a/docs/Makefile.am ++++ b/docs/Makefile.am +@@ -120,6 +120,7 @@ dist_man_MANS = \ + libssh2_sftp_fstat.3 \ + libssh2_sftp_fstat_ex.3 \ + libssh2_sftp_fstatvfs.3 \ ++ libssh2_sftp_fsync.3 \ + libssh2_sftp_get_channel.3 \ + libssh2_sftp_init.3 \ + libssh2_sftp_last_error.3 \ +diff --git a/docs/libssh2_sftp_fsync.3 b/docs/libssh2_sftp_fsync.3 +new file mode 100644 +index 0000000..646760a +--- /dev/null ++++ b/docs/libssh2_sftp_fsync.3 +@@ -0,0 +1,39 @@ ++.TH libssh2_sftp_fsync 3 "8 Apr 2013" "libssh2 1.4.4" "libssh2 manual" ++.SH NAME ++libssh2_sftp_fsync - synchronize file to disk ++.SH SYNOPSIS ++.nf ++#include ++#include ++ ++int ++libssh2_sftp_fsync(LIBSSH2_SFTP_HANDLE *handle) ++.fi ++.SH DESCRIPTION ++This function causes the remote server to synchronize the file ++data and metadata to disk (like fsync(2)). ++ ++For this to work requires fsync@openssh.com support on the server. ++ ++\fIhandle\fP - SFTP File Handle as returned by ++.BR libssh2_sftp_open_ex(3) ++ ++.SH RETURN VALUE ++Returns 0 on success or negative on failure. If used in non-blocking mode, it ++returns LIBSSH2_ERROR_EAGAIN when it would otherwise block. While ++LIBSSH2_ERROR_EAGAIN is a negative number, it isn't really a failure per se. ++.SH ERRORS ++\fILIBSSH2_ERROR_ALLOC\fP - An internal memory allocation call failed. ++ ++\fILIBSSH2_ERROR_SOCKET_SEND\fP - Unable to send data on socket. ++ ++\fILIBSSH2_ERROR_SFTP_PROTOCOL\fP - An invalid SFTP protocol response ++was received on the socket, or an SFTP operation caused an errorcode ++to be returned by the server. In particular, this can be returned if ++the SSH server does not support the fsync operation: the SFTP subcode ++\fILIBSSH2_FX_OP_UNSUPPORTED\fP will be returned in this case. ++ ++.SH AVAILABILITY ++Added in libssh2 1.4.4 and OpenSSH 6.3. ++.SH SEE ALSO ++.BR fsync(2) +diff --git a/include/libssh2_sftp.h b/include/libssh2_sftp.h +index 74884fb..677faf2 100644 +--- a/include/libssh2_sftp.h ++++ b/include/libssh2_sftp.h +@@ -247,6 +247,7 @@ LIBSSH2_API int libssh2_sftp_readdir_ex(LIBSSH2_SFTP_HANDLE *handle, \ + + LIBSSH2_API ssize_t libssh2_sftp_write(LIBSSH2_SFTP_HANDLE *handle, + const char *buffer, size_t count); ++LIBSSH2_API int libssh2_sftp_fsync(LIBSSH2_SFTP_HANDLE *handle); + + LIBSSH2_API int libssh2_sftp_close_handle(LIBSSH2_SFTP_HANDLE *handle); + #define libssh2_sftp_close(handle) libssh2_sftp_close_handle(handle) +diff --git a/src/sftp.c b/src/sftp.c +index 65fa77a..01017fd 100644 +--- a/src/sftp.c ++++ b/src/sftp.c +@@ -986,6 +986,10 @@ sftp_shutdown(LIBSSH2_SFTP *sftp) + LIBSSH2_FREE(session, sftp->symlink_packet); + sftp->symlink_packet = NULL; + } ++ if (sftp->fsync_packet) { ++ LIBSSH2_FREE(session, sftp->fsync_packet); ++ sftp->fsync_packet = NULL; ++ } + + sftp_packet_flush(sftp); + +@@ -2014,6 +2018,99 @@ libssh2_sftp_write(LIBSSH2_SFTP_HANDLE *hnd, const char *buffer, + + } + ++static int sftp_fsync(LIBSSH2_SFTP_HANDLE *handle) ++{ ++ LIBSSH2_SFTP *sftp = handle->sftp; ++ LIBSSH2_CHANNEL *channel = sftp->channel; ++ LIBSSH2_SESSION *session = channel->session; ++ /* 34 = packet_len(4) + packet_type(1) + request_id(4) + ++ string_len(4) + strlen("fsync@openssh.com")(17) + handle_len(4) */ ++ uint32_t packet_len = handle->handle_len + 34; ++ size_t data_len; ++ unsigned char *packet, *s, *data; ++ ssize_t rc; ++ uint32_t retcode; ++ ++ if (sftp->fsync_state == libssh2_NB_state_idle) { ++ _libssh2_debug(session, LIBSSH2_TRACE_SFTP, ++ "Issuing fsync command"); ++ s = packet = LIBSSH2_ALLOC(session, packet_len); ++ if (!packet) { ++ return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, ++ "Unable to allocate memory for FXP_EXTENDED " ++ "packet"); ++ } ++ ++ _libssh2_store_u32(&s, packet_len - 4); ++ *(s++) = SSH_FXP_EXTENDED; ++ sftp->fsync_request_id = sftp->request_id++; ++ _libssh2_store_u32(&s, sftp->fsync_request_id); ++ _libssh2_store_str(&s, "fsync@openssh.com", 17); ++ _libssh2_store_str(&s, handle->handle, handle->handle_len); ++ ++ sftp->fsync_state = libssh2_NB_state_created; ++ } else { ++ packet = sftp->fsync_packet; ++ } ++ ++ if (sftp->fsync_state == libssh2_NB_state_created) { ++ rc = _libssh2_channel_write(channel, 0, packet, packet_len); ++ if (rc == LIBSSH2_ERROR_EAGAIN || ++ (0 <= rc && rc < (ssize_t)packet_len)) { ++ sftp->fsync_packet = packet; ++ return LIBSSH2_ERROR_EAGAIN; ++ } ++ ++ LIBSSH2_FREE(session, packet); ++ sftp->fsync_packet = NULL; ++ ++ if (rc < 0) { ++ sftp->fsync_state = libssh2_NB_state_idle; ++ return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, ++ "_libssh2_channel_write() failed"); ++ } ++ sftp->fsync_state = libssh2_NB_state_sent; ++ } ++ ++ rc = sftp_packet_require(sftp, SSH_FXP_STATUS, ++ sftp->fsync_request_id, &data, &data_len); ++ if (rc == LIBSSH2_ERROR_EAGAIN) { ++ return rc; ++ } else if (rc) { ++ sftp->fsync_state = libssh2_NB_state_idle; ++ return _libssh2_error(session, rc, ++ "Error waiting for FXP EXTENDED REPLY"); ++ } ++ ++ sftp->fsync_state = libssh2_NB_state_idle; ++ ++ retcode = _libssh2_ntohu32(data + 5); ++ LIBSSH2_FREE(session, data); ++ ++ if (retcode != LIBSSH2_FX_OK) { ++ sftp->last_errno = retcode; ++ return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, ++ "fsync failed"); ++ } ++ ++ return 0; ++} ++ ++/* libssh2_sftp_fsync ++ * Commit data on the handle to disk. ++ */ ++LIBSSH2_API int ++libssh2_sftp_fsync(LIBSSH2_SFTP_HANDLE *hnd) ++{ ++ int rc; ++ if(!hnd) ++ return LIBSSH2_ERROR_BAD_USE; ++ BLOCK_ADJUST(rc, hnd->sftp->channel->session, ++ sftp_fsync(hnd)); ++ return rc; ++} ++ ++ + /* + * sftp_fstat + * +diff --git a/src/sftp.h b/src/sftp.h +index 55bdb46..63e8139 100644 +--- a/src/sftp.h ++++ b/src/sftp.h +@@ -175,6 +175,11 @@ struct _LIBSSH2_SFTP + /* State variable used in sftp_write() */ + libssh2_nonblocking_states write_state; + ++ /* State variables used in sftp_fsync() */ ++ libssh2_nonblocking_states fsync_state; ++ unsigned char *fsync_packet; ++ uint32_t fsync_request_id; ++ + /* State variables used in libssh2_sftp_readdir() */ + libssh2_nonblocking_states readdir_state; + unsigned char *readdir_packet; +-- +1.8.1.4 + diff --git a/libssh2.spec b/libssh2.spec index ef86d61..8c936f9 100644 --- a/libssh2.spec +++ b/libssh2.spec @@ -19,6 +19,9 @@ URL: http://www.libssh2.org/ Source0: http://libssh2.org/download/libssh2-%{version}.tar.gz Patch0: libssh2-1.4.2-utf8.patch +Patch1: 0001-sftp-seek-Don-t-flush-buffers-on-same-offset.patch +Patch2: 0002-sftp-statvfs-Along-error-path-reset-the-correct-stat.patch +Patch3: 0003-sftp-Add-support-for-fsync-OpenSSH-extension.patch BuildRequires: openssl-devel BuildRequires: zlib-devel @@ -70,6 +73,11 @@ sed -i s/4711/47%{?__isa_bits}/ tests/ssh2.{c,sh} # Make sure things are UTF-8... %patch0 -p1 +# Three upstream patches required for qemu ssh block driver. +%patch1 -p1 +%patch2 -p1 +%patch3 -p1 + # Make sshd transition appropriately if building in an SELinux environment %if !(0%{?fedora} >= 17 || 0%{?rhel} >= 7) chcon $(/usr/sbin/matchpathcon -n /etc/rc.d/init.d/sshd) tests/ssh2.sh || : @@ -133,6 +141,7 @@ make -C tests check %changelog * Tue Apr 9 2013 Richard W.M. Jones 1.4.3-5 +- Add three patches from upstream git required for qemu ssh block driver. - Modernize the spec file: * Remove BuildRoot. * Remove Group.