[PATCH] Improved sftp I/O error handling
- From: Christian Neumair <chris gnome-de org>
- To: "gnome-vfs-list gnome org" <gnome-vfs-list gnome org>
- Subject: [PATCH] Improved sftp I/O error handling
- Date: Mon, 21 May 2007 15:41:46 +0200
The attached patch ensures that buffer_recv and buffer_send errors are
propagated to their parents. While hangs may still occur, crashes
shouldn't happen anymore.
--
Christian Neumair <chris gnome-de org>
Index: modules/sftp-method.c
===================================================================
--- modules/sftp-method.c (Revision 5338)
+++ modules/sftp-method.c (Arbeitskopie)
@@ -305,7 +305,7 @@ buffer_write (Buffer *buf, gconstpointer
buf->write_ptr += size;
}
-static GnomeVFSResult
+static G_GNUC_WARN_UNUSED_RESULT GnomeVFSResult
buffer_send (Buffer *buf, int fd)
{
guint bytes_written = 0;
@@ -343,7 +343,7 @@ buffer_send (Buffer *buf, int fd)
return res;
}
-static GnomeVFSResult
+static G_GNUC_WARN_UNUSED_RESULT GnomeVFSResult
buffer_recv (Buffer *buf, int fd)
{
guint32 r_len, len, bytes_read;
@@ -673,14 +673,19 @@ sftp_status_to_vfs_result (guint status)
/* Derived from OpenSSH, sftp-client.c:get_status */
-static GnomeVFSResult
+static G_GNUC_WARN_UNUSED_RESULT GnomeVFSResult
iobuf_read_result (int fd, guint expected_id)
{
Buffer msg;
+ GnomeVFSResult res;
guint type, id, status;
buffer_init (&msg);
- buffer_recv (&msg, fd);
+ res = buffer_recv (&msg, fd);
+ if (res != GNOME_VFS_OK) {
+ return res;
+ }
+
type = buffer_read_gchar (&msg);
id = buffer_read_gint32 (&msg);
@@ -699,15 +704,19 @@ iobuf_read_result (int fd, guint expecte
/* Derived from OpenSSH, sftp-client.c:get_handle */
-static GnomeVFSResult
+static G_GNUC_WARN_UNUSED_RESULT GnomeVFSResult
iobuf_read_handle (int fd, gchar **handle, guint expected_id, guint32 *len)
{
Buffer msg;
+ GnomeVFSResult res;
gchar type;
guint id, status;
buffer_init (&msg);
- buffer_recv (&msg, fd);
+ res = buffer_recv (&msg, fd);
+ if (res != GNOME_VFS_OK) {
+ return res;
+ }
type = buffer_read_gchar (&msg);
id = buffer_read_gint32 (&msg);
@@ -736,7 +745,7 @@ iobuf_read_handle (int fd, gchar **handl
/* this neither includes the name nor the MIME type,
* which are set in update_mime_type_and_name_from_path */
-static GnomeVFSResult
+static G_GNUC_WARN_UNUSED_RESULT GnomeVFSResult
iobuf_read_file_info (int fd, GnomeVFSFileInfo *info, guint expected_id)
{
Buffer msg;
@@ -745,7 +754,10 @@ iobuf_read_file_info (int fd, GnomeVFSFi
GnomeVFSResult res;
buffer_init (&msg);
- buffer_recv (&msg, fd);
+ res = buffer_recv (&msg, fd);
+ if (res != GNOME_VFS_OK) {
+ return res;
+ }
type = buffer_read_gchar (&msg);
id = buffer_read_gint32 (&msg);
@@ -775,7 +787,7 @@ iobuf_read_file_info (int fd, GnomeVFSFi
/* Derived from OpenSSH, sftp-client.c:send_read_request */
-static GnomeVFSResult
+static G_GNUC_WARN_UNUSED_RESULT GnomeVFSResult
iobuf_send_read_request (int fd,
guint id,
guint64 offset,
@@ -802,7 +814,7 @@ iobuf_send_read_request (int
/* Derived from OpenSSH, sftp-client.c:send_string_request */
-static void
+static G_GNUC_WARN_UNUSED_RESULT GnomeVFSResult
iobuf_send_string_request (int fd,
guint id,
guint code,
@@ -810,20 +822,24 @@ iobuf_send_string_request (int
guint len)
{
Buffer msg;
+ GnomeVFSResult res;
buffer_init (&msg);
buffer_write_gchar (&msg, code);
buffer_write_gint32 (&msg, id);
buffer_write_block (&msg, s, len);
- buffer_send (&msg, fd);
+ res = buffer_send (&msg, fd);
buffer_free (&msg);
+
+ return res;
}
/* Derived from OpenSSH, sftp-client.c:send_string_attrs_request */
-static void
+
+static G_GNUC_WARN_UNUSED_RESULT GnomeVFSResult
iobuf_send_string_request_with_file_info (int fd,
guint id,
guint code,
@@ -833,6 +849,7 @@ iobuf_send_string_request_with_file_info
GnomeVFSSetFileInfoMask mask)
{
Buffer msg;
+ GnomeVFSResult res;
buffer_init (&msg);
@@ -840,9 +857,11 @@ iobuf_send_string_request_with_file_info
buffer_write_gint32 (&msg, id);
buffer_write_block (&msg, s, len);
buffer_write_file_info (&msg, info, mask);
- buffer_send (&msg, fd);
+ res = buffer_send (&msg, fd);
buffer_free (&msg);
+
+ return res;
}
static char*
@@ -1232,7 +1251,10 @@ tty_retry:
buffer_write_gchar (&msg, SSH2_FXP_INIT);
buffer_write_gint32 (&msg, SSH2_FILEXFER_VERSION);
- buffer_send (&msg, out_fd);
+ res = buffer_send (&msg, out_fd);
+ if (res != GNOME_VFS_OK) {
+ goto bail;
+ }
tty_channel = NULL;
if (tty_fd != -1) {
@@ -1897,10 +1919,12 @@ do_open (GnomeVFSMethod *method,
memset (&info, 0, sizeof (GnomeVFSFileInfo));
buffer_write_file_info (&msg, &info, GNOME_VFS_SET_FILE_INFO_NONE);
- buffer_send (&msg, conn->out_fd);
+ res = buffer_send (&msg, conn->out_fd);
buffer_free (&msg);
-
- res = iobuf_read_handle (conn->in_fd, &sftp_handle, id, (guint32 *)&sftp_handle_len);
+
+ if (res == GNOME_VFS_OK) {
+ res = iobuf_read_handle (conn->in_fd, &sftp_handle, id, (guint32 *)&sftp_handle_len);
+ }
if (res == GNOME_VFS_OK) {
handle = g_new0 (SftpOpenHandle, 1);
@@ -1982,10 +2006,12 @@ do_create (GnomeVFSMethod *method
info.permissions = perm;
buffer_write_file_info (&msg, &info, GNOME_VFS_SET_FILE_INFO_PERMISSIONS);
- buffer_send (&msg, conn->out_fd);
+ res = buffer_send (&msg, conn->out_fd);
buffer_free (&msg);
- res = iobuf_read_handle (conn->in_fd, &sftp_handle, id, &sftp_handle_len);
+ if (res == GNOME_VFS_OK) {
+ res = iobuf_read_handle (conn->in_fd, &sftp_handle, id, &sftp_handle_len);
+ }
if (res == GNOME_VFS_OK) {
handle = g_new0 (SftpOpenHandle, 1);
@@ -2019,10 +2045,9 @@ do_close (GnomeVFSMethod *method,
{
SftpOpenHandle *handle;
- guint id, status;
+ guint i, id;
Buffer msg;
-
- guint i;
+ GnomeVFSResult res;
DEBUG (g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "%s: Enter", G_GNUC_FUNCTION));
@@ -2036,9 +2061,11 @@ do_close (GnomeVFSMethod *method,
buffer_write_gchar (&msg, SSH2_FXP_CLOSE);
buffer_write_gint32 (&msg, id);
buffer_write_block (&msg, handle->sftp_handle, handle->sftp_handle_len);
- buffer_send (&msg, handle->connection->out_fd);
+ res = buffer_send (&msg, handle->connection->out_fd);
- status = iobuf_read_result (handle->connection->in_fd, id);
+ if (res == GNOME_VFS_OK) {
+ res = iobuf_read_result (handle->connection->in_fd, id);
+ }
buffer_free (&msg);
sftp_connection_unref (handle->connection);
@@ -2054,7 +2081,7 @@ do_close (GnomeVFSMethod *method,
DEBUG (g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "%s: Exit", G_GNUC_FUNCTION));
- return status;
+ return res;
}
static GnomeVFSResult
@@ -2124,20 +2151,25 @@ do_read (GnomeVFSMethod *method,
read_req[req_ptr].req_len, read_req[req_ptr].ptr));
outstanding++;
- iobuf_send_read_request (handle->connection->out_fd,
+ result = iobuf_send_read_request (handle->connection->out_fd,
read_req[req_ptr].id,
handle->offset + (read_req[req_ptr].ptr - buffer),
read_req[req_ptr].req_len,
handle->sftp_handle, handle->sftp_handle_len);
+ if (result != GNOME_VFS_OK) {
+ break;
+ }
curr_ptr += read_req[req_ptr].req_len;
req_ptr = (req_ptr + 1) % queue_len;
}
- buffer_clear (&msg);
- result = buffer_recv (&msg, handle->connection->in_fd);
- outstanding--;
+ if (result == GNOME_VFS_OK) {
+ buffer_clear (&msg);
+ result = buffer_recv (&msg, handle->connection->in_fd);
+ outstanding--;
+ }
if (result != GNOME_VFS_OK) {
buffer_free (&msg);
@@ -2203,18 +2235,27 @@ do_read (GnomeVFSMethod *method,
*bytes_read += len;
if (len < read_req[req_svc].req_len) {
+ GnomeVFSResult result;
+
/* Missing data. Request that part */
read_req[req_svc].id = sftp_connection_get_id (handle->connection);
read_req[req_svc].req_len -= len;
read_req[req_svc].ptr += len;
- outstanding++;
- iobuf_send_read_request
+ result = iobuf_send_read_request
(handle->connection->out_fd,
read_req[req_svc].id,
handle->offset + (read_req[req_svc].ptr - buffer),
read_req[req_svc].req_len,
handle->sftp_handle, handle->sftp_handle_len);
+ if (result != GNOME_VFS_OK) {
+ buffer_free (&msg);
+ g_free (read_req);
+ sftp_connection_unlock (handle->connection);
+ return GNOME_VFS_ERROR_PROTOCOL_ERROR;
+ }
+
+ outstanding++;
} else
read_req[req_svc].id = 0;
@@ -2293,6 +2334,8 @@ do_write (GnomeVFSMethod *method,
sftp_connection_lock (handle->connection);
while (*bytes_written < num_bytes) {
+ GnomeVFSResult res = GNOME_VFS_OK;
+
while (curr_offset < num_bytes &&
(req_ptr + 1) % queue_len != req_svc_ptr) {
write_req[req_ptr].id = sftp_connection_get_id (handle->connection);
@@ -2314,13 +2357,24 @@ do_write (GnomeVFSMethod *method,
buffer_write_block (&msg, buffer + write_req[req_ptr].offset,
write_req[req_ptr].req_len);
- buffer_send (&msg, handle->connection->out_fd);
+ res = buffer_send (&msg, handle->connection->out_fd);
req_ptr = (req_ptr + 1) % queue_len;
}
buffer_clear (&msg);
- buffer_recv (&msg, handle->connection->in_fd);
+
+ if (res == GNOME_VFS_OK) {
+ res = buffer_recv (&msg, handle->connection->in_fd);
+ }
+
+ if (res != GNOME_VFS_OK) {
+ buffer_free (&msg);
+ g_free (write_req);
+ sftp_connection_unlock (handle->connection);
+ return res;
+ }
+
type = buffer_read_gchar (&msg);
recv_id = buffer_read_gint32 (&msg);
@@ -2445,6 +2499,7 @@ sftp_readlink (SftpConnection *connectio
char type;
unsigned int id;
char *ret;
+ GnomeVFSResult res;
DEBUG (g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "%s: Enter", G_GNUC_FUNCTION));
@@ -2453,21 +2508,27 @@ sftp_readlink (SftpConnection *connectio
DEBUG (g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "%s: Requesting symlink target for %s",
G_GNUC_FUNCTION, path));
+ ret = NULL;
+
buffer_init (&msg);
buffer_write_gchar (&msg, SSH2_FXP_READLINK);
buffer_write_gint32 (&msg, id);
buffer_write_string (&msg, path);
- buffer_send (&msg, connection->out_fd);
+ res = buffer_send (&msg, connection->out_fd);
+ if (res != GNOME_VFS_OK) {
+ goto out;
+ }
buffer_clear (&msg);
- buffer_recv (&msg, connection->in_fd);
+ res = buffer_recv (&msg, connection->in_fd);
+ if (res != GNOME_VFS_OK) {
+ goto out;
+ }
type = buffer_read_gchar (&msg);
recv_id = buffer_read_gint32 (&msg);
- ret = NULL;
-
if (recv_id != id)
g_critical ("%s: ID mismatch (%u != %u)", G_GNUC_FUNCTION, recv_id, id);
else if (type == SSH2_FXP_NAME) {
@@ -2494,6 +2555,7 @@ sftp_readlink (SftpConnection *connectio
G_GNUC_FUNCTION, type));
}
+out:
buffer_free (&msg);
return ret;
@@ -2559,9 +2621,12 @@ get_file_info_for_path (SftpConnection
id = sftp_connection_get_id (conn);
- iobuf_send_string_request (conn->out_fd, id,
+ res = iobuf_send_string_request (conn->out_fd, id,
SSH2_FXP_LSTAT,
path, strlen (path));
+ if (res != GNOME_VFS_OK) {
+ return res;
+ }
res = iobuf_read_file_info (conn->in_fd, file_info, id);
if (res != GNOME_VFS_OK) return res;
@@ -2617,11 +2682,14 @@ get_file_info_for_path (SftpConnection
g_free (tmp);
id = sftp_connection_get_id (conn);
- iobuf_send_string_request (conn->out_fd, id,
+ res = iobuf_send_string_request (conn->out_fd, id,
SSH2_FXP_LSTAT,
target_path, strlen (target_path));
- res = iobuf_read_file_info (conn->in_fd, target_info, id);
+ if (res == GNOME_VFS_OK) {
+ res = iobuf_read_file_info (conn->in_fd, target_info, id);
+ }
+
if (res != GNOME_VFS_OK ||
(target_info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_TYPE) == 0) {
DEBUG (g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG,
@@ -2761,11 +2829,13 @@ do_open_directory (GnomeVFSMethod
buffer_write_gchar (&msg, SSH2_FXP_OPENDIR);
buffer_write_gint32 (&msg, id);
buffer_write_string (&msg, path);
- buffer_send (&msg, conn->out_fd);
+ res = buffer_send (&msg, conn->out_fd);
buffer_free (&msg);
- res = iobuf_read_handle (conn->in_fd, &sftp_handle, id, &sftp_handle_len);
+ if (res == GNOME_VFS_OK) {
+ res = iobuf_read_handle (conn->in_fd, &sftp_handle, id, &sftp_handle_len);
+ }
DEBUG (g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "%s: Result is %d", G_GNUC_FUNCTION, res));
@@ -2823,6 +2893,7 @@ do_read_directory (GnomeVFSMethod
gint status, count, i;
Buffer msg;
gchar type;
+ GnomeVFSResult res;
DEBUG (g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "%s: Enter", G_GNUC_FUNCTION));
@@ -2850,11 +2921,17 @@ do_read_directory (GnomeVFSMethod
buffer_write_gchar (&msg, SSH2_FXP_READDIR);
buffer_write_gint32 (&msg, id);
buffer_write_block (&msg, handle->sftp_handle, handle->sftp_handle_len);
- buffer_send (&msg, handle->connection->out_fd);
+ res = buffer_send (&msg, handle->connection->out_fd);
buffer_clear (&msg);
- buffer_recv (&msg, handle->connection->in_fd);
+ if (res == GNOME_VFS_OK) {
+ res = buffer_recv (&msg, handle->connection->in_fd);
+ }
+
+ if (res != GNOME_VFS_OK) {
+ return res;
+ }
type = buffer_read_gchar (&msg);
recv_id = buffer_read_gint32 (&msg);
@@ -2994,13 +3071,15 @@ do_make_directory (GnomeVFSMethod *meth
URI_TO_PATH (uri, path);
memset (&info, 0, sizeof (GnomeVFSFileInfo));
- iobuf_send_string_request_with_file_info (conn->out_fd, id, SSH2_FXP_MKDIR,
+ res = iobuf_send_string_request_with_file_info (conn->out_fd, id, SSH2_FXP_MKDIR,
path, strlen (path), &info,
GNOME_VFS_SET_FILE_INFO_NONE);
g_free (path);
- res = iobuf_read_result (conn->in_fd, id);
+ if (res == GNOME_VFS_OK) {
+ res = iobuf_read_result (conn->in_fd, id);
+ }
sftp_connection_unref (conn);
sftp_connection_unlock (conn);
@@ -3029,10 +3108,12 @@ do_remove_directory (GnomeVFSMethod *me
id = sftp_connection_get_id (conn);
URI_TO_PATH (uri, path);
- iobuf_send_string_request (conn->out_fd, id, SSH2_FXP_RMDIR, path, strlen (path));
+ res = iobuf_send_string_request (conn->out_fd, id, SSH2_FXP_RMDIR, path, strlen (path));
g_free (path);
- res = iobuf_read_result (conn->in_fd, id);
+ if (res == GNOME_VFS_OK) {
+ res = iobuf_read_result (conn->in_fd, id);
+ }
sftp_connection_unref (conn);
sftp_connection_unlock (conn);
@@ -3072,12 +3153,16 @@ do_move (GnomeVFSMethod *method,
/* if force_replace is specified, try to remove new_uri */
if (force_replace) {
- iobuf_send_string_request (conn->out_fd,
+ res = iobuf_send_string_request (conn->out_fd,
id,
SSH2_FXP_REMOVE,
new_path,
strlen (new_path));
- res = iobuf_read_result (conn->in_fd, id);
+
+ if (res == GNOME_VFS_OK) {
+ res = iobuf_read_result (conn->in_fd, id);
+ }
+
if (res != GNOME_VFS_OK && res != GNOME_VFS_ERROR_NOT_FOUND)
goto bail;
}
@@ -3087,10 +3172,12 @@ do_move (GnomeVFSMethod *method,
buffer_write_gint32 (&msg, id);
buffer_write_string (&msg, old_path);
buffer_write_string (&msg, new_path);
- buffer_send (&msg, conn->out_fd);
+ res = buffer_send (&msg, conn->out_fd);
buffer_free (&msg);
- res = iobuf_read_result (conn->in_fd, id);
+ if (res == GNOME_VFS_OK) {
+ res = iobuf_read_result (conn->in_fd, id);
+ }
bail:
g_free (old_path);
@@ -3141,13 +3228,15 @@ do_rename (GnomeVFSMethod *method,
buffer_write_gint32 (&msg, id);
buffer_write_string (&msg, old_path);
buffer_write_string (&msg, new_path);
- buffer_send (&msg, conn->out_fd);
+ res = buffer_send (&msg, conn->out_fd);
buffer_free (&msg);
g_free (old_path);
g_free (new_path);
- res = iobuf_read_result (conn->in_fd, id);
+ if (res == GNOME_VFS_OK) {
+ res = iobuf_read_result (conn->in_fd, id);
+ }
sftp_connection_unref (conn);
sftp_connection_unlock (conn);
@@ -3171,10 +3260,12 @@ do_unlink (GnomeVFSMethod *method,
id = sftp_connection_get_id (conn);
URI_TO_PATH (uri, path);
- iobuf_send_string_request (conn->out_fd, id, SSH2_FXP_REMOVE, path, strlen (path));
+ res = iobuf_send_string_request (conn->out_fd, id, SSH2_FXP_REMOVE, path, strlen (path));
g_free (path);
- res = iobuf_read_result (conn->in_fd, id);
+ if (res == GNOME_VFS_OK) {
+ res = iobuf_read_result (conn->in_fd, id);
+ }
sftp_connection_unref (conn);
sftp_connection_unlock (conn);
@@ -3257,11 +3348,13 @@ do_set_file_info (GnomeVFSMethod
id = sftp_connection_get_id (conn);
URI_TO_PATH (uri, path);
- iobuf_send_string_request_with_file_info (conn->out_fd, id, SSH2_FXP_SETSTAT,
- path, strlen (path), info, mask);
+ res = iobuf_send_string_request_with_file_info (conn->out_fd, id, SSH2_FXP_SETSTAT,
+ path, strlen (path), info, mask);
g_free (path);
- res = iobuf_read_result (conn->in_fd, id);
+ if (res == GNOME_VFS_OK) {
+ res = iobuf_read_result (conn->in_fd, id);
+ }
sftp_connection_unref (conn);
sftp_connection_unlock (conn);
@@ -3329,10 +3422,12 @@ do_create_symlink (GnomeVFSMethod *met
buffer_write_gint32 (&msg, id);
buffer_write_string (&msg, real_target);
buffer_write_string (&msg, path);
- buffer_send (&msg, conn->out_fd);
+ res = buffer_send (&msg, conn->out_fd);
buffer_free (&msg);
- res = iobuf_read_result (conn->in_fd, id);
+ if (res == GNOME_VFS_OK) {
+ res = iobuf_read_result (conn->in_fd, id);
+ }
sftp_connection_unref (conn);
sftp_connection_unlock (conn);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]