fix a possible segfault upon invalid selection.
[Rockbox.git] / rbutil / sansapatcher / sansapatcher.c
blob6b4b80896c7f58ea1faa1c139d1a98c1dd596dd8
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2006-2007 Dave Chapman
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
20 #include <stdio.h>
21 #include <unistd.h>
22 #include <fcntl.h>
23 #include <string.h>
24 #include <stdlib.h>
25 #include <inttypes.h>
26 #include <sys/types.h>
27 #include <sys/stat.h>
29 #include "sansaio.h"
30 #include "sansapatcher.h"
32 #ifndef RBUTIL
33 #include "bootimg.h"
34 #endif
35 /* The offset of the MI4 image header in the firmware partition */
36 #define PPMI_OFFSET 0x80000
38 extern int verbose;
40 /* Windows requires the buffer for disk I/O to be aligned in memory on a
41 multiple of the disk volume size - so we use a single global variable
42 and initialise it with sansa_alloc_buf() in main().
45 extern unsigned char* sectorbuf;
47 static off_t filesize(int fd) {
48 struct stat buf;
50 if (fstat(fd,&buf) < 0) {
51 perror("[ERR] Checking filesize of input file");
52 return -1;
53 } else {
54 return(buf.st_size);
58 /* Partition table parsing code taken from Rockbox */
60 #define MAX_SECTOR_SIZE 2048
61 #define SECTOR_SIZE 512
63 static inline int32_t le2int(unsigned char* buf)
65 int32_t res = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
67 return res;
70 static inline uint32_t le2uint(unsigned char* buf)
72 uint32_t res = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
74 return res;
77 static inline void int2le(unsigned int val, unsigned char* addr)
79 addr[0] = val & 0xFF;
80 addr[1] = (val >> 8) & 0xff;
81 addr[2] = (val >> 16) & 0xff;
82 addr[3] = (val >> 24) & 0xff;
85 #define BYTES2INT32(array,pos)\
86 ((long)array[pos] | ((long)array[pos+1] << 8 ) |\
87 ((long)array[pos+2] << 16 ) | ((long)array[pos+3] << 24 ))
89 int sansa_read_partinfo(struct sansa_t* sansa, int silent)
91 int i;
92 unsigned long count;
94 count = sansa_read(sansa,sectorbuf, sansa->sector_size);
96 if (count <= 0) {
97 print_error(" Error reading from disk: ");
98 return -1;
101 if ((sectorbuf[510] == 0x55) && (sectorbuf[511] == 0xaa)) {
102 /* parse partitions */
103 for ( i = 0; i < 4; i++ ) {
104 unsigned char* ptr = sectorbuf + 0x1be + 16*i;
105 sansa->pinfo[i].type = ptr[4];
106 sansa->pinfo[i].start = BYTES2INT32(ptr, 8);
107 sansa->pinfo[i].size = BYTES2INT32(ptr, 12);
109 /* extended? */
110 if ( sansa->pinfo[i].type == 5 ) {
111 /* not handled yet */
114 } else if ((sectorbuf[0] == 'E') && (sectorbuf[1] == 'R')) {
115 if (!silent) fprintf(stderr,"[ERR] Bad boot sector signature\n");
116 return -1;
119 /* Calculate the starting position of the firmware partition */
120 sansa->start = (loff_t)sansa->pinfo[1].start*(loff_t)sansa->sector_size;
121 return 0;
126 * CRC32 implementation taken from:
128 * efone - Distributed internet phone system.
130 * (c) 1999,2000 Krzysztof Dabrowski
131 * (c) 1999,2000 ElysiuM deeZine
133 * This program is free software; you can redistribute it and/or
134 * modify it under the terms of the GNU General Public License
135 * as published by the Free Software Foundation; either version
136 * 2 of the License, or (at your option) any later version.
140 /* crc_tab[] -- this crcTable is being build by chksum_crc32GenTab().
141 * so make sure, you call it before using the other
142 * functions!
144 static unsigned int crc_tab[256];
146 /* chksum_crc() -- to a given block, this one calculates the
147 * crc32-checksum until the length is
148 * reached. the crc32-checksum will be
149 * the result.
151 static unsigned int chksum_crc32 (unsigned char *block, unsigned int length)
153 register unsigned long crc;
154 unsigned long i;
156 crc = 0;
157 for (i = 0; i < length; i++)
159 crc = ((crc >> 8) & 0x00FFFFFF) ^ crc_tab[(crc ^ *block++) & 0xFF];
161 return (crc);
164 /* chksum_crc32gentab() -- to a global crc_tab[256], this one will
165 * calculate the crcTable for crc32-checksums.
166 * it is generated to the polynom [..]
169 static void chksum_crc32gentab (void)
171 unsigned long crc, poly;
172 int i, j;
174 poly = 0xEDB88320L;
175 for (i = 0; i < 256; i++)
177 crc = i;
178 for (j = 8; j > 0; j--)
180 if (crc & 1)
182 crc = (crc >> 1) ^ poly;
184 else
186 crc >>= 1;
189 crc_tab[i] = crc;
193 /* Known keys for Sansa E200 firmwares: */
194 #define NUM_KEYS 2
195 static uint32_t keys[][4] = {
196 { 0xe494e96e, 0x3ee32966, 0x6f48512b, 0xa93fbb42 }, /* "sansa" */
197 { 0xd7b10538, 0xc662945b, 0x1b3fce68, 0xf389c0e6 }, /* "sansa_gh" */
202 tea_decrypt() from http://en.wikipedia.org/wiki/Tiny_Encryption_Algorithm
204 "Following is an adaptation of the reference encryption and decryption
205 routines in C, released into the public domain by David Wheeler and
206 Roger Needham:"
210 /* NOTE: The mi4 version of TEA uses a different initial value to sum compared
211 to the reference implementation and the main loop is 8 iterations, not
215 void tea_decrypt(uint32_t* v0, uint32_t* v1, uint32_t* k) {
216 uint32_t sum=0xF1BBCDC8, i; /* set up */
217 uint32_t delta=0x9E3779B9; /* a key schedule constant */
218 uint32_t k0=k[0], k1=k[1], k2=k[2], k3=k[3]; /* cache key */
219 for(i=0; i<8; i++) { /* basic cycle start */
220 *v1 -= ((*v0<<4) + k2) ^ (*v0 + sum) ^ ((*v0>>5) + k3);
221 *v0 -= ((*v1<<4) + k0) ^ (*v1 + sum) ^ ((*v1>>5) + k1);
222 sum -= delta; /* end cycle */
226 /* mi4 files are encrypted in 64-bit blocks (two little-endian 32-bit
227 integers) and the key is incremented after each block
230 void tea_decrypt_buf(unsigned char* src, unsigned char* dest, size_t n, uint32_t * key)
232 uint32_t v0, v1;
233 unsigned int i;
235 for (i = 0; i < (n / 8); i++) {
236 v0 = le2int(src);
237 v1 = le2int(src+4);
239 tea_decrypt(&v0, &v1, key);
241 int2le(v0, dest);
242 int2le(v1, dest+4);
244 src += 8;
245 dest += 8;
247 /* Now increment the key */
248 key[0]++;
249 if (key[0]==0) {
250 key[1]++;
251 if (key[1]==0) {
252 key[2]++;
253 if (key[2]==0) {
254 key[3]++;
261 static int get_mi4header(unsigned char* buf,struct mi4header_t* mi4header)
263 if (memcmp(buf,"PPOS",4)!=0)
264 return -1;
266 mi4header->version = le2int(buf+0x04);
267 mi4header->length = le2int(buf+0x08);
268 mi4header->crc32 = le2int(buf+0x0c);
269 mi4header->enctype = le2int(buf+0x10);
270 mi4header->mi4size = le2int(buf+0x14);
271 mi4header->plaintext = le2int(buf+0x18);
273 return 0;
276 static int set_mi4header(unsigned char* buf,struct mi4header_t* mi4header)
278 if (memcmp(buf,"PPOS",4)!=0)
279 return -1;
281 int2le(mi4header->version ,buf+0x04);
282 int2le(mi4header->length ,buf+0x08);
283 int2le(mi4header->crc32 ,buf+0x0c);
284 int2le(mi4header->enctype ,buf+0x10);
285 int2le(mi4header->mi4size ,buf+0x14);
286 int2le(mi4header->plaintext ,buf+0x18);
288 /* Add a dummy DSA signature */
289 memset(buf+0x1c,0,40);
290 buf[0x2f] = 1;
292 return 0;
295 static int sansa_seek_and_read(struct sansa_t* sansa, loff_t pos, unsigned char* buf, int nbytes)
297 int n;
299 if (sansa_seek(sansa, pos) < 0) {
300 return -1;
303 if ((n = sansa_read(sansa,buf,nbytes)) < 0) {
304 return -1;
307 if (n < nbytes) {
308 fprintf(stderr,"[ERR] Short read - requested %d bytes, received %d\n",
309 nbytes,n);
310 return -1;
313 return 0;
317 /* We identify an E200 based on the following criteria:
319 1) Exactly two partitions;
320 2) First partition is type "W95 FAT32" (0x0b);
321 3) Second partition is type "OS/2 hidden C: drive" (0x84);
322 4) The "PPBL" string appears at offset 0 in the 2nd partition;
323 5) The "PPMI" string appears at offset PPMI_OFFSET in the 2nd partition.
326 int is_e200(struct sansa_t* sansa)
328 struct mi4header_t mi4header;
329 int ppmi_length;
331 /* Check partition layout */
333 if ((sansa->pinfo[0].type != 0x0b) || (sansa->pinfo[1].type != 0x84) ||
334 (sansa->pinfo[2].type != 0x00) || (sansa->pinfo[3].type != 0x00)) {
335 /* Bad partition layout, abort */
336 return -1;
339 /* Check Bootloader header */
340 if (sansa_seek_and_read(sansa, sansa->start, sectorbuf, 0x200) < 0) {
341 return -2;
343 if (memcmp(sectorbuf,"PPBL",4)!=0) {
344 /* No bootloader header, abort */
345 return -4;
348 /* Check Main firmware header */
349 if (sansa_seek_and_read(sansa, sansa->start+PPMI_OFFSET, sectorbuf, 0x200) < 0) {
350 fprintf(stderr,"[ERR] Seek to 0x%08llx in is_e200 failed.\n",
351 sansa->start+PPMI_OFFSET);
352 return -5;
354 if (memcmp(sectorbuf,"PPMI",4)!=0) {
355 /* No bootloader header, abort */
356 return -7;
358 ppmi_length = le2int(sectorbuf+4);
360 /* Check main mi4 file header */
361 if (sansa_seek_and_read(sansa, sansa->start+PPMI_OFFSET+0x200, sectorbuf, 0x200) < 0) {
362 fprintf(stderr,"[ERR] Seek to 0x%08llx in is_e200 failed.\n",
363 sansa->start+PPMI_OFFSET+0x200);
364 return -5;
367 if (get_mi4header(sectorbuf,&mi4header) < 0) {
368 fprintf(stderr,"[ERR] Invalid mi4header\n");
369 return -6;
372 /* Some sanity checks:
374 1) Main MI4 image without RBBL and < 100000 bytes -> old install
375 2) Main MI4 image with RBBL but no second image -> old install
378 sansa->hasoldbootloader = 0;
379 if (memcmp(sectorbuf+0x1f8,"RBBL",4)==0) {
380 /* Look for an original firmware after the first image */
381 if (sansa_seek_and_read(sansa,
382 sansa->start + PPMI_OFFSET + 0x200 + ppmi_length,
383 sectorbuf, 512) < 0) {
384 return -7;
387 if (get_mi4header(sectorbuf,&mi4header)!=0) {
388 fprintf(stderr,"[ERR] No original firmware found\n");
389 sansa->hasoldbootloader = 1;
391 } else if (mi4header.mi4size < 100000) {
392 fprintf(stderr,"[ERR] Old bootloader found\n");
393 sansa->hasoldbootloader = 1;
396 return 0;
399 int sansa_scan(struct sansa_t* sansa)
401 int i;
402 int n = 0;
403 char last_disk[4096];
405 printf("[INFO] Scanning disk devices...\n");
407 for (i = 0; i <= 25 ; i++) {
408 #ifdef __WIN32__
409 sprintf(sansa->diskname,"\\\\.\\PhysicalDrive%d",i);
410 #elif defined(linux) || defined (__linux)
411 sprintf(sansa->diskname,"/dev/sd%c",'a'+i);
412 #elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) \
413 || defined(__bsdi__) || defined(__DragonFly__)
414 sprintf(sansa->diskname,"/dev/da%d",i);
415 #elif defined(__APPLE__) && defined(__MACH__)
416 sprintf(sansa->diskname,"/dev/disk%d",i);
417 #else
418 #error No disk paths defined for this platform
419 #endif
420 if (sansa_open(sansa, 1) < 0) {
421 continue;
424 if (sansa_read_partinfo(sansa,1) < 0) {
425 continue;
428 if (is_e200(sansa) < 0) {
429 continue;
432 #ifdef __WIN32__
433 printf("[INFO] E200 found - disk device %d\n",i);
434 #else
435 printf("[INFO] E200 found - %s\n",sansa->diskname);
436 #endif
437 n++;
438 strcpy(last_disk,sansa->diskname);
439 sansa_close(sansa);
442 if (n==1) {
443 /* Remember the disk name */
444 strcpy(sansa->diskname,last_disk);
446 return n;
449 /* Prepare original firmware for writing to the firmware partition by decrypting
450 and updating the header */
451 static int prepare_original_firmware(unsigned char* buf, struct mi4header_t* mi4header)
453 unsigned char* tmpbuf;
454 int i;
455 int key_found;
457 get_mi4header(buf,mi4header);
459 #if 0
460 printf("mi4header->version =0x%08x\n",mi4header->version);
461 printf("mi4header->length =0x%08x\n",mi4header->length);
462 printf("mi4header->crc32 =0x%08x\n",mi4header->crc32);
463 printf("mi4header->enctype =0x%08x\n",mi4header->enctype);
464 printf("mi4header->mi4size =0x%08x\n",mi4header->mi4size);
465 printf("mi4header->plaintext =0x%08x\n",mi4header->plaintext);
466 #endif
468 /* Decrypt anything that needs decrypting. */
469 if (mi4header->plaintext < mi4header->mi4size - 0x200) {
470 /* TODO: Check different keys */
471 tmpbuf=malloc(mi4header->mi4size-(mi4header->plaintext+0x200));
472 if (tmpbuf==NULL) {
473 fprintf(stderr,"[ERR] Can not allocate memory\n");
474 return -1;
477 key_found=0;
478 for (i=0; i < NUM_KEYS && !key_found ; i++) {
479 tea_decrypt_buf(buf+(mi4header->plaintext+0x200),
480 tmpbuf,
481 mi4header->mi4size-(mi4header->plaintext+0x200),
482 keys[i]);
483 key_found = (le2uint(tmpbuf+mi4header->length-mi4header->plaintext-4) == 0xaa55aa55);
486 if (key_found) {
487 memcpy(buf+(mi4header->plaintext+0x200),tmpbuf,mi4header->mi4size-(mi4header->plaintext+0x200));
488 free(tmpbuf);
489 } else {
490 fprintf(stderr,"[ERR] Failed to decrypt image, aborting\n");
491 free(tmpbuf);
492 return -1;
496 /* Increase plaintext value to full file */
497 mi4header->plaintext = mi4header->mi4size - 0x200;
499 /* Update CRC checksum */
500 chksum_crc32gentab ();
501 mi4header->crc32 = chksum_crc32(buf+0x200,mi4header->mi4size-0x200);
503 set_mi4header(buf,mi4header);
505 /* Add Rockbox-specific header */
506 memcpy(buf+0x1f8,"RBOFe200",8);
508 return 0;
511 static int load_original_firmware(struct sansa_t* sansa, unsigned char* buf, struct mi4header_t* mi4header)
513 int ppmi_length;
514 int n;
516 /* Read 512 bytes from PPMI_OFFSET - the PPMI header plus the mi4 header */
517 if (sansa_seek_and_read(sansa, sansa->start + PPMI_OFFSET, buf, 512) < 0) {
518 return -1;
521 /* No need to check PPMI magic - it's done during init to confirm
522 this is an E200 */
523 ppmi_length = le2int(buf+4);
525 /* Firstly look for an original firmware after the first image */
526 if (sansa_seek_and_read(sansa, sansa->start + PPMI_OFFSET + 0x200 + ppmi_length, buf, 512) < 0) {
527 return -1;
530 if (get_mi4header(buf,mi4header)==0) {
531 /* We have a valid MI4 file after a bootloader, so we use this. */
532 if ((n = sansa_seek_and_read(sansa,
533 sansa->start + PPMI_OFFSET + 0x200 + ppmi_length,
534 buf, mi4header->mi4size)) < 0) {
535 return -1;
537 } else {
538 /* No valid MI4 file, so read the first image. */
539 if ((n = sansa_seek_and_read(sansa,
540 sansa->start + PPMI_OFFSET + 0x200,
541 buf, ppmi_length)) < 0) {
542 return -1;
545 return prepare_original_firmware(buf, mi4header);
548 int sansa_read_firmware(struct sansa_t* sansa, char* filename)
550 int res;
551 int outfile;
552 struct mi4header_t mi4header;
554 res = load_original_firmware(sansa,sectorbuf,&mi4header);
555 if (res < 0)
556 return res;
558 outfile = open(filename,O_CREAT|O_TRUNC|O_WRONLY|O_BINARY,0666);
559 if (outfile < 0) {
560 fprintf(stderr,"[ERR] Couldn't open file %s\n",filename);
561 return -1;
564 res = write(outfile,sectorbuf,mi4header.mi4size);
565 if (res != (int)mi4header.mi4size) {
566 fprintf(stderr,"[ERR] Write error - %d\n", res);
567 return -1;
569 close(outfile);
571 return 0;
575 int sansa_add_bootloader(struct sansa_t* sansa, char* filename, int type)
577 int res;
578 int infile = -1; /* Prevent an erroneous "may be used uninitialised" gcc warning */
579 int bl_length = 0; /* Keep gcc happy when building for rbutil */
580 struct mi4header_t mi4header;
581 int n;
582 int length;
584 if (type==FILETYPE_MI4) {
585 /* Step 1 - read bootloader into RAM. */
586 infile=open(filename,O_RDONLY|O_BINARY);
587 if (infile < 0) {
588 fprintf(stderr,"[ERR] Couldn't open input file %s\n",filename);
589 return -1;
592 bl_length = filesize(infile);
593 } else {
594 #ifndef RBUTIL
595 bl_length = LEN_bootimg;
596 #endif
599 /* Create PPMI header */
600 memset(sectorbuf,0,0x200);
601 memcpy(sectorbuf,"PPMI",4);
602 int2le(bl_length, sectorbuf+4);
603 int2le(0x00020000, sectorbuf+8);
605 if (type==FILETYPE_MI4) {
606 /* Read bootloader into sectorbuf+0x200 */
607 n = read(infile,sectorbuf+0x200,bl_length);
608 close(infile);
609 if (n < bl_length) {
610 fprintf(stderr,"[ERR] Short read - requested %d bytes, received %d\n"
611 ,bl_length,n);
612 return -1;
615 if (memcmp(sectorbuf+0x200+0x1f8,"RBBL",4)!=0) {
616 fprintf(stderr,"[ERR] %s is not a Rockbox bootloader, aborting.\n",
617 filename);
618 return -1;
620 } else {
621 #ifndef RBUTIL
622 memcpy(sectorbuf+0x200,bootimg,LEN_bootimg);
623 #endif
626 /* Load original firmware from Sansa to the space after the bootloader */
627 res = load_original_firmware(sansa,sectorbuf+0x200+bl_length,&mi4header);
628 if (res < 0)
629 return res;
631 /* Now write the whole thing back to the Sansa */
633 if (sansa_seek(sansa, sansa->start+PPMI_OFFSET) < 0) {
634 fprintf(stderr,"[ERR] Seek to 0x%08llx in add_bootloader failed.\n",
635 sansa->start+PPMI_OFFSET);
636 return -5;
639 length = 0x200 + bl_length + mi4header.mi4size;
641 n=sansa_write(sansa, sectorbuf, length);
642 if (n < length) {
643 fprintf(stderr,"[ERR] Short write in add_bootloader\n");
644 return -6;
647 return 0;
650 int sansa_delete_bootloader(struct sansa_t* sansa)
652 int res;
653 struct mi4header_t mi4header;
654 int n;
655 int length;
657 /* Load original firmware from Sansa to sectorbuf+0x200 */
658 res = load_original_firmware(sansa,sectorbuf+0x200,&mi4header);
659 if (res < 0)
660 return res;
662 /* Create PPMI header */
663 memset(sectorbuf,0,0x200);
664 memcpy(sectorbuf,"PPMI",4);
665 int2le(mi4header.mi4size, sectorbuf+4);
666 int2le(0x00020000, sectorbuf+8);
668 /* Now write the whole thing back to the Sansa */
670 if (sansa_seek(sansa, sansa->start+PPMI_OFFSET) < 0) {
671 fprintf(stderr,"[ERR] Seek to 0x%08llx in add_bootloader failed.\n",
672 sansa->start+PPMI_OFFSET);
673 return -5;
676 length = 0x200 + mi4header.mi4size;
678 n=sansa_write(sansa, sectorbuf, length);
679 if (n < length) {
680 fprintf(stderr,"[ERR] Short write in delete_bootloader\n");
681 return -6;
684 return 0;
687 void sansa_list_images(struct sansa_t* sansa)
689 struct mi4header_t mi4header;
690 loff_t ppmi_length;
692 /* Check Main firmware header */
693 if (sansa_seek_and_read(sansa, sansa->start+PPMI_OFFSET, sectorbuf, 0x200) < 0) {
694 return;
697 ppmi_length = le2int(sectorbuf+4);
699 printf("[INFO] Image 1 - %llu bytes\n",ppmi_length);
701 /* Look for an original firmware after the first image */
702 if (sansa_seek_and_read(sansa, sansa->start + PPMI_OFFSET + 0x200 + ppmi_length, sectorbuf, 512) < 0) {
703 return;
706 if (get_mi4header(sectorbuf,&mi4header)==0) {
707 printf("[INFO] Image 2 - %d bytes\n",mi4header.mi4size);
711 int sansa_update_of(struct sansa_t* sansa, char* filename)
713 int n;
714 int infile = -1; /* Prevent an erroneous "may be used uninitialised" gcc warning */
715 int of_length = 0; /* Keep gcc happy when building for rbutil */
716 int ppmi_length;
717 struct mi4header_t mi4header;
718 unsigned char buf[512];
720 /* Step 1 - check we have an OF on the Sansa to upgrade. We expect the
721 Rockbox bootloader to be installed and the OF to be after it on disk. */
723 /* Read 512 bytes from PPMI_OFFSET - the PPMI header */
724 if (sansa_seek_and_read(sansa, sansa->start + PPMI_OFFSET,
725 buf, 512) < 0) {
726 return -1;
729 /* No need to check PPMI magic - it's done during init to confirm
730 this is an E200 */
731 ppmi_length = le2int(buf+4);
733 /* Look for an original firmware after the first image */
734 if (sansa_seek_and_read(sansa, sansa->start+PPMI_OFFSET+0x200+ppmi_length,
735 buf, 512) < 0) {
736 return -1;
739 if (get_mi4header(buf,&mi4header)!=0) {
740 /* We don't have a valid MI4 file after a bootloader, so do nothing. */
741 fprintf(stderr,"[ERR] No original firmware found at 0x%08llx\n",
742 sansa->start+PPMI_OFFSET+0x200+ppmi_length);
743 return -1;
746 /* Step 2 - read OF into RAM. */
747 infile=open(filename,O_RDONLY|O_BINARY);
748 if (infile < 0) {
749 fprintf(stderr,"[ERR] Couldn't open input file %s\n",filename);
750 return -1;
753 of_length = filesize(infile);
755 /* Load original firmware from file */
756 memset(sectorbuf,0,0x200);
757 n = read(infile,sectorbuf,of_length);
758 close(infile);
759 if (n < of_length) {
760 fprintf(stderr,"[ERR] Short read - requested %d bytes, received %d\n"
761 , of_length, n);
762 return -1;
765 /* Check we have a valid MI4 file. */
766 if (get_mi4header(sectorbuf,&mi4header)!=0) {
767 fprintf(stderr,"[ERR] %s is not a valid mi4 file\n",filename);
768 return -1;
771 /* Decrypt and build the header */
772 if(prepare_original_firmware(sectorbuf, &mi4header)!=0){
773 fprintf(stderr,"[ERR] Unable to build decrypted mi4 from %s\n"
774 ,filename);
775 return -1;
778 /* Step 3 - write the OF to the Sansa */
779 if (sansa_seek(sansa, sansa->start+PPMI_OFFSET+0x200+ppmi_length) < 0) {
780 fprintf(stderr,"[ERR] Seek to 0x%08llx in sansa_update_of failed.\n",
781 sansa->start+PPMI_OFFSET+0x200+ppmi_length);
782 return -1;
785 n=sansa_write(sansa, sectorbuf, of_length);
786 if (n < of_length) {
787 fprintf(stderr,"[ERR] Short write in sansa_update_of\n");
788 return -1;
791 return 0;