Blame SOURCES/0003-sftp-Add-support-for-fsync-OpenSSH-extension.patch

9bf74a
From 6e0d757f24a45252c4cae9ea09732eda2562c767 Mon Sep 17 00:00:00 2001
9bf74a
From: "Richard W.M. Jones" <rjones@redhat.com>
9bf74a
Date: Tue, 9 Apr 2013 11:42:09 +0200
9bf74a
Subject: [PATCH 3/3] sftp: Add support for fsync (OpenSSH extension).
9bf74a
9bf74a
The new libssh2_sftp_fsync API causes data and metadata in the
9bf74a
currently open file to be committed to disk at the server.
9bf74a
9bf74a
This is an OpenSSH extension to the SFTP protocol.  See:
9bf74a
9bf74a
https://bugzilla.mindrot.org/show_bug.cgi?id=1798
9bf74a
---
9bf74a
 docs/Makefile.am          |  1 +
9bf74a
 docs/libssh2_sftp_fsync.3 | 39 +++++++++++++++++++
9bf74a
 include/libssh2_sftp.h    |  1 +
9bf74a
 src/sftp.c                | 97 +++++++++++++++++++++++++++++++++++++++++++++++
9bf74a
 src/sftp.h                |  5 +++
9bf74a
 5 files changed, 143 insertions(+)
9bf74a
 create mode 100644 docs/libssh2_sftp_fsync.3
9bf74a
9bf74a
diff --git a/docs/Makefile.am b/docs/Makefile.am
9bf74a
index e4cf487..e6ab394 100644
9bf74a
--- a/docs/Makefile.am
9bf74a
+++ b/docs/Makefile.am
9bf74a
@@ -120,6 +120,7 @@ dist_man_MANS = \
9bf74a
 	libssh2_sftp_fstat.3 \
9bf74a
 	libssh2_sftp_fstat_ex.3 \
9bf74a
 	libssh2_sftp_fstatvfs.3 \
9bf74a
+	libssh2_sftp_fsync.3 \
9bf74a
 	libssh2_sftp_get_channel.3 \
9bf74a
 	libssh2_sftp_init.3 \
9bf74a
 	libssh2_sftp_last_error.3 \
9bf74a
diff --git a/docs/libssh2_sftp_fsync.3 b/docs/libssh2_sftp_fsync.3
9bf74a
new file mode 100644
9bf74a
index 0000000..646760a
9bf74a
--- /dev/null
9bf74a
+++ b/docs/libssh2_sftp_fsync.3
9bf74a
@@ -0,0 +1,39 @@
9bf74a
+.TH libssh2_sftp_fsync 3 "8 Apr 2013" "libssh2 1.4.4" "libssh2 manual"
9bf74a
+.SH NAME
9bf74a
+libssh2_sftp_fsync - synchronize file to disk
9bf74a
+.SH SYNOPSIS
9bf74a
+.nf
9bf74a
+#include <libssh2.h>
9bf74a
+#include <libssh2_sftp.h>
9bf74a
+
9bf74a
+int
9bf74a
+libssh2_sftp_fsync(LIBSSH2_SFTP_HANDLE *handle)
9bf74a
+.fi
9bf74a
+.SH DESCRIPTION
9bf74a
+This function causes the remote server to synchronize the file
9bf74a
+data and metadata to disk (like fsync(2)).
9bf74a
+
9bf74a
+For this to work requires fsync@openssh.com support on the server.
9bf74a
+
9bf74a
+\fIhandle\fP - SFTP File Handle as returned by
9bf74a
+.BR libssh2_sftp_open_ex(3)
9bf74a
+
9bf74a
+.SH RETURN VALUE
9bf74a
+Returns 0 on success or negative on failure. If used in non-blocking mode, it
9bf74a
+returns LIBSSH2_ERROR_EAGAIN when it would otherwise block. While
9bf74a
+LIBSSH2_ERROR_EAGAIN is a negative number, it isn't really a failure per se.
9bf74a
+.SH ERRORS
9bf74a
+\fILIBSSH2_ERROR_ALLOC\fP -  An internal memory allocation call failed.
9bf74a
+
9bf74a
+\fILIBSSH2_ERROR_SOCKET_SEND\fP - Unable to send data on socket.
9bf74a
+
9bf74a
+\fILIBSSH2_ERROR_SFTP_PROTOCOL\fP - An invalid SFTP protocol response
9bf74a
+was received on the socket, or an SFTP operation caused an errorcode
9bf74a
+to be returned by the server.  In particular, this can be returned if
9bf74a
+the SSH server does not support the fsync operation: the SFTP subcode
9bf74a
+\fILIBSSH2_FX_OP_UNSUPPORTED\fP will be returned in this case.
9bf74a
+
9bf74a
+.SH AVAILABILITY
9bf74a
+Added in libssh2 1.4.4 and OpenSSH 6.3.
9bf74a
+.SH SEE ALSO
9bf74a
+.BR fsync(2)
9bf74a
diff --git a/include/libssh2_sftp.h b/include/libssh2_sftp.h
9bf74a
index 74884fb..677faf2 100644
9bf74a
--- a/include/libssh2_sftp.h
9bf74a
+++ b/include/libssh2_sftp.h
9bf74a
@@ -247,6 +247,7 @@ LIBSSH2_API int libssh2_sftp_readdir_ex(LIBSSH2_SFTP_HANDLE *handle, \
9bf74a
 
9bf74a
 LIBSSH2_API ssize_t libssh2_sftp_write(LIBSSH2_SFTP_HANDLE *handle,
9bf74a
                                        const char *buffer, size_t count);
9bf74a
+LIBSSH2_API int libssh2_sftp_fsync(LIBSSH2_SFTP_HANDLE *handle);
9bf74a
 
9bf74a
 LIBSSH2_API int libssh2_sftp_close_handle(LIBSSH2_SFTP_HANDLE *handle);
9bf74a
 #define libssh2_sftp_close(handle) libssh2_sftp_close_handle(handle)
9bf74a
diff --git a/src/sftp.c b/src/sftp.c
9bf74a
index 65fa77a..01017fd 100644
9bf74a
--- a/src/sftp.c
9bf74a
+++ b/src/sftp.c
9bf74a
@@ -986,6 +986,10 @@ sftp_shutdown(LIBSSH2_SFTP *sftp)
9bf74a
         LIBSSH2_FREE(session, sftp->symlink_packet);
9bf74a
         sftp->symlink_packet = NULL;
9bf74a
     }
9bf74a
+    if (sftp->fsync_packet) {
9bf74a
+        LIBSSH2_FREE(session, sftp->fsync_packet);
9bf74a
+        sftp->fsync_packet = NULL;
9bf74a
+    }
9bf74a
 
9bf74a
     sftp_packet_flush(sftp);
9bf74a
 
9bf74a
@@ -2014,6 +2018,99 @@ libssh2_sftp_write(LIBSSH2_SFTP_HANDLE *hnd, const char *buffer,
9bf74a
 
9bf74a
 }
9bf74a
 
9bf74a
+static int sftp_fsync(LIBSSH2_SFTP_HANDLE *handle)
9bf74a
+{
9bf74a
+    LIBSSH2_SFTP *sftp = handle->sftp;
9bf74a
+    LIBSSH2_CHANNEL *channel = sftp->channel;
9bf74a
+    LIBSSH2_SESSION *session = channel->session;
9bf74a
+    /* 34 = packet_len(4) + packet_type(1) + request_id(4) +
9bf74a
+       string_len(4) + strlen("fsync@openssh.com")(17) + handle_len(4) */
9bf74a
+    uint32_t packet_len = handle->handle_len + 34;
9bf74a
+    size_t data_len;
9bf74a
+    unsigned char *packet, *s, *data;
9bf74a
+    ssize_t rc;
9bf74a
+    uint32_t retcode;
9bf74a
+
9bf74a
+    if (sftp->fsync_state == libssh2_NB_state_idle) {
9bf74a
+        _libssh2_debug(session, LIBSSH2_TRACE_SFTP,
9bf74a
+                       "Issuing fsync command");
9bf74a
+        s = packet = LIBSSH2_ALLOC(session, packet_len);
9bf74a
+        if (!packet) {
9bf74a
+            return _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
9bf74a
+                                  "Unable to allocate memory for FXP_EXTENDED "
9bf74a
+                                  "packet");
9bf74a
+        }
9bf74a
+
9bf74a
+        _libssh2_store_u32(&s, packet_len - 4);
9bf74a
+        *(s++) = SSH_FXP_EXTENDED;
9bf74a
+        sftp->fsync_request_id = sftp->request_id++;
9bf74a
+        _libssh2_store_u32(&s, sftp->fsync_request_id);
9bf74a
+        _libssh2_store_str(&s, "fsync@openssh.com", 17);
9bf74a
+        _libssh2_store_str(&s, handle->handle, handle->handle_len);
9bf74a
+
9bf74a
+        sftp->fsync_state = libssh2_NB_state_created;
9bf74a
+    } else {
9bf74a
+        packet = sftp->fsync_packet;
9bf74a
+    }
9bf74a
+
9bf74a
+    if (sftp->fsync_state == libssh2_NB_state_created) {
9bf74a
+        rc = _libssh2_channel_write(channel, 0, packet, packet_len);
9bf74a
+        if (rc == LIBSSH2_ERROR_EAGAIN ||
9bf74a
+            (0 <= rc && rc < (ssize_t)packet_len)) {
9bf74a
+            sftp->fsync_packet = packet;
9bf74a
+            return LIBSSH2_ERROR_EAGAIN;
9bf74a
+        }
9bf74a
+
9bf74a
+        LIBSSH2_FREE(session, packet);
9bf74a
+        sftp->fsync_packet = NULL;
9bf74a
+
9bf74a
+        if (rc < 0) {
9bf74a
+            sftp->fsync_state = libssh2_NB_state_idle;
9bf74a
+            return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
9bf74a
+                                  "_libssh2_channel_write() failed");
9bf74a
+        }
9bf74a
+        sftp->fsync_state = libssh2_NB_state_sent;
9bf74a
+    }
9bf74a
+
9bf74a
+    rc = sftp_packet_require(sftp, SSH_FXP_STATUS,
9bf74a
+                             sftp->fsync_request_id, &data, &data_len);
9bf74a
+    if (rc == LIBSSH2_ERROR_EAGAIN) {
9bf74a
+        return rc;
9bf74a
+    } else if (rc) {
9bf74a
+        sftp->fsync_state = libssh2_NB_state_idle;
9bf74a
+        return _libssh2_error(session, rc,
9bf74a
+                              "Error waiting for FXP EXTENDED REPLY");
9bf74a
+    }
9bf74a
+
9bf74a
+    sftp->fsync_state = libssh2_NB_state_idle;
9bf74a
+
9bf74a
+    retcode = _libssh2_ntohu32(data + 5);
9bf74a
+    LIBSSH2_FREE(session, data);
9bf74a
+
9bf74a
+    if (retcode != LIBSSH2_FX_OK) {
9bf74a
+        sftp->last_errno = retcode;
9bf74a
+        return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
9bf74a
+                              "fsync failed");
9bf74a
+    }
9bf74a
+
9bf74a
+    return 0;
9bf74a
+}
9bf74a
+
9bf74a
+/* libssh2_sftp_fsync
9bf74a
+ * Commit data on the handle to disk.
9bf74a
+ */
9bf74a
+LIBSSH2_API int
9bf74a
+libssh2_sftp_fsync(LIBSSH2_SFTP_HANDLE *hnd)
9bf74a
+{
9bf74a
+    int rc;
9bf74a
+    if(!hnd)
9bf74a
+        return LIBSSH2_ERROR_BAD_USE;
9bf74a
+    BLOCK_ADJUST(rc, hnd->sftp->channel->session,
9bf74a
+                 sftp_fsync(hnd));
9bf74a
+    return rc;
9bf74a
+}
9bf74a
+
9bf74a
+
9bf74a
 /*
9bf74a
  * sftp_fstat
9bf74a
  *
9bf74a
diff --git a/src/sftp.h b/src/sftp.h
9bf74a
index 55bdb46..63e8139 100644
9bf74a
--- a/src/sftp.h
9bf74a
+++ b/src/sftp.h
9bf74a
@@ -175,6 +175,11 @@ struct _LIBSSH2_SFTP
9bf74a
     /* State variable used in sftp_write() */
9bf74a
     libssh2_nonblocking_states write_state;
9bf74a
 
9bf74a
+    /* State variables used in sftp_fsync() */
9bf74a
+    libssh2_nonblocking_states fsync_state;
9bf74a
+    unsigned char *fsync_packet;
9bf74a
+    uint32_t fsync_request_id;
9bf74a
+
9bf74a
     /* State variables used in libssh2_sftp_readdir() */
9bf74a
     libssh2_nonblocking_states readdir_state;
9bf74a
     unsigned char *readdir_packet;
9bf74a
-- 
9bf74a
1.8.1.4
9bf74a