diff options
Diffstat (limited to 'src/afc.c')
-rw-r--r-- | src/afc.c | 1161 |
1 files changed, 499 insertions, 662 deletions
@@ -1,308 +1,243 @@ | |||
1 | /* | 1 | /* |
2 | * afc.c | 2 | * afc.c |
3 | * Contains functions for the built-in AFC client. | 3 | * Contains functions for the built-in AFC client. |
4 | * | 4 | * |
5 | * Copyright (c) 2014 Martin Szulecki All Rights Reserved. | ||
6 | * Copyright (c) 2009-2014 Nikias Bassen. All Rights Reserved. | ||
5 | * Copyright (c) 2008 Zach C. All Rights Reserved. | 7 | * Copyright (c) 2008 Zach C. All Rights Reserved. |
6 | * | 8 | * |
7 | * This library is free software; you can redistribute it and/or | 9 | * This library is free software; you can redistribute it and/or |
8 | * modify it under the terms of the GNU Lesser General Public | 10 | * modify it under the terms of the GNU Lesser General Public |
9 | * License as published by the Free Software Foundation; either | 11 | * License as published by the Free Software Foundation; either |
10 | * version 2.1 of the License, or (at your option) any later version. | 12 | * version 2.1 of the License, or (at your option) any later version. |
11 | * | 13 | * |
12 | * This library is distributed in the hope that it will be useful, | 14 | * This library is distributed in the hope that it will be useful, |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
15 | * Lesser General Public License for more details. | 17 | * Lesser General Public License for more details. |
16 | * | 18 | * |
17 | * You should have received a copy of the GNU Lesser General Public | 19 | * You should have received a copy of the GNU Lesser General Public |
18 | * License along with this library; if not, write to the Free Software | 20 | * License along with this library; if not, write to the Free Software |
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | 21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
20 | */ | 22 | */ |
21 | 23 | ||
24 | #ifdef HAVE_CONFIG_H | ||
25 | #include <config.h> | ||
26 | #endif | ||
22 | #include <stdio.h> | 27 | #include <stdio.h> |
23 | #include <stdlib.h> | 28 | #include <stdlib.h> |
24 | #include <unistd.h> | 29 | #include <unistd.h> |
25 | #include <string.h> | 30 | #include <string.h> |
26 | 31 | ||
27 | #include "afc.h" | ||
28 | #include "idevice.h" | 32 | #include "idevice.h" |
29 | #include "debug.h" | 33 | #include "afc.h" |
30 | 34 | #include "common/debug.h" | |
31 | /** The maximum size an AFC data packet can be */ | 35 | #include "endianness.h" |
32 | static const int MAXIMUM_PACKET_SIZE = (2 << 15); | ||
33 | 36 | ||
34 | /** | 37 | /** |
35 | * Locks an AFC client, done for thread safety stuff | 38 | * Locks an AFC client, done for thread safety stuff |
36 | * | 39 | * |
37 | * @param client The AFC client connection to lock | 40 | * @param client The AFC client connection to lock |
38 | */ | 41 | */ |
39 | static void afc_lock(afc_client_t client) | 42 | static void afc_lock(afc_client_t client) |
40 | { | 43 | { |
41 | debug_info("Locked"); | 44 | debug_info("Locked"); |
42 | g_mutex_lock(client->mutex); | 45 | mutex_lock(&client->mutex); |
43 | } | 46 | } |
44 | 47 | ||
45 | /** | 48 | /** |
46 | * Unlocks an AFC client, done for thread safety stuff. | 49 | * Unlocks an AFC client, done for thread safety stuff. |
47 | * | 50 | * |
48 | * @param client The AFC | 51 | * @param client The AFC |
49 | */ | 52 | */ |
50 | static void afc_unlock(afc_client_t client) | 53 | static void afc_unlock(afc_client_t client) |
51 | { | 54 | { |
52 | debug_info("Unlocked"); | 55 | debug_info("Unlocked"); |
53 | g_mutex_unlock(client->mutex); | 56 | mutex_unlock(&client->mutex); |
54 | } | 57 | } |
55 | 58 | ||
56 | /** | 59 | /** |
57 | * Makes a connection to the AFC service on the device using the given | 60 | * Makes a connection to the AFC service on the device using the given |
58 | * connection. | 61 | * connection. |
59 | * | 62 | * |
60 | * @param connection An idevice_connection_t that must have been previously | 63 | * @param service_client A connected service client |
61 | * connected using idevice_connect(). Note that this connection will | ||
62 | * not be closed by calling afc_client_free(). | ||
63 | * @param client Pointer that will be set to a newly allocated afc_client_t | 64 | * @param client Pointer that will be set to a newly allocated afc_client_t |
64 | * upon successful return. | 65 | * upon successful return. |
65 | * | 66 | * |
66 | * @return AFC_E_SUCCESS on success, AFC_E_INVALID_ARG if connection is | 67 | * @return AFC_E_SUCCESS on success, AFC_E_INVALID_ARG if connection is |
67 | * invalid, or AFC_E_NO_MEM if there is a memory allocation problem. | 68 | * invalid, or AFC_E_NO_MEM if there is a memory allocation problem. |
68 | */ | 69 | */ |
69 | 70 | ||
70 | afc_error_t afc_client_new_from_connection(idevice_connection_t connection, afc_client_t *client) | 71 | afc_error_t afc_client_new_with_service_client(service_client_t service_client, afc_client_t *client) |
71 | { | 72 | { |
72 | /* makes sure thread environment is available */ | 73 | if (!service_client) |
73 | if (!g_thread_supported()) | ||
74 | g_thread_init(NULL); | ||
75 | |||
76 | if (!connection) | ||
77 | return AFC_E_INVALID_ARG; | 74 | return AFC_E_INVALID_ARG; |
78 | 75 | ||
79 | afc_client_t client_loc = (afc_client_t) malloc(sizeof(struct afc_client_private)); | 76 | afc_client_t client_loc = (afc_client_t) malloc(sizeof(struct afc_client_private)); |
80 | client_loc->connection = connection; | 77 | client_loc->parent = service_client; |
81 | client_loc->own_connection = 0; | 78 | client_loc->free_parent = 0; |
82 | 79 | ||
83 | /* allocate a packet */ | 80 | /* allocate a packet */ |
84 | client_loc->afc_packet = (AFCPacket *) malloc(sizeof(AFCPacket)); | 81 | client_loc->packet_extra = 1024; |
82 | client_loc->afc_packet = (AFCPacket *) malloc(sizeof(AFCPacket) + client_loc->packet_extra); | ||
85 | if (!client_loc->afc_packet) { | 83 | if (!client_loc->afc_packet) { |
86 | free(client_loc); | 84 | free(client_loc); |
87 | return AFC_E_NO_MEM; | 85 | return AFC_E_NO_MEM; |
88 | } | 86 | } |
89 | |||
90 | client_loc->afc_packet->packet_num = 0; | 87 | client_loc->afc_packet->packet_num = 0; |
91 | client_loc->afc_packet->entire_length = 0; | 88 | client_loc->afc_packet->entire_length = 0; |
92 | client_loc->afc_packet->this_length = 0; | 89 | client_loc->afc_packet->this_length = 0; |
93 | memcpy(client_loc->afc_packet->magic, AFC_MAGIC, AFC_MAGIC_LEN); | 90 | memcpy(client_loc->afc_packet->magic, AFC_MAGIC, AFC_MAGIC_LEN); |
94 | client_loc->file_handle = 0; | 91 | mutex_init(&client_loc->mutex); |
95 | client_loc->lock = 0; | ||
96 | client_loc->mutex = g_mutex_new(); | ||
97 | 92 | ||
98 | *client = client_loc; | 93 | *client = client_loc; |
99 | return AFC_E_SUCCESS; | 94 | return AFC_E_SUCCESS; |
100 | } | 95 | } |
101 | 96 | ||
102 | /** | 97 | afc_error_t afc_client_new(idevice_t device, lockdownd_service_descriptor_t service, afc_client_t * client) |
103 | * Makes a connection to the AFC service on the device. | ||
104 | * This function calls afc_client_new_from_connection() after creating | ||
105 | * a connection to the specified device and port. | ||
106 | * | ||
107 | * @see afc_client_new_from_connection | ||
108 | * | ||
109 | * @param device The device to connect to. | ||
110 | * @param port The destination port. | ||
111 | * @param client Pointer that will be set to a newly allocated afc_client_t | ||
112 | * upon successful return. | ||
113 | * | ||
114 | * @return AFC_E_SUCCESS on success, AFC_E_INVALID_ARG if device or port is | ||
115 | * invalid, AFC_E_MUX_ERROR if the connection cannot be established, | ||
116 | * or AFC_E_NO_MEM if there is a memory allocation problem. | ||
117 | */ | ||
118 | afc_error_t afc_client_new(idevice_t device, uint16_t port, afc_client_t * client) | ||
119 | { | 98 | { |
120 | /* makes sure thread environment is available */ | 99 | if (!device || !service || service->port == 0) |
121 | if (!g_thread_supported()) | ||
122 | g_thread_init(NULL); | ||
123 | |||
124 | if (!device || port==0) | ||
125 | return AFC_E_INVALID_ARG; | 100 | return AFC_E_INVALID_ARG; |
126 | 101 | ||
127 | /* attempt connection */ | 102 | service_client_t parent = NULL; |
128 | idevice_connection_t connection = NULL; | 103 | if (service_client_new(device, service, &parent) != SERVICE_E_SUCCESS) { |
129 | if (idevice_connect(device, port, &connection) != IDEVICE_E_SUCCESS) { | ||
130 | return AFC_E_MUX_ERROR; | 104 | return AFC_E_MUX_ERROR; |
131 | } | 105 | } |
132 | 106 | ||
133 | afc_error_t err = afc_client_new_from_connection(connection, client); | 107 | afc_error_t err = afc_client_new_with_service_client(parent, client); |
134 | if (err != AFC_E_SUCCESS) { | 108 | if (err != AFC_E_SUCCESS) { |
135 | idevice_disconnect(connection); | 109 | service_client_free(parent); |
136 | } else { | 110 | } else { |
137 | (*client)->own_connection = 1; | 111 | (*client)->free_parent = 1; |
138 | } | 112 | } |
139 | return err; | 113 | return err; |
140 | } | 114 | } |
141 | 115 | ||
142 | /** | 116 | afc_error_t afc_client_start_service(idevice_t device, afc_client_t * client, const char* label) |
143 | * Frees up an AFC client. If the connection was created by the | 117 | { |
144 | * client itself, the connection will be closed. | 118 | afc_error_t err = AFC_E_UNKNOWN_ERROR; |
145 | * | 119 | service_client_factory_start_service(device, AFC_SERVICE_NAME, (void**)client, label, SERVICE_CONSTRUCTOR(afc_client_new), &err); |
146 | * @param client The client to free. | 120 | return err; |
147 | */ | 121 | } |
122 | |||
148 | afc_error_t afc_client_free(afc_client_t client) | 123 | afc_error_t afc_client_free(afc_client_t client) |
149 | { | 124 | { |
150 | if (!client || !client->afc_packet) | 125 | if (!client || !client->afc_packet) |
151 | return AFC_E_INVALID_ARG; | 126 | return AFC_E_INVALID_ARG; |
152 | 127 | ||
153 | if (client->own_connection && client->connection) { | 128 | if (client->free_parent && client->parent) { |
154 | idevice_disconnect(client->connection); | 129 | service_client_free(client->parent); |
155 | client->connection = NULL; | 130 | client->parent = NULL; |
156 | } | 131 | } |
157 | free(client->afc_packet); | 132 | free(client->afc_packet); |
158 | if (client->mutex) { | 133 | mutex_destroy(&client->mutex); |
159 | g_mutex_free(client->mutex); | ||
160 | } | ||
161 | free(client); | 134 | free(client); |
162 | return AFC_E_SUCCESS; | 135 | return AFC_E_SUCCESS; |
163 | } | 136 | } |
164 | 137 | ||
165 | /** | 138 | /** |
166 | * Dispatches an AFC packet over a client. | 139 | * Dispatches an AFC packet over a client. |
167 | * | 140 | * |
168 | * @param client The client to send data through. | 141 | * @param client The client to send data through. |
169 | * @param data The data to send. | 142 | * @param operation The operation to perform. |
170 | * @param length The length to send. | 143 | * @param data The data to send together with the header. |
171 | * @param bytes_sent The number of bytes actually sent. | 144 | * @param data_length The length of the data to send with the header. |
145 | * @param payload The data to send after the header has been sent. | ||
146 | * @param payload_length The length of data to send after the header. | ||
147 | * @param bytes_sent The total number of bytes actually sent. | ||
172 | * | 148 | * |
173 | * @return AFC_E_SUCCESS on success or an AFC_E_* error value. | 149 | * @return AFC_E_SUCCESS on success or an AFC_E_* error value. |
174 | * | ||
175 | * @warning set client->afc_packet->this_length and | ||
176 | * client->afc_packet->entire_length to 0 before calling this. The | ||
177 | * reason is that if you set them to different values, it indicates | ||
178 | * you want to send the data as two packets. | ||
179 | */ | 150 | */ |
180 | static afc_error_t afc_dispatch_packet(afc_client_t client, const char *data, uint32_t length, uint32_t *bytes_sent) | 151 | static afc_error_t afc_dispatch_packet(afc_client_t client, uint64_t operation, uint32_t data_length, const char* payload, uint32_t payload_length, uint32_t *bytes_sent) |
181 | { | 152 | { |
182 | uint32_t offset = 0; | ||
183 | uint32_t sent = 0; | 153 | uint32_t sent = 0; |
184 | 154 | ||
185 | if (!client || !client->connection || !client->afc_packet) | 155 | if (!client || !client->parent || !client->afc_packet) |
186 | return AFC_E_INVALID_ARG; | 156 | return AFC_E_INVALID_ARG; |
187 | 157 | ||
188 | *bytes_sent = 0; | 158 | *bytes_sent = 0; |
189 | 159 | ||
190 | if (!data || !length) | 160 | if (!payload || !payload_length) |
191 | length = 0; | 161 | payload_length = 0; |
192 | 162 | ||
193 | client->afc_packet->packet_num++; | 163 | client->afc_packet->packet_num++; |
194 | if (!client->afc_packet->entire_length) { | 164 | client->afc_packet->operation = operation; |
195 | client->afc_packet->entire_length = (length) ? sizeof(AFCPacket) + length : sizeof(AFCPacket); | 165 | client->afc_packet->entire_length = sizeof(AFCPacket) + data_length + payload_length; |
196 | client->afc_packet->this_length = client->afc_packet->entire_length; | 166 | client->afc_packet->this_length = sizeof(AFCPacket) + data_length; |
197 | } | 167 | |
198 | if (!client->afc_packet->this_length) { | 168 | debug_info("packet length = %i", client->afc_packet->this_length); |
199 | client->afc_packet->this_length = sizeof(AFCPacket); | 169 | |
200 | } | 170 | /* send AFC packet header and data */ |
201 | /* We want to send two segments; buffer+sizeof(AFCPacket) to this_length | 171 | AFCPacket_to_LE(client->afc_packet); |
202 | is the parameters and everything beyond that is the next packet. | 172 | debug_buffer((char*)client->afc_packet, sizeof(AFCPacket) + data_length); |
203 | (for writing) */ | 173 | sent = 0; |
204 | if (client->afc_packet->this_length != client->afc_packet->entire_length) { | 174 | service_send(client->parent, (void*)client->afc_packet, sizeof(AFCPacket) + data_length, &sent); |
205 | offset = client->afc_packet->this_length - sizeof(AFCPacket); | 175 | AFCPacket_from_LE(client->afc_packet); |
206 | 176 | *bytes_sent += sent; | |
207 | debug_info("Offset: %i", offset); | 177 | if (sent < sizeof(AFCPacket) + data_length) { |
208 | if ((length) < (client->afc_packet->entire_length - client->afc_packet->this_length)) { | ||
209 | debug_info("Length did not resemble what it was supposed to based on packet"); | ||
210 | debug_info("length minus offset: %i", length - offset); | ||
211 | debug_info("rest of packet: %i\n", client->afc_packet->entire_length - client->afc_packet->this_length); | ||
212 | return AFC_E_INTERNAL_ERROR; | ||
213 | } | ||
214 | |||
215 | /* send AFC packet header */ | ||
216 | AFCPacket_to_LE(client->afc_packet); | ||
217 | sent = 0; | ||
218 | idevice_connection_send(client->connection, (void*)client->afc_packet, sizeof(AFCPacket), &sent); | ||
219 | AFCPacket_from_LE(client->afc_packet); | ||
220 | if (sent == 0) { | ||
221 | /* FIXME: should this be handled as success?! */ | ||
222 | return AFC_E_SUCCESS; | ||
223 | } | ||
224 | *bytes_sent += sent; | ||
225 | |||
226 | /* send AFC packet data */ | ||
227 | sent = 0; | ||
228 | idevice_connection_send(client->connection, data, offset, &sent); | ||
229 | if (sent == 0) { | ||
230 | return AFC_E_SUCCESS; | ||
231 | } | ||
232 | *bytes_sent += sent; | ||
233 | |||
234 | debug_info("sent the first now go with the second"); | ||
235 | debug_info("Length: %i", length - offset); | ||
236 | debug_info("Buffer: "); | ||
237 | debug_buffer(data + offset, length - offset); | ||
238 | |||
239 | sent = 0; | ||
240 | idevice_connection_send(client->connection, data + offset, length - offset, &sent); | ||
241 | |||
242 | *bytes_sent = sent; | ||
243 | return AFC_E_SUCCESS; | 178 | return AFC_E_SUCCESS; |
244 | } else { | 179 | } |
245 | debug_info("doin things the old way"); | ||
246 | debug_info("packet length = %i", client->afc_packet->this_length); | ||
247 | |||
248 | debug_buffer((char*)client->afc_packet, sizeof(AFCPacket)); | ||
249 | 180 | ||
250 | /* send AFC packet header */ | 181 | sent = 0; |
251 | AFCPacket_to_LE(client->afc_packet); | 182 | if (payload_length > 0) { |
252 | sent = 0; | 183 | if (payload_length > 256) { |
253 | idevice_connection_send(client->connection, (void*)client->afc_packet, sizeof(AFCPacket), &sent); | 184 | debug_info("packet payload follows (256/%u)", payload_length); |
254 | AFCPacket_from_LE(client->afc_packet); | 185 | debug_buffer(payload, 256); |
255 | if (sent == 0) { | 186 | } else { |
256 | return AFC_E_SUCCESS; | 187 | debug_info("packet payload follows"); |
257 | } | 188 | debug_buffer(payload, payload_length); |
258 | *bytes_sent += sent; | ||
259 | /* send AFC packet data (if there's data to send) */ | ||
260 | if (length > 0) { | ||
261 | debug_info("packet data follows"); | ||
262 | |||
263 | debug_buffer(data, length); | ||
264 | idevice_connection_send(client->connection, data, length, &sent); | ||
265 | *bytes_sent += sent; | ||
266 | } | 189 | } |
190 | service_send(client->parent, payload, payload_length, &sent); | ||
191 | } | ||
192 | *bytes_sent += sent; | ||
193 | if (sent < payload_length) { | ||
267 | return AFC_E_SUCCESS; | 194 | return AFC_E_SUCCESS; |
268 | } | 195 | } |
269 | return AFC_E_INTERNAL_ERROR; | 196 | |
197 | return AFC_E_SUCCESS; | ||
270 | } | 198 | } |
271 | 199 | ||
272 | /** | 200 | /** |
273 | * Receives data through an AFC client and sets a variable to the received data. | 201 | * Receives data through an AFC client and sets a variable to the received data. |
274 | * | 202 | * |
275 | * @param client The client to receive data on. | 203 | * @param client The client to receive data on. |
276 | * @param dump_here The char* to point to the newly-received data. | 204 | * @param bytes The char* to point to the newly-received data. |
277 | * @param bytes_recv How much data was received. | 205 | * @param bytes_recv How much data was received. |
278 | * | 206 | * |
279 | * @return AFC_E_SUCCESS on success or an AFC_E_* error value. | 207 | * @return AFC_E_SUCCESS on success or an AFC_E_* error value. |
280 | */ | 208 | */ |
281 | static afc_error_t afc_receive_data(afc_client_t client, char **dump_here, uint32_t *bytes_recv) | 209 | static afc_error_t afc_receive_data(afc_client_t client, char **bytes, uint32_t *bytes_recv) |
282 | { | 210 | { |
283 | AFCPacket header; | 211 | AFCPacket header; |
284 | uint32_t entire_len = 0; | 212 | uint32_t entire_len = 0; |
285 | uint32_t this_len = 0; | 213 | uint32_t this_len = 0; |
286 | uint32_t current_count = 0; | 214 | uint32_t current_count = 0; |
287 | uint64_t param1 = -1; | 215 | uint64_t param1 = -1; |
216 | char *buf = NULL; | ||
217 | uint32_t recv_len = 0; | ||
288 | 218 | ||
289 | *bytes_recv = 0; | 219 | if (bytes_recv) { |
220 | *bytes_recv = 0; | ||
221 | } | ||
222 | if (bytes) { | ||
223 | *bytes = NULL; | ||
224 | } | ||
290 | 225 | ||
291 | /* first, read the AFC header */ | 226 | /* first, read the AFC header */ |
292 | idevice_connection_receive(client->connection, (char*)&header, sizeof(AFCPacket), bytes_recv); | 227 | service_receive(client->parent, (char*)&header, sizeof(AFCPacket), &recv_len); |
293 | AFCPacket_from_LE(&header); | 228 | AFCPacket_from_LE(&header); |
294 | if (*bytes_recv == 0) { | 229 | if (recv_len == 0) { |
295 | debug_info("Just didn't get enough."); | 230 | debug_info("Just didn't get enough."); |
296 | *dump_here = NULL; | ||
297 | return AFC_E_MUX_ERROR; | 231 | return AFC_E_MUX_ERROR; |
298 | } else if (*bytes_recv < sizeof(AFCPacket)) { | 232 | } |
233 | |||
234 | if (recv_len < sizeof(AFCPacket)) { | ||
299 | debug_info("Did not even get the AFCPacket header"); | 235 | debug_info("Did not even get the AFCPacket header"); |
300 | *dump_here = NULL; | ||
301 | return AFC_E_MUX_ERROR; | 236 | return AFC_E_MUX_ERROR; |
302 | } | 237 | } |
303 | 238 | ||
304 | /* check if it's a valid AFC header */ | 239 | /* check if it's a valid AFC header */ |
305 | if (strncmp(header.magic, AFC_MAGIC, AFC_MAGIC_LEN)) { | 240 | if (strncmp(header.magic, AFC_MAGIC, AFC_MAGIC_LEN) != 0) { |
306 | debug_info("Invalid AFC packet received (magic != " AFC_MAGIC ")!"); | 241 | debug_info("Invalid AFC packet received (magic != " AFC_MAGIC ")!"); |
307 | } | 242 | } |
308 | 243 | ||
@@ -310,25 +245,21 @@ static afc_error_t afc_receive_data(afc_client_t client, char **dump_here, uint3 | |||
310 | if (header.packet_num != client->afc_packet->packet_num) { | 245 | if (header.packet_num != client->afc_packet->packet_num) { |
311 | /* otherwise print a warning but do not abort */ | 246 | /* otherwise print a warning but do not abort */ |
312 | debug_info("ERROR: Unexpected packet number (%lld != %lld) aborting.", header.packet_num, client->afc_packet->packet_num); | 247 | debug_info("ERROR: Unexpected packet number (%lld != %lld) aborting.", header.packet_num, client->afc_packet->packet_num); |
313 | *dump_here = NULL; | ||
314 | return AFC_E_OP_HEADER_INVALID; | 248 | return AFC_E_OP_HEADER_INVALID; |
315 | } | 249 | } |
316 | 250 | ||
317 | /* then, read the attached packet */ | 251 | /* then, read the attached packet */ |
318 | if (header.this_length < sizeof(AFCPacket)) { | 252 | if (header.this_length < sizeof(AFCPacket)) { |
319 | debug_info("Invalid AFCPacket header received!"); | 253 | debug_info("Invalid AFCPacket header received!"); |
320 | *dump_here = NULL; | ||
321 | return AFC_E_OP_HEADER_INVALID; | 254 | return AFC_E_OP_HEADER_INVALID; |
322 | } else if ((header.this_length == header.entire_length) | 255 | } |
323 | && header.entire_length == sizeof(AFCPacket)) { | 256 | if ((header.this_length == header.entire_length) |
257 | && header.entire_length == sizeof(AFCPacket)) { | ||
324 | debug_info("Empty AFCPacket received!"); | 258 | debug_info("Empty AFCPacket received!"); |
325 | *dump_here = NULL; | ||
326 | *bytes_recv = 0; | ||
327 | if (header.operation == AFC_OP_DATA) { | 259 | if (header.operation == AFC_OP_DATA) { |
328 | return AFC_E_SUCCESS; | 260 | return AFC_E_SUCCESS; |
329 | } else { | ||
330 | return AFC_E_IO_ERROR; | ||
331 | } | 261 | } |
262 | return AFC_E_IO_ERROR; | ||
332 | } | 263 | } |
333 | 264 | ||
334 | debug_info("received AFC packet, full len=%lld, this len=%lld, operation=0x%llx", header.entire_length, header.this_length, header.operation); | 265 | debug_info("received AFC packet, full len=%lld, this len=%lld, operation=0x%llx", header.entire_length, header.this_length, header.operation); |
@@ -336,22 +267,17 @@ static afc_error_t afc_receive_data(afc_client_t client, char **dump_here, uint3 | |||
336 | entire_len = (uint32_t)header.entire_length - sizeof(AFCPacket); | 267 | entire_len = (uint32_t)header.entire_length - sizeof(AFCPacket); |
337 | this_len = (uint32_t)header.this_length - sizeof(AFCPacket); | 268 | this_len = (uint32_t)header.this_length - sizeof(AFCPacket); |
338 | 269 | ||
339 | /* this is here as a check (perhaps a different upper limit is good?) */ | 270 | buf = (char*)malloc(entire_len); |
340 | if (entire_len > (uint32_t)MAXIMUM_PACKET_SIZE) { | ||
341 | fprintf(stderr, "%s: entire_len is larger than MAXIMUM_PACKET_SIZE, (%d > %d)!", __func__, entire_len, MAXIMUM_PACKET_SIZE); | ||
342 | } | ||
343 | |||
344 | *dump_here = (char*)malloc(entire_len); | ||
345 | if (this_len > 0) { | 271 | if (this_len > 0) { |
346 | idevice_connection_receive(client->connection, *dump_here, this_len, bytes_recv); | 272 | recv_len = 0; |
347 | if (*bytes_recv <= 0) { | 273 | service_receive(client->parent, buf, this_len, &recv_len); |
348 | free(*dump_here); | 274 | if (recv_len <= 0) { |
349 | *dump_here = NULL; | 275 | free(buf); |
350 | debug_info("Did not get packet contents!"); | 276 | debug_info("Did not get packet contents!"); |
351 | return AFC_E_NOT_ENOUGH_DATA; | 277 | return AFC_E_NOT_ENOUGH_DATA; |
352 | } else if (*bytes_recv < this_len) { | 278 | } |
353 | free(*dump_here); | 279 | if (recv_len < this_len) { |
354 | *dump_here = NULL; | 280 | free(buf); |
355 | debug_info("Could not receive this_len=%d bytes", this_len); | 281 | debug_info("Could not receive this_len=%d bytes", this_len); |
356 | return AFC_E_NOT_ENOUGH_DATA; | 282 | return AFC_E_NOT_ENOUGH_DATA; |
357 | } | 283 | } |
@@ -361,12 +287,13 @@ static afc_error_t afc_receive_data(afc_client_t client, char **dump_here, uint3 | |||
361 | 287 | ||
362 | if (entire_len > this_len) { | 288 | if (entire_len > this_len) { |
363 | while (current_count < entire_len) { | 289 | while (current_count < entire_len) { |
364 | idevice_connection_receive(client->connection, (*dump_here)+current_count, entire_len - current_count, bytes_recv); | 290 | recv_len = 0; |
365 | if (*bytes_recv <= 0) { | 291 | service_receive(client->parent, buf+current_count, entire_len - current_count, &recv_len); |
366 | debug_info("Error receiving data (recv returned %d)", *bytes_recv); | 292 | if (recv_len <= 0) { |
293 | debug_info("Error receiving data (recv returned %d)", recv_len); | ||
367 | break; | 294 | break; |
368 | } | 295 | } |
369 | current_count += *bytes_recv; | 296 | current_count += recv_len; |
370 | } | 297 | } |
371 | if (current_count < entire_len) { | 298 | if (current_count < entire_len) { |
372 | debug_info("WARNING: could not receive full packet (read %s, size %d)", current_count, entire_len); | 299 | debug_info("WARNING: could not receive full packet (read %s, size %d)", current_count, entire_len); |
@@ -374,12 +301,17 @@ static afc_error_t afc_receive_data(afc_client_t client, char **dump_here, uint3 | |||
374 | } | 301 | } |
375 | 302 | ||
376 | if (current_count >= sizeof(uint64_t)) { | 303 | if (current_count >= sizeof(uint64_t)) { |
377 | param1 = GUINT64_FROM_LE(*(uint64_t*)(*dump_here)); | 304 | param1 = le64toh(*(uint64_t*)(buf)); |
378 | } | 305 | } |
379 | 306 | ||
380 | debug_info("packet data size = %i", current_count); | 307 | debug_info("packet data size = %i", current_count); |
381 | debug_info("packet data follows"); | 308 | if (current_count > 256) { |
382 | debug_buffer(*dump_here, current_count); | 309 | debug_info("packet data follows (256/%u)", current_count); |
310 | debug_buffer(buf, 256); | ||
311 | } else { | ||
312 | debug_info("packet data follows"); | ||
313 | debug_buffer(buf, current_count); | ||
314 | } | ||
383 | 315 | ||
384 | /* check operation types */ | 316 | /* check operation types */ |
385 | if (header.operation == AFC_OP_STATUS) { | 317 | if (header.operation == AFC_OP_STATUS) { |
@@ -389,8 +321,7 @@ static afc_error_t afc_receive_data(afc_client_t client, char **dump_here, uint3 | |||
389 | if (param1 != AFC_E_SUCCESS) { | 321 | if (param1 != AFC_E_SUCCESS) { |
390 | /* error status */ | 322 | /* error status */ |
391 | /* free buffer */ | 323 | /* free buffer */ |
392 | free(*dump_here); | 324 | free(buf); |
393 | *dump_here = NULL; | ||
394 | return (afc_error_t)param1; | 325 | return (afc_error_t)param1; |
395 | } | 326 | } |
396 | } else if (header.operation == AFC_OP_DATA) { | 327 | } else if (header.operation == AFC_OP_DATA) { |
@@ -404,16 +335,22 @@ static afc_error_t afc_receive_data(afc_client_t client, char **dump_here, uint3 | |||
404 | debug_info("got a tell response, position=%lld", param1); | 335 | debug_info("got a tell response, position=%lld", param1); |
405 | } else { | 336 | } else { |
406 | /* unknown operation code received */ | 337 | /* unknown operation code received */ |
407 | free(*dump_here); | 338 | free(buf); |
408 | *dump_here = NULL; | ||
409 | *bytes_recv = 0; | ||
410 | 339 | ||
411 | debug_info("WARNING: Unknown operation code received 0x%llx param1=%lld", header.operation, param1); | 340 | debug_info("WARNING: Unknown operation code received 0x%llx param1=%lld", header.operation, param1); |
341 | #ifndef WIN32 | ||
412 | fprintf(stderr, "%s: WARNING: Unknown operation code received 0x%llx param1=%lld", __func__, (long long)header.operation, (long long)param1); | 342 | fprintf(stderr, "%s: WARNING: Unknown operation code received 0x%llx param1=%lld", __func__, (long long)header.operation, (long long)param1); |
343 | #endif | ||
413 | 344 | ||
414 | return AFC_E_OP_NOT_SUPPORTED; | 345 | return AFC_E_OP_NOT_SUPPORTED; |
415 | } | 346 | } |
416 | 347 | ||
348 | if (bytes) { | ||
349 | *bytes = buf; | ||
350 | } else { | ||
351 | free(buf); | ||
352 | } | ||
353 | |||
417 | *bytes_recv = current_count; | 354 | *bytes_recv = current_count; |
418 | return AFC_E_SUCCESS; | 355 | return AFC_E_SUCCESS; |
419 | } | 356 | } |
@@ -421,7 +358,7 @@ static afc_error_t afc_receive_data(afc_client_t client, char **dump_here, uint3 | |||
421 | /** | 358 | /** |
422 | * Returns counts of null characters within a string. | 359 | * Returns counts of null characters within a string. |
423 | */ | 360 | */ |
424 | static uint32_t count_nullspaces(char *string, uint32_t number) | 361 | static uint32_t count_nullspaces(const char *string, uint32_t number) |
425 | { | 362 | { |
426 | uint32_t i = 0, nulls = 0; | 363 | uint32_t i = 0, nulls = 0; |
427 | 364 | ||
@@ -462,32 +399,42 @@ static char **make_strings_list(char *tokens, uint32_t length) | |||
462 | return list; | 399 | return list; |
463 | } | 400 | } |
464 | 401 | ||
465 | /** | 402 | static int _afc_check_packet_buffer(afc_client_t client, uint32_t data_len) |
466 | * Gets a directory listing of the directory requested. | 403 | { |
467 | * | 404 | if (data_len > client->packet_extra) { |
468 | * @param client The client to get a directory listing from. | 405 | client->packet_extra = (data_len & ~8) + 8; |
469 | * @param dir The directory to list. (must be a fully-qualified path) | 406 | AFCPacket* newpkt = (AFCPacket*)realloc(client->afc_packet, sizeof(AFCPacket) + client->packet_extra); |
470 | * @param list A char list of files in that directory, terminated by an empty | 407 | if (!newpkt) { |
471 | * string or NULL if there was an error. | 408 | return -1; |
472 | * | 409 | } |
473 | * @return AFC_E_SUCCESS on success or an AFC_E_* error value. | 410 | client->afc_packet = newpkt; |
474 | */ | 411 | } |
475 | afc_error_t afc_read_directory(afc_client_t client, const char *dir, char ***list) | 412 | return 0; |
413 | } | ||
414 | |||
415 | #define AFC_PACKET_DATA_PTR ((char*)client->afc_packet + sizeof(AFCPacket)) | ||
416 | |||
417 | afc_error_t afc_read_directory(afc_client_t client, const char *path, char ***directory_information) | ||
476 | { | 418 | { |
477 | uint32_t bytes = 0; | 419 | uint32_t bytes = 0; |
478 | char *data = NULL, **list_loc = NULL; | 420 | char *data = NULL, **list_loc = NULL; |
479 | afc_error_t ret = AFC_E_UNKNOWN_ERROR; | 421 | afc_error_t ret = AFC_E_UNKNOWN_ERROR; |
480 | 422 | ||
481 | if (!client || !dir || !list || (list && *list)) | 423 | if (!client || !path || !directory_information || (directory_information && *directory_information)) |
482 | return AFC_E_INVALID_ARG; | 424 | return AFC_E_INVALID_ARG; |
483 | 425 | ||
484 | afc_lock(client); | 426 | afc_lock(client); |
485 | 427 | ||
428 | uint32_t data_len = (uint32_t)strlen(path)+1; | ||
429 | if (_afc_check_packet_buffer(client, data_len) < 0) { | ||
430 | afc_unlock(client); | ||
431 | debug_info("Failed to realloc packet buffer"); | ||
432 | return AFC_E_NO_MEM; | ||
433 | } | ||
434 | |||
486 | /* Send the command */ | 435 | /* Send the command */ |
487 | client->afc_packet->operation = AFC_OP_READ_DIR; | 436 | memcpy(AFC_PACKET_DATA_PTR, path, data_len); |
488 | client->afc_packet->entire_length = 0; | 437 | ret = afc_dispatch_packet(client, AFC_OP_READ_DIR, data_len, NULL, 0, &bytes); |
489 | client->afc_packet->this_length = 0; | ||
490 | ret = afc_dispatch_packet(client, dir, strlen(dir)+1, &bytes); | ||
491 | if (ret != AFC_E_SUCCESS) { | 438 | if (ret != AFC_E_SUCCESS) { |
492 | afc_unlock(client); | 439 | afc_unlock(client); |
493 | return AFC_E_NOT_ENOUGH_DATA; | 440 | return AFC_E_NOT_ENOUGH_DATA; |
@@ -495,6 +442,8 @@ afc_error_t afc_read_directory(afc_client_t client, const char *dir, char ***lis | |||
495 | /* Receive the data */ | 442 | /* Receive the data */ |
496 | ret = afc_receive_data(client, &data, &bytes); | 443 | ret = afc_receive_data(client, &data, &bytes); |
497 | if (ret != AFC_E_SUCCESS) { | 444 | if (ret != AFC_E_SUCCESS) { |
445 | if (data) | ||
446 | free(data); | ||
498 | afc_unlock(client); | 447 | afc_unlock(client); |
499 | return ret; | 448 | return ret; |
500 | } | 449 | } |
@@ -504,37 +453,24 @@ afc_error_t afc_read_directory(afc_client_t client, const char *dir, char ***lis | |||
504 | free(data); | 453 | free(data); |
505 | 454 | ||
506 | afc_unlock(client); | 455 | afc_unlock(client); |
507 | *list = list_loc; | 456 | *directory_information = list_loc; |
508 | 457 | ||
509 | return ret; | 458 | return ret; |
510 | } | 459 | } |
511 | 460 | ||
512 | /** | 461 | afc_error_t afc_get_device_info(afc_client_t client, char ***device_information) |
513 | * Get device info for a client connection to phone. The device information | ||
514 | * returned is the device model as well as the free space, the total capacity | ||
515 | * and blocksize on the accessed disk partition. | ||
516 | * | ||
517 | * @param client The client to get device info for. | ||
518 | * @param infos A char ** list of parameters as given by AFC or NULL if there | ||
519 | * was an error. | ||
520 | * | ||
521 | * @return AFC_E_SUCCESS on success or an AFC_E_* error value. | ||
522 | */ | ||
523 | afc_error_t afc_get_device_info(afc_client_t client, char ***infos) | ||
524 | { | 462 | { |
525 | uint32_t bytes = 0; | 463 | uint32_t bytes = 0; |
526 | char *data = NULL, **list = NULL; | 464 | char *data = NULL, **list = NULL; |
527 | afc_error_t ret = AFC_E_UNKNOWN_ERROR; | 465 | afc_error_t ret = AFC_E_UNKNOWN_ERROR; |
528 | 466 | ||
529 | if (!client || !infos) | 467 | if (!client || !device_information) |
530 | return AFC_E_INVALID_ARG; | 468 | return AFC_E_INVALID_ARG; |
531 | 469 | ||
532 | afc_lock(client); | 470 | afc_lock(client); |
533 | 471 | ||
534 | /* Send the command */ | 472 | /* Send the command */ |
535 | client->afc_packet->operation = AFC_OP_GET_DEVINFO; | 473 | ret = afc_dispatch_packet(client, AFC_OP_GET_DEVINFO, 0, NULL, 0, &bytes); |
536 | client->afc_packet->entire_length = client->afc_packet->this_length = 0; | ||
537 | ret = afc_dispatch_packet(client, NULL, 0, &bytes); | ||
538 | if (ret != AFC_E_SUCCESS) { | 474 | if (ret != AFC_E_SUCCESS) { |
539 | afc_unlock(client); | 475 | afc_unlock(client); |
540 | return AFC_E_NOT_ENOUGH_DATA; | 476 | return AFC_E_NOT_ENOUGH_DATA; |
@@ -542,6 +478,8 @@ afc_error_t afc_get_device_info(afc_client_t client, char ***infos) | |||
542 | /* Receive the data */ | 478 | /* Receive the data */ |
543 | ret = afc_receive_data(client, &data, &bytes); | 479 | ret = afc_receive_data(client, &data, &bytes); |
544 | if (ret != AFC_E_SUCCESS) { | 480 | if (ret != AFC_E_SUCCESS) { |
481 | if (data) | ||
482 | free(data); | ||
545 | afc_unlock(client); | 483 | afc_unlock(client); |
546 | return ret; | 484 | return ret; |
547 | } | 485 | } |
@@ -552,22 +490,11 @@ afc_error_t afc_get_device_info(afc_client_t client, char ***infos) | |||
552 | 490 | ||
553 | afc_unlock(client); | 491 | afc_unlock(client); |
554 | 492 | ||
555 | *infos = list; | 493 | *device_information = list; |
556 | 494 | ||
557 | return ret; | 495 | return ret; |
558 | } | 496 | } |
559 | 497 | ||
560 | /** | ||
561 | * Get a specific key of the device info list for a client connection. | ||
562 | * Known key values are: Model, FSTotalBytes, FSFreeBytes and FSBlockSize. | ||
563 | * This is a helper function for afc_get_device_info(). | ||
564 | * | ||
565 | * @param client The client to get device info for. | ||
566 | * @param key The key to get the value of. | ||
567 | * @param value The value for the key if successful or NULL otherwise. | ||
568 | * | ||
569 | * @return AFC_E_SUCCESS on success or an AFC_E_* error value. | ||
570 | */ | ||
571 | afc_error_t afc_get_device_info_key(afc_client_t client, const char *key, char **value) | 498 | afc_error_t afc_get_device_info_key(afc_client_t client, const char *key, char **value) |
572 | { | 499 | { |
573 | afc_error_t ret = AFC_E_INTERNAL_ERROR; | 500 | afc_error_t ret = AFC_E_INTERNAL_ERROR; |
@@ -587,43 +514,40 @@ afc_error_t afc_get_device_info_key(afc_client_t client, const char *key, char * | |||
587 | break; | 514 | break; |
588 | } | 515 | } |
589 | } | 516 | } |
590 | 517 | for (ptr = kvps; *ptr; ptr++) { | |
591 | g_strfreev(kvps); | 518 | free(*ptr); |
519 | } | ||
520 | free(kvps); | ||
592 | 521 | ||
593 | return ret; | 522 | return ret; |
594 | } | 523 | } |
595 | 524 | ||
596 | /** | ||
597 | * Deletes a file or directory. | ||
598 | * | ||
599 | * @param client The client to use. | ||
600 | * @param path The path to delete. (must be a fully-qualified path) | ||
601 | * | ||
602 | * @return AFC_E_SUCCESS on success or an AFC_E_* error value. | ||
603 | */ | ||
604 | afc_error_t afc_remove_path(afc_client_t client, const char *path) | 525 | afc_error_t afc_remove_path(afc_client_t client, const char *path) |
605 | { | 526 | { |
606 | char *response = NULL; | ||
607 | uint32_t bytes = 0; | 527 | uint32_t bytes = 0; |
608 | afc_error_t ret = AFC_E_UNKNOWN_ERROR; | 528 | afc_error_t ret = AFC_E_UNKNOWN_ERROR; |
609 | 529 | ||
610 | if (!client || !path || !client->afc_packet || !client->connection) | 530 | if (!client || !path || !client->afc_packet || !client->parent) |
611 | return AFC_E_INVALID_ARG; | 531 | return AFC_E_INVALID_ARG; |
612 | 532 | ||
613 | afc_lock(client); | 533 | afc_lock(client); |
614 | 534 | ||
535 | uint32_t data_len = (uint32_t)strlen(path)+1; | ||
536 | if (_afc_check_packet_buffer(client, data_len) < 0) { | ||
537 | afc_unlock(client); | ||
538 | debug_info("Failed to realloc packet buffer"); | ||
539 | return AFC_E_NO_MEM; | ||
540 | } | ||
541 | |||
615 | /* Send command */ | 542 | /* Send command */ |
616 | client->afc_packet->this_length = client->afc_packet->entire_length = 0; | 543 | memcpy(AFC_PACKET_DATA_PTR, path, data_len); |
617 | client->afc_packet->operation = AFC_OP_REMOVE_PATH; | 544 | ret = afc_dispatch_packet(client, AFC_OP_REMOVE_PATH, data_len, NULL, 0, &bytes); |
618 | ret = afc_dispatch_packet(client, path, strlen(path)+1, &bytes); | ||
619 | if (ret != AFC_E_SUCCESS) { | 545 | if (ret != AFC_E_SUCCESS) { |
620 | afc_unlock(client); | 546 | afc_unlock(client); |
621 | return AFC_E_NOT_ENOUGH_DATA; | 547 | return AFC_E_NOT_ENOUGH_DATA; |
622 | } | 548 | } |
623 | /* Receive response */ | 549 | /* Receive response */ |
624 | ret = afc_receive_data(client, &response, &bytes); | 550 | ret = afc_receive_data(client, NULL, &bytes); |
625 | if (response) | ||
626 | free(response); | ||
627 | 551 | ||
628 | /* special case; unknown error actually means directory not empty */ | 552 | /* special case; unknown error actually means directory not empty */ |
629 | if (ret == AFC_E_UNKNOWN_ERROR) | 553 | if (ret == AFC_E_UNKNOWN_ERROR) |
@@ -634,61 +558,45 @@ afc_error_t afc_remove_path(afc_client_t client, const char *path) | |||
634 | return ret; | 558 | return ret; |
635 | } | 559 | } |
636 | 560 | ||
637 | /** | ||
638 | * Renames a file or directory on the phone. | ||
639 | * | ||
640 | * @param client The client to have rename. | ||
641 | * @param from The name to rename from. (must be a fully-qualified path) | ||
642 | * @param to The new name. (must also be a fully-qualified path) | ||
643 | * | ||
644 | * @return AFC_E_SUCCESS on success or an AFC_E_* error value. | ||
645 | */ | ||
646 | afc_error_t afc_rename_path(afc_client_t client, const char *from, const char *to) | 561 | afc_error_t afc_rename_path(afc_client_t client, const char *from, const char *to) |
647 | { | 562 | { |
648 | char *response = NULL; | 563 | if (!client || !from || !to || !client->afc_packet || !client->parent) |
649 | char *send = (char *) malloc(sizeof(char) * (strlen(from) + strlen(to) + 1 + sizeof(uint32_t))); | 564 | return AFC_E_INVALID_ARG; |
565 | |||
650 | uint32_t bytes = 0; | 566 | uint32_t bytes = 0; |
651 | afc_error_t ret = AFC_E_UNKNOWN_ERROR; | 567 | afc_error_t ret = AFC_E_UNKNOWN_ERROR; |
652 | 568 | ||
653 | if (!client || !from || !to || !client->afc_packet || !client->connection) | 569 | size_t from_len = strlen(from); |
654 | return AFC_E_INVALID_ARG; | 570 | size_t to_len = strlen(to); |
655 | 571 | ||
656 | afc_lock(client); | 572 | afc_lock(client); |
657 | 573 | ||
574 | uint32_t data_len = (uint32_t)(from_len+1 + to_len+1); | ||
575 | if (_afc_check_packet_buffer(client, data_len) < 0) { | ||
576 | afc_unlock(client); | ||
577 | debug_info("Failed to realloc packet buffer"); | ||
578 | return AFC_E_NO_MEM; | ||
579 | } | ||
580 | |||
658 | /* Send command */ | 581 | /* Send command */ |
659 | memcpy(send, from, strlen(from) + 1); | 582 | memcpy(AFC_PACKET_DATA_PTR, from, from_len+1); |
660 | memcpy(send + strlen(from) + 1, to, strlen(to) + 1); | 583 | memcpy(AFC_PACKET_DATA_PTR + from_len+1, to, to_len+1); |
661 | client->afc_packet->entire_length = client->afc_packet->this_length = 0; | 584 | ret = afc_dispatch_packet(client, AFC_OP_RENAME_PATH, data_len, NULL, 0, &bytes); |
662 | client->afc_packet->operation = AFC_OP_RENAME_PATH; | ||
663 | ret = afc_dispatch_packet(client, send, strlen(to)+1 + strlen(from)+1, &bytes); | ||
664 | free(send); | ||
665 | if (ret != AFC_E_SUCCESS) { | 585 | if (ret != AFC_E_SUCCESS) { |
666 | afc_unlock(client); | 586 | afc_unlock(client); |
667 | return AFC_E_NOT_ENOUGH_DATA; | 587 | return AFC_E_NOT_ENOUGH_DATA; |
668 | } | 588 | } |
669 | /* Receive response */ | 589 | /* Receive response */ |
670 | ret = afc_receive_data(client, &response, &bytes); | 590 | ret = afc_receive_data(client, NULL, &bytes); |
671 | if (response) | ||
672 | free(response); | ||
673 | 591 | ||
674 | afc_unlock(client); | 592 | afc_unlock(client); |
675 | 593 | ||
676 | return ret; | 594 | return ret; |
677 | } | 595 | } |
678 | 596 | ||
679 | /** | 597 | afc_error_t afc_make_directory(afc_client_t client, const char *path) |
680 | * Creates a directory on the phone. | ||
681 | * | ||
682 | * @param client The client to use to make a directory. | ||
683 | * @param dir The directory's path. (must be a fully-qualified path, I assume | ||
684 | * all other mkdir restrictions apply as well) | ||
685 | * | ||
686 | * @return AFC_E_SUCCESS on success or an AFC_E_* error value. | ||
687 | */ | ||
688 | afc_error_t afc_make_directory(afc_client_t client, const char *dir) | ||
689 | { | 598 | { |
690 | uint32_t bytes = 0; | 599 | uint32_t bytes = 0; |
691 | char *response = NULL; | ||
692 | afc_error_t ret = AFC_E_UNKNOWN_ERROR; | 600 | afc_error_t ret = AFC_E_UNKNOWN_ERROR; |
693 | 601 | ||
694 | if (!client) | 602 | if (!client) |
@@ -696,50 +604,51 @@ afc_error_t afc_make_directory(afc_client_t client, const char *dir) | |||
696 | 604 | ||
697 | afc_lock(client); | 605 | afc_lock(client); |
698 | 606 | ||
607 | uint32_t data_len = (uint32_t)strlen(path)+1; | ||
608 | if (_afc_check_packet_buffer(client, data_len) < 0) { | ||
609 | afc_unlock(client); | ||
610 | debug_info("Failed to realloc packet buffer"); | ||
611 | return AFC_E_NO_MEM; | ||
612 | } | ||
613 | |||
699 | /* Send command */ | 614 | /* Send command */ |
700 | client->afc_packet->operation = AFC_OP_MAKE_DIR; | 615 | memcpy(AFC_PACKET_DATA_PTR, path, data_len); |
701 | client->afc_packet->this_length = client->afc_packet->entire_length = 0; | 616 | ret = afc_dispatch_packet(client, AFC_OP_MAKE_DIR, data_len, NULL, 0, &bytes); |
702 | ret = afc_dispatch_packet(client, dir, strlen(dir)+1, &bytes); | ||
703 | if (ret != AFC_E_SUCCESS) { | 617 | if (ret != AFC_E_SUCCESS) { |
704 | afc_unlock(client); | 618 | afc_unlock(client); |
705 | return AFC_E_NOT_ENOUGH_DATA; | 619 | return AFC_E_NOT_ENOUGH_DATA; |
706 | } | 620 | } |
707 | /* Receive response */ | 621 | /* Receive response */ |
708 | ret = afc_receive_data(client, &response, &bytes); | 622 | ret = afc_receive_data(client, NULL, &bytes); |
709 | if (response) | ||
710 | free(response); | ||
711 | 623 | ||
712 | afc_unlock(client); | 624 | afc_unlock(client); |
713 | 625 | ||
714 | return ret; | 626 | return ret; |
715 | } | 627 | } |
716 | 628 | ||
717 | /** | 629 | afc_error_t afc_get_file_info(afc_client_t client, const char *path, char ***file_information) |
718 | * Gets information about a specific file. | ||
719 | * | ||
720 | * @param client The client to use to get the information of the file. | ||
721 | * @param path The fully-qualified path to the file. | ||
722 | * @param infolist Pointer to a buffer that will be filled with a NULL-terminated | ||
723 | * list of strings with the file information. | ||
724 | * Set to NULL before calling this function. | ||
725 | * | ||
726 | * @return AFC_E_SUCCESS on success or an AFC_E_* error value. | ||
727 | */ | ||
728 | afc_error_t afc_get_file_info(afc_client_t client, const char *path, char ***infolist) | ||
729 | { | 630 | { |
730 | char *received = NULL; | 631 | char *received = NULL; |
731 | uint32_t bytes = 0; | 632 | uint32_t bytes = 0; |
732 | afc_error_t ret = AFC_E_UNKNOWN_ERROR; | 633 | afc_error_t ret = AFC_E_UNKNOWN_ERROR; |
733 | 634 | ||
734 | if (!client || !path || !infolist) | 635 | if (!client || !path || !file_information) |
735 | return AFC_E_INVALID_ARG; | 636 | return AFC_E_INVALID_ARG; |
736 | 637 | ||
737 | afc_lock(client); | 638 | afc_lock(client); |
738 | 639 | ||
640 | uint32_t data_len = (uint32_t)strlen(path)+1; | ||
641 | if (_afc_check_packet_buffer(client, data_len) < 0) { | ||
642 | afc_unlock(client); | ||
643 | debug_info("Failed to realloc packet buffer"); | ||
644 | return AFC_E_NO_MEM; | ||
645 | } | ||
646 | |||
647 | debug_info("We got %p and %p", client->afc_packet, AFC_PACKET_DATA_PTR); | ||
648 | |||
739 | /* Send command */ | 649 | /* Send command */ |
740 | client->afc_packet->operation = AFC_OP_GET_FILE_INFO; | 650 | memcpy(AFC_PACKET_DATA_PTR, path, data_len); |
741 | client->afc_packet->entire_length = client->afc_packet->this_length = 0; | 651 | ret = afc_dispatch_packet(client, AFC_OP_GET_FILE_INFO, data_len, NULL, 0, &bytes); |
742 | ret = afc_dispatch_packet(client, path, strlen(path)+1, &bytes); | ||
743 | if (ret != AFC_E_SUCCESS) { | 652 | if (ret != AFC_E_SUCCESS) { |
744 | afc_unlock(client); | 653 | afc_unlock(client); |
745 | return AFC_E_NOT_ENOUGH_DATA; | 654 | return AFC_E_NOT_ENOUGH_DATA; |
@@ -748,7 +657,7 @@ afc_error_t afc_get_file_info(afc_client_t client, const char *path, char ***inf | |||
748 | /* Receive data */ | 657 | /* Receive data */ |
749 | ret = afc_receive_data(client, &received, &bytes); | 658 | ret = afc_receive_data(client, &received, &bytes); |
750 | if (received) { | 659 | if (received) { |
751 | *infolist = make_strings_list(received, bytes); | 660 | *file_information = make_strings_list(received, bytes); |
752 | free(received); | 661 | free(received); |
753 | } | 662 | } |
754 | 663 | ||
@@ -757,51 +666,39 @@ afc_error_t afc_get_file_info(afc_client_t client, const char *path, char ***inf | |||
757 | return ret; | 666 | return ret; |
758 | } | 667 | } |
759 | 668 | ||
760 | /** | 669 | afc_error_t afc_file_open(afc_client_t client, const char *filename, afc_file_mode_t file_mode, uint64_t *handle) |
761 | * Opens a file on the phone. | ||
762 | * | ||
763 | * @param client The client to use to open the file. | ||
764 | * @param filename The file to open. (must be a fully-qualified path) | ||
765 | * @param file_mode The mode to use to open the file. Can be AFC_FILE_READ or | ||
766 | * AFC_FILE_WRITE; the former lets you read and write, | ||
767 | * however, and the second one will *create* the file, | ||
768 | * destroying anything previously there. | ||
769 | * @param handle Pointer to a uint64_t that will hold the handle of the file | ||
770 | * | ||
771 | * @return AFC_E_SUCCESS on success or an AFC_E_* error value. | ||
772 | */ | ||
773 | idevice_error_t | ||
774 | afc_file_open(afc_client_t client, const char *filename, | ||
775 | afc_file_mode_t file_mode, uint64_t *handle) | ||
776 | { | 670 | { |
777 | uint64_t file_mode_loc = GUINT64_TO_LE(file_mode); | 671 | if (!client || !client->parent || !client->afc_packet) |
672 | return AFC_E_INVALID_ARG; | ||
673 | |||
674 | //uint64_t file_mode_loc = htole64(file_mode); | ||
778 | uint32_t bytes = 0; | 675 | uint32_t bytes = 0; |
779 | char *data = (char *) malloc(sizeof(char) * (8 + strlen(filename) + 1)); | ||
780 | afc_error_t ret = AFC_E_UNKNOWN_ERROR; | 676 | afc_error_t ret = AFC_E_UNKNOWN_ERROR; |
781 | 677 | ||
782 | /* set handle to 0 so in case an error occurs, the handle is invalid */ | 678 | /* set handle to 0 so in case an error occurs, the handle is invalid */ |
783 | *handle = 0; | 679 | *handle = 0; |
784 | 680 | ||
785 | if (!client || !client->connection || !client->afc_packet) | ||
786 | return AFC_E_INVALID_ARG; | ||
787 | |||
788 | afc_lock(client); | 681 | afc_lock(client); |
789 | 682 | ||
790 | /* Send command */ | 683 | uint32_t data_len = (uint32_t)(strlen(filename)+1 + 8); |
791 | memcpy(data, &file_mode_loc, 8); | 684 | if (_afc_check_packet_buffer(client, data_len) < 0) { |
792 | memcpy(data + 8, filename, strlen(filename)); | 685 | afc_unlock(client); |
793 | data[8 + strlen(filename)] = '\0'; | 686 | debug_info("Failed to realloc packet buffer"); |
794 | client->afc_packet->operation = AFC_OP_FILE_OPEN; | 687 | return AFC_E_NO_MEM; |
795 | client->afc_packet->entire_length = client->afc_packet->this_length = 0; | 688 | } |
796 | ret = afc_dispatch_packet(client, data, 8 + strlen(filename) + 1, &bytes); | ||
797 | free(data); | ||
798 | 689 | ||
690 | /* Send command */ | ||
691 | //memcpy(AFC_PACKET_DATA_PTR, &file_mode_loc, 8); | ||
692 | *(uint64_t*)(AFC_PACKET_DATA_PTR) = htole64(file_mode); | ||
693 | memcpy(AFC_PACKET_DATA_PTR + 8, filename, data_len-8); | ||
694 | ret = afc_dispatch_packet(client, AFC_OP_FILE_OPEN, data_len, NULL, 0, &bytes); | ||
799 | if (ret != AFC_E_SUCCESS) { | 695 | if (ret != AFC_E_SUCCESS) { |
800 | debug_info("Didn't receive a response to the command"); | 696 | debug_info("Didn't receive a response to the command"); |
801 | afc_unlock(client); | 697 | afc_unlock(client); |
802 | return AFC_E_NOT_ENOUGH_DATA; | 698 | return AFC_E_NOT_ENOUGH_DATA; |
803 | } | 699 | } |
804 | /* Receive the data */ | 700 | /* Receive the data */ |
701 | char* data = NULL; | ||
805 | ret = afc_receive_data(client, &data, &bytes); | 702 | ret = afc_receive_data(client, &data, &bytes); |
806 | if ((ret == AFC_E_SUCCESS) && (bytes > 0) && data) { | 703 | if ((ret == AFC_E_SUCCESS) && (bytes > 0) && data) { |
807 | afc_unlock(client); | 704 | afc_unlock(client); |
@@ -811,6 +708,8 @@ afc_file_open(afc_client_t client, const char *filename, | |||
811 | free(data); | 708 | free(data); |
812 | return ret; | 709 | return ret; |
813 | } | 710 | } |
711 | /* in case memory was allocated but no data received or an error occurred */ | ||
712 | free(data); | ||
814 | 713 | ||
815 | debug_info("Didn't get any further data"); | 714 | debug_info("Didn't get any further data"); |
816 | 715 | ||
@@ -819,156 +718,81 @@ afc_file_open(afc_client_t client, const char *filename, | |||
819 | return ret; | 718 | return ret; |
820 | } | 719 | } |
821 | 720 | ||
822 | /** | 721 | afc_error_t afc_file_read(afc_client_t client, uint64_t handle, char *data, uint32_t length, uint32_t *bytes_read) |
823 | * Attempts to the read the given number of bytes from the given file. | ||
824 | * | ||
825 | * @param client The relevant AFC client | ||
826 | * @param handle File handle of a previously opened file | ||
827 | * @param data The pointer to the memory region to store the read data | ||
828 | * @param length The number of bytes to read | ||
829 | * @param bytes_read The number of bytes actually read. | ||
830 | * | ||
831 | * @return AFC_E_SUCCESS on success or an AFC_E_* error value. | ||
832 | */ | ||
833 | idevice_error_t | ||
834 | afc_file_read(afc_client_t client, uint64_t handle, char *data, uint32_t length, uint32_t *bytes_read) | ||
835 | { | 722 | { |
836 | char *input = NULL; | 723 | char *input = NULL; |
837 | uint32_t current_count = 0, bytes_loc = 0; | 724 | uint32_t current_count = 0, bytes_loc = 0; |
838 | const uint32_t MAXIMUM_READ_SIZE = 1 << 16; | 725 | struct readinfo { |
726 | uint64_t handle; | ||
727 | uint64_t size; | ||
728 | }; | ||
839 | afc_error_t ret = AFC_E_SUCCESS; | 729 | afc_error_t ret = AFC_E_SUCCESS; |
840 | 730 | ||
841 | if (!client || !client->afc_packet || !client->connection || handle == 0) | 731 | if (!client || !client->afc_packet || !client->parent || handle == 0) |
842 | return AFC_E_INVALID_ARG; | 732 | return AFC_E_INVALID_ARG; |
843 | debug_info("called for length %i", length); | 733 | debug_info("called for length %i", length); |
844 | 734 | ||
735 | //uint32_t data_len = 8 + 8; | ||
736 | |||
845 | afc_lock(client); | 737 | afc_lock(client); |
846 | 738 | ||
847 | /* Looping here to get around the maximum amount of data that | 739 | /* Send the read command */ |
848 | afc_receive_data can handle */ | 740 | struct readinfo* readinfo = (struct readinfo*)(AFC_PACKET_DATA_PTR); |
849 | while (current_count < length) { | 741 | readinfo->handle = handle; |
850 | debug_info("current count is %i but length is %i", current_count, length); | 742 | readinfo->size = htole64(length); |
851 | 743 | ret = afc_dispatch_packet(client, AFC_OP_FILE_READ, sizeof(struct readinfo), NULL, 0, &bytes_loc); | |
852 | /* Send the read command */ | 744 | if (ret != AFC_E_SUCCESS) { |
853 | AFCFilePacket *packet = (AFCFilePacket *) malloc(sizeof(AFCFilePacket)); | 745 | afc_unlock(client); |
854 | packet->filehandle = handle; | 746 | return AFC_E_NOT_ENOUGH_DATA; |
855 | packet->size = GUINT64_TO_LE(((length - current_count) < MAXIMUM_READ_SIZE) ? (length - current_count) : MAXIMUM_READ_SIZE); | 747 | } |
856 | client->afc_packet->operation = AFC_OP_READ; | 748 | /* Receive the data */ |
857 | client->afc_packet->entire_length = client->afc_packet->this_length = 0; | 749 | ret = afc_receive_data(client, &input, &bytes_loc); |
858 | ret = afc_dispatch_packet(client, (char *) packet, sizeof(AFCFilePacket), &bytes_loc); | 750 | debug_info("afc_receive_data returned error: %d", ret); |
859 | free(packet); | 751 | debug_info("bytes returned: %i", bytes_loc); |
860 | 752 | if (ret != AFC_E_SUCCESS) { | |
861 | if (ret != AFC_E_SUCCESS) { | 753 | afc_unlock(client); |
862 | afc_unlock(client); | 754 | return ret; |
863 | return AFC_E_NOT_ENOUGH_DATA; | 755 | } |
864 | } | 756 | if (bytes_loc == 0) { |
865 | /* Receive the data */ | 757 | if (input) |
866 | ret = afc_receive_data(client, &input, &bytes_loc); | 758 | free(input); |
867 | debug_info("afc_receive_data returned error: %d", ret); | 759 | afc_unlock(client); |
868 | debug_info("bytes returned: %i", bytes_loc); | 760 | *bytes_read = current_count; |
869 | if (ret != AFC_E_SUCCESS) { | 761 | /* FIXME: check that's actually a success */ |
870 | afc_unlock(client); | 762 | return ret; |
871 | return ret; | 763 | } |
872 | } else if (bytes_loc == 0) { | 764 | if (input) { |
873 | if (input) | 765 | debug_info("%d", bytes_loc); |
874 | free(input); | 766 | memcpy(data + current_count, input, (bytes_loc > length) ? length : bytes_loc); |
875 | afc_unlock(client); | 767 | free(input); |
876 | *bytes_read = current_count; | 768 | input = NULL; |
877 | /* FIXME: check that's actually a success */ | 769 | current_count += (bytes_loc > length) ? length : bytes_loc; |
878 | return ret; | ||
879 | } else { | ||
880 | if (input) { | ||
881 | debug_info("%d", bytes_loc); | ||
882 | memcpy(data + current_count, input, (bytes_loc > length) ? length : bytes_loc); | ||
883 | free(input); | ||
884 | input = NULL; | ||
885 | current_count += (bytes_loc > length) ? length : bytes_loc; | ||
886 | } | ||
887 | } | ||
888 | } | 770 | } |
889 | debug_info("returning current_count as %i", current_count); | ||
890 | 771 | ||
891 | afc_unlock(client); | 772 | afc_unlock(client); |
892 | *bytes_read = current_count; | 773 | *bytes_read = current_count; |
893 | return ret; | 774 | return ret; |
894 | } | 775 | } |
895 | 776 | ||
896 | /** | 777 | afc_error_t afc_file_write(afc_client_t client, uint64_t handle, const char *data, uint32_t length, uint32_t *bytes_written) |
897 | * Writes a given number of bytes to a file. | ||
898 | * | ||
899 | * @param client The client to use to write to the file. | ||
900 | * @param handle File handle of previously opened file. | ||
901 | * @param data The data to write to the file. | ||
902 | * @param length How much data to write. | ||
903 | * @param bytes_written The number of bytes actually written to the file. | ||
904 | * | ||
905 | * @return AFC_E_SUCCESS on success or an AFC_E_* error value. | ||
906 | */ | ||
907 | idevice_error_t | ||
908 | afc_file_write(afc_client_t client, uint64_t handle, const char *data, uint32_t length, uint32_t *bytes_written) | ||
909 | { | 778 | { |
910 | char *acknowledgement = NULL; | 779 | uint32_t current_count = 0; |
911 | const uint32_t MAXIMUM_WRITE_SIZE = 1 << 15; | ||
912 | uint32_t current_count = 0, i = 0; | ||
913 | uint32_t segments = (length / MAXIMUM_WRITE_SIZE); | ||
914 | uint32_t bytes_loc = 0; | 780 | uint32_t bytes_loc = 0; |
915 | char *out_buffer = NULL; | ||
916 | afc_error_t ret = AFC_E_SUCCESS; | 781 | afc_error_t ret = AFC_E_SUCCESS; |
917 | 782 | ||
918 | if (!client || !client->afc_packet || !client->connection || !bytes_written || (handle == 0)) | 783 | if (!client || !client->afc_packet || !client->parent || !bytes_written || (handle == 0)) |
919 | return AFC_E_INVALID_ARG; | 784 | return AFC_E_INVALID_ARG; |
920 | 785 | ||
786 | uint32_t data_len = 8; | ||
787 | |||
921 | afc_lock(client); | 788 | afc_lock(client); |
922 | 789 | ||
923 | debug_info("Write length: %i", length); | 790 | debug_info("Write length: %i", length); |
924 | 791 | ||
925 | /* Divide the file into segments. */ | 792 | *(uint64_t*)(AFC_PACKET_DATA_PTR) = handle; |
926 | for (i = 0; i < segments; i++) { | 793 | ret = afc_dispatch_packet(client, AFC_OP_FILE_WRITE, data_len, data, length, &bytes_loc); |
927 | /* Send the segment */ | ||
928 | client->afc_packet->this_length = sizeof(AFCPacket) + 8; | ||
929 | client->afc_packet->entire_length = client->afc_packet->this_length + MAXIMUM_WRITE_SIZE; | ||
930 | client->afc_packet->operation = AFC_OP_WRITE; | ||
931 | out_buffer = (char *) malloc(sizeof(char) * client->afc_packet->entire_length - sizeof(AFCPacket)); | ||
932 | memcpy(out_buffer, (char *)&handle, sizeof(uint64_t)); | ||
933 | memcpy(out_buffer + 8, data + current_count, MAXIMUM_WRITE_SIZE); | ||
934 | ret = afc_dispatch_packet(client, out_buffer, MAXIMUM_WRITE_SIZE + 8, &bytes_loc); | ||
935 | if (ret != AFC_E_SUCCESS) { | ||
936 | afc_unlock(client); | ||
937 | return AFC_E_NOT_ENOUGH_DATA; | ||
938 | } | ||
939 | free(out_buffer); | ||
940 | out_buffer = NULL; | ||
941 | |||
942 | current_count += bytes_loc; | ||
943 | ret = afc_receive_data(client, &acknowledgement, &bytes_loc); | ||
944 | if (ret != AFC_E_SUCCESS) { | ||
945 | afc_unlock(client); | ||
946 | return ret; | ||
947 | } else { | ||
948 | free(acknowledgement); | ||
949 | } | ||
950 | } | ||
951 | |||
952 | /* By this point, we should be at the end. i.e. the last segment that didn't | ||
953 | get sent in the for loop. This length is fine because it's always | ||
954 | sizeof(AFCPacket) + 8, but to be sure we do it again */ | ||
955 | if (current_count == length) { | ||
956 | afc_unlock(client); | ||
957 | *bytes_written = current_count; | ||
958 | return ret; | ||
959 | } | ||
960 | |||
961 | client->afc_packet->this_length = sizeof(AFCPacket) + 8; | ||
962 | client->afc_packet->entire_length = client->afc_packet->this_length + (length - current_count); | ||
963 | client->afc_packet->operation = AFC_OP_WRITE; | ||
964 | out_buffer = (char *) malloc(sizeof(char) * client->afc_packet->entire_length - sizeof(AFCPacket)); | ||
965 | memcpy(out_buffer, (char *) &handle, sizeof(uint64_t)); | ||
966 | memcpy(out_buffer + 8, data + current_count, (length - current_count)); | ||
967 | ret = afc_dispatch_packet(client, out_buffer, (length - current_count) + 8, &bytes_loc); | ||
968 | free(out_buffer); | ||
969 | out_buffer = NULL; | ||
970 | 794 | ||
971 | current_count += bytes_loc; | 795 | current_count += bytes_loc - (sizeof(AFCPacket) + 8); |
972 | 796 | ||
973 | if (ret != AFC_E_SUCCESS) { | 797 | if (ret != AFC_E_SUCCESS) { |
974 | afc_unlock(client); | 798 | afc_unlock(client); |
@@ -976,43 +800,32 @@ afc_file_write(afc_client_t client, uint64_t handle, const char *data, uint32_t | |||
976 | return AFC_E_SUCCESS; | 800 | return AFC_E_SUCCESS; |
977 | } | 801 | } |
978 | 802 | ||
979 | ret = afc_receive_data(client, &acknowledgement, &bytes_loc); | 803 | ret = afc_receive_data(client, NULL, &bytes_loc); |
980 | afc_unlock(client); | 804 | afc_unlock(client); |
981 | if (ret != AFC_E_SUCCESS) { | 805 | if (ret != AFC_E_SUCCESS) { |
982 | debug_info("uh oh?"); | 806 | debug_info("Failed to receive reply (%d)", ret); |
983 | } else { | ||
984 | free(acknowledgement); | ||
985 | } | 807 | } |
986 | *bytes_written = current_count; | 808 | *bytes_written = current_count; |
987 | return ret; | 809 | return ret; |
988 | } | 810 | } |
989 | 811 | ||
990 | /** | ||
991 | * Closes a file on the phone. | ||
992 | * | ||
993 | * @param client The client to close the file with. | ||
994 | * @param handle File handle of a previously opened file. | ||
995 | */ | ||
996 | afc_error_t afc_file_close(afc_client_t client, uint64_t handle) | 812 | afc_error_t afc_file_close(afc_client_t client, uint64_t handle) |
997 | { | 813 | { |
998 | char *buffer = malloc(sizeof(char) * 8); | ||
999 | uint32_t bytes = 0; | 814 | uint32_t bytes = 0; |
1000 | afc_error_t ret = AFC_E_UNKNOWN_ERROR; | 815 | afc_error_t ret = AFC_E_UNKNOWN_ERROR; |
1001 | 816 | ||
1002 | if (!client || (handle == 0)) | 817 | if (!client || (handle == 0)) |
1003 | return AFC_E_INVALID_ARG; | 818 | return AFC_E_INVALID_ARG; |
1004 | 819 | ||
820 | uint32_t data_len = 8; | ||
821 | |||
1005 | afc_lock(client); | 822 | afc_lock(client); |
1006 | 823 | ||
1007 | debug_info("File handle %i", handle); | 824 | debug_info("File handle %i", handle); |
1008 | 825 | ||
1009 | /* Send command */ | 826 | /* Send command */ |
1010 | memcpy(buffer, &handle, sizeof(uint64_t)); | 827 | *(uint64_t*)(AFC_PACKET_DATA_PTR) = handle; |
1011 | client->afc_packet->operation = AFC_OP_FILE_CLOSE; | 828 | ret = afc_dispatch_packet(client, AFC_OP_FILE_CLOSE, data_len, NULL, 0, &bytes); |
1012 | client->afc_packet->entire_length = client->afc_packet->this_length = 0; | ||
1013 | ret = afc_dispatch_packet(client, buffer, 8, &bytes); | ||
1014 | free(buffer); | ||
1015 | buffer = NULL; | ||
1016 | 829 | ||
1017 | if (ret != AFC_E_SUCCESS) { | 830 | if (ret != AFC_E_SUCCESS) { |
1018 | afc_unlock(client); | 831 | afc_unlock(client); |
@@ -1020,32 +833,20 @@ afc_error_t afc_file_close(afc_client_t client, uint64_t handle) | |||
1020 | } | 833 | } |
1021 | 834 | ||
1022 | /* Receive the response */ | 835 | /* Receive the response */ |
1023 | ret = afc_receive_data(client, &buffer, &bytes); | 836 | ret = afc_receive_data(client, NULL, &bytes); |
1024 | if (buffer) | ||
1025 | free(buffer); | ||
1026 | 837 | ||
1027 | afc_unlock(client); | 838 | afc_unlock(client); |
1028 | 839 | ||
1029 | return ret; | 840 | return ret; |
1030 | } | 841 | } |
1031 | 842 | ||
1032 | /** | ||
1033 | * Locks or unlocks a file on the phone. | ||
1034 | * | ||
1035 | * makes use of flock on the device, see | ||
1036 | * http://developer.apple.com/documentation/Darwin/Reference/ManPages/man2/flock.2.html | ||
1037 | * | ||
1038 | * @param client The client to lock the file with. | ||
1039 | * @param handle File handle of a previously opened file. | ||
1040 | * @param operation the lock or unlock operation to perform, this is one of | ||
1041 | * AFC_LOCK_SH (shared lock), AFC_LOCK_EX (exclusive lock), | ||
1042 | * or AFC_LOCK_UN (unlock). | ||
1043 | */ | ||
1044 | afc_error_t afc_file_lock(afc_client_t client, uint64_t handle, afc_lock_op_t operation) | 843 | afc_error_t afc_file_lock(afc_client_t client, uint64_t handle, afc_lock_op_t operation) |
1045 | { | 844 | { |
1046 | char *buffer = malloc(16); | ||
1047 | uint32_t bytes = 0; | 845 | uint32_t bytes = 0; |
1048 | uint64_t op = GUINT64_TO_LE(operation); | 846 | struct lockinfo { |
847 | uint64_t handle; | ||
848 | uint64_t op; | ||
849 | }; | ||
1049 | afc_error_t ret = AFC_E_UNKNOWN_ERROR; | 850 | afc_error_t ret = AFC_E_UNKNOWN_ERROR; |
1050 | 851 | ||
1051 | if (!client || (handle == 0)) | 852 | if (!client || (handle == 0)) |
@@ -1056,47 +857,31 @@ afc_error_t afc_file_lock(afc_client_t client, uint64_t handle, afc_lock_op_t op | |||
1056 | debug_info("file handle %i", handle); | 857 | debug_info("file handle %i", handle); |
1057 | 858 | ||
1058 | /* Send command */ | 859 | /* Send command */ |
1059 | memcpy(buffer, &handle, sizeof(uint64_t)); | 860 | struct lockinfo* lockinfo = (struct lockinfo*)(AFC_PACKET_DATA_PTR); |
1060 | memcpy(buffer + 8, &op, 8); | 861 | lockinfo->handle = handle; |
1061 | 862 | lockinfo->op = htole64(operation); | |
1062 | client->afc_packet->operation = AFC_OP_FILE_LOCK; | 863 | ret = afc_dispatch_packet(client, AFC_OP_FILE_LOCK, sizeof(struct lockinfo), NULL, 0, &bytes); |
1063 | client->afc_packet->entire_length = client->afc_packet->this_length = 0; | ||
1064 | ret = afc_dispatch_packet(client, buffer, 16, &bytes); | ||
1065 | free(buffer); | ||
1066 | buffer = NULL; | ||
1067 | |||
1068 | if (ret != AFC_E_SUCCESS) { | 864 | if (ret != AFC_E_SUCCESS) { |
1069 | afc_unlock(client); | 865 | afc_unlock(client); |
1070 | debug_info("could not send lock command"); | 866 | debug_info("could not send lock command"); |
1071 | return AFC_E_UNKNOWN_ERROR; | 867 | return AFC_E_UNKNOWN_ERROR; |
1072 | } | 868 | } |
1073 | /* Receive the response */ | 869 | /* Receive the response */ |
1074 | ret = afc_receive_data(client, &buffer, &bytes); | 870 | ret = afc_receive_data(client, NULL, &bytes); |
1075 | if (buffer) { | 871 | |
1076 | debug_buffer(buffer, bytes); | ||
1077 | free(buffer); | ||
1078 | } | ||
1079 | afc_unlock(client); | 872 | afc_unlock(client); |
1080 | 873 | ||
1081 | return ret; | 874 | return ret; |
1082 | } | 875 | } |
1083 | 876 | ||
1084 | /** | ||
1085 | * Seeks to a given position of a pre-opened file on the phone. | ||
1086 | * | ||
1087 | * @param client The client to use to seek to the position. | ||
1088 | * @param handle File handle of a previously opened. | ||
1089 | * @param offset Seek offset. | ||
1090 | * @param whence Seeking direction, one of SEEK_SET, SEEK_CUR, or SEEK_END. | ||
1091 | * | ||
1092 | * @return AFC_E_SUCCESS on success or an AFC_E_* error value. | ||
1093 | */ | ||
1094 | afc_error_t afc_file_seek(afc_client_t client, uint64_t handle, int64_t offset, int whence) | 877 | afc_error_t afc_file_seek(afc_client_t client, uint64_t handle, int64_t offset, int whence) |
1095 | { | 878 | { |
1096 | char *buffer = (char *) malloc(sizeof(char) * 24); | ||
1097 | int64_t offset_loc = (int64_t)GUINT64_TO_LE(offset); | ||
1098 | uint64_t whence_loc = GUINT64_TO_LE(whence); | ||
1099 | uint32_t bytes = 0; | 879 | uint32_t bytes = 0; |
880 | struct seekinfo { | ||
881 | uint64_t handle; | ||
882 | uint64_t whence; | ||
883 | int64_t offset; | ||
884 | }; | ||
1100 | afc_error_t ret = AFC_E_UNKNOWN_ERROR; | 885 | afc_error_t ret = AFC_E_UNKNOWN_ERROR; |
1101 | 886 | ||
1102 | if (!client || (handle == 0)) | 887 | if (!client || (handle == 0)) |
@@ -1105,57 +890,40 @@ afc_error_t afc_file_seek(afc_client_t client, uint64_t handle, int64_t offset, | |||
1105 | afc_lock(client); | 890 | afc_lock(client); |
1106 | 891 | ||
1107 | /* Send the command */ | 892 | /* Send the command */ |
1108 | memcpy(buffer, &handle, sizeof(uint64_t)); /* handle */ | 893 | struct seekinfo* seekinfo = (struct seekinfo*)(AFC_PACKET_DATA_PTR); |
1109 | memcpy(buffer + 8, &whence_loc, sizeof(uint64_t)); /* fromwhere */ | 894 | seekinfo->handle = handle; |
1110 | memcpy(buffer + 16, &offset_loc, sizeof(uint64_t)); /* offset */ | 895 | seekinfo->whence = htole64(whence); |
1111 | client->afc_packet->operation = AFC_OP_FILE_SEEK; | 896 | seekinfo->offset = (int64_t)htole64(offset); |
1112 | client->afc_packet->this_length = client->afc_packet->entire_length = 0; | 897 | ret = afc_dispatch_packet(client, AFC_OP_FILE_SEEK, sizeof(struct seekinfo), NULL, 0, &bytes); |
1113 | ret = afc_dispatch_packet(client, buffer, 24, &bytes); | ||
1114 | free(buffer); | ||
1115 | buffer = NULL; | ||
1116 | 898 | ||
1117 | if (ret != AFC_E_SUCCESS) { | 899 | if (ret != AFC_E_SUCCESS) { |
1118 | afc_unlock(client); | 900 | afc_unlock(client); |
1119 | return AFC_E_NOT_ENOUGH_DATA; | 901 | return AFC_E_NOT_ENOUGH_DATA; |
1120 | } | 902 | } |
1121 | /* Receive response */ | 903 | /* Receive response */ |
1122 | ret = afc_receive_data(client, &buffer, &bytes); | 904 | ret = afc_receive_data(client, NULL, &bytes); |
1123 | if (buffer) | ||
1124 | free(buffer); | ||
1125 | 905 | ||
1126 | afc_unlock(client); | 906 | afc_unlock(client); |
1127 | 907 | ||
1128 | return ret; | 908 | return ret; |
1129 | } | 909 | } |
1130 | 910 | ||
1131 | /** | ||
1132 | * Returns current position in a pre-opened file on the phone. | ||
1133 | * | ||
1134 | * @param client The client to use. | ||
1135 | * @param handle File handle of a previously opened file. | ||
1136 | * @param position Position in bytes of indicator | ||
1137 | * | ||
1138 | * @return AFC_E_SUCCESS on success or an AFC_E_* error value. | ||
1139 | */ | ||
1140 | afc_error_t afc_file_tell(afc_client_t client, uint64_t handle, uint64_t *position) | 911 | afc_error_t afc_file_tell(afc_client_t client, uint64_t handle, uint64_t *position) |
1141 | { | 912 | { |
1142 | char *buffer = (char *) malloc(sizeof(char) * 8); | 913 | char *buffer = NULL; |
1143 | uint32_t bytes = 0; | 914 | uint32_t bytes = 0; |
1144 | afc_error_t ret = AFC_E_UNKNOWN_ERROR; | 915 | afc_error_t ret = AFC_E_UNKNOWN_ERROR; |
1145 | 916 | ||
1146 | if (!client || (handle == 0)) | 917 | if (!client || (handle == 0)) |
1147 | return AFC_E_INVALID_ARG; | 918 | return AFC_E_INVALID_ARG; |
1148 | 919 | ||
920 | uint32_t data_len = 8; | ||
921 | |||
1149 | afc_lock(client); | 922 | afc_lock(client); |
1150 | 923 | ||
1151 | /* Send the command */ | 924 | /* Send the command */ |
1152 | memcpy(buffer, &handle, sizeof(uint64_t)); /* handle */ | 925 | *(uint64_t*)(AFC_PACKET_DATA_PTR) = handle; |
1153 | client->afc_packet->operation = AFC_OP_FILE_TELL; | 926 | ret = afc_dispatch_packet(client, AFC_OP_FILE_TELL, data_len, NULL, 0, &bytes); |
1154 | client->afc_packet->this_length = client->afc_packet->entire_length = 0; | ||
1155 | ret = afc_dispatch_packet(client, buffer, 8, &bytes); | ||
1156 | free(buffer); | ||
1157 | buffer = NULL; | ||
1158 | |||
1159 | if (ret != AFC_E_SUCCESS) { | 927 | if (ret != AFC_E_SUCCESS) { |
1160 | afc_unlock(client); | 928 | afc_unlock(client); |
1161 | return AFC_E_NOT_ENOUGH_DATA; | 929 | return AFC_E_NOT_ENOUGH_DATA; |
@@ -1166,33 +934,22 @@ afc_error_t afc_file_tell(afc_client_t client, uint64_t handle, uint64_t *positi | |||
1166 | if (bytes > 0 && buffer) { | 934 | if (bytes > 0 && buffer) { |
1167 | /* Get the position */ | 935 | /* Get the position */ |
1168 | memcpy(position, buffer, sizeof(uint64_t)); | 936 | memcpy(position, buffer, sizeof(uint64_t)); |
1169 | *position = GUINT64_FROM_LE(*position); | 937 | *position = le64toh(*position); |
1170 | } | 938 | } |
1171 | if (buffer) | 939 | free(buffer); |
1172 | free(buffer); | ||
1173 | 940 | ||
1174 | afc_unlock(client); | 941 | afc_unlock(client); |
1175 | 942 | ||
1176 | return ret; | 943 | return ret; |
1177 | } | 944 | } |
1178 | 945 | ||
1179 | /** | ||
1180 | * Sets the size of a file on the phone. | ||
1181 | * | ||
1182 | * @param client The client to use to set the file size. | ||
1183 | * @param handle File handle of a previously opened file. | ||
1184 | * @param newsize The size to set the file to. | ||
1185 | * | ||
1186 | * @return AFC_E_SUCCESS on success or an AFC_E_* error value. | ||
1187 | * | ||
1188 | * @note This function is more akin to ftruncate than truncate, and truncate | ||
1189 | * calls would have to open the file before calling this, sadly. | ||
1190 | */ | ||
1191 | afc_error_t afc_file_truncate(afc_client_t client, uint64_t handle, uint64_t newsize) | 946 | afc_error_t afc_file_truncate(afc_client_t client, uint64_t handle, uint64_t newsize) |
1192 | { | 947 | { |
1193 | char *buffer = (char *) malloc(sizeof(char) * 16); | ||
1194 | uint32_t bytes = 0; | 948 | uint32_t bytes = 0; |
1195 | uint64_t newsize_loc = GUINT64_TO_LE(newsize); | 949 | struct truncinfo { |
950 | uint64_t handle; | ||
951 | uint64_t newsize; | ||
952 | }; | ||
1196 | afc_error_t ret = AFC_E_UNKNOWN_ERROR; | 953 | afc_error_t ret = AFC_E_UNKNOWN_ERROR; |
1197 | 954 | ||
1198 | if (!client || (handle == 0)) | 955 | if (!client || (handle == 0)) |
@@ -1201,160 +958,240 @@ afc_error_t afc_file_truncate(afc_client_t client, uint64_t handle, uint64_t new | |||
1201 | afc_lock(client); | 958 | afc_lock(client); |
1202 | 959 | ||
1203 | /* Send command */ | 960 | /* Send command */ |
1204 | memcpy(buffer, &handle, sizeof(uint64_t)); /* handle */ | 961 | struct truncinfo* truncinfo = (struct truncinfo*)(AFC_PACKET_DATA_PTR); |
1205 | memcpy(buffer + 8, &newsize_loc, sizeof(uint64_t)); /* newsize */ | 962 | truncinfo->handle = handle; |
1206 | client->afc_packet->operation = AFC_OP_FILE_SET_SIZE; | 963 | truncinfo->newsize = htole64(newsize); |
1207 | client->afc_packet->this_length = client->afc_packet->entire_length = 0; | 964 | ret = afc_dispatch_packet(client, AFC_OP_FILE_SET_SIZE, sizeof(struct truncinfo), NULL, 0, &bytes); |
1208 | ret = afc_dispatch_packet(client, buffer, 16, &bytes); | ||
1209 | free(buffer); | ||
1210 | buffer = NULL; | ||
1211 | 965 | ||
1212 | if (ret != AFC_E_SUCCESS) { | 966 | if (ret != AFC_E_SUCCESS) { |
1213 | afc_unlock(client); | 967 | afc_unlock(client); |
1214 | return AFC_E_NOT_ENOUGH_DATA; | 968 | return AFC_E_NOT_ENOUGH_DATA; |
1215 | } | 969 | } |
1216 | /* Receive response */ | 970 | /* Receive response */ |
1217 | ret = afc_receive_data(client, &buffer, &bytes); | 971 | ret = afc_receive_data(client, NULL, &bytes); |
1218 | if (buffer) | ||
1219 | free(buffer); | ||
1220 | 972 | ||
1221 | afc_unlock(client); | 973 | afc_unlock(client); |
1222 | 974 | ||
1223 | return ret; | 975 | return ret; |
1224 | } | 976 | } |
1225 | 977 | ||
1226 | /** | ||
1227 | * Sets the size of a file on the phone without prior opening it. | ||
1228 | * | ||
1229 | * @param client The client to use to set the file size. | ||
1230 | * @param path The path of the file to be truncated. | ||
1231 | * @param newsize The size to set the file to. | ||
1232 | * | ||
1233 | * @return AFC_E_SUCCESS on success or an AFC_E_* error value. | ||
1234 | */ | ||
1235 | afc_error_t afc_truncate(afc_client_t client, const char *path, uint64_t newsize) | 978 | afc_error_t afc_truncate(afc_client_t client, const char *path, uint64_t newsize) |
1236 | { | 979 | { |
1237 | char *response = NULL; | 980 | if (!client || !path || !client->afc_packet || !client->parent) |
1238 | char *send = (char *) malloc(sizeof(char) * (strlen(path) + 1 + 8)); | 981 | return AFC_E_INVALID_ARG; |
982 | |||
1239 | uint32_t bytes = 0; | 983 | uint32_t bytes = 0; |
1240 | uint64_t size_requested = GUINT64_TO_LE(newsize); | ||
1241 | afc_error_t ret = AFC_E_UNKNOWN_ERROR; | 984 | afc_error_t ret = AFC_E_UNKNOWN_ERROR; |
1242 | 985 | ||
1243 | if (!client || !path || !client->afc_packet || !client->connection) | ||
1244 | return AFC_E_INVALID_ARG; | ||
1245 | |||
1246 | afc_lock(client); | 986 | afc_lock(client); |
1247 | 987 | ||
988 | uint32_t data_len = 8 + (uint32_t)(strlen(path)+1); | ||
989 | if (_afc_check_packet_buffer(client, data_len) < 0) { | ||
990 | afc_unlock(client); | ||
991 | debug_info("Failed to realloc packet buffer"); | ||
992 | return AFC_E_NO_MEM; | ||
993 | } | ||
994 | |||
1248 | /* Send command */ | 995 | /* Send command */ |
1249 | memcpy(send, &size_requested, 8); | 996 | *(uint64_t*)(AFC_PACKET_DATA_PTR) = htole64(newsize); |
1250 | memcpy(send + 8, path, strlen(path) + 1); | 997 | memcpy(AFC_PACKET_DATA_PTR + 8, path, data_len-8); |
1251 | client->afc_packet->entire_length = client->afc_packet->this_length = 0; | 998 | ret = afc_dispatch_packet(client, AFC_OP_TRUNCATE, data_len, NULL, 0, &bytes); |
1252 | client->afc_packet->operation = AFC_OP_TRUNCATE; | ||
1253 | ret = afc_dispatch_packet(client, send, 8 + strlen(path) + 1, &bytes); | ||
1254 | free(send); | ||
1255 | if (ret != AFC_E_SUCCESS) { | 999 | if (ret != AFC_E_SUCCESS) { |
1256 | afc_unlock(client); | 1000 | afc_unlock(client); |
1257 | return AFC_E_NOT_ENOUGH_DATA; | 1001 | return AFC_E_NOT_ENOUGH_DATA; |
1258 | } | 1002 | } |
1259 | /* Receive response */ | 1003 | /* Receive response */ |
1260 | ret = afc_receive_data(client, &response, &bytes); | 1004 | ret = afc_receive_data(client, NULL, &bytes); |
1261 | if (response) | ||
1262 | free(response); | ||
1263 | 1005 | ||
1264 | afc_unlock(client); | 1006 | afc_unlock(client); |
1265 | 1007 | ||
1266 | return ret; | 1008 | return ret; |
1267 | } | 1009 | } |
1268 | 1010 | ||
1269 | /** | ||
1270 | * Creates a hard link or symbolic link on the device. | ||
1271 | * | ||
1272 | * @param client The client to use for making a link | ||
1273 | * @param linktype 1 = hard link, 2 = symlink | ||
1274 | * @param target The file to be linked. | ||
1275 | * @param linkname The name of link. | ||
1276 | * | ||
1277 | * @return AFC_E_SUCCESS on success or an AFC_E_* error value. | ||
1278 | */ | ||
1279 | afc_error_t afc_make_link(afc_client_t client, afc_link_type_t linktype, const char *target, const char *linkname) | 1011 | afc_error_t afc_make_link(afc_client_t client, afc_link_type_t linktype, const char *target, const char *linkname) |
1280 | { | 1012 | { |
1281 | char *response = NULL; | 1013 | if (!client || !target || !linkname || !client->afc_packet || !client->parent) |
1282 | char *send = (char *) malloc(sizeof(char) * (strlen(target)+1 + strlen(linkname)+1 + 8)); | 1014 | return AFC_E_INVALID_ARG; |
1015 | |||
1283 | uint32_t bytes = 0; | 1016 | uint32_t bytes = 0; |
1284 | uint64_t type = GUINT64_TO_LE(linktype); | ||
1285 | afc_error_t ret = AFC_E_UNKNOWN_ERROR; | 1017 | afc_error_t ret = AFC_E_UNKNOWN_ERROR; |
1286 | 1018 | ||
1287 | if (!client || !target || !linkname || !client->afc_packet || !client->connection) | 1019 | size_t target_len = strlen(target); |
1288 | return AFC_E_INVALID_ARG; | 1020 | size_t link_len = strlen(linkname); |
1289 | 1021 | ||
1290 | afc_lock(client); | 1022 | afc_lock(client); |
1291 | 1023 | ||
1292 | debug_info("link type: %lld", type); | 1024 | uint32_t data_len = 8 + target_len + 1 + link_len + 1; |
1293 | debug_info("target: %s, length:%d", target, strlen(target)); | 1025 | if (_afc_check_packet_buffer(client, data_len) < 0) { |
1294 | debug_info("linkname: %s, length:%d", linkname, strlen(linkname)); | 1026 | afc_unlock(client); |
1027 | debug_info("Failed to realloc packet buffer"); | ||
1028 | return AFC_E_NO_MEM; | ||
1029 | } | ||
1030 | |||
1031 | debug_info("link type: %lld", htole64(linktype)); | ||
1032 | debug_info("target: %s, length:%d", target, target_len); | ||
1033 | debug_info("linkname: %s, length:%d", linkname, link_len); | ||
1295 | 1034 | ||
1296 | /* Send command */ | 1035 | /* Send command */ |
1297 | memcpy(send, &type, 8); | 1036 | *(uint64_t*)(AFC_PACKET_DATA_PTR) = htole64(linktype); |
1298 | memcpy(send + 8, target, strlen(target) + 1); | 1037 | memcpy(AFC_PACKET_DATA_PTR + 8, target, target_len + 1); |
1299 | memcpy(send + 8 + strlen(target) + 1, linkname, strlen(linkname) + 1); | 1038 | memcpy(AFC_PACKET_DATA_PTR + 8 + target_len + 1, linkname, link_len + 1); |
1300 | client->afc_packet->entire_length = client->afc_packet->this_length = 0; | 1039 | ret = afc_dispatch_packet(client, AFC_OP_MAKE_LINK, data_len, NULL, 0, &bytes); |
1301 | client->afc_packet->operation = AFC_OP_MAKE_LINK; | ||
1302 | ret = afc_dispatch_packet(client, send, 8 + strlen(linkname) + 1 + strlen(target) + 1, &bytes); | ||
1303 | free(send); | ||
1304 | if (ret != AFC_E_SUCCESS) { | 1040 | if (ret != AFC_E_SUCCESS) { |
1305 | afc_unlock(client); | 1041 | afc_unlock(client); |
1306 | return AFC_E_NOT_ENOUGH_DATA; | 1042 | return AFC_E_NOT_ENOUGH_DATA; |
1307 | } | 1043 | } |
1308 | /* Receive response */ | 1044 | /* Receive response */ |
1309 | ret = afc_receive_data(client, &response, &bytes); | 1045 | ret = afc_receive_data(client, NULL, &bytes); |
1310 | if (response) | ||
1311 | free(response); | ||
1312 | 1046 | ||
1313 | afc_unlock(client); | 1047 | afc_unlock(client); |
1314 | 1048 | ||
1315 | return ret; | 1049 | return ret; |
1316 | } | 1050 | } |
1317 | 1051 | ||
1318 | /** | ||
1319 | * Sets the modification time of a file on the phone. | ||
1320 | * | ||
1321 | * @param client The client to use to set the file size. | ||
1322 | * @param path Path of the file for which the modification time should be set. | ||
1323 | * @param mtime The modification time to set in nanoseconds since epoch. | ||
1324 | * | ||
1325 | * @return AFC_E_SUCCESS on success or an AFC_E_* error value. | ||
1326 | */ | ||
1327 | afc_error_t afc_set_file_time(afc_client_t client, const char *path, uint64_t mtime) | 1052 | afc_error_t afc_set_file_time(afc_client_t client, const char *path, uint64_t mtime) |
1328 | { | 1053 | { |
1329 | char *response = NULL; | 1054 | if (!client || !path || !client->afc_packet || !client->parent) |
1330 | char *send = (char *) malloc(sizeof(char) * (strlen(path) + 1 + 8)); | 1055 | return AFC_E_INVALID_ARG; |
1056 | |||
1331 | uint32_t bytes = 0; | 1057 | uint32_t bytes = 0; |
1332 | uint64_t mtime_loc = GUINT64_TO_LE(mtime); | ||
1333 | afc_error_t ret = AFC_E_UNKNOWN_ERROR; | 1058 | afc_error_t ret = AFC_E_UNKNOWN_ERROR; |
1334 | 1059 | ||
1335 | if (!client || !path || !client->afc_packet || !client->connection) | 1060 | afc_lock(client); |
1061 | |||
1062 | uint32_t data_len = 8 + strlen(path) + 1; | ||
1063 | if (_afc_check_packet_buffer(client, data_len) < 0) { | ||
1064 | afc_unlock(client); | ||
1065 | debug_info("Failed to realloc packet buffer"); | ||
1066 | return AFC_E_NO_MEM; | ||
1067 | } | ||
1068 | |||
1069 | /* Send command */ | ||
1070 | *(uint64_t*)(AFC_PACKET_DATA_PTR) = htole64(mtime); | ||
1071 | memcpy(AFC_PACKET_DATA_PTR + 8, path, data_len-8); | ||
1072 | ret = afc_dispatch_packet(client, AFC_OP_SET_FILE_MOD_TIME, data_len, NULL, 0, &bytes); | ||
1073 | if (ret != AFC_E_SUCCESS) { | ||
1074 | afc_unlock(client); | ||
1075 | return AFC_E_NOT_ENOUGH_DATA; | ||
1076 | } | ||
1077 | /* Receive response */ | ||
1078 | ret = afc_receive_data(client, NULL, &bytes); | ||
1079 | |||
1080 | afc_unlock(client); | ||
1081 | |||
1082 | return ret; | ||
1083 | } | ||
1084 | |||
1085 | afc_error_t afc_remove_path_and_contents(afc_client_t client, const char *path) | ||
1086 | { | ||
1087 | uint32_t bytes = 0; | ||
1088 | afc_error_t ret = AFC_E_UNKNOWN_ERROR; | ||
1089 | |||
1090 | if (!client || !path || !client->afc_packet || !client->parent) | ||
1336 | return AFC_E_INVALID_ARG; | 1091 | return AFC_E_INVALID_ARG; |
1337 | 1092 | ||
1338 | afc_lock(client); | 1093 | afc_lock(client); |
1339 | 1094 | ||
1095 | uint32_t data_len = strlen(path) + 1; | ||
1096 | if (_afc_check_packet_buffer(client, data_len) < 0) { | ||
1097 | afc_unlock(client); | ||
1098 | debug_info("Failed to realloc packet buffer"); | ||
1099 | return AFC_E_NO_MEM; | ||
1100 | } | ||
1101 | |||
1340 | /* Send command */ | 1102 | /* Send command */ |
1341 | memcpy(send, &mtime_loc, 8); | 1103 | memcpy(AFC_PACKET_DATA_PTR, path, data_len); |
1342 | memcpy(send + 8, path, strlen(path) + 1); | 1104 | ret = afc_dispatch_packet(client, AFC_OP_REMOVE_PATH_AND_CONTENTS, data_len, NULL, 0, &bytes); |
1343 | client->afc_packet->entire_length = client->afc_packet->this_length = 0; | ||
1344 | client->afc_packet->operation = AFC_OP_SET_FILE_TIME; | ||
1345 | ret = afc_dispatch_packet(client, send, 8 + strlen(path) + 1, &bytes); | ||
1346 | free(send); | ||
1347 | if (ret != AFC_E_SUCCESS) { | 1105 | if (ret != AFC_E_SUCCESS) { |
1348 | afc_unlock(client); | 1106 | afc_unlock(client); |
1349 | return AFC_E_NOT_ENOUGH_DATA; | 1107 | return AFC_E_NOT_ENOUGH_DATA; |
1350 | } | 1108 | } |
1351 | /* Receive response */ | 1109 | /* Receive response */ |
1352 | ret = afc_receive_data(client, &response, &bytes); | 1110 | ret = afc_receive_data(client, NULL, &bytes); |
1353 | if (response) | ||
1354 | free(response); | ||
1355 | 1111 | ||
1356 | afc_unlock(client); | 1112 | afc_unlock(client); |
1357 | 1113 | ||
1358 | return ret; | 1114 | return ret; |
1359 | } | 1115 | } |
1360 | 1116 | ||
1117 | afc_error_t afc_dictionary_free(char **dictionary) | ||
1118 | { | ||
1119 | int i = 0; | ||
1120 | |||
1121 | if (!dictionary) | ||
1122 | return AFC_E_INVALID_ARG; | ||
1123 | |||
1124 | for (i = 0; dictionary[i]; i++) { | ||
1125 | free(dictionary[i]); | ||
1126 | } | ||
1127 | free(dictionary); | ||
1128 | |||
1129 | return AFC_E_SUCCESS; | ||
1130 | } | ||
1131 | |||
1132 | const char* afc_strerror(afc_error_t err) | ||
1133 | { | ||
1134 | switch (err) { | ||
1135 | case AFC_E_SUCCESS: | ||
1136 | return "Success"; | ||
1137 | case AFC_E_UNKNOWN_ERROR: | ||
1138 | return "Unknown Error"; | ||
1139 | case AFC_E_OP_HEADER_INVALID: | ||
1140 | return "Operation header invalid"; | ||
1141 | case AFC_E_NO_RESOURCES: | ||
1142 | return "No resources"; | ||
1143 | case AFC_E_READ_ERROR: | ||
1144 | return "Read error"; | ||
1145 | case AFC_E_WRITE_ERROR: | ||
1146 | return "Write error"; | ||
1147 | case AFC_E_UNKNOWN_PACKET_TYPE: | ||
1148 | return "Unknown packet type"; | ||
1149 | case AFC_E_INVALID_ARG: | ||
1150 | return "Invalid argument"; | ||
1151 | case AFC_E_OBJECT_NOT_FOUND: | ||
1152 | return "Not found"; | ||
1153 | case AFC_E_OBJECT_IS_DIR: | ||
1154 | return "Object is a directory"; | ||
1155 | case AFC_E_PERM_DENIED: | ||
1156 | return "Permission denied"; | ||
1157 | case AFC_E_SERVICE_NOT_CONNECTED: | ||
1158 | return "Service not connected"; | ||
1159 | case AFC_E_OP_TIMEOUT: | ||
1160 | return "Timeout"; | ||
1161 | case AFC_E_TOO_MUCH_DATA: | ||
1162 | return "Too much data"; | ||
1163 | case AFC_E_END_OF_DATA: | ||
1164 | return "End of data"; | ||
1165 | case AFC_E_OP_NOT_SUPPORTED: | ||
1166 | return "Operation not supported"; | ||
1167 | case AFC_E_OBJECT_EXISTS: | ||
1168 | return "Object exists"; | ||
1169 | case AFC_E_OBJECT_BUSY: | ||
1170 | return "Object busy"; | ||
1171 | case AFC_E_NO_SPACE_LEFT: | ||
1172 | return "No space left on device"; | ||
1173 | case AFC_E_OP_WOULD_BLOCK: | ||
1174 | return "Operation would block"; | ||
1175 | case AFC_E_IO_ERROR: | ||
1176 | return "I/O error"; | ||
1177 | case AFC_E_OP_INTERRUPTED: | ||
1178 | return "Operation interrupted"; | ||
1179 | case AFC_E_OP_IN_PROGRESS: | ||
1180 | return "Operation on progress"; | ||
1181 | case AFC_E_INTERNAL_ERROR: | ||
1182 | return "Internal error"; | ||
1183 | case AFC_E_MUX_ERROR: | ||
1184 | return "MUX error"; | ||
1185 | case AFC_E_NO_MEM: | ||
1186 | return "Out of memory"; | ||
1187 | case AFC_E_NOT_ENOUGH_DATA: | ||
1188 | return "Not enough data"; | ||
1189 | case AFC_E_DIR_NOT_EMPTY: | ||
1190 | return "Directory not empty"; | ||
1191 | case AFC_E_FORCE_SIGNED_TYPE: | ||
1192 | return "Force signed type"; | ||
1193 | default: | ||
1194 | break; | ||
1195 | } | ||
1196 | return "Unknown Error"; | ||
1197 | } | ||