648f18794c9e17a4fc2940364f52927fe954f2d7
[openocd.git] / src / helper / fileio.c
1 /***************************************************************************
2 * Copyright (C) 2007 by Dominic Rath *
3 * Dominic.Rath@gmx.de *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include "types.h"
25 #include "replacements.h"
26 #include "log.h"
27
28 #include "fileio.h"
29
30 #include <stdio.h>
31 #include <string.h>
32 #include <unistd.h>
33 #include <stdlib.h>
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <errno.h>
37 #include <ctype.h>
38
39 int fileio_close(fileio_t *fileio);
40 int fileio_dispatch_read(fileio_t *fileio, u32 size, u8 *buffer, u32 *size_read);
41
42 int fileio_open_local(fileio_t *fileio)
43 {
44 fileio_local_t *fileio_local = malloc(sizeof(fileio_local_t));
45 char access[4];
46
47 fileio->location_private = fileio_local;
48
49 if ((fileio->access != FILEIO_WRITE) && (fileio->access != FILEIO_READWRITE))
50 {
51 if (stat(fileio->url, &fileio_local->file_stat) == -1)
52 {
53 free(fileio_local);
54 snprintf(fileio->error_str, FILEIO_MAX_ERROR_STRING,
55 "couldn't stat() %s: %s", fileio->url, strerror(errno));
56 return ERROR_FILEIO_NOT_FOUND;
57 }
58
59 if (S_ISDIR(fileio_local->file_stat.st_mode))
60 {
61 free(fileio_local);
62 snprintf(fileio->error_str, FILEIO_MAX_ERROR_STRING, "%s is a directory", fileio->url);
63 return ERROR_FILEIO_NOT_FOUND;
64 }
65 }
66
67 switch (fileio->access)
68 {
69 case FILEIO_READ:
70 strcpy(access, "r");
71 break;
72 case FILEIO_WRITE:
73 strcpy(access, "w");
74 break;
75 case FILEIO_READWRITE:
76 strcpy(access, "w+");
77 break;
78 case FILEIO_APPEND:
79 strcpy(access, "a");
80 break;
81 case FILEIO_APPENDREAD:
82 strcpy(access, "a+");
83 break;
84 default:
85 free(fileio_local);
86 ERROR("BUG: access neither read, write nor readwrite");
87 return ERROR_INVALID_ARGUMENTS;
88 }
89
90 if (fileio->access == FILEIO_READ)
91 {
92 if (fileio_local->file_stat.st_size == 0)
93 {
94 /* tried to open an empty file for reading */
95 free(fileio_local);
96 snprintf(fileio->error_str, FILEIO_MAX_ERROR_STRING, "empty file %s", fileio->url);
97 return ERROR_FILEIO_OPERATION_FAILED;
98 }
99 }
100
101 if (fileio->pri_type == FILEIO_IMAGE)
102 strcat(access, "b");
103
104 if (!(fileio_local->file = fopen(fileio->url, access)))
105 {
106 free(fileio_local);
107 snprintf(fileio->error_str, FILEIO_MAX_ERROR_STRING, "couldn't open %s", fileio->url);
108 return ERROR_FILEIO_OPERATION_FAILED;
109 }
110
111 if ((fileio->access != FILEIO_WRITE) || (fileio->access == FILEIO_READWRITE))
112 {
113 fileio->size = fileio_local->file_stat.st_size;
114 }
115 else
116 {
117 fileio->size = 0x0;
118 }
119
120 return ERROR_OK;
121 }
122
123 //#ifdef FILEIO_BUFFER_COMPLETE_IHEX
124 int fileio_ihex_buffer_complete(fileio_t *fileio)
125 {
126 fileio_image_t *image = fileio->pri_type_private;
127 fileio_ihex_t *ihex = fileio->sec_type_private;
128 u32 raw_bytes_read, raw_bytes;
129 int retval;
130 u32 full_address = image->base_address;
131 char *buffer = malloc(ihex->raw_size);
132 u32 cooked_bytes = 0x0;
133
134 ihex->raw_size = fileio->size;
135 ihex->buffer = malloc(ihex->raw_size >> 1);
136
137 if ((retval = fileio_dispatch_read(fileio, ihex->raw_size, (u8*)buffer, &raw_bytes_read)) != ERROR_OK)
138 {
139 free(buffer);
140 ERROR("failed buffering IHEX file, read failed");
141 return ERROR_FILEIO_OPERATION_FAILED;
142 }
143
144 if (raw_bytes_read != ihex->raw_size)
145 {
146 free(buffer);
147 ERROR("failed buffering complete IHEX file, only partially read");
148 return ERROR_FILEIO_OPERATION_FAILED;
149 }
150
151 raw_bytes = 0x0;
152 while (raw_bytes < raw_bytes_read)
153 {
154 u32 count;
155 u32 address;
156 u32 record_type;
157 u32 checksum;
158
159 if (sscanf(&buffer[raw_bytes], ":%2x%4x%2x", &count, &address, &record_type) != 3)
160 {
161 snprintf(fileio->error_str, FILEIO_MAX_ERROR_STRING, "invalid IHEX record");
162 return ERROR_FILEIO_OPERATION_FAILED;
163 }
164 raw_bytes += 9;
165
166 if (record_type == 0)
167 {
168 if ((full_address & 0xffff) != address)
169 {
170 free(buffer);
171 ERROR("can't handle non-linear IHEX file");
172 snprintf(fileio->error_str, FILEIO_MAX_ERROR_STRING, "can't handle non-linear IHEX file");
173 return ERROR_FILEIO_OPERATION_FAILED;
174 }
175
176 while (count-- > 0)
177 {
178 sscanf(&buffer[raw_bytes], "%2hhx", &ihex->buffer[cooked_bytes]);
179 raw_bytes += 2;
180 cooked_bytes += 1;
181 full_address++;
182 }
183 }
184 else if (record_type == 1)
185 {
186 free(buffer);
187 fileio->size = cooked_bytes;
188 return ERROR_OK;
189 }
190 else if (record_type == 4)
191 {
192 u16 upper_address;
193
194 sscanf(&buffer[raw_bytes], "%4hx", &upper_address);
195 raw_bytes += 4;
196
197 if ((full_address >> 16) != upper_address)
198 {
199 free(buffer);
200 ERROR("can't handle non-linear IHEX file");
201 snprintf(fileio->error_str, FILEIO_MAX_ERROR_STRING, "can't handle non-linear IHEX file");
202 return ERROR_FILEIO_OPERATION_FAILED;
203 }
204 }
205 else if (record_type == 5)
206 {
207 u32 start_address;
208
209 sscanf(&buffer[raw_bytes], "%8x", &start_address);
210 raw_bytes += 8;
211
212 image->has_start_address = 1;
213 image->start_address = be_to_h_u32((u8*)&start_address);
214 }
215 else
216 {
217 free(buffer);
218 ERROR("unhandled IHEX record type: %i", record_type);
219 snprintf(fileio->error_str, FILEIO_MAX_ERROR_STRING, "unhandled IHEX record type: %i", record_type);
220 return ERROR_FILEIO_OPERATION_FAILED;
221 }
222
223 sscanf(&buffer[raw_bytes], "%2x", &checksum);
224 raw_bytes += 2;
225
226 /* consume new-line character(s) */
227 if ((buffer[raw_bytes] == '\n') || (buffer[raw_bytes] == '\r'))
228 raw_bytes++;
229
230 if ((buffer[raw_bytes] == '\n') || (buffer[raw_bytes] == '\r'))
231 raw_bytes++;
232 }
233
234 free(buffer);
235 ERROR("premature end of IHEX file, no end-of-file record found");
236 snprintf(fileio->error_str, FILEIO_MAX_ERROR_STRING, "premature end of IHEX file, no end-of-file record found");
237 return ERROR_FILEIO_OPERATION_FAILED;
238 }
239 //#endif
240
241 int fileio_open(fileio_t *fileio, char *url, enum fileio_access access,
242 enum fileio_pri_type pri_type, void *pri_info, enum fileio_sec_type sec_type)
243 {
244 int retval = ERROR_OK;
245 char *resource_identifier = NULL;
246
247 /* try to identify file location */
248 if ((resource_identifier = strstr(url, "bootp://")) && (resource_identifier == url))
249 {
250 ERROR("bootp resource location isn't supported yet");
251 return ERROR_FILEIO_RESOURCE_TYPE_UNKNOWN;
252 }
253 else if ((resource_identifier = strstr(url, "tftp://")) && (resource_identifier == url))
254 {
255 ERROR("tftp resource location isn't supported yet");
256 return ERROR_FILEIO_RESOURCE_TYPE_UNKNOWN;
257 }
258 else
259 {
260 /* default to local files */
261 fileio->location = FILEIO_LOCAL;
262 }
263
264 fileio->access = access;
265 fileio->pri_type = pri_type;
266 fileio->sec_type = sec_type;
267 fileio->url = strdup(url);
268
269 switch (fileio->location)
270 {
271 case FILEIO_LOCAL:
272 retval = fileio_open_local(fileio);
273 break;
274 default:
275 ERROR("BUG: should never get here");
276 exit(-1);
277 }
278
279 if (retval != ERROR_OK)
280 return retval;
281
282 if (fileio->pri_type == FILEIO_TEXT)
283 {
284 /* do nothing for now */
285 return ERROR_OK;
286 }
287 else if (fileio->pri_type == FILEIO_IMAGE)
288 {
289 fileio_image_t *image = malloc(sizeof(fileio_image_t));
290 fileio_image_t *image_info = pri_info;
291
292 fileio->pri_type_private = image;
293 *image = *image_info;
294
295 if (fileio->sec_type == FILEIO_PLAIN)
296 {
297 fileio->sec_type_private = NULL;
298 }
299 else if (fileio->sec_type == FILEIO_IHEX)
300 {
301 fileio_ihex_t *fileio_ihex;
302
303 if (fileio->access != FILEIO_READ)
304 {
305 ERROR("can't write/append to a IHEX file");
306 snprintf(fileio->error_str, FILEIO_MAX_ERROR_STRING, "can't write/append to a IHEX file");
307 fileio_close(fileio);
308 return ERROR_FILEIO_OPERATION_FAILED;
309 }
310
311 fileio_ihex = malloc(sizeof(fileio_ihex_t));
312 fileio->sec_type_private = fileio_ihex;
313
314 fileio_ihex->position = 0;
315 fileio_ihex->raw_size = fileio->size;
316 #ifdef FILEIO_BUFFER_COMPLETE_IHEX
317 if (fileio_ihex_buffer_complete(fileio) != ERROR_OK)
318 {
319 fileio_close(fileio);
320 return ERROR_FILEIO_OPERATION_FAILED;
321 }
322 #endif
323 }
324 }
325
326 return ERROR_OK;
327 }
328
329 int fileio_close_local(fileio_t *fileio)
330 {
331 int retval;
332 fileio_local_t *fileio_local = fileio->location_private;
333
334 if ((retval = fclose(fileio_local->file)) != 0)
335 {
336 if (retval == EBADF)
337 {
338 snprintf(fileio->error_str, FILEIO_MAX_ERROR_STRING, "BUG: fileio_local->file not a valid file descriptor");
339 }
340 else
341 {
342 snprintf(fileio->error_str, FILEIO_MAX_ERROR_STRING, "couldn't close %s: %s", fileio->url, strerror(errno));
343 }
344
345 return ERROR_FILEIO_OPERATION_FAILED;
346 }
347
348 free(fileio->location_private);
349
350 return ERROR_OK;
351 }
352
353 int fileio_close(fileio_t *fileio)
354 {
355 int retval;
356
357 switch (fileio->location)
358 {
359 case FILEIO_LOCAL:
360 retval = fileio_close_local(fileio);
361 break;
362 default:
363 ERROR("BUG: should never get here");
364 retval = ERROR_FILEIO_OPERATION_FAILED;
365 }
366
367 if (retval != ERROR_OK)
368 return retval;
369
370 free(fileio->url);
371
372 if (fileio->pri_type == FILEIO_TEXT)
373 {
374 /* do nothing for now */
375 }
376 else if (fileio->pri_type == FILEIO_IMAGE)
377 {
378 if (fileio->sec_type == FILEIO_PLAIN)
379 {
380 /* nothing special to do for plain binary */
381 }
382 else if (fileio->sec_type == FILEIO_IHEX)
383 {
384 fileio_ihex_t *fileio_ihex = fileio->sec_type_private;
385
386 if (fileio_ihex->buffer)
387 free(fileio_ihex->buffer);
388
389 free(fileio->sec_type_private);
390 }
391
392 free(fileio->pri_type_private);
393 }
394
395 return ERROR_OK;
396 }
397
398 int fileio_seek_local(fileio_t *fileio, u32 position)
399 {
400 int retval;
401 fileio_local_t *fileio_local = fileio->location_private;
402
403 if ((retval = fseek(fileio_local->file, position, SEEK_SET)) != 0)
404 {
405 snprintf(fileio->error_str, FILEIO_MAX_ERROR_STRING, "couldn't seek file %s: %s", fileio->url, strerror(errno));
406 return ERROR_FILEIO_OPERATION_FAILED;
407 }
408
409 return ERROR_OK;
410 }
411
412 int fileio_seek(fileio_t *fileio, u32 position)
413 {
414 switch (fileio->location)
415 {
416 case FILEIO_LOCAL:
417 return fileio_seek_local(fileio, position);
418 break;
419 default:
420 ERROR("BUG: should never get here");
421 }
422
423 return ERROR_OK;
424 }
425
426 int fileio_local_read(fileio_t *fileio, u32 size, u8 *buffer, u32 *size_read)
427 {
428 fileio_local_t *fileio_local = fileio->location_private;
429
430 *size_read = fread(buffer, 1, size, fileio_local->file);
431
432 return ERROR_OK;
433 }
434
435 int fileio_dispatch_read(fileio_t *fileio, u32 size, u8 *buffer, u32 *size_read)
436 {
437 switch (fileio->location)
438 {
439 case FILEIO_LOCAL:
440 return fileio_local_read(fileio, size, buffer, size_read);
441 break;
442 default:
443 ERROR("BUG: should never get here");
444 exit(-1);
445 }
446 }
447
448 int fileio_read_ihex(fileio_t *fileio, u32 size, u8 *buffer, u32 *size_read)
449 {
450 fileio_ihex_t *fileio_ihex = fileio->sec_type_private;
451
452 if ((fileio_ihex->position + size) > fileio->size)
453 {
454 /* don't read past the end of the file */
455 size = (fileio->size - fileio_ihex->position);
456 }
457
458 #ifdef FILEIO_BUFFER_COMPLETE_IHEX
459 memcpy(buffer, fileio_ihex->buffer + fileio_ihex->position, size);
460 *size_read = size;
461 #endif
462
463 return ERROR_OK;
464 }
465
466 int fileio_read(fileio_t *fileio, u32 size, u8 *buffer, u32 *size_read)
467 {
468 if (fileio->sec_type == FILEIO_PLAIN)
469 {
470 return fileio_dispatch_read(fileio, size, buffer, size_read);
471 }
472 else if (fileio->sec_type == FILEIO_IHEX)
473 {
474 return fileio_read_ihex(fileio, size, buffer, size_read);
475 }
476
477 return ERROR_OK;
478 }
479
480 int fileio_local_write(fileio_t *fileio, u32 size, u8 *buffer, u32 *size_written)
481 {
482 fileio_local_t *fileio_local = fileio->location_private;
483
484 *size_written = fwrite(buffer, 1, size, fileio_local->file);
485
486 return ERROR_OK;
487 }
488
489 int fileio_dispatch_write(fileio_t *fileio, u32 size, u8 *buffer, u32 *size_written)
490 {
491 switch (fileio->location)
492 {
493 case FILEIO_LOCAL:
494 return fileio_local_write(fileio, size, buffer, size_written);
495 break;
496 default:
497 ERROR("BUG: should never get here");
498 }
499
500 return ERROR_OK;
501 }
502
503 int fileio_write(fileio_t *fileio, u32 size, u8 *buffer, u32 *size_written)
504 {
505 int retval = ERROR_FILEIO_OPERATION_NOT_SUPPORTED;
506 if (fileio->sec_type == FILEIO_PLAIN)
507 {
508 retval = fileio_dispatch_write(fileio, size, buffer, size_written);
509 }
510 else if (fileio->sec_type == FILEIO_IHEX)
511 {
512 return ERROR_FILEIO_OPERATION_NOT_SUPPORTED;
513 }
514
515 if (retval != ERROR_OK)
516 return retval;
517
518 fileio->size += size;
519
520 return ERROR_OK;
521 }
522
523 int fileio_identify_image_type(enum fileio_sec_type *sec_type, char *type_string)
524 {
525 if (type_string)
526 {
527 if (!strcmp(type_string, "bin"))
528 {
529 *sec_type = FILEIO_PLAIN;
530 }
531 else if (!strcmp(type_string, "ihex"))
532 {
533 *sec_type = FILEIO_IHEX;
534 }
535 else
536 {
537 return ERROR_FILEIO_RESOURCE_TYPE_UNKNOWN;
538 }
539 }
540 else
541 {
542 *sec_type = FILEIO_PLAIN;
543 }
544
545 return ERROR_OK;
546 }