summaryrefslogtreecommitdiffstats
path: root/src/AFC.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/AFC.c')
-rw-r--r--src/AFC.c724
1 files changed, 511 insertions, 213 deletions
diff --git a/src/AFC.c b/src/AFC.c
index e3f0bba..0f454a3 100644
--- a/src/AFC.c
+++ b/src/AFC.c
@@ -19,122 +19,182 @@
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */ 20 */
21 21
22#include <stdio.h>
22#include "AFC.h" 23#include "AFC.h"
23#include "plist.h" 24#include "plist.h"
25
24// This is the maximum size an AFC data packet can be 26// This is the maximum size an AFC data packet can be
25const int MAXIMUM_PACKET_SIZE = (2 << 15) - 32; 27const int MAXIMUM_PACKET_SIZE = (2 << 15) - 32;
26 28
27extern int debug; 29extern int debug;
28 30
29 31/** Locks an AFC client, done for thread safety stuff
30/* Locking, for thread-safety (well... kind of, hehe) */ 32 *
33 * @param client The AFC client connection to lock
34 */
31static void afc_lock(AFClient *client) { 35static void afc_lock(AFClient *client) {
32 if (debug) printf("In the midst of a lock...\n"); 36 if (debug) fprintf(stderr, "Locked\n");
33 while (client->lock) { 37 while (client->lock) {
34 usleep(500); // they say it's obsolete, but whatever 38 usleep(500); // they say it's obsolete, but whatever
35 } 39 }
36 client->lock = 1; 40 client->lock = 1;
37} 41}
38 42
43/** Unlocks an AFC client, done for thread safety stuff.
44 *
45 * @param client The AFC
46 */
39static void afc_unlock(AFClient *client) { // just to be pretty 47static void afc_unlock(AFClient *client) { // just to be pretty
40 if (debug) printf("Unlock!\n"); 48 if (debug) fprintf(stderr, "Unlocked\n");
41 client->lock = 0; 49 client->lock = 0;
42} 50}
43 51
44/* main AFC functions */ 52/** Makes a connection to the AFC service on the phone.
45 53 *
54 * @param phone The iPhone to connect on.
55 * @param s_port The source port.
56 * @param d_port The destination port.
57 *
58 * @return A handle to the newly-connected client or NULL upon error.
59 */
46AFClient *afc_connect(iPhone *phone, int s_port, int d_port) { 60AFClient *afc_connect(iPhone *phone, int s_port, int d_port) {
47 if (!phone) return NULL;
48 AFClient *client = (AFClient*)malloc(sizeof(AFClient)); 61 AFClient *client = (AFClient*)malloc(sizeof(AFClient));
62
63 if (!phone) return NULL;
64
65 // Attempt connection
49 client->connection = mux_connect(phone, s_port, d_port); 66 client->connection = mux_connect(phone, s_port, d_port);
50 if (!client->connection) { free(client); return NULL; } 67 if (!client->connection) {
51 else { 68 free(client);
52 client->afc_packet = (AFCPacket*)malloc(sizeof(AFCPacket)); 69 return NULL;
53 if (client->afc_packet) {
54 client->afc_packet->packet_num = 0;
55 client->afc_packet->unknown1 = client->afc_packet->unknown2 = client->afc_packet->unknown3 = client->afc_packet->unknown4 = client->afc_packet->entire_length = client->afc_packet->this_length = 0;
56 client->afc_packet->header1 = 0x36414643;
57 client->afc_packet->header2 = 0x4141504C;
58 client->file_handle = 0;
59 client->lock = 0;
60 return client;
61 } else {
62 mux_close_connection(client->connection);
63 free(client);
64 return NULL;
65 }
66 } 70 }
67 71
68 return NULL; // should never get to this point 72 // Allocate a packet
73 client->afc_packet = (AFCPacket*)malloc(sizeof(AFCPacket));
74 if (!client->afc_packet) {
75 mux_close_connection(client->connection);
76 free(client);
77 return NULL;
78 }
79
80 client->afc_packet->packet_num = 0;
81 client->afc_packet->unknown1 = 0;
82 client->afc_packet->unknown2 = 0;
83 client->afc_packet->unknown3 = 0;
84 client->afc_packet->unknown4 = 0;
85 client->afc_packet->entire_length = 0;
86 client->afc_packet->this_length = 0;
87 client->afc_packet->header1 = 0x36414643;
88 client->afc_packet->header2 = 0x4141504C;
89 client->file_handle = 0;
90 client->lock = 0;
91
92 return client;
69} 93}
70 94
95/** Disconnects an AFC client from the phone.
96 *
97 * @param client The client to disconnect.
98 */
99
71void afc_disconnect(AFClient *client) { 100void afc_disconnect(AFClient *client) {
72 // client and its members should never be NULL is assumed here.
73 if (!client || !client->connection || !client->afc_packet) return; 101 if (!client || !client->connection || !client->afc_packet) return;
102
74 mux_close_connection(client->connection); 103 mux_close_connection(client->connection);
75 free(client->afc_packet); 104 free(client->afc_packet);
76 free(client); 105 free(client);
77} 106}
78 107
79static int count_nullspaces(char *string, int number) {
80 int i = 0, nulls = 0;
81 for (i = 0; i < number; i++) {
82 if (string[i] == '\0') nulls++;
83 }
84 return nulls;
85}
86 108
109/** Dispatches an AFC packet over a client.
110 *
111 * @param client The client to send data through.
112 * @param data The data to send.
113 * @param length The length to send.
114 *
115 * @return The number of bytes actually sent, or -1 on error.
116 *
117 * @warning set client->afc_packet->this_length and
118 * client->afc_packet->entire_length to 0 before calling this. The
119 * reason is that if you set them to different values, it indicates
120 * you want to send the data as two packets.
121 */
87static int dispatch_AFC_packet(AFClient *client, const char *data, int length) { 122static int dispatch_AFC_packet(AFClient *client, const char *data, int length) {
88 int bytes = 0, offset = 0; 123 int bytes = 0, offset = 0;
124 char *buffer;
125
89 if (!client || !client->connection || !client->afc_packet) return 0; 126 if (!client || !client->connection || !client->afc_packet) return 0;
90 if (!data || !length) length = 0; 127 if (!data || !length) length = 0;
91 128
92 client->afc_packet->packet_num++; 129 client->afc_packet->packet_num++;
93 if (!client->afc_packet->entire_length) client->afc_packet->entire_length = client->afc_packet->this_length = (length) ? sizeof(AFCPacket) + length + 1 : sizeof(AFCPacket); 130 if (!client->afc_packet->entire_length) {
94 if (!client->afc_packet->this_length) client->afc_packet->this_length = sizeof(AFCPacket); 131 client->afc_packet->entire_length = (length) ? sizeof(AFCPacket) + length + 1 : sizeof(AFCPacket);
95 132 client->afc_packet->this_length = client->afc_packet->entire_length;
133 }
134 if (!client->afc_packet->this_length){
135 client->afc_packet->this_length = sizeof(AFCPacket);
136 }
137
138 // We want to send two segments; buffer+sizeof(AFCPacket) to this_length is the parameters
139 // And everything beyond that is the next packet. (for writing)
96 if (client->afc_packet->this_length != client->afc_packet->entire_length) { 140 if (client->afc_packet->this_length != client->afc_packet->entire_length) {
97 // We want to send two segments; buffer+sizeof(AFCPacket) to this_length is the parameters 141 buffer = (char*)malloc(client->afc_packet->this_length);
98 // And everything beyond that is the next packet. (for writing)
99 char *buffer = (char*)malloc(client->afc_packet->this_length);
100 memcpy(buffer, (char*)client->afc_packet, sizeof(AFCPacket)); 142 memcpy(buffer, (char*)client->afc_packet, sizeof(AFCPacket));
101 offset = client->afc_packet->this_length - sizeof(AFCPacket); 143 offset = client->afc_packet->this_length - sizeof(AFCPacket);
102 if (debug) printf("dispatch_AFC_packet: Offset: %i\n", offset); 144
145 if (debug) fprintf(stderr, "dispatch_AFC_packet: Offset: %i\n", offset);
103 if ((length) < (client->afc_packet->entire_length - client->afc_packet->this_length)) { 146 if ((length) < (client->afc_packet->entire_length - client->afc_packet->this_length)) {
104 if (debug) printf("dispatch_AFC_packet: Length did not resemble what it was supposed to based on the packet.\nlength minus offset: %i\nrest of packet: %i\n", length-offset, client->afc_packet->entire_length - client->afc_packet->this_length); 147 if (debug){
148 fprintf(stderr, "dispatch_AFC_packet: Length did not resemble what it was supposed");
149 fprintf(stderr, "to based on the packet.\n");
150 fprintf(stderr, "length minus offset: %i\n", length-offset);
151 fprintf(stderr, "rest of packet: %i\n", client->afc_packet->entire_length - client->afc_packet->this_length);
152 }
105 free(buffer); 153 free(buffer);
106 return -1; 154 return -1;
107 } 155 }
108 if (debug) printf("dispatch_AFC_packet: fucked-up packet method (probably a write)\n");
109 memcpy(buffer+sizeof(AFCPacket), data, offset); 156 memcpy(buffer+sizeof(AFCPacket), data, offset);
110 bytes = mux_send(client->connection, buffer, client->afc_packet->this_length); 157 bytes = mux_send(client->connection, buffer, client->afc_packet->this_length);
111 free(buffer); 158 free(buffer);
112 if (bytes <= 0) { return bytes; } 159 if (bytes <= 0) {
160 return bytes;
161 }
162
113 if (debug) { 163 if (debug) {
114 printf("dispatch_AFC_packet: sent the first now go with the second\n"); 164 fprintf(stderr, "dispatch_AFC_packet: sent the first now go with the second\n");
115 printf("Length: %i\n", length-offset); 165 fprintf(stderr, "Length: %i\n", length-offset);
116 printf("Buffer: \n"); 166 fprintf(stderr, "Buffer: \n");
117 fwrite(data+offset, 1, length-offset, stdout); 167 fwrite(data+offset, 1, length-offset, stdout);
118 } 168 }
119 169
120
121 bytes = mux_send(client->connection, data+offset, length-offset); 170 bytes = mux_send(client->connection, data+offset, length-offset);
122 return bytes; 171 return bytes;
123 } else { 172 } else {
124 if (debug) printf("dispatch_AFC_packet doin things the old way\n"); 173 if (debug) fprintf(stderr, "dispatch_AFC_packet doin things the old way\n");
125 char *buffer = (char*)malloc(sizeof(char) * client->afc_packet->this_length); 174 char *buffer = (char*)malloc(sizeof(char) * client->afc_packet->this_length);
126 if (debug) printf("dispatch_AFC_packet packet length = %i\n", client->afc_packet->this_length); 175 if (debug) fprintf(stderr, "dispatch_AFC_packet packet length = %i\n", client->afc_packet->this_length);
127 memcpy(buffer, (char*)client->afc_packet, sizeof(AFCPacket)); 176 memcpy(buffer, (char*)client->afc_packet, sizeof(AFCPacket));
128 if (debug) printf("dispatch_AFC_packet packet data follows\n"); 177 if (debug) fprintf(stderr, "dispatch_AFC_packet packet data follows\n");
129 if (length > 0) { memcpy(buffer+sizeof(AFCPacket), data, length); buffer[sizeof(AFCPacket)+length] = '\0'; } 178 if (length > 0) { memcpy(buffer+sizeof(AFCPacket), data, length); buffer[sizeof(AFCPacket)+length] = '\0'; }
130 if (debug) fwrite(buffer, 1, client->afc_packet->this_length, stdout); 179 if (debug) fwrite(buffer, 1, client->afc_packet->this_length, stdout);
131 if (debug) printf("\n"); 180 if (debug) fprintf(stderr, "\n");
132 bytes = mux_send(client->connection, buffer, client->afc_packet->this_length); 181 bytes = mux_send(client->connection, buffer, client->afc_packet->this_length);
133 return bytes; 182 return bytes;
134 } 183 }
135 return -1; 184 return -1;
136} 185}
137 186
187/** Receives data through an AFC client and sets a variable to the received data.
188 *
189 * @param client The client to receive data on.
190 * @param dump_here The char* to point to the newly-received data.
191 *
192 * @return How much data was received, 0 on successful receive with no errors,
193 * -1 if there was an error involved with receiving or if the packet
194 * received raised a non-trivial error condition (i.e. non-zero with
195 * AFC_ERROR operation)
196 */
197
138static int receive_AFC_data(AFClient *client, char **dump_here) { 198static int receive_AFC_data(AFClient *client, char **dump_here) {
139 AFCPacket *r_packet; 199 AFCPacket *r_packet;
140 char *buffer = (char*)malloc(sizeof(AFCPacket) * 4); 200 char *buffer = (char*)malloc(sizeof(AFCPacket) * 4);
@@ -145,7 +205,7 @@ static int receive_AFC_data(AFClient *client, char **dump_here) {
145 bytes = mux_recv(client->connection, buffer, sizeof(AFCPacket) * 4); 205 bytes = mux_recv(client->connection, buffer, sizeof(AFCPacket) * 4);
146 if (bytes <= 0) { 206 if (bytes <= 0) {
147 free(buffer); 207 free(buffer);
148 printf("Just didn't get enough.\n"); 208 fprintf(stderr, "Just didn't get enough.\n");
149 *dump_here = NULL; 209 *dump_here = NULL;
150 return -1; 210 return -1;
151 } 211 }
@@ -165,25 +225,22 @@ static int receive_AFC_data(AFClient *client, char **dump_here) {
165 uint32 param1 = buffer[sizeof(AFCPacket)]; 225 uint32 param1 = buffer[sizeof(AFCPacket)];
166 free(buffer); 226 free(buffer);
167 227
168 if (r_packet->operation == AFC_ERROR 228 if (r_packet->operation == AFC_ERROR && !(client->afc_packet->operation == AFC_DELETE && param1 == 7)) {
169 && !(client->afc_packet->operation == AFC_DELETE && param1 == 7) 229 if (debug) fprintf(stderr, "Oops? Bad operation code received: 0x%X, operation=0x%X, param1=%d\n",
170 )
171 {
172 if (debug) printf("Oops? Bad operation code received: 0x%X, operation=0x%X, param1=%d\n",
173 r_packet->operation, client->afc_packet->operation, param1); 230 r_packet->operation, client->afc_packet->operation, param1);
174 recv_len = r_packet->entire_length - r_packet->this_length; 231 recv_len = r_packet->entire_length - r_packet->this_length;
175 if (debug) printf("recv_len=%d\n", recv_len); 232 if (debug) fprintf(stderr, "recv_len=%d\n", recv_len);
176 if(param1 == 0) { 233 if(param1 == 0) {
177 if (debug) printf("... false alarm, but still\n"); 234 if (debug) fprintf(stderr, "... false alarm, but still\n");
178 *dump_here = NULL; 235 *dump_here = NULL;
179 return 0; 236 return 0;
180 } 237 }
181 else { if (debug) printf("Errno %i\n", param1); } 238 else { if (debug) fprintf(stderr, "Errno %i\n", param1); }
182 free(r_packet); 239 free(r_packet);
183 *dump_here = NULL; 240 *dump_here = NULL;
184 return -1; 241 return -1;
185 } else { 242 } else {
186 if (debug) printf("Operation code %x\nFull length %i and this length %i\n", r_packet->operation, r_packet->entire_length, r_packet->this_length); 243 if (debug) fprintf(stderr, "Operation code %x\nFull length %i and this length %i\n", r_packet->operation, r_packet->entire_length, r_packet->this_length);
187 } 244 }
188 245
189 recv_len = r_packet->entire_length - r_packet->this_length; 246 recv_len = r_packet->entire_length - r_packet->this_length;
@@ -199,21 +256,20 @@ static int receive_AFC_data(AFClient *client, char **dump_here) {
199 final_buffer = (char*)malloc(sizeof(char) * recv_len); 256 final_buffer = (char*)malloc(sizeof(char) * recv_len);
200 while(current_count < recv_len){ 257 while(current_count < recv_len){
201 bytes = mux_recv(client->connection, buffer, recv_len-current_count); 258 bytes = mux_recv(client->connection, buffer, recv_len-current_count);
202 if (debug) printf("receive_AFC_data: still collecting packets\n"); 259 if (debug) fprintf(stderr, "receive_AFC_data: still collecting packets\n");
203 if (bytes < 0) 260 if (bytes < 0)
204 { 261 {
205 if(debug) printf("receive_AFC_data: mux_recv failed: %d\n", bytes); 262 if(debug) fprintf(stderr, "receive_AFC_data: mux_recv failed: %d\n", bytes);
206 break; 263 break;
207 } 264 }
208 if (bytes > recv_len-current_count) 265 if (bytes > recv_len-current_count)
209 { 266 {
210 if(debug) printf("receive_AFC_data: mux_recv delivered too much data\n"); 267 if(debug) fprintf(stderr, "receive_AFC_data: mux_recv delivered too much data\n");
211 break; 268 break;
212 } 269 }
213 if (strstr(buffer, "CFA6LPAA")) { 270 if (strstr(buffer, "CFA6LPAA")) {
214 if (debug) printf("receive_AFC_data: WARNING: there is AFC data in this packet at %ti\n", strstr(buffer, "CFA6LPAA") - buffer); 271 if (debug) fprintf(stderr, "receive_AFC_data: WARNING: there is AFC data in this packet at %ti\n", strstr(buffer, "CFA6LPAA") - buffer);
215 if (debug) printf("receive_AFC_data: the total packet length is %i\n", bytes); 272 if (debug) fprintf(stderr, "receive_AFC_data: the total packet length is %i\n", bytes);
216 //continue; // but we do need to continue because packets/headers != data
217 } 273 }
218 274
219 memcpy(final_buffer+current_count, buffer, bytes); 275 memcpy(final_buffer+current_count, buffer, bytes);
@@ -221,22 +277,26 @@ static int receive_AFC_data(AFClient *client, char **dump_here) {
221 } 277 }
222 free(buffer); 278 free(buffer);
223 279
224 /*if (bytes <= 0) { 280 *dump_here = final_buffer;
225 free(final_buffer);
226 printf("Didn't get it at the second pass.\n");
227 *dump_here = NULL;
228 return 0;
229 }*/
230
231 *dump_here = final_buffer; // what they do beyond this point = not my problem
232 return current_count; 281 return current_count;
233} 282}
234 283
284static int count_nullspaces(char *string, int number) {
285 int i = 0, nulls = 0;
286
287 for (i = 0; i < number; i++) {
288 if (string[i] == '\0') nulls++;
289 }
290
291 return nulls;
292}
293
235static char **make_strings_list(char *tokens, int true_length) { 294static char **make_strings_list(char *tokens, int true_length) {
236 if (!tokens || !true_length) return NULL;
237 int nulls = 0, i = 0, j = 0; 295 int nulls = 0, i = 0, j = 0;
238 char **list = NULL; 296 char **list = NULL;
239 297
298 if (!tokens || !true_length) return NULL;
299
240 nulls = count_nullspaces(tokens, true_length); 300 nulls = count_nullspaces(tokens, true_length);
241 list = (char**)malloc(sizeof(char*) * (nulls + 1)); 301 list = (char**)malloc(sizeof(char*) * (nulls + 1));
242 for (i = 0; i < nulls; i++) { 302 for (i = 0; i < nulls; i++) {
@@ -244,118 +304,242 @@ static char **make_strings_list(char *tokens, int true_length) {
244 j += strlen(list[i]) + 1; 304 j += strlen(list[i]) + 1;
245 } 305 }
246 list[i] = strdup(""); 306 list[i] = strdup("");
307
247 return list; 308 return list;
248} 309}
249 310
311/** Gets a directory listing of the directory requested.
312 *
313 * @param client The client to get a directory listing from.
314 * @param dir The directory to list. (must be a fully-qualified path)
315 *
316 * @return A char ** list of files in that directory, terminated by an empty
317 * string for now or NULL if there was an error.
318 */
250char **afc_get_dir_list(AFClient *client, const char *dir) { 319char **afc_get_dir_list(AFClient *client, const char *dir) {
320 int bytes = 0;
321 char *data = NULL, **list = NULL;
322
323 if (!client || !dir) return NULL;
324
251 afc_lock(client); 325 afc_lock(client);
326
327 // Send the command
252 client->afc_packet->operation = AFC_LIST_DIR; 328 client->afc_packet->operation = AFC_LIST_DIR;
253 int bytes = 0; 329 client->afc_packet->entire_length = 0;
254 char *blah = NULL, **list = NULL; 330 client->afc_packet->this_length = 0;
255 client->afc_packet->entire_length = client->afc_packet->this_length = 0;
256 bytes = dispatch_AFC_packet(client, dir, strlen(dir)); 331 bytes = dispatch_AFC_packet(client, dir, strlen(dir));
257 if (bytes <= 0) { afc_unlock(client); return NULL; } 332 if (bytes <= 0) {
333 afc_unlock(client);
334 return NULL;
335 }
258 336
259 bytes = receive_AFC_data(client, &blah); 337 // Receive the data
260 if (bytes < 0 && !blah) { afc_unlock(client); return NULL; } 338 bytes = receive_AFC_data(client, &data);
339 if (bytes < 0 && !data) {
340 afc_unlock(client);
341 return NULL;
342 }
261 343
262 list = make_strings_list(blah, bytes); 344 // Parse the data
263 free(blah); 345 list = make_strings_list(data, bytes);
346 if (data) free(data);
347
264 afc_unlock(client); 348 afc_unlock(client);
349
265 return list; 350 return list;
266} 351}
267 352
353/** Get device info for a client connection to phone. (free space on disk, etc.)
354 *
355 * @param client The client to get device info for.
356 *
357 * @return A char ** list of parameters as given by AFC or NULL if there was an
358 * error.
359 */
268char **afc_get_devinfo(AFClient *client) { 360char **afc_get_devinfo(AFClient *client) {
361 int bytes = 0;
362 char *data = NULL, **list = NULL;
363
364 if (!client) return NULL;
365
269 afc_lock(client); 366 afc_lock(client);
367
368 // Send the command
270 client->afc_packet->operation = AFC_GET_DEVINFO; 369 client->afc_packet->operation = AFC_GET_DEVINFO;
271 int bytes = 0;
272 char *blah = NULL, **list = NULL;
273 client->afc_packet->entire_length = client->afc_packet->this_length = 0; 370 client->afc_packet->entire_length = client->afc_packet->this_length = 0;
274 bytes = dispatch_AFC_packet(client, NULL, 0); 371 bytes = dispatch_AFC_packet(client, NULL, 0);
275 if (bytes < 0) { afc_unlock(client); return NULL; } 372 if (bytes < 0) {
373 afc_unlock(client);
374 return NULL;
375 }
276 376
277 bytes = receive_AFC_data(client, &blah); 377 // Receive the data
278 if (bytes < 0 && !blah) { afc_unlock(client); return NULL; } 378 bytes = receive_AFC_data(client, &data);
379 if (bytes < 0 && !data) {
380 afc_unlock(client);
381 return NULL;
382 }
383
384 // Parse the data
385 list = make_strings_list(data, bytes);
386 if (data) free(data);
279 387
280 list = make_strings_list(blah, bytes);
281 free(blah);
282 afc_unlock(client); 388 afc_unlock(client);
389
283 return list; 390 return list;
284} 391}
285 392
286 393/** Deletes a file.
394 *
395 * @param client The client to have delete the file.
396 * @param path The file to delete. (must be a fully-qualified path)
397 *
398 * @return 1 on success, 0 on failure.
399 */
287int afc_delete_file(AFClient *client, const char *path) { 400int afc_delete_file(AFClient *client, const char *path) {
401 char *response = NULL;
402 int bytes;
403
288 if (!client || !path || !client->afc_packet || !client->connection) return 0; 404 if (!client || !path || !client->afc_packet || !client->connection) return 0;
405
289 afc_lock(client); 406 afc_lock(client);
290 char *receive = NULL; 407
408 // Send command
291 client->afc_packet->this_length = client->afc_packet->entire_length = 0; 409 client->afc_packet->this_length = client->afc_packet->entire_length = 0;
292 client->afc_packet->operation = AFC_DELETE; 410 client->afc_packet->operation = AFC_DELETE;
293 int bytes;
294 bytes = dispatch_AFC_packet(client, path, strlen(path)); 411 bytes = dispatch_AFC_packet(client, path, strlen(path));
295 if (bytes <= 0) { afc_unlock(client); return 0; } 412 if (bytes <= 0) {
413 afc_unlock(client);
414 return 0;
415 }
416
417 // Receive response
418 bytes = receive_AFC_data(client, &response);
419 if (response) free(response);
296 420
297 bytes = receive_AFC_data(client, &receive);
298 free(receive);
299 afc_unlock(client); 421 afc_unlock(client);
300 if (bytes < 0) { return 0; } 422
301 else return 1; 423 if (bytes < 0) {
424 return 0;
425 } else {
426 return 1;
427 }
302} 428}
303 429
430/** Renames a file on the phone.
431 *
432 * @param client The client to have rename the file.
433 * @param from The file to rename. (must be a fully-qualified path)
434 * @param to The new name of the file. (must also be a fully-qualified path)
435 *
436 * @return 1 on success, 0 on failure.
437 */
304int afc_rename_file(AFClient *client, const char *from, const char *to) { 438int afc_rename_file(AFClient *client, const char *from, const char *to) {
305 if (!client || !from || !to || !client->afc_packet || !client->connection) return 0; 439 char *response = NULL;
306 afc_lock(client);
307 char *receive = NULL;
308 char *send = (char*)malloc(sizeof(char) * (strlen(from) + strlen(to) + 1 + sizeof(uint32))); 440 char *send = (char*)malloc(sizeof(char) * (strlen(from) + strlen(to) + 1 + sizeof(uint32)));
309 int bytes = 0; 441 int bytes = 0;
310 442
443 if (!client || !from || !to || !client->afc_packet || !client->connection) return 0;
444
445 afc_lock(client);
446
447 // Send command
311 memcpy(send, from, strlen(from)+1); 448 memcpy(send, from, strlen(from)+1);
312 memcpy(send+strlen(from)+1, to, strlen(to)); 449 memcpy(send+strlen(from)+1, to, strlen(to));
313 fwrite(send, 1, strlen(from)+1+strlen(to), stdout);
314 printf("\n");
315 client->afc_packet->entire_length = client->afc_packet->this_length = 0; 450 client->afc_packet->entire_length = client->afc_packet->this_length = 0;
316 client->afc_packet->operation = AFC_RENAME; 451 client->afc_packet->operation = AFC_RENAME;
317 bytes = dispatch_AFC_packet(client, send, strlen(to) + strlen(from) + 2); 452 bytes = dispatch_AFC_packet(client, send, strlen(to) + strlen(from) + 2);
318 if (bytes <= 0) { afc_unlock(client); return 0; } 453 if (bytes <= 0) {
454 afc_unlock(client);
455 return 0;
456 }
319 457
320 bytes = receive_AFC_data(client, &receive); 458 // Receive response
321 free(receive); 459 bytes = receive_AFC_data(client, &response);
460 if (response) free(response);
461
322 afc_unlock(client); 462 afc_unlock(client);
323 if (bytes < 0) return 0; 463
324 else return 1; 464 if (bytes < 0) {
465 return 0;
466 } else {
467 return 1;
468 }
325} 469}
326 470
471/** Creates a directory on the phone.
472 *
473 * @param client The client to use to make a directory.
474 * @param dir The directory's path. (must be a fully-qualified path, I assume
475 * all other mkdir restrictions apply as well)
476 *
477 * @return 1 on success, 0 on failure.
478 */
479
327int afc_mkdir(AFClient *client, const char *dir) { 480int afc_mkdir(AFClient *client, const char *dir) {
481 int bytes = 0;
482 char *response = NULL;
483
328 if (!client) return 0; 484 if (!client) return 0;
485
329 afc_lock(client); 486 afc_lock(client);
330 int bytes = 0;
331 char *recvd = NULL;
332 487
488 // Send command
333 client->afc_packet->operation = AFC_MAKE_DIR; 489 client->afc_packet->operation = AFC_MAKE_DIR;
334 client->afc_packet->this_length = client->afc_packet->entire_length = 0; 490 client->afc_packet->this_length = client->afc_packet->entire_length = 0;
335 bytes = dispatch_AFC_packet(client, dir, strlen(dir)); 491 bytes = dispatch_AFC_packet(client, dir, strlen(dir));
336 if (bytes <= 0) { afc_unlock(client); return 0; } 492 if (bytes <= 0) {
493 afc_unlock(client);
494 return 0;
495 }
337 496
338 bytes = receive_AFC_data(client, &recvd); 497 // Receive response
498 bytes = receive_AFC_data(client, &response);
499 if (response) free(response);
500
339 afc_unlock(client); 501 afc_unlock(client);
340 if (recvd) { free(recvd); recvd = NULL; } 502
341 if (bytes == 0) return 1; 503 if (bytes == 0) {
342 else return 0; 504 return 1;
505 } else {
506 return 0;
507 }
343} 508}
344 509
510/** Gets information about a specific file.
511 *
512 * @param client The client to use to get the information of the file.
513 * @param path The fully-qualified path to the file.
514 *
515 * @return A pointer to an AFCFile struct containing the information received,
516 * or NULL on failure.
517 */
345AFCFile *afc_get_file_info(AFClient *client, const char *path) { 518AFCFile *afc_get_file_info(AFClient *client, const char *path) {
346 client->afc_packet->operation = AFC_GET_INFO;
347 client->afc_packet->entire_length = client->afc_packet->this_length = 0;
348 afc_lock(client);
349 dispatch_AFC_packet(client, path, strlen(path));
350
351 char *received, **list; 519 char *received, **list;
352 AFCFile *my_file; 520 AFCFile *my_file;
353 int length, i = 0; 521 int length, i = 0;
354 522
523 afc_lock(client);
524
525 // Send command
526 client->afc_packet->operation = AFC_GET_INFO;
527 client->afc_packet->entire_length = client->afc_packet->this_length = 0;
528 dispatch_AFC_packet(client, path, strlen(path));
529
530 // Receive data
355 length = receive_AFC_data(client, &received); 531 length = receive_AFC_data(client, &received);
356 list = make_strings_list(received, length); 532 if (received) {
357 free(received); 533 list = make_strings_list(received, length);
358 afc_unlock(client); // the rest is just interpretation anyway 534 free(received);
535 } else {
536 afc_unlock(client);
537 return NULL;
538 }
539
540 afc_unlock(client);
541
542 // Parse the data
359 if (list) { 543 if (list) {
360 my_file = (AFCFile *)malloc(sizeof(AFCFile)); 544 my_file = (AFCFile *)malloc(sizeof(AFCFile));
361 for (i = 0; strcmp(list[i], ""); i++) { 545 for (i = 0; strcmp(list[i], ""); i++) {
@@ -383,42 +567,62 @@ AFCFile *afc_get_file_info(AFClient *client, const char *path) {
383 } 567 }
384} 568}
385 569
570/** Opens a file on the phone.
571 *
572 * @param client The client to use to open the file.
573 * @param filename The file to open. (must be a fully-qualified path)
574 * @param file_mode The mode to use to open the file. Can be AFC_FILE_READ or
575 * AFC_FILE_WRITE; the former lets you read and write,
576 * however, and the second one will *create* the file,
577 * destroying anything previously there.
578 *
579 * @return A pointer to an AFCFile struct containing the file information (as
580 * received by afc_get_file_info) as well as the handle to the file or
581 * NULL in the case of failure.
582 */
386AFCFile *afc_open_file(AFClient *client, const char *filename, uint32 file_mode) { 583AFCFile *afc_open_file(AFClient *client, const char *filename, uint32 file_mode) {
387 //if (file_mode != AFC_FILE_READ && file_mode != AFC_FILE_WRITE) return NULL;
388 if (!client ||!client->connection || !client->afc_packet) return NULL;
389 afc_lock(client);
390 char *further_data = (char*)malloc(sizeof(char) * (8 + strlen(filename) + 1));
391 AFCFile *file_infos = NULL; 584 AFCFile *file_infos = NULL;
392 memcpy(further_data, &file_mode, 4);
393 uint32 ag = 0; 585 uint32 ag = 0;
394 memcpy(further_data+4, &ag, 4); 586 int bytes = 0, length = 0;
395 memcpy(further_data+8, filename, strlen(filename)); 587 char *data = (char*)malloc(sizeof(char) * (8 + strlen(filename) + 1));
396 further_data[8+strlen(filename)] = '\0'; 588
397 int bytes = 0, length_thing = 0; 589 if (!client ||!client->connection || !client->afc_packet) return NULL;
398 client->afc_packet->operation = AFC_FILE_OPEN; 590
591 afc_lock(client);
399 592
593 // Send command
594 memcpy(data, &file_mode, 4);
595 memcpy(data+4, &ag, 4);
596 memcpy(data+8, filename, strlen(filename));
597 data[8+strlen(filename)] = '\0';
598 client->afc_packet->operation = AFC_FILE_OPEN;
400 client->afc_packet->entire_length = client->afc_packet->this_length = 0; 599 client->afc_packet->entire_length = client->afc_packet->this_length = 0;
401 bytes = dispatch_AFC_packet(client, further_data, 8+strlen(filename)); 600 bytes = dispatch_AFC_packet(client, data, 8+strlen(filename));
402 free(further_data); 601 free(data);
602
403 if (bytes <= 0) { 603 if (bytes <= 0) {
404 if (debug) printf("didn't read enough\n"); 604 if (debug) fprintf(stderr, "afc_open_file: Didn't receive a response to the command\n");
405 afc_unlock(client); 605 afc_unlock(client);
406 return NULL; 606 return NULL;
607 }
608
609 // Receive the data
610 length = receive_AFC_data(client, &data);
611 if (length > 0 && data) {
612 afc_unlock(client);
613
614 // Get the file info and return it
615 file_infos = afc_get_file_info(client, filename);
616 memcpy(&file_infos->filehandle, data, 4);
617 return file_infos;
407 } else { 618 } else {
408 length_thing = receive_AFC_data(client, &further_data); 619 if (debug) fprintf(stderr, "afc_open_file: Didn't get any further data\n");
409 if (length_thing > 0 && further_data) { 620 afc_unlock(client);
410 afc_unlock(client); // don't want to hang on the next call... and besides, it'll re-lock, do its thing, and unlock again anyway. 621 return NULL;
411 file_infos = afc_get_file_info(client, filename);
412 memcpy(&file_infos->filehandle, further_data, 4);
413 return file_infos;
414 } else {
415 if (debug) printf("didn't get further data or something\n");
416 afc_unlock(client);
417 return NULL;
418 }
419 } 622 }
420 if (debug) printf("what the fuck\n"); 623
421 afc_unlock(client); 624 afc_unlock(client);
625
422 return NULL; 626 return NULL;
423} 627}
424 628
@@ -429,22 +633,21 @@ AFCFile *afc_open_file(AFClient *client, const char *filename, uint32 file_mode)
429 * @param data The pointer to the memory region to store the read data 633 * @param data The pointer to the memory region to store the read data
430 * @param length The number of bytes to read 634 * @param length The number of bytes to read
431 * 635 *
432 * @return The number of bytes read if successful. If there was an error 636 * @return The number of bytes read if successful. If there was an error -1.
433 */ 637 */
434int afc_read_file(AFClient *client, AFCFile *file, char *data, int length) { 638int afc_read_file(AFClient *client, AFCFile *file, char *data, int length) {
435 if (!client || !client->afc_packet || !client->connection || !file) return -1;
436 if (debug) printf("afc_read_file called for length %i\n", length);
437
438 char *input = NULL; 639 char *input = NULL;
439 int current_count = 0, bytes = 0; 640 int current_count = 0, bytes = 0;
440 const int MAXIMUM_READ_SIZE = 1 << 16; 641 const int MAXIMUM_READ_SIZE = 1 << 16;
441 642
442 afc_lock(client); 643 if (!client || !client->afc_packet || !client->connection || !file) return -1;
644 if (debug) fprintf(stderr, "afc_read_file called for length %i\n", length);
443 645
646 afc_lock(client);
444 647
445 // Looping here to get around the maximum amount of data that recieve_AFC_data can handle 648 // Looping here to get around the maximum amount of data that recieve_AFC_data can handle
446 while (current_count < length){ 649 while (current_count < length){
447 if (debug) printf("afc_read_file: current count is %i but length is %i\n", current_count, length); 650 if (debug) fprintf(stderr, "afc_read_file: current count is %i but length is %i\n", current_count, length);
448 651
449 // Send the read command 652 // Send the read command
450 AFCFilePacket *packet = (AFCFilePacket*)malloc(sizeof(AFCFilePacket)); 653 AFCFilePacket *packet = (AFCFilePacket*)malloc(sizeof(AFCFilePacket));
@@ -455,120 +658,182 @@ int afc_read_file(AFClient *client, AFCFile *file, char *data, int length) {
455 client->afc_packet->entire_length = client->afc_packet->this_length = 0; 658 client->afc_packet->entire_length = client->afc_packet->this_length = 0;
456 bytes = dispatch_AFC_packet(client, (char*)packet, sizeof(AFCFilePacket)); 659 bytes = dispatch_AFC_packet(client, (char*)packet, sizeof(AFCFilePacket));
457 660
458 // If we get a positive reponse to the command gather the data 661 if (bytes <= 0) {
459 if (bytes > 0) {
460 bytes = receive_AFC_data(client, &input);
461 if (debug) printf("afc_read_file: bytes returned: %i\n", bytes);
462 if (bytes < 0) {
463 if (input) free(input);
464 afc_unlock(client);
465 return -1;
466 } else if (bytes == 0) {
467 if (input) free(input);
468 afc_unlock(client);
469 return current_count;
470 } else {
471 if (input) {
472 if (debug) printf("afc_read_file: %d\n", bytes);
473 memcpy(data+current_count, input, (bytes > length) ? length : bytes);
474 free(input);
475 input = NULL;
476 current_count += (bytes > length) ? length : bytes;
477 }
478 }
479 } else {
480 afc_unlock(client); 662 afc_unlock(client);
481 return -1; 663 return -1;
482 } 664 }
665
666 // Receive the data
667 bytes = receive_AFC_data(client, &input);
668 if (debug) fprintf(stderr, "afc_read_file: bytes returned: %i\n", bytes);
669 if (bytes < 0) {
670 if (input) free(input);
671 afc_unlock(client);
672 return -1;
673 } else if (bytes == 0) {
674 if (input) free(input);
675 afc_unlock(client);
676 return current_count;
677 } else {
678 if (input) {
679 if (debug) fprintf(stderr, "afc_read_file: %d\n", bytes);
680 memcpy(data+current_count, input, (bytes > length) ? length : bytes);
681 free(input);
682 input = NULL;
683 current_count += (bytes > length) ? length : bytes;
684 }
685 }
483 } 686 }
687 if (debug) fprintf(stderr, "afc_read_file: returning current_count as %i\n", current_count);
688
484 afc_unlock(client); 689 afc_unlock(client);
485 if (debug) printf("afc_read_file: returning current_count as %i\n", current_count); 690
486 return current_count; 691 return current_count;
487} 692}
488 693
694/** Writes a given number of bytes to a file.
695 *
696 * @param client The client to use to write to the file.
697 * @param file A pointer to an AFCFile struct; serves as the file handle.
698 * @param data The data to write to the file.
699 * @param length How much data to write.
700 *
701 * @return The number of bytes written to the file, or a value less than 0 if
702 * none were written...
703 */
704
489int afc_write_file(AFClient *client, AFCFile *file, const char *data, int length) { 705int afc_write_file(AFClient *client, AFCFile *file, const char *data, int length) {
490 char *acknowledgement = NULL; 706 char *acknowledgement = NULL;
491 if (!client ||!client->afc_packet || !client->connection || !file) return -1;
492 afc_lock(client);
493 if (debug) printf("afc_write_file: Write length: %i\n", length);
494 const int MAXIMUM_WRITE_SIZE = 1 << 16; 707 const int MAXIMUM_WRITE_SIZE = 1 << 16;
495 uint32 zero = 0, bytes = 0, segments = (length / MAXIMUM_WRITE_SIZE), current_count = 0, i = 0; 708 uint32 zero = 0, bytes = 0, segments = (length / MAXIMUM_WRITE_SIZE), current_count = 0, i = 0;
496 char *out_buffer = NULL; 709 char *out_buffer = NULL;
710
711 if (!client ||!client->afc_packet || !client->connection || !file) return -1;
712
713 afc_lock(client);
714
715 if (debug) fprintf(stderr, "afc_write_file: Write length: %i\n", length);
497 716
498 for (i = 0; i < segments; i++) { // Essentially, yeah, divide it into segments. 717 // Divide the file into segments.
718 for (i = 0; i < segments; i++) {
719 // Send the segment
499 client->afc_packet->this_length = sizeof(AFCPacket) + 8; 720 client->afc_packet->this_length = sizeof(AFCPacket) + 8;
500 //client->afc_packet->entire_length = client->afc_packet->this_length + length;
501 client->afc_packet->entire_length = client->afc_packet->this_length + MAXIMUM_WRITE_SIZE; 721 client->afc_packet->entire_length = client->afc_packet->this_length + MAXIMUM_WRITE_SIZE;
502 client->afc_packet->operation = AFC_WRITE; 722 client->afc_packet->operation = AFC_WRITE;
503 out_buffer = (char*)malloc(sizeof(char) * client->afc_packet->entire_length - sizeof(AFCPacket)); 723 out_buffer = (char*)malloc(sizeof(char) * client->afc_packet->entire_length - sizeof(AFCPacket));
504 memcpy(out_buffer, (char*)&file->filehandle, sizeof(uint32)); 724 memcpy(out_buffer, (char*)&file->filehandle, sizeof(uint32));
505 memcpy(out_buffer+4, (char*)&zero, sizeof(uint32)); 725 memcpy(out_buffer+4, (char*)&zero, sizeof(uint32));
506 memcpy(out_buffer+8, data+current_count, MAXIMUM_WRITE_SIZE); 726 memcpy(out_buffer+8, data+current_count, MAXIMUM_WRITE_SIZE);
507
508 bytes = dispatch_AFC_packet(client, out_buffer, MAXIMUM_WRITE_SIZE + 8); 727 bytes = dispatch_AFC_packet(client, out_buffer, MAXIMUM_WRITE_SIZE + 8);
509 if (bytes < 0) { afc_unlock(client); return bytes; } 728 if (bytes < 0) {
510 free(out_buffer); out_buffer = NULL; // cleanup and hope it works 729 afc_unlock(client);
730 return bytes;
731 }
732 free(out_buffer);
733 out_buffer = NULL;
734
511 current_count += bytes; 735 current_count += bytes;
512 bytes = receive_AFC_data(client, &acknowledgement); 736 bytes = receive_AFC_data(client, &acknowledgement);
513 if (bytes < 0) { afc_unlock(client); return current_count; } 737 if (bytes < 0) {
738 afc_unlock(client);
739 return current_count;
740 }
514 } 741 }
515 742
516 // By this point, we should be at the end. i.e. the last segment that didn't get sent in the for loop 743 // By this point, we should be at the end. i.e. the last segment that didn't get sent in the for loop
517 // this length is fine because it's always sizeof(AFCPacket) + 8, but to be sure we do it again 744 // this length is fine because it's always sizeof(AFCPacket) + 8, but to be sure we do it again
518 if (current_count == length) { afc_unlock(client); return current_count; } 745 if (current_count == length) {
746 afc_unlock(client);
747 return current_count;
748 }
749
519 client->afc_packet->this_length = sizeof(AFCPacket) + 8; 750 client->afc_packet->this_length = sizeof(AFCPacket) + 8;
520 client->afc_packet->entire_length = client->afc_packet->this_length + (length - current_count); 751 client->afc_packet->entire_length = client->afc_packet->this_length + (length - current_count);
521 // operation is already AFC_WRITE, but set again to be sure
522 client->afc_packet->operation = AFC_WRITE; 752 client->afc_packet->operation = AFC_WRITE;
523 out_buffer = (char*)malloc(sizeof(char) * client->afc_packet->entire_length - sizeof(AFCPacket)); 753 out_buffer = (char*)malloc(sizeof(char) * client->afc_packet->entire_length - sizeof(AFCPacket));
524 memcpy(out_buffer, (char*)&file->filehandle, sizeof(uint32)); 754 memcpy(out_buffer, (char*)&file->filehandle, sizeof(uint32));
525 memcpy(out_buffer+4, (char*)&zero, sizeof(uint32)); 755 memcpy(out_buffer+4, (char*)&zero, sizeof(uint32));
526 memcpy(out_buffer+8, data+current_count, (length - current_count)); 756 memcpy(out_buffer+8, data+current_count, (length - current_count));
527 bytes = dispatch_AFC_packet(client, out_buffer, (length - current_count) + 8); 757 bytes = dispatch_AFC_packet(client, out_buffer, (length - current_count) + 8);
528 free(out_buffer); out_buffer = NULL; 758 free(out_buffer);
759 out_buffer = NULL;
760
529 current_count += bytes; 761 current_count += bytes;
530 if (bytes <= 0) { afc_unlock(client); return current_count; } 762
763 if (bytes <= 0) {
764 afc_unlock(client);
765 return current_count;
766 }
531 767
532 zero = bytes; 768 zero = bytes;
533 bytes = receive_AFC_data(client, &acknowledgement); 769 bytes = receive_AFC_data(client, &acknowledgement);
534 afc_unlock(client); 770 afc_unlock(client);
535 if (bytes < 0) { 771 if (bytes < 0) {
536 if (debug) printf("afc_write_file: uh oh?\n"); 772 if (debug) fprintf(stderr, "afc_write_file: uh oh?\n");
537 } 773 }
538 774
539 return current_count; 775 return current_count;
540} 776}
541 777
778/** Closes a file on the phone.
779 *
780 * @param client The client to close the file with.
781 * @param file A pointer to an AFCFile struct containing the file handle of the
782 * file to close.
783 */
542void afc_close_file(AFClient *client, AFCFile *file) { 784void afc_close_file(AFClient *client, AFCFile *file) {
543 char *buffer = malloc(sizeof(char) * 8); 785 char *buffer = malloc(sizeof(char) * 8);
544 uint32 zero = 0; 786 uint32 zero = 0;
545 if (debug) printf("File handle %i\n", file->filehandle); 787 int bytes = 0;
788
546 afc_lock(client); 789 afc_lock(client);
790
791 if (debug) fprintf(stderr, "afc_close_file: File handle %i\n", file->filehandle);
792
793 // Send command
547 memcpy(buffer, &file->filehandle, sizeof(uint32)); 794 memcpy(buffer, &file->filehandle, sizeof(uint32));
548 memcpy(buffer+sizeof(uint32), &zero, sizeof(zero)); 795 memcpy(buffer+sizeof(uint32), &zero, sizeof(zero));
549 client->afc_packet->operation = AFC_FILE_CLOSE; 796 client->afc_packet->operation = AFC_FILE_CLOSE;
550 int bytes = 0;
551 client->afc_packet->entire_length = client->afc_packet->this_length = 0; 797 client->afc_packet->entire_length = client->afc_packet->this_length = 0;
552 bytes = dispatch_AFC_packet(client, buffer, sizeof(char) * 8); 798 bytes = dispatch_AFC_packet(client, buffer, sizeof(char) * 8);
553
554 free(buffer); 799 free(buffer);
555 client->afc_packet->entire_length = client->afc_packet->this_length = 0; 800 buffer = NULL;
556 if (bytes <= 0) { afc_unlock(client); return; } 801
802 // FIXME: Is this necesary?
803 //client->afc_packet->entire_length = client->afc_packet->this_length = 0;
557 804
805 if (bytes <= 0) {
806 afc_unlock(client);
807 return;
808 }
809
810 // Receive the response
558 bytes = receive_AFC_data(client, &buffer); 811 bytes = receive_AFC_data(client, &buffer);
812 if (buffer) free(buffer);
813
559 afc_unlock(client); 814 afc_unlock(client);
560 if (buffer) { free(buffer); }
561 return;
562} 815}
563 816
817/** Seeks to a given position of a pre-opened file on the phone.
818 *
819 * @param client The client to use to seek to the position.
820 * @param file The file to seek to a position on.
821 * @param seekpos Where to seek to. If passed a negative value, this will seek
822 * from the end of the file.
823 *
824 * @return 0 on success, -1 on failure.
825 */
826
564int afc_seek_file(AFClient *client, AFCFile *file, int seekpos) { 827int afc_seek_file(AFClient *client, AFCFile *file, int seekpos) {
565 afc_lock(client);
566
567 char *buffer = (char*)malloc(sizeof(char) * 24); 828 char *buffer = (char*)malloc(sizeof(char) * 24);
568 uint32 seekto = 0, bytes = 0, zero = 0; 829 uint32 seekto = 0, bytes = 0, zero = 0;
830
569 if (seekpos < 0) seekpos = file->size - abs(seekpos); 831 if (seekpos < 0) seekpos = file->size - abs(seekpos);
570 seekto = seekpos; 832
833 afc_lock(client);
571 834
835 // Send the command
836 seekto = seekpos;
572 memcpy(buffer, &file->filehandle, sizeof(uint32)); // handle 837 memcpy(buffer, &file->filehandle, sizeof(uint32)); // handle
573 memcpy(buffer+4, &zero, sizeof(uint32)); // pad 838 memcpy(buffer+4, &zero, sizeof(uint32)); // pad
574 memcpy(buffer+8, &zero, sizeof(uint32)); // fromwhere 839 memcpy(buffer+8, &zero, sizeof(uint32)); // fromwhere
@@ -578,22 +843,45 @@ int afc_seek_file(AFClient *client, AFCFile *file, int seekpos) {
578 client->afc_packet->operation = AFC_FILE_SEEK; 843 client->afc_packet->operation = AFC_FILE_SEEK;
579 client->afc_packet->this_length = client->afc_packet->entire_length = 0; 844 client->afc_packet->this_length = client->afc_packet->entire_length = 0;
580 bytes = dispatch_AFC_packet(client, buffer, 23); 845 bytes = dispatch_AFC_packet(client, buffer, 23);
581 free(buffer); buffer = NULL; 846 free(buffer);
582 if (bytes <= 0) { afc_unlock(client); return -1; } 847 buffer = NULL;
848
849 if (bytes <= 0) {
850 afc_unlock(client);
851 return -1;
852 }
583 853
854 // Receive response
584 bytes = receive_AFC_data(client, &buffer); 855 bytes = receive_AFC_data(client, &buffer);
585 if (buffer) free(buffer); 856 if (buffer) free(buffer);
857
586 afc_unlock(client); 858 afc_unlock(client);
587 if (bytes >= 0) return 0; 859
588 else return -1; 860 if (bytes >= 0) {
861 return 0;
862 } else {
863 return -1;
864 }
589} 865}
590 866
867/** Sets the size of a file on the phone.
868 *
869 * @param client The client to use to set the file size.
870 * @param file The (pre-opened) file to set the size on.
871 * @param newsize The size to set the file to.
872 *
873 * @return 0 on success, -1 on failure.
874 *
875 * @note This function is more akin to ftruncate than truncate, and truncate
876 * calls would have to open the file before calling this, sadly.
877 */
591int afc_truncate_file(AFClient *client, AFCFile *file, uint32 newsize) { 878int afc_truncate_file(AFClient *client, AFCFile *file, uint32 newsize) {
592 afc_lock(client);
593
594 char *buffer = (char*)malloc(sizeof(char) * 16); 879 char *buffer = (char*)malloc(sizeof(char) * 16);
595 uint32 bytes = 0, zero = 0; 880 uint32 bytes = 0, zero = 0;
596 881
882 afc_lock(client);
883
884 // Send command
597 memcpy(buffer, &file->filehandle, sizeof(uint32)); // handle 885 memcpy(buffer, &file->filehandle, sizeof(uint32)); // handle
598 memcpy(buffer+4, &zero, sizeof(uint32)); // pad 886 memcpy(buffer+4, &zero, sizeof(uint32)); // pad
599 memcpy(buffer+8, &newsize, sizeof(uint32)); // newsize 887 memcpy(buffer+8, &newsize, sizeof(uint32)); // newsize
@@ -601,13 +889,23 @@ int afc_truncate_file(AFClient *client, AFCFile *file, uint32 newsize) {
601 client->afc_packet->operation = AFC_FILE_TRUNCATE; 889 client->afc_packet->operation = AFC_FILE_TRUNCATE;
602 client->afc_packet->this_length = client->afc_packet->entire_length = 0; 890 client->afc_packet->this_length = client->afc_packet->entire_length = 0;
603 bytes = dispatch_AFC_packet(client, buffer, 15); 891 bytes = dispatch_AFC_packet(client, buffer, 15);
604 free(buffer); buffer = NULL; 892 free(buffer);
605 if (bytes <= 0) { afc_unlock(client); return -1; } 893 buffer = NULL;
894
895 if (bytes <= 0) {
896 afc_unlock(client);
897 return -1;
898 }
606 899
900 // Receive response
607 bytes = receive_AFC_data(client, &buffer); 901 bytes = receive_AFC_data(client, &buffer);
608 if (buffer) free(buffer); 902 if (buffer) free(buffer);
903
609 afc_unlock(client); 904 afc_unlock(client);
610 if (bytes >= 0) return 0; 905
611 else return -1; 906 if (bytes >= 0) {
907 return 0;
908 } else {
909 return -1;
910 }
612} 911}
613