Thu, 07 Apr 2016 15:07:47 +0200
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);