Mercurial > pidgin
comparison libpurple/ft.c @ 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 | 53aab96e61a9 |
children | 18667ce1f55d |
comparison
equal
deleted
inserted
replaced
29123:bb873040d7de | 29124:51c5cbc0d325 |
---|---|
55 enum { | 55 enum { |
56 PURPLE_XFER_READY_NONE = 0x0, | 56 PURPLE_XFER_READY_NONE = 0x0, |
57 PURPLE_XFER_READY_UI = 0x1, | 57 PURPLE_XFER_READY_UI = 0x1, |
58 PURPLE_XFER_READY_PRPL = 0x2, | 58 PURPLE_XFER_READY_PRPL = 0x2, |
59 } ready; | 59 } ready; |
60 GByteArray *buffer; | |
60 } PurpleXferPrivData; | 61 } PurpleXferPrivData; |
61 | 62 |
62 static int purple_xfer_choose_file(PurpleXfer *xfer); | 63 static int purple_xfer_choose_file(PurpleXfer *xfer); |
63 | 64 |
64 static void | 65 static void |
65 purple_xfer_priv_data_destroy(gpointer data) | 66 purple_xfer_priv_data_destroy(gpointer data) |
66 { | 67 { |
67 PurpleXferPrivData *priv = data; | 68 PurpleXferPrivData *priv = data; |
68 | 69 |
70 if (priv->buffer) | |
71 g_byte_array_free(priv->buffer, TRUE); | |
72 | |
69 g_free(priv); | 73 g_free(priv); |
70 } | 74 } |
71 | 75 |
72 GList * | 76 GList * |
73 purple_xfers_get_all() | 77 purple_xfers_get_all() |
91 | 95 |
92 xfer->ref = 1; | 96 xfer->ref = 1; |
93 xfer->type = type; | 97 xfer->type = type; |
94 xfer->account = account; | 98 xfer->account = account; |
95 xfer->who = g_strdup(who); | 99 xfer->who = g_strdup(who); |
96 xfer->ui_ops = purple_xfers_get_ui_ops(); | 100 xfer->ui_ops = ui_ops = purple_xfers_get_ui_ops(); |
97 xfer->message = NULL; | 101 xfer->message = NULL; |
98 xfer->current_buffer_size = FT_INITIAL_BUFFER_SIZE; | 102 xfer->current_buffer_size = FT_INITIAL_BUFFER_SIZE; |
99 xfer->fd = -1; | 103 xfer->fd = -1; |
100 | 104 |
101 priv = g_new0(PurpleXferPrivData, 1); | 105 priv = g_new0(PurpleXferPrivData, 1); |
102 priv->ready = PURPLE_XFER_READY_NONE; | 106 priv->ready = PURPLE_XFER_READY_NONE; |
103 | 107 |
108 if (ui_ops && ui_ops->data_not_sent) { | |
109 /* If the ui will handle unsent data no need for buffer */ | |
110 priv->buffer = NULL; | |
111 } else { | |
112 priv->buffer = g_byte_array_sized_new(FT_INITIAL_BUFFER_SIZE); | |
113 } | |
114 | |
104 g_hash_table_insert(xfers_data, xfer, priv); | 115 g_hash_table_insert(xfers_data, xfer, priv); |
105 | 116 |
106 ui_ops = purple_xfer_get_ui_ops(xfer); | 117 ui_ops = purple_xfer_get_ui_ops(xfer); |
107 | 118 |
108 if (ui_ops != NULL && ui_ops->new_xfer != NULL) | 119 if (ui_ops != NULL && ui_ops->new_xfer != NULL) |
114 | 125 |
115 static void | 126 static void |
116 purple_xfer_destroy(PurpleXfer *xfer) | 127 purple_xfer_destroy(PurpleXfer *xfer) |
117 { | 128 { |
118 PurpleXferUiOps *ui_ops; | 129 PurpleXferUiOps *ui_ops; |
119 | 130 PurpleXferPrivData *priv; |
120 g_return_if_fail(xfer != NULL); | 131 |
132 g_return_if_fail(xfer != NULL); | |
133 | |
134 priv = g_hash_table_lookup(xfers_data, xfer); | |
121 | 135 |
122 /* Close the file browser, if it's open */ | 136 /* Close the file browser, if it's open */ |
123 purple_request_close_with_handle(xfer); | 137 purple_request_close_with_handle(xfer); |
124 | 138 |
125 if (purple_xfer_get_status(xfer) == PURPLE_XFER_STATUS_STARTED) | 139 if (purple_xfer_get_status(xfer) == PURPLE_XFER_STATUS_STARTED) |
1008 return; | 1022 return; |
1009 } | 1023 } |
1010 } else if (xfer->type == PURPLE_XFER_SEND) { | 1024 } else if (xfer->type == PURPLE_XFER_SEND) { |
1011 size_t result; | 1025 size_t result; |
1012 size_t s = MIN(purple_xfer_get_bytes_remaining(xfer), xfer->current_buffer_size); | 1026 size_t s = MIN(purple_xfer_get_bytes_remaining(xfer), xfer->current_buffer_size); |
1027 PurpleXferPrivData *priv = g_hash_table_lookup(xfers_data, xfer); | |
1013 | 1028 |
1014 /* this is so the prpl can keep the connection open | 1029 /* this is so the prpl can keep the connection open |
1015 if it needs to for some odd reason. */ | 1030 if it needs to for some odd reason. */ |
1016 if (s == 0) { | 1031 if (s == 0) { |
1017 if (xfer->watcher) { | 1032 if (xfer->watcher) { |
1018 purple_input_remove(xfer->watcher); | 1033 purple_input_remove(xfer->watcher); |
1019 xfer->watcher = 0; | 1034 xfer->watcher = 0; |
1020 } | 1035 } |
1021 return; | 1036 return; |
1022 } | 1037 } |
1038 | |
1039 if (priv->buffer) { | |
1040 s = s - priv->buffer->len; | |
1041 } | |
1023 | 1042 |
1024 if (ui_ops && ui_ops->ui_read) { | 1043 if (ui_ops && ui_ops->ui_read) { |
1025 gssize tmp = ui_ops->ui_read(xfer, &buffer, s); | 1044 gssize tmp = ui_ops->ui_read(xfer, &buffer, s); |
1026 if (tmp == 0) { | 1045 if (tmp == 0) { |
1027 /* | 1046 /* |
1031 */ | 1050 */ |
1032 if (xfer->watcher != 0) { | 1051 if (xfer->watcher != 0) { |
1033 purple_input_remove(xfer->watcher); | 1052 purple_input_remove(xfer->watcher); |
1034 xfer->watcher = 0; | 1053 xfer->watcher = 0; |
1035 } | 1054 } |
1036 | 1055 /* |
1037 return; | 1056 * if we requested 0 bytes it's only normal that en up here |
1057 * we shouldn't return as we still have something to | |
1058 * write in priv->buffer | |
1059 */ | |
1060 if (s != 0) | |
1061 return; | |
1038 } else if (tmp < 0) { | 1062 } else if (tmp < 0) { |
1039 purple_debug_error("filetransfer", "Unable to read whole buffer.\n"); | 1063 purple_debug_error("filetransfer", "Unable to read whole buffer.\n"); |
1040 purple_xfer_cancel_local(xfer); | 1064 purple_xfer_cancel_local(xfer); |
1041 return; | 1065 return; |
1042 } | 1066 } |
1050 purple_xfer_cancel_local(xfer); | 1074 purple_xfer_cancel_local(xfer); |
1051 g_free(buffer); | 1075 g_free(buffer); |
1052 return; | 1076 return; |
1053 } | 1077 } |
1054 } | 1078 } |
1055 | 1079 |
1056 /* Write as much as we're allowed to. */ | 1080 if (priv->buffer) { |
1081 priv->buffer = g_byte_array_append(priv->buffer, buffer, result); | |
1082 g_free(buffer); | |
1083 buffer = priv->buffer->data; | |
1084 result = priv->buffer->len; | |
1085 } | |
1086 | |
1057 r = purple_xfer_write(xfer, buffer, result); | 1087 r = purple_xfer_write(xfer, buffer, result); |
1058 | 1088 |
1059 if (r == -1) { | 1089 if (r == -1) { |
1060 purple_xfer_cancel_remote(xfer); | 1090 purple_xfer_cancel_remote(xfer); |
1061 g_free(buffer); | 1091 g_free(buffer); |
1062 return; | 1092 return; |
1063 } else if (r < result) { | 1093 } else if (r == result) { |
1064 if (ui_ops == NULL || (ui_ops->ui_read == NULL && ui_ops->ui_write == NULL)) { | |
1065 /* We have to seek back in the file now. */ | |
1066 fseek(xfer->dest_fp, r - s, SEEK_CUR); | |
1067 } | |
1068 else { | |
1069 ui_ops->data_not_sent(xfer, buffer + r, result - r); | |
1070 } | |
1071 } else { | |
1072 /* | 1094 /* |
1073 * We managed to write the entire buffer. This means our | 1095 * We managed to write the entire buffer. This means our |
1074 * network is fast and our buffer is too small, so make it | 1096 * network is fast and our buffer is too small, so make it |
1075 * bigger. | 1097 * bigger. |
1076 */ | 1098 */ |
1077 purple_xfer_increase_buffer_size(xfer); | 1099 purple_xfer_increase_buffer_size(xfer); |
1100 } else { | |
1101 if (ui_ops && ui_ops->data_not_sent) | |
1102 ui_ops->data_not_sent(xfer, buffer + r, result -r); | |
1103 } | |
1104 | |
1105 if (priv->buffer) { | |
1106 /* | |
1107 * Remove what we wrote | |
1108 * If we wrote the whole buffer the byte array will be empty | |
1109 * Otherwise we'll kee what wasn't sent for next time. | |
1110 */ | |
1111 buffer = NULL; | |
1112 priv->buffer = g_byte_array_remove_range(priv->buffer, 0, r); | |
1078 } | 1113 } |
1079 } | 1114 } |
1080 | 1115 |
1081 if (r > 0) { | 1116 if (r > 0) { |
1082 if (purple_xfer_get_size(xfer) > 0) | 1117 if (purple_xfer_get_size(xfer) > 0) |