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)