Fix purple_xfer_write() during do_transfer()

Thu, 07 Apr 2016 15:07:47 +0200

author
Jakub Adam <jakub.adam@ktknet.cz>
date
Thu, 07 Apr 2016 15:07:47 +0200
changeset 37644
451ed08be0b9
parent 37638
66ee77378d82
child 37645
ef1519ab5f2c

Fix purple_xfer_write() during do_transfer()

Consider sending a small (say 10 bytes) file in do_transfer().

First, the buffer is filled in purple_xfer_read_file(), which also calls
purple_xfer_set_bytes_sent(); because the file is small, bytes sent now
equals the file size. Later in purple_xfer_write(), the size of
the write buffer is adjusted so that it's not bigger than the remaining
portion of the file being sent - but at that point
purple_xfer_get_bytes_remaining() already returns 0, nothing is written
and the file transfer gets stuck.

As I understant it, the meaning of buffer size adjustment in
purple_xfer_write() is to ensure that external protocol plugin which
handles file transfer input and output on its own can't by accident send
more data than the size of the file. In do_transfer(), though, that
check is redundant and can be skipped.

libpurple/xfer.c file | annotate | diff | comparison | revisions
--- a/libpurple/xfer.c	Sat Apr 09 14:07:55 2016 -0300
+++ b/libpurple/xfer.c	Thu Apr 07 15:07:47 2016 +0200
@@ -1205,22 +1205,20 @@
 	return r;
 }
 
-gssize
-purple_xfer_write(PurpleXfer *xfer, const guchar *buffer, gsize size)
+static gssize
+do_write(PurpleXfer *xfer, const guchar *buffer, gsize size)
 {
 	PurpleXferPrivate *priv = PURPLE_XFER_GET_PRIVATE(xfer);
-	gssize r, s;
+	gssize r;
 
 	g_return_val_if_fail(priv   != NULL, 0);
 	g_return_val_if_fail(buffer != NULL, 0);
 	g_return_val_if_fail(size   != 0,    0);
 
-	s = MIN((gssize)purple_xfer_get_bytes_remaining(xfer), (gssize)size);
-
 	if (priv->ops.write != NULL) {
-		r = (priv->ops.write)(buffer, s, xfer);
+		r = (priv->ops.write)(buffer, size, xfer);
 	} else {
-		r = write(priv->fd, buffer, s);
+		r = write(priv->fd, buffer, size);
 		if (r < 0 && errno == EAGAIN)
 			r = 0;
 	}
@@ -1228,6 +1226,19 @@
 	return r;
 }
 
+gssize
+purple_xfer_write(PurpleXfer *xfer, const guchar *buffer, gsize size)
+{
+	PurpleXferPrivate *priv = PURPLE_XFER_GET_PRIVATE(xfer);
+	gssize s;
+
+	g_return_val_if_fail(priv != NULL, 0);
+
+	s = MIN((gssize)purple_xfer_get_bytes_remaining(xfer), (gssize)size);
+
+	return do_write(xfer, buffer, s);
+}
+
 gboolean
 purple_xfer_write_file(PurpleXfer *xfer, const guchar *buffer, gsize size)
 {
@@ -1405,7 +1416,7 @@
 			result = priv->buffer->len;
 		}
 
-		r = purple_xfer_write(xfer, buffer, result);
+		r = do_write(xfer, buffer, result);
 
 		if (r == -1) {
 			purple_xfer_cancel_remote(xfer);

mercurial