Mercurial > pidgin
changeset 29124:51c5cbc0d325
Kill off the use of fseek for non-seekable streams in file transfers.
Fixes #9841.
committer: John Bailey <rekkanoryo@rekkanoryo.org>
author | foufou33@gmail.com |
---|---|
date | Mon, 12 Oct 2009 18:41:51 +0000 |
parents | bb873040d7de |
children | 18667ce1f55d |
files | libpurple/ft.c |
diffstat | 1 files changed, 50 insertions(+), 15 deletions(-) [+] |
line wrap: on
line diff
--- a/libpurple/ft.c Mon Oct 12 17:45:33 2009 +0000 +++ b/libpurple/ft.c Mon Oct 12 18:41:51 2009 +0000 @@ -57,6 +57,7 @@ PURPLE_XFER_READY_UI = 0x1, PURPLE_XFER_READY_PRPL = 0x2, } ready; + GByteArray *buffer; } PurpleXferPrivData; static int purple_xfer_choose_file(PurpleXfer *xfer); @@ -66,6 +67,9 @@ { PurpleXferPrivData *priv = data; + if (priv->buffer) + g_byte_array_free(priv->buffer, TRUE); + g_free(priv); } @@ -93,14 +97,21 @@ xfer->type = type; xfer->account = account; xfer->who = g_strdup(who); - xfer->ui_ops = purple_xfers_get_ui_ops(); + xfer->ui_ops = ui_ops = purple_xfers_get_ui_ops(); xfer->message = NULL; xfer->current_buffer_size = FT_INITIAL_BUFFER_SIZE; xfer->fd = -1; priv = g_new0(PurpleXferPrivData, 1); priv->ready = PURPLE_XFER_READY_NONE; - + + if (ui_ops && ui_ops->data_not_sent) { + /* If the ui will handle unsent data no need for buffer */ + priv->buffer = NULL; + } else { + priv->buffer = g_byte_array_sized_new(FT_INITIAL_BUFFER_SIZE); + } + g_hash_table_insert(xfers_data, xfer, priv); ui_ops = purple_xfer_get_ui_ops(xfer); @@ -116,9 +127,12 @@ purple_xfer_destroy(PurpleXfer *xfer) { PurpleXferUiOps *ui_ops; + PurpleXferPrivData *priv; g_return_if_fail(xfer != NULL); + priv = g_hash_table_lookup(xfers_data, xfer); + /* Close the file browser, if it's open */ purple_request_close_with_handle(xfer); @@ -1010,6 +1024,7 @@ } else if (xfer->type == PURPLE_XFER_SEND) { size_t result; size_t s = MIN(purple_xfer_get_bytes_remaining(xfer), xfer->current_buffer_size); + PurpleXferPrivData *priv = g_hash_table_lookup(xfers_data, xfer); /* this is so the prpl can keep the connection open if it needs to for some odd reason. */ @@ -1021,6 +1036,10 @@ return; } + if (priv->buffer) { + s = s - priv->buffer->len; + } + if (ui_ops && ui_ops->ui_read) { gssize tmp = ui_ops->ui_read(xfer, &buffer, s); if (tmp == 0) { @@ -1033,8 +1052,13 @@ purple_input_remove(xfer->watcher); xfer->watcher = 0; } - - return; + /* + * if we requested 0 bytes it's only normal that en up here + * we shouldn't return as we still have something to + * write in priv->buffer + */ + if (s != 0) + return; } else if (tmp < 0) { purple_debug_error("filetransfer", "Unable to read whole buffer.\n"); purple_xfer_cancel_local(xfer); @@ -1052,29 +1076,40 @@ return; } } - - /* Write as much as we're allowed to. */ + + if (priv->buffer) { + priv->buffer = g_byte_array_append(priv->buffer, buffer, result); + g_free(buffer); + buffer = priv->buffer->data; + result = priv->buffer->len; + } + r = purple_xfer_write(xfer, buffer, result); if (r == -1) { purple_xfer_cancel_remote(xfer); g_free(buffer); return; - } else if (r < result) { - if (ui_ops == NULL || (ui_ops->ui_read == NULL && ui_ops->ui_write == NULL)) { - /* We have to seek back in the file now. */ - fseek(xfer->dest_fp, r - s, SEEK_CUR); - } - else { - ui_ops->data_not_sent(xfer, buffer + r, result - r); - } - } else { + } else if (r == result) { /* * We managed to write the entire buffer. This means our * network is fast and our buffer is too small, so make it * bigger. */ purple_xfer_increase_buffer_size(xfer); + } else { + if (ui_ops && ui_ops->data_not_sent) + ui_ops->data_not_sent(xfer, buffer + r, result -r); + } + + if (priv->buffer) { + /* + * Remove what we wrote + * If we wrote the whole buffer the byte array will be empty + * Otherwise we'll kee what wasn't sent for next time. + */ + buffer = NULL; + priv->buffer = g_byte_array_remove_range(priv->buffer, 0, r); } }