Correct manual entry for Sansa Clip keymap
[kugel-rb.git] / rbutil / ipodpatcher / ipodpatcher.c
blobb2f01b8223c91de7dd552ffcd28d836a4b43262b
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2006-2007 Dave Chapman
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
22 #include <stdio.h>
23 #include <unistd.h>
24 #include <fcntl.h>
25 #include <string.h>
26 #include <stdlib.h>
27 #include <inttypes.h>
28 #include <stdbool.h>
29 #include <sys/types.h>
30 #include <sys/stat.h>
32 #include "parttypes.h"
33 #include "ipodio.h"
34 #include "ipodpatcher.h"
36 #ifdef WITH_BOOTOBJS
37 #include "ipod1g2g.h"
38 #include "ipod3g.h"
39 #include "ipod4g.h"
40 #include "ipodmini1g.h"
41 #include "ipodmini2g.h"
42 #include "ipodcolor.h"
43 #include "ipodnano1g.h"
44 #include "ipodvideo.h"
45 #include "ipodnano2g.h"
46 #endif
48 #ifndef RBUTIL
49 #include "arc4.h"
50 #endif
52 int ipod_verbose = 0;
54 unsigned char* ipod_sectorbuf = NULL;
56 /* The following string appears at the start of the firmware partition */
57 static const char *apple_stop_sign = "{{~~ /-----\\ "\
58 "{{~~ / \\ "\
59 "{{~~| | "\
60 "{{~~| S T O P | "\
61 "{{~~| | "\
62 "{{~~ \\ / "\
63 "{{~~ \\-----/ "\
64 "Copyright(C) 200"\
65 "1 Apple Computer"\
66 ", Inc.----------"\
67 "----------------"\
68 "----------------"\
69 "----------------"\
70 "----------------"\
71 "----------------"\
72 "---------------";
74 /* Windows requires the buffer for disk I/O to be aligned in memory on a
75 multiple of the disk volume size - so we use a single global variable
76 and initialise it with ipod_alloc_buf()
79 char* get_parttype(int pt)
81 int i;
82 static char unknown[]="Unknown";
84 if (pt == PARTTYPE_HFS) {
85 return "HFS/HFS+";
88 i=0;
89 while (parttypes[i].name != NULL) {
90 if (parttypes[i].type == pt) {
91 return (parttypes[i].name);
93 i++;
96 return unknown;
99 off_t filesize(int fd) {
100 struct stat buf;
102 if (fstat(fd,&buf) < 0) {
103 perror("[ERR] Checking filesize of input file");
104 return -1;
105 } else {
106 return(buf.st_size);
110 /* Partition table parsing code taken from Rockbox */
112 #define MAX_SECTOR_SIZE 2048
113 #define SECTOR_SIZE 512
115 static inline unsigned short le2ushort(unsigned char* buf)
117 unsigned short res = (buf[1] << 8) | buf[0];
119 return res;
122 static inline int le2int(unsigned char* buf)
124 int32_t res = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
126 return res;
129 static inline int be2int(unsigned char* buf)
131 int32_t res = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
133 return res;
136 static inline int getint16le(char* buf)
138 int16_t res = (buf[1] << 8) | buf[0];
140 return res;
143 static inline void short2le(unsigned short val, unsigned char* addr)
145 addr[0] = val & 0xFF;
146 addr[1] = (val >> 8) & 0xff;
149 static inline void int2le(unsigned int val, unsigned char* addr)
151 addr[0] = val & 0xFF;
152 addr[1] = (val >> 8) & 0xff;
153 addr[2] = (val >> 16) & 0xff;
154 addr[3] = (val >> 24) & 0xff;
157 static inline void int2be(unsigned int val, unsigned char* addr)
159 addr[0] = (val >> 24) & 0xff;
160 addr[1] = (val >> 16) & 0xff;
161 addr[2] = (val >> 8) & 0xff;
162 addr[3] = val & 0xFF;
166 #define BYTES2INT32(array,pos)\
167 ((long)array[pos] | ((long)array[pos+1] << 8 ) |\
168 ((long)array[pos+2] << 16 ) | ((long)array[pos+3] << 24 ))
170 int read_partinfo(struct ipod_t* ipod, int silent)
172 int i;
173 unsigned long count;
175 count = ipod_read(ipod,ipod_sectorbuf, ipod->sector_size);
177 if (count <= 0) {
178 ipod_print_error(" Error reading from disk: ");
179 return -1;
182 memset(ipod->pinfo, 0, sizeof(ipod->pinfo));
184 if ((ipod_sectorbuf[510] == 0x55) && (ipod_sectorbuf[511] == 0xaa)) {
185 /* DOS partition table */
186 ipod->macpod = 0;
187 /* parse partitions */
188 for ( i = 0; i < 4; i++ ) {
189 unsigned char* ptr = ipod_sectorbuf + 0x1be + 16*i;
190 ipod->pinfo[i].type = ptr[4];
191 ipod->pinfo[i].start = BYTES2INT32(ptr, 8);
192 ipod->pinfo[i].size = BYTES2INT32(ptr, 12);
194 /* extended? */
195 if ( ipod->pinfo[i].type == 5 ) {
196 /* not handled yet */
199 } else if ((ipod_sectorbuf[0] == 'E') && (ipod_sectorbuf[1] == 'R')) {
200 /* Apple Partition Map */
202 /* APM parsing code based on the check_mac_partitions() function in
203 ipodloader2 - written by Thomas Tempelmann and released
204 under the GPL. */
206 int blkNo = 1;
207 int partBlkCount = 1;
208 int partBlkSizMul = ipod_sectorbuf[2] / 2;
210 int pmMapBlkCnt; /* # of blks in partition map */
211 int pmPyPartStart; /* physical start blk of partition */
212 int pmPartBlkCnt; /* # of blks in this partition */
213 int i = 0;
215 ipod->macpod = 1;
217 memset(ipod->pinfo,0,sizeof(ipod->pinfo));
219 while (blkNo <= partBlkCount) {
220 if (ipod_seek(ipod, blkNo * partBlkSizMul * 512) < 0) {
221 fprintf(stderr,"[ERR] Seek failed whilst reading APM\n");
222 return -1;
225 count = ipod_read(ipod, ipod_sectorbuf, ipod->sector_size);
227 if (count <= 0) {
228 ipod_print_error(" Error reading from disk: ");
229 return -1;
232 /* see if it's a partition entry */
233 if ((ipod_sectorbuf[0] != 'P') || (ipod_sectorbuf[1] != 'M')) {
234 /* end of partition table -> leave the loop */
235 break;
238 /* Extract the interesting entries */
239 pmMapBlkCnt = be2int(ipod_sectorbuf + 4);
240 pmPyPartStart = be2int(ipod_sectorbuf + 8);
241 pmPartBlkCnt = be2int(ipod_sectorbuf + 12);
243 /* update the number of part map blocks */
244 partBlkCount = pmMapBlkCnt;
246 if (strncmp((char*)(ipod_sectorbuf + 48), "Apple_MDFW", 32)==0) {
247 /* A Firmware partition */
248 ipod->pinfo[i].start = pmPyPartStart;
249 ipod->pinfo[i].size = pmPartBlkCnt;
250 ipod->pinfo[i].type = 0;
251 i++;
252 } else if (strncmp((char*)(ipod_sectorbuf + 48), "Apple_HFS", 32)==0) {
253 /* A HFS partition */
254 ipod->pinfo[i].start = pmPyPartStart;
255 ipod->pinfo[i].size = pmPartBlkCnt;
256 ipod->pinfo[i].type = PARTTYPE_HFS;
257 i++;
260 blkNo++; /* read next partition map entry */
262 } else {
263 if (!silent) fprintf(stderr,"[ERR] Bad boot sector signature\n");
264 return -1;
267 /* Check that the partition table looks like an ipod:
268 1) Partition 1 is of type 0 (Empty) but isn't empty.
269 2) Partition 2 is of type 0xb or 0xc (winpod) or -1 (macpod)
271 if ((ipod->pinfo[0].type != 0) || (ipod->pinfo[0].size == 0) ||
272 ((ipod->pinfo[1].type != 0xb) && (ipod->pinfo[1].type != 0xc) &&
273 (ipod->pinfo[1].type != PARTTYPE_HFS))) {
274 if (!silent) fprintf(stderr,"[ERR] Partition layout is not an ipod\n");
275 return -1;
278 ipod->start = ipod->pinfo[0].start*ipod->sector_size;
279 return 0;
282 int read_partition(struct ipod_t* ipod, int outfile)
284 int res;
285 ssize_t n;
286 int bytesleft;
287 int chunksize;
288 int count = ipod->pinfo[0].size;
290 if (ipod_seek(ipod, ipod->start) < 0) {
291 return -1;
294 fprintf(stderr,"[INFO] Writing %d sectors to output file\n",count);
296 bytesleft = count * ipod->sector_size;
297 while (bytesleft > 0) {
298 if (bytesleft > BUFFER_SIZE) {
299 chunksize = BUFFER_SIZE;
300 } else {
301 chunksize = bytesleft;
304 n = ipod_read(ipod, ipod_sectorbuf, chunksize);
306 if (n < 0) {
307 return -1;
310 if (n < chunksize) {
311 fprintf(stderr,
312 "[ERR] Short read in disk_read() - requested %d, got %d\n",
313 chunksize,(int)n);
314 return -1;
317 bytesleft -= n;
319 res = write(outfile,ipod_sectorbuf,n);
321 if (res < 0) {
322 perror("[ERR] write in disk_read");
323 return -1;
326 if (res != n) {
327 fprintf(stderr,
328 "Short write - requested %d, received %d - aborting.\n",(int)n,res);
329 return -1;
333 fprintf(stderr,"[INFO] Done.\n");
334 return 0;
337 int write_partition(struct ipod_t* ipod, int infile)
339 ssize_t res;
340 int n;
341 int bytesread;
342 int byteswritten = 0;
343 int eof;
344 int padding = 0;
346 if (ipod_seek(ipod, ipod->start) < 0) {
347 return -1;
350 fprintf(stderr,"[INFO] Writing input file to device\n");
351 bytesread = 0;
352 eof = 0;
353 while (!eof) {
354 n = read(infile,ipod_sectorbuf,BUFFER_SIZE);
356 if (n < 0) {
357 perror("[ERR] read in disk_write");
358 return -1;
361 if (n < BUFFER_SIZE) {
362 eof = 1;
363 /* We need to pad the last write to a multiple of SECTOR_SIZE */
364 if ((n % ipod->sector_size) != 0) {
365 padding = (ipod->sector_size-(n % ipod->sector_size));
366 n += padding;
370 bytesread += n;
372 res = ipod_write(ipod, ipod_sectorbuf, n);
374 if (res < 0) {
375 ipod_print_error(" Error writing to disk: ");
376 fprintf(stderr,"Bytes written: %d\n",byteswritten);
377 return -1;
380 if (res != n) {
381 fprintf(stderr,"[ERR] Short write - requested %d, received %d - aborting.\n",n,(int)res);
382 return -1;
385 byteswritten += res;
388 fprintf(stderr,"[INFO] Wrote %d bytes plus %d bytes padding.\n",
389 byteswritten-padding,padding);
390 return 0;
393 char* ftypename[] = { "OSOS", "RSRC", "AUPD", "HIBE", "OSBK" };
395 int diskmove(struct ipod_t* ipod, int delta)
397 int src_start;
398 int src_end;
399 int bytesleft;
400 int chunksize;
401 int n;
403 src_start = ipod->ipod_directory[1].devOffset;
404 src_end = (ipod->ipod_directory[ipod->nimages-1].devOffset + ipod->sector_size +
405 ipod->ipod_directory[ipod->nimages-1].len +
406 (ipod->sector_size-1)) & ~(ipod->sector_size-1);
407 bytesleft = src_end - src_start;
409 if (ipod_verbose) {
410 fprintf(stderr,"[INFO] Need to move images 2-%d forward %08x bytes\n", ipod->nimages,delta);
411 fprintf(stderr,"[VERB] src_start = %08x\n",src_start);
412 fprintf(stderr,"[VERB] src_end = %08x\n",src_end);
413 fprintf(stderr,"[VERB] dest_start = %08x\n",src_start+delta);
414 fprintf(stderr,"[VERB] dest_end = %08x\n",src_end+delta);
415 fprintf(stderr,"[VERB] bytes to copy = %08x\n",bytesleft);
418 while (bytesleft > 0) {
419 if (bytesleft <= BUFFER_SIZE) {
420 chunksize = bytesleft;
421 } else {
422 chunksize = BUFFER_SIZE;
425 if (ipod_verbose) {
426 fprintf(stderr,"[VERB] Copying %08x bytes from %08x to %08x (absolute %08x to %08x)\n",
427 chunksize,
428 src_end-chunksize,
429 src_end-chunksize+delta,
430 (unsigned int)(ipod->start+src_end-chunksize),
431 (unsigned int)(ipod->start+src_end-chunksize+delta));
435 if (ipod_seek(ipod, ipod->start+src_end-chunksize) < 0) {
436 fprintf(stderr,"[ERR] Seek failed\n");
437 return -1;
440 if ((n = ipod_read(ipod,ipod_sectorbuf,chunksize)) < 0) {
441 perror("[ERR] Write failed\n");
442 return -1;
445 if (n < chunksize) {
446 fprintf(stderr,"[ERR] Short read - requested %d bytes, received %d\n",
447 chunksize,n);
448 return -1;
451 if (ipod_seek(ipod, ipod->start+src_end-chunksize+delta) < 0) {
452 fprintf(stderr,"[ERR] Seek failed\n");
453 return -1;
456 if ((n = ipod_write(ipod,ipod_sectorbuf,chunksize)) < 0) {
457 perror("[ERR] Write failed\n");
458 return -1;
461 if (n < chunksize) {
462 fprintf(stderr,"[ERR] Short write - requested %d bytes, received %d\n"
463 ,chunksize,n);
464 return -1;
467 src_end -= chunksize;
468 bytesleft -= chunksize;
471 return 0;
474 static int rename_image(struct ipod_t* ipod, char* from, char* to)
476 int n;
477 int x;
478 int found;
479 int i;
480 unsigned char* p;
482 /* diroffset may not be sector-aligned */
483 x = ipod->diroffset % ipod->sector_size;
485 /* Read directory */
486 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) {
487 fprintf(stderr,"[ERR] Seek to diroffset (%08x) failed.\n",(unsigned)ipod->diroffset);
488 return -1;
491 n=ipod_read(ipod, ipod_sectorbuf, ipod->sector_size);
492 if (n < 0) {
493 fprintf(stderr,"[ERR] Read of directory failed.\n");
494 return -1;
497 p = ipod_sectorbuf + x;
499 /* A hack to detect 2nd gen Nanos - maybe there is a better way? */
500 if (p[0] == 0)
502 /* Adjust diroffset */
503 ipod->diroffset += ipod->sector_size - x;
505 n=ipod_read(ipod, ipod_sectorbuf, ipod->sector_size);
506 if (n < 0) {
507 fprintf(stderr,"[ERR] Read of directory failed.\n");
508 return -1;
510 p = ipod_sectorbuf;
513 found = 0;
514 for (i=0 ; !found && i < MAX_IMAGES; i++) {
515 if (memcmp(p + 4, from, 4) == 0) {
516 memcpy(p + 4, to, 4);
518 found = 1;
520 p += 40;
523 if (!found) {
524 fprintf(stderr,"[ERR] Unexpected error - no \"%s\" image!\n", from);
525 return -1;
528 /* Write directory back to disk */
529 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) {
530 fprintf(stderr,"[ERR] Seek to diroffset (%08x) failed.\n",(unsigned)ipod->diroffset);
531 return -1;
534 n=ipod_write(ipod, ipod_sectorbuf, ipod->sector_size);
535 if (n < 0) {
536 fprintf(stderr,"[ERR] Write of directory failed in rename_image.\n");
537 return -1;
540 return 0;
543 static int delete_image(struct ipod_t* ipod, char* name)
545 int n;
546 int x;
547 int found;
548 int i;
549 unsigned char* p;
551 /* diroffset may not be sector-aligned */
552 x = ipod->diroffset % ipod->sector_size;
554 /* Read directory */
555 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) {
556 fprintf(stderr,"[ERR] Seek to diroffset (%08x) failed.\n",(unsigned)ipod->diroffset);
557 return -1;
560 n=ipod_read(ipod, ipod_sectorbuf, ipod->sector_size);
561 if (n < 0) {
562 fprintf(stderr,"[ERR] Read of directory failed.\n");
563 return -1;
566 p = ipod_sectorbuf + x;
568 /* A hack to detect 2nd gen Nanos - maybe there is a better way? */
569 if (p[0] == 0)
571 /* Adjust diroffset */
572 ipod->diroffset += ipod->sector_size - x;
574 n=ipod_read(ipod, ipod_sectorbuf, ipod->sector_size);
575 if (n < 0) {
576 fprintf(stderr,"[ERR] Read of directory failed.\n");
577 return -1;
579 p = ipod_sectorbuf;
582 found = 0;
583 for (i=0 ; !found && i < MAX_IMAGES; i++) {
584 if (memcmp(p + 4, name, 4) == 0) {
585 memset(p, 0, 40); /* Delete directory entry */
586 found = 1;
588 p += 40;
591 if (!found) {
592 fprintf(stderr,"[ERR] Unexpected error - no \"%s\" image!\n", name);
593 return -1;
596 /* Write directory back to disk */
597 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) {
598 fprintf(stderr,"[ERR] Seek to diroffset (%08x) failed.\n",(unsigned)ipod->diroffset);
599 return -1;
602 n=ipod_write(ipod, ipod_sectorbuf, ipod->sector_size);
603 if (n < 0) {
604 fprintf(stderr,"[ERR] Write of directory failed in delete_image.\n");
605 return -1;
608 return 0;
611 int add_new_image(struct ipod_t* ipod, char* imagename, char* filename, int type)
613 int length;
614 int found;
615 int i;
616 int x;
617 int n;
618 int infile;
619 int newsize;
620 unsigned long chksum=0;
621 unsigned long filechksum=0;
622 unsigned long offset;
623 unsigned char header[8]; /* Header for .ipod file */
624 unsigned char* p;
626 #ifdef WITH_BOOTOBJS
627 if (type == FILETYPE_INTERNAL) {
628 fprintf(stderr,"[INFO] Using internal bootloader - %d bytes\n",ipod->bootloader_len);
629 length = ipod->bootloader_len;
630 infile = -1;
632 else
633 #endif
635 /* First check that the input file is the correct type for this ipod. */
636 infile=open(filename,O_RDONLY);
637 if (infile < 0) {
638 fprintf(stderr,"[ERR] Couldn't open input file %s\n",filename);
639 return -1;
642 if (type==FILETYPE_DOT_IPOD) {
643 n = read(infile,header,8);
644 if (n < 8) {
645 fprintf(stderr,"[ERR] Failed to read header from %s\n",filename);
646 close(infile);
647 return -1;
650 if (memcmp(header+4, ipod->modelname,4)!=0) {
651 fprintf(stderr,"[ERR] Model name in input file (%c%c%c%c) doesn't match ipod model (%s)\n",
652 header[4],header[5],header[6],header[7], ipod->modelname);
653 close(infile);
654 return -1;
657 filechksum = be2int(header);
659 length = filesize(infile)-8;
660 } else {
661 length = filesize(infile);
665 newsize=(length+ipod->sector_size-1)&~(ipod->sector_size-1);
667 fprintf(stderr,"[INFO] Padding input file from 0x%08x to 0x%08x bytes\n",
668 length,newsize);
670 if (newsize > BUFFER_SIZE) {
671 fprintf(stderr,"[ERR] Input file too big for buffer\n");
672 if (infile >= 0) close(infile);
673 return -1;
676 /* TODO: Check if we have enough space in the partition for the new image */
678 #ifdef WITH_BOOTOBJS
679 if (type == FILETYPE_INTERNAL) {
680 memcpy(ipod_sectorbuf,ipod->bootloader,ipod->bootloader_len);
682 else
683 #endif
685 fprintf(stderr,"[INFO] Reading input file...\n");
687 n = read(infile,ipod_sectorbuf,length);
688 if (n < 0) {
689 fprintf(stderr,"[ERR] Couldn't read input file\n");
690 close(infile);
691 return -1;
693 close(infile);
696 /* Pad the data with zeros */
697 memset(ipod_sectorbuf+length,0,newsize-length);
699 if (type==FILETYPE_DOT_IPOD) {
700 chksum = ipod->modelnum;
701 for (i = 0; i < length; i++) {
702 /* add 8 unsigned bits but keep a 32 bit sum */
703 chksum += ipod_sectorbuf[i];
706 if (chksum == filechksum) {
707 fprintf(stderr,"[INFO] Checksum OK in %s\n",filename);
708 } else {
709 fprintf(stderr,"[ERR] Checksum in %s failed check\n",filename);
710 return -1;
715 offset = ipod->fwoffset + ipod->ipod_directory[ipod->nimages - 1].devOffset +
716 ipod->ipod_directory[ipod->nimages - 1].len + ipod->sector_size;
718 /* 2nd Gen Nano has encrypted firmware, and the sector
719 preceeding the firmware contains hashes that need to be
720 preserved. Nano 2G images include these extra 2048 (0x800)
721 bytes
723 if (ipod_seek(ipod, offset - (ipod->modelnum == 62 ? 0x800 : 0)) < 0) {
724 fprintf(stderr,"[ERR] Seek failed\n");
725 return -1;
728 if ((n = ipod_write(ipod,ipod_sectorbuf,newsize)) < 0) {
729 perror("[ERR] Write failed\n");
730 return -1;
733 if (n < newsize) {
734 fprintf(stderr,"[ERR] Short write - requested %d bytes, received %d\n"
735 ,newsize,n);
736 return -1;
738 fprintf(stderr,"[INFO] Wrote %d bytes to firmware partition\n",n);
740 /* Now we need to create a new directory entry
742 NOTE: On the Nano 2G, the checksum is the checksum of the
743 unencrypted firmware. But this isn't checked by the NOR
744 bootloader (there are cryptographic hashes in the
745 firmware itself), so it doesn't matter that this is
746 wrong.
748 chksum = 0;
749 for (i = 0; i < length; i++) {
750 /* add 8 unsigned bits but keep a 32 bit sum */
751 chksum += ipod_sectorbuf[i];
754 x = ipod->diroffset % ipod->sector_size;
756 /* Read directory */
757 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; }
759 n=ipod_read(ipod, ipod_sectorbuf, ipod->sector_size);
760 if (n < 0) { return -1; }
762 /* Create a new directory entry */
764 /* Copy OSOS or OSBK details - we assume one of them exists */
765 p = ipod_sectorbuf + x;
766 found = 0;
767 for (i = 0; !found && i < ipod->nimages; i++) {
768 if ((memcmp(p + 4, "soso", 4)==0) || (memcmp(p + 4, "kbso", 4)==0)) {
769 found = 1;
770 } else {
771 p += 40;
775 if (!found) {
776 fprintf(stderr,"[ERR] No OSOS or OSBK image to copy directory from\n");
777 return -1;
780 /* Copy directory image */
781 memcpy(ipod_sectorbuf + x + (ipod->nimages * 40), p, 40);
782 p = ipod_sectorbuf + x + (ipod->nimages * 40);
784 /* Modify directory. */
785 memcpy(p + 4, imagename, 4);
786 int2le(offset - ipod->fwoffset, p + 12); /* devOffset */
787 int2le(length - (ipod->modelnum==62 ? 0x800: 0), p + 16); /* len */
788 int2le(chksum, p + 28); /* checksum */
790 /* Write directory */
791 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; }
792 n=ipod_write(ipod, ipod_sectorbuf, ipod->sector_size);
793 if (n < 0) { return -1; }
795 return 0;
800 Bootloader installation on the Nano2G consists of renaming the
801 OSOS image to OSBK and then writing the Rockbox bootloader as a
802 new OSOS image.
804 Maybe this approach can/should be adapted for other ipods, as it
805 prevents the Apple bootloader loading the original firmware into
806 RAM along with the Rockbox bootloader (and hence will give a
807 faster boot when the user just wants to start Rockbox).
811 static int add_bootloader_nano2g(struct ipod_t* ipod, char* filename, int type)
813 int i;
814 int has_osbk = 0;
816 /* Check if we already have an OSBK image */
817 for (i = 0; i < ipod->nimages; i++) {
818 if (ipod->ipod_directory[i].ftype==FTYPE_OSBK) {
819 has_osbk = 1;
823 if (has_osbk == 0) {
824 /* First-time install - rename OSOS to OSBK and create new OSOS for bootloader */
825 fprintf(stderr,"[INFO] Creating OSBK backup image of original firmware\n");
827 if (rename_image(ipod, "soso", "kbso") < 0) {
828 fprintf(stderr,"[ERR] Could not rename OSOS image\n");
829 return -1;
832 /* Add our bootloader as a brand new image */
833 return add_new_image(ipod, "soso", filename, type);
834 } else {
835 /* This is an update, just replace OSOS with our bootloader */
837 return write_firmware(ipod, filename, type);
842 static int delete_bootloader_nano2g(struct ipod_t* ipod)
844 int i;
845 int has_osbk = 0;
847 /* Check if we have an OSBK image */
848 for (i = 0; i < ipod->nimages; i++) {
849 if (ipod->ipod_directory[i].ftype==FTYPE_OSBK) {
850 has_osbk = 1;
854 if (has_osbk == 0) {
855 fprintf(stderr,"[ERR] No OSBK image found - nothing to uninstall\n");
856 return -1;
857 } else {
858 /* Delete our bootloader image */
859 if (delete_image(ipod, "soso") < 0) {
860 fprintf(stderr,"[WARN] Could not delete OSOS image\n");
861 } else {
862 fprintf(stderr,"[INFO] OSOS image deleted\n");
865 if (rename_image(ipod, "kbso", "soso") < 0) {
866 fprintf(stderr,"[ERR] Could not rename OSBK image\n");
867 return -1;
871 fprintf(stderr,"[INFO] OSBK image renamed to OSOS - bootloader uninstalled.\n");
872 return 0;
877 int add_bootloader(struct ipod_t* ipod, char* filename, int type)
879 int length;
880 int i;
881 int x;
882 int n;
883 int infile;
884 int paddedlength;
885 int entryOffset;
886 int delta = 0;
887 unsigned long chksum=0;
888 unsigned long filechksum=0;
889 unsigned char header[8]; /* Header for .ipod file */
890 unsigned char* bootloader_buf;
892 /* The 2nd gen Nano is installed differently */
893 if (ipod->modelnum == 62) {
894 return add_bootloader_nano2g(ipod, filename, type);
897 /* Calculate the position in the OSOS image where our bootloader will go. */
898 if (ipod->ipod_directory[0].entryOffset>0) {
899 /* Keep the same entryOffset */
900 entryOffset = ipod->ipod_directory[0].entryOffset;
901 } else {
902 entryOffset = (ipod->ipod_directory[0].len+ipod->sector_size-1)&~(ipod->sector_size-1);
905 #ifdef WITH_BOOTOBJS
906 if (type == FILETYPE_INTERNAL) {
907 fprintf(stderr,"[INFO] Using internal bootloader - %d bytes\n",ipod->bootloader_len);
908 memcpy(ipod_sectorbuf+entryOffset,ipod->bootloader,ipod->bootloader_len);
909 length = ipod->bootloader_len;
910 paddedlength=(ipod->bootloader_len+ipod->sector_size-1)&~(ipod->sector_size-1);
912 else
913 #endif
915 infile=open(filename,O_RDONLY);
916 if (infile < 0) {
917 fprintf(stderr,"[ERR] Couldn't open input file %s\n",filename);
918 return -1;
921 if (type==FILETYPE_DOT_IPOD) {
922 /* First check that the input file is the correct type for this ipod. */
923 n = read(infile,header,8);
924 if (n < 8) {
925 fprintf(stderr,"[ERR] Failed to read header from %s\n",filename);
926 close(infile);
927 return -1;
930 if (memcmp(header+4, ipod->modelname,4)!=0) {
931 fprintf(stderr,"[ERR] Model name in input file (%c%c%c%c) doesn't match ipod model (%s)\n",
932 header[4],header[5],header[6],header[7], ipod->modelname);
933 close(infile);
934 return -1;
937 filechksum = be2int(header);
939 length=filesize(infile)-8;
940 } else {
941 length=filesize(infile);
943 paddedlength=(length+ipod->sector_size-1)&~(ipod->sector_size-1);
945 bootloader_buf = malloc(length);
946 if (bootloader_buf == NULL) {
947 fprintf(stderr,"[ERR] Can not allocate memory for bootloader\n");
948 return -1;
950 /* Now read our bootloader - we need to check it before modifying the partition*/
951 n = read(infile,bootloader_buf,length);
952 close(infile);
954 if (n < 0) {
955 fprintf(stderr,"[ERR] Couldn't read input file\n");
956 return -1;
959 if (type==FILETYPE_DOT_IPOD) {
960 /* Calculate and confirm bootloader checksum */
961 chksum = ipod->modelnum;
962 for (i = 0; i < length; i++) {
963 /* add 8 unsigned bits but keep a 32 bit sum */
964 chksum += bootloader_buf[i];
967 if (chksum == filechksum) {
968 fprintf(stderr,"[INFO] Checksum OK in %s\n",filename);
969 } else {
970 fprintf(stderr,"[ERR] Checksum in %s failed check\n",filename);
971 return -1;
976 if (entryOffset+paddedlength > BUFFER_SIZE) {
977 fprintf(stderr,"[ERR] Input file too big for buffer\n");
978 return -1;
981 if (ipod_verbose) {
982 fprintf(stderr,"[VERB] Original firmware begins at 0x%08x\n", ipod->ipod_directory[0].devOffset + ipod->sector_size);
983 fprintf(stderr,"[VERB] New entryOffset will be 0x%08x\n",entryOffset);
984 fprintf(stderr,"[VERB] End of bootloader will be at 0x%08x\n",entryOffset+paddedlength);
987 /* Check if we have enough space */
988 /* TODO: Check the size of the partition. */
989 if (ipod->nimages > 1) {
990 if ((ipod->ipod_directory[0].devOffset+entryOffset+paddedlength) >
991 ipod->ipod_directory[1].devOffset) {
992 fprintf(stderr,"[INFO] Moving images to create room for new firmware...\n");
993 delta = ipod->ipod_directory[0].devOffset + entryOffset+paddedlength
994 - ipod->ipod_directory[1].devOffset + ipod->sector_size;
996 if (diskmove(ipod, delta) < 0) {
997 fprintf(stderr,"[ERR] Image movement failed.\n");
998 return -1;
1004 /* We have moved the partitions, now we can write our bootloader */
1006 /* Firstly read the original firmware into ipod_sectorbuf */
1007 fprintf(stderr,"[INFO] Reading original firmware...\n");
1008 if (ipod_seek(ipod, ipod->fwoffset+ipod->ipod_directory[0].devOffset) < 0) {
1009 fprintf(stderr,"[ERR] Seek failed\n");
1010 return -1;
1013 if ((n = ipod_read(ipod,ipod_sectorbuf,entryOffset)) < 0) {
1014 perror("[ERR] Read failed\n");
1015 return -1;
1018 if (n < entryOffset) {
1019 fprintf(stderr,"[ERR] Short read - requested %d bytes, received %d\n"
1020 ,entryOffset,n);
1021 return -1;
1024 #ifdef WITH_BOOTOBJS
1025 if (type == FILETYPE_INTERNAL) {
1026 memcpy(ipod_sectorbuf+entryOffset,ipod->bootloader,ipod->bootloader_len);
1028 else
1029 #endif
1031 memcpy(ipod_sectorbuf+entryOffset,bootloader_buf,length);
1032 free(bootloader_buf);
1035 /* Calculate new checksum for combined image */
1036 chksum = 0;
1037 for (i=0;i<entryOffset + length; i++) {
1038 chksum += ipod_sectorbuf[i];
1041 /* Now write the combined firmware image to the disk */
1043 if (ipod_seek(ipod, ipod->fwoffset+ipod->ipod_directory[0].devOffset) < 0) {
1044 fprintf(stderr,"[ERR] Seek failed\n");
1045 return -1;
1048 if ((n = ipod_write(ipod,ipod_sectorbuf,entryOffset+paddedlength)) < 0) {
1049 perror("[ERR] Write failed\n");
1050 return -1;
1053 if (n < (entryOffset+paddedlength)) {
1054 fprintf(stderr,"[ERR] Short read - requested %d bytes, received %d\n"
1055 ,entryOffset+paddedlength,n);
1056 return -1;
1059 fprintf(stderr,"[INFO] Wrote %d bytes to firmware partition\n",entryOffset+paddedlength);
1061 x = ipod->diroffset % ipod->sector_size;
1063 /* Read directory */
1064 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) {
1065 fprintf(stderr,"[ERR] Seek failed\n");
1066 return -1;
1069 n=ipod_read(ipod, ipod_sectorbuf, ipod->sector_size);
1070 if (n < 0) {
1071 fprintf(stderr,"[ERR] Directory read failed\n");
1072 return -1;
1075 /* Update entries for image 0 */
1076 int2le(entryOffset+length,ipod_sectorbuf+x+16);
1077 int2le(entryOffset,ipod_sectorbuf+x+24);
1078 int2le(chksum,ipod_sectorbuf+x+28);
1079 int2le(0xffffffff,ipod_sectorbuf+x+36); /* loadAddr */
1081 /* Update devOffset entries for other images, if we have moved them */
1082 if (delta > 0) {
1083 for (i=1;i<ipod->nimages;i++) {
1084 int2le(le2int(ipod_sectorbuf+x+i*40+12)+delta,ipod_sectorbuf+x+i*40+12);
1088 /* Write directory */
1089 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) {
1090 fprintf(stderr,"[ERR] Seek to %d failed\n", (int)(ipod->start+ipod->diroffset-x));
1091 return -1;
1093 n=ipod_write(ipod, ipod_sectorbuf, ipod->sector_size);
1094 if (n < 0) {
1095 fprintf(stderr,"[ERR] Directory write failed\n");
1096 return -1;
1099 return 0;
1102 int delete_bootloader(struct ipod_t* ipod)
1104 int length;
1105 int i;
1106 int x;
1107 int n;
1108 unsigned long chksum=0; /* 32 bit checksum - Rockbox .ipod style*/
1110 /* The 2nd gen Nano is installed differently */
1111 if (ipod->modelnum == 62) {
1112 return delete_bootloader_nano2g(ipod);
1115 /* Removing the bootloader involves adjusting the "length",
1116 "chksum" and "entryOffset" values in the osos image's directory
1117 entry. */
1119 /* Firstly check we have a bootloader... */
1121 if (ipod->ipod_directory[0].entryOffset == 0) {
1122 fprintf(stderr,"[ERR] No bootloader found.\n");
1123 return -1;
1126 length = ipod->ipod_directory[0].entryOffset;
1128 /* Read the firmware so we can calculate the checksum */
1129 fprintf(stderr,"[INFO] Reading firmware (%d bytes)\n",length);
1131 if (ipod_seek(ipod, ipod->fwoffset+ipod->ipod_directory[0].devOffset) < 0) {
1132 return -1;
1135 i = (length+ipod->sector_size-1) & ~(ipod->sector_size-1);
1136 fprintf(stderr,"[INFO] Padding read from 0x%08x to 0x%08x bytes\n",
1137 length,i);
1139 if ((n = ipod_read(ipod,ipod_sectorbuf,i)) < 0) {
1140 return -1;
1143 if (n < i) {
1144 fprintf(stderr,"[ERR] Short read - requested %d bytes, received %d\n",
1145 i,n);
1146 return -1;
1149 chksum = 0;
1150 for (i = 0; i < length; i++) {
1151 /* add 8 unsigned bits but keep a 32 bit sum */
1152 chksum += ipod_sectorbuf[i];
1155 /* Now write back the updated directory entry */
1157 fprintf(stderr,"[INFO] Updating firmware checksum\n");
1159 x = ipod->diroffset % ipod->sector_size;
1161 /* Read directory */
1162 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; }
1164 n=ipod_read(ipod, ipod_sectorbuf, ipod->sector_size);
1165 if (n < 0) { return -1; }
1167 /* Update entries for image 0 */
1168 int2le(length,ipod_sectorbuf+x+16);
1169 int2le(0,ipod_sectorbuf+x+24);
1170 int2le(chksum,ipod_sectorbuf+x+28);
1172 /* Write directory */
1173 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; }
1174 n=ipod_write(ipod, ipod_sectorbuf, ipod->sector_size);
1175 if (n < 0) { return -1; }
1177 return 0;
1180 int write_firmware(struct ipod_t* ipod, char* filename, int type)
1182 int length;
1183 int i;
1184 int x;
1185 int n;
1186 int infile;
1187 int newsize;
1188 int bytesavailable;
1189 unsigned long chksum=0;
1190 unsigned long filechksum=0;
1191 unsigned long offset;
1192 unsigned char header[8]; /* Header for .ipod file */
1193 unsigned char* p;
1195 #ifdef WITH_BOOTOBJS
1196 if (type == FILETYPE_INTERNAL) {
1197 fprintf(stderr,"[INFO] Using internal bootloader - %d bytes\n",ipod->bootloader_len);
1198 length = ipod->bootloader_len;
1199 infile = -1;
1201 else
1202 #endif
1204 /* First check that the input file is the correct type for this ipod. */
1205 infile=open(filename,O_RDONLY);
1206 if (infile < 0) {
1207 fprintf(stderr,"[ERR] Couldn't open input file %s\n",filename);
1208 return -1;
1211 if (type==FILETYPE_DOT_IPOD) {
1212 n = read(infile,header,8);
1213 if (n < 8) {
1214 fprintf(stderr,"[ERR] Failed to read header from %s\n",filename);
1215 close(infile);
1216 return -1;
1219 if (memcmp(header+4, ipod->modelname,4)!=0) {
1220 fprintf(stderr,"[ERR] Model name in input file (%c%c%c%c) doesn't match ipod model (%s)\n",
1221 header[4],header[5],header[6],header[7], ipod->modelname);
1222 close(infile);
1223 return -1;
1226 filechksum = be2int(header);
1228 length = filesize(infile)-8;
1229 } else {
1230 length = filesize(infile);
1234 newsize=(length+ipod->sector_size-1)&~(ipod->sector_size-1);
1236 fprintf(stderr,"[INFO] Padding input file from 0x%08x to 0x%08x bytes\n",
1237 length,newsize);
1239 if (newsize > BUFFER_SIZE) {
1240 fprintf(stderr,"[ERR] Input file too big for buffer\n");
1241 if (infile >= 0) close(infile);
1242 return -1;
1245 /* Check if we have enough space */
1246 /* TODO: Check the size of the partition. */
1247 if (ipod->nimages > 1) {
1248 bytesavailable=ipod->ipod_directory[1].devOffset-ipod->ipod_directory[0].devOffset;
1249 if (bytesavailable < newsize) {
1250 fprintf(stderr,"[INFO] Moving images to create room for new firmware...\n");
1252 /* TODO: Implement image movement */
1253 fprintf(stderr,"[ERR] Image movement not yet implemented.\n");
1254 close(infile);
1255 return -1;
1259 #ifdef WITH_BOOTOBJS
1260 if (type == FILETYPE_INTERNAL) {
1261 memcpy(ipod_sectorbuf,ipod->bootloader,ipod->bootloader_len);
1263 else
1264 #endif
1266 fprintf(stderr,"[INFO] Reading input file...\n");
1267 /* We now know we have enough space, so write it. */
1268 n = read(infile,ipod_sectorbuf,length);
1269 if (n < 0) {
1270 fprintf(stderr,"[ERR] Couldn't read input file\n");
1271 close(infile);
1272 return -1;
1274 close(infile);
1277 /* Pad the data with zeros */
1278 memset(ipod_sectorbuf+length,0,newsize-length);
1280 if (type==FILETYPE_DOT_IPOD) {
1281 chksum = ipod->modelnum;
1282 for (i = 0; i < length; i++) {
1283 /* add 8 unsigned bits but keep a 32 bit sum */
1284 chksum += ipod_sectorbuf[i];
1287 if (chksum == filechksum) {
1288 fprintf(stderr,"[INFO] Checksum OK in %s\n",filename);
1289 } else {
1290 fprintf(stderr,"[ERR] Checksum in %s failed check\n",filename);
1291 return -1;
1296 offset = ipod->fwoffset+ipod->ipod_directory[ipod->ososimage].devOffset;
1298 if (ipod->modelnum==62) {
1300 /* 2nd Gen Nano has encrypted firmware, and the sector
1301 preceeding the firmware contains hashes that need to be
1302 preserved. Nano 2G images include these extra 2048 (0x800)
1303 bytes
1306 offset -= 0x800;
1308 /* TODO: The above checks need to take into account this 0x800 bytes */
1311 if (ipod_seek(ipod, offset) < 0) {
1312 fprintf(stderr,"[ERR] Seek failed\n");
1313 return -1;
1316 if ((n = ipod_write(ipod,ipod_sectorbuf,newsize)) < 0) {
1317 perror("[ERR] Write failed\n");
1318 return -1;
1321 if (n < newsize) {
1322 fprintf(stderr,"[ERR] Short write - requested %d bytes, received %d\n"
1323 ,newsize,n);
1324 return -1;
1326 fprintf(stderr,"[INFO] Wrote %d bytes to firmware partition\n",n);
1328 /* Now we need to update the "len", "entryOffset" and "chksum" fields
1330 NOTE: On the Nano 2G, the checksum is the checksum of the
1331 unencrypted firmware. But this isn't checked by the NOR
1332 bootloader (there are cryptographic hashes in the
1333 firmware itself), so it doesn't matter that this is
1334 wrong.
1336 chksum = 0;
1337 for (i = 0; i < length; i++) {
1338 /* add 8 unsigned bits but keep a 32 bit sum */
1339 chksum += ipod_sectorbuf[i];
1342 x = ipod->diroffset % ipod->sector_size;
1344 /* Read directory */
1345 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; }
1347 n=ipod_read(ipod, ipod_sectorbuf, ipod->sector_size);
1348 if (n < 0) { return -1; }
1350 /* Update entries for image */
1351 p = ipod_sectorbuf + x + (ipod->ososimage * 40);
1352 int2le(length - (ipod->modelnum==62 ? 0x800: 0), p + 16);
1353 int2le(0, p + 24);
1354 int2le(chksum, p + 28);
1356 /* Write directory */
1357 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; }
1358 n=ipod_write(ipod, ipod_sectorbuf, ipod->sector_size);
1359 if (n < 0) { return -1; }
1361 return 0;
1364 int read_firmware(struct ipod_t* ipod, char* filename, int type)
1366 int length;
1367 int i;
1368 int outfile;
1369 int n;
1370 unsigned long offset;
1371 unsigned long chksum=0; /* 32 bit checksum - Rockbox .ipod style*/
1372 unsigned char header[8]; /* Header for .ipod file */
1374 if (ipod->ipod_directory[ipod->ososimage].entryOffset != 0) {
1375 /* We have a bootloader... */
1376 length = ipod->ipod_directory[ipod->ososimage].entryOffset;
1377 } else {
1378 length = ipod->ipod_directory[ipod->ososimage].len;
1381 fprintf(stderr,"[INFO] Reading firmware (%d bytes)\n",length);
1383 offset = ipod->fwoffset + ipod->ipod_directory[ipod->ososimage].devOffset;
1384 i = (length+ipod->sector_size-1) & ~(ipod->sector_size-1);
1385 fprintf(stderr,"[INFO] Padding read from 0x%08x to 0x%08x bytes\n",
1386 length,i);
1388 if (ipod->modelnum==62) {
1389 /* 2nd Gen Nano has encrypted firmware, and we need to dump the
1390 sector preceeding the image - it contains hashes */
1391 offset -= 0x800;
1392 length += 0x800;
1393 i += 0x800;
1396 if (ipod_seek(ipod, offset)) {
1397 return -1;
1400 if ((n = ipod_read(ipod,ipod_sectorbuf,i)) < 0) {
1401 return -1;
1404 if (n < i) {
1405 fprintf(stderr,"[ERR] Short read - requested %d bytes, received %d\n",
1406 i,n);
1407 return -1;
1410 outfile = open(filename,O_CREAT|O_TRUNC|O_WRONLY|O_BINARY,0666);
1411 if (outfile < 0) {
1412 fprintf(stderr,"[ERR] Couldn't open file %s\n",filename);
1413 return -1;
1416 if (type == FILETYPE_DOT_IPOD) {
1417 chksum = ipod->modelnum;
1418 for (i = 0; i < length; i++) {
1419 /* add 8 unsigned bits but keep a 32 bit sum */
1420 chksum += ipod_sectorbuf[i];
1423 int2be(chksum,header);
1424 memcpy(header+4, ipod->modelname,4);
1426 n = write(outfile,header,8);
1427 if (n != 8) {
1428 fprintf(stderr,"[ERR] Write error - %d\n",n);
1432 n = write(outfile,ipod_sectorbuf,length);
1433 if (n != length) {
1434 fprintf(stderr,"[ERR] Write error - %d\n",n);
1436 close(outfile);
1438 return 0;
1441 int read_directory(struct ipod_t* ipod)
1443 int n;
1444 int x;
1445 unsigned char* p;
1446 unsigned short version;
1448 ipod->nimages=0;
1450 /* Read firmware partition header (first 512 bytes of disk - but
1451 let's read a whole sector) */
1453 if (ipod_seek(ipod, ipod->start) < 0) {
1454 fprintf(stderr,"[ERR] Seek to 0x%08x in read_directory() failed.\n",
1455 (unsigned int)(ipod->start));
1456 return -1;
1459 n=ipod_read(ipod, ipod_sectorbuf, ipod->sector_size);
1460 if (n < 0) {
1461 fprintf(stderr,"[ERR] ipod_read(ipod,buf,0x%08x) failed in read_directory()\n", ipod->sector_size);
1462 return -1;
1465 if (memcmp(ipod_sectorbuf,apple_stop_sign,sizeof(apple_stop_sign))!=0) {
1466 fprintf(stderr,"[ERR] Firmware partition doesn't contain Apple copyright, aborting.\n");
1467 return -1;
1470 if (memcmp(ipod_sectorbuf+0x100,"]ih[",4)!=0) {
1471 fprintf(stderr,"[ERR] Bad firmware directory\n");
1472 return -1;
1475 version = le2ushort(ipod_sectorbuf+0x10a);
1476 if ((version != 2) && (version != 3)) {
1477 fprintf(stderr,"[ERR] Unknown firmware format version %04x\n",
1478 version);
1480 ipod->diroffset=le2int(ipod_sectorbuf+0x104) + 0x200;
1482 /* diroffset may not be sector-aligned */
1483 x = ipod->diroffset % ipod->sector_size;
1485 /* Read directory */
1486 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) {
1487 fprintf(stderr,"[ERR] Seek to diroffset (%08x) failed.\n",(unsigned)ipod->diroffset);
1488 return -1;
1491 n=ipod_read(ipod, ipod_sectorbuf, ipod->sector_size);
1492 if (n < 0) {
1493 fprintf(stderr,"[ERR] Read of directory failed.\n");
1494 return -1;
1497 p = ipod_sectorbuf + x;
1499 /* A hack to detect 2nd gen Nanos - maybe there is a better way? */
1500 if (p[0] == 0)
1502 /* Adjust diroffset */
1503 ipod->diroffset += ipod->sector_size - x;
1505 n=ipod_read(ipod, ipod_sectorbuf, ipod->sector_size);
1506 if (n < 0) {
1507 fprintf(stderr,"[ERR] Read of directory failed.\n");
1508 return -1;
1510 p = ipod_sectorbuf;
1513 ipod->ososimage = -1;
1514 while ((ipod->nimages < MAX_IMAGES) && (p < (ipod_sectorbuf + x + 400)) &&
1515 ((memcmp(p,"!ATA",4)==0) || (memcmp(p,"DNAN",4)==0))) {
1516 p+=4;
1517 if (memcmp(p,"soso",4)==0) {
1518 ipod->ipod_directory[ipod->nimages].ftype=FTYPE_OSOS;
1519 ipod->ososimage = ipod->nimages;
1520 } else if (memcmp(p,"crsr",4)==0) {
1521 ipod->ipod_directory[ipod->nimages].ftype=FTYPE_RSRC;
1522 } else if (memcmp(p,"dpua",4)==0) {
1523 ipod->ipod_directory[ipod->nimages].ftype=FTYPE_AUPD;
1524 } else if (memcmp(p,"kbso",4)==0) {
1525 ipod->ipod_directory[ipod->nimages].ftype=FTYPE_OSBK;
1526 } else if (memcmp(p,"ebih",4)==0) {
1527 ipod->ipod_directory[ipod->nimages].ftype=FTYPE_HIBE;
1528 } else {
1529 fprintf(stderr,"[ERR] Unknown image type %c%c%c%c\n",
1530 p[0],p[1],p[2],p[3]);
1532 p+=4;
1533 ipod->ipod_directory[ipod->nimages].id=le2int(p);
1534 p+=4;
1535 ipod->ipod_directory[ipod->nimages].devOffset=le2int(p);
1536 p+=4;
1537 ipod->ipod_directory[ipod->nimages].len=le2int(p);
1538 p+=4;
1539 ipod->ipod_directory[ipod->nimages].addr=le2int(p);
1540 p+=4;
1541 ipod->ipod_directory[ipod->nimages].entryOffset=le2int(p);
1542 p+=4;
1543 ipod->ipod_directory[ipod->nimages].chksum=le2int(p);
1544 p+=4;
1545 ipod->ipod_directory[ipod->nimages].vers=le2int(p);
1546 p+=4;
1547 ipod->ipod_directory[ipod->nimages].loadAddr=le2int(p);
1548 p+=4;
1549 ipod->nimages++;
1552 if (ipod->ososimage < 0) {
1553 fprintf(stderr,"[ERR] No OSOS image found.\n");
1554 return -1;
1557 if ((ipod->nimages > 1) && (version==2)) {
1558 /* The 3g firmware image doesn't appear to have a version, so
1559 let's make one up... Note that this is never written back to the
1560 ipod, so it's OK to do. */
1562 if (ipod->ipod_directory[ipod->ososimage].vers == 0) { ipod->ipod_directory[ipod->ososimage].vers = 3; }
1564 ipod->fwoffset = ipod->start;
1565 } else {
1566 ipod->fwoffset = ipod->start + ipod->sector_size;
1569 return 0;
1572 int list_images(struct ipod_t* ipod)
1574 int i;
1576 if (ipod_verbose) {
1577 printf(" Type id devOffset len addr entryOffset chksum vers loadAddr devOffset+len\n");
1578 for (i = 0 ; i < ipod->nimages; i++) {
1579 printf("%d - %s 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n",i,
1580 ftypename[ipod->ipod_directory[i].ftype],
1581 ipod->ipod_directory[i].id,
1582 ipod->ipod_directory[i].devOffset,
1583 ipod->ipod_directory[i].len,
1584 ipod->ipod_directory[i].addr,
1585 ipod->ipod_directory[i].entryOffset,
1586 ipod->ipod_directory[i].chksum,
1587 ipod->ipod_directory[i].vers,
1588 ipod->ipod_directory[i].loadAddr,
1589 ipod->ipod_directory[i].devOffset+((ipod->ipod_directory[i].len+ipod->sector_size-1)&~(ipod->sector_size-1)));
1593 printf("\n");
1594 printf("Listing firmware partition contents:\n");
1595 printf("\n");
1597 for (i = 0 ; i < ipod->nimages; i++) {
1598 printf("Image %d:\n",i+1);
1599 switch(ipod->ipod_directory[i].ftype) {
1600 case FTYPE_OSOS:
1601 if (ipod->ipod_directory[i].entryOffset==0) {
1602 printf(" Main firmware - %d bytes\n",
1603 ipod->ipod_directory[i].len);
1604 } else {
1605 printf(" Main firmware - %d bytes\n",
1606 ipod->ipod_directory[i].entryOffset);
1607 printf(" Third-party bootloader - %d bytes\n",
1608 ipod->ipod_directory[i].len-ipod->ipod_directory[i].entryOffset);
1610 break;
1611 default:
1612 printf(" %s - %d bytes\n",
1613 ftypename[ipod->ipod_directory[i].ftype],
1614 ipod->ipod_directory[i].len);
1617 printf("\n");
1619 return 0;
1622 int getmodel(struct ipod_t* ipod, int ipod_version)
1624 switch (ipod_version) {
1625 case 0x01:
1626 ipod->modelstr="1st or 2nd Generation";
1627 ipod->modelnum = 19;
1628 ipod->modelname = "1g2g";
1629 ipod->targetname = "ipod1g2g";
1630 #ifdef WITH_BOOTOBJS
1631 ipod->bootloader = ipod1g2g;
1632 ipod->bootloader_len = LEN_ipod1g2g;
1633 #endif
1634 break;
1635 case 0x02:
1636 ipod->modelstr="3rd Generation";
1637 ipod->modelnum = 7;
1638 ipod->modelname = "ip3g";
1639 ipod->targetname = "ipod3g";
1640 #ifdef WITH_BOOTOBJS
1641 ipod->bootloader = ipod3g;
1642 ipod->bootloader_len = LEN_ipod3g;
1643 #endif
1644 break;
1645 case 0x40:
1646 ipod->modelstr="1st Generation Mini";
1647 ipod->modelnum = 9;
1648 ipod->modelname = "mini";
1649 ipod->targetname = "ipodmini1g";
1650 #ifdef WITH_BOOTOBJS
1651 ipod->bootloader = ipodmini1g;
1652 ipod->bootloader_len = LEN_ipodmini1g;
1653 #endif
1654 break;
1655 case 0x50:
1656 ipod->modelstr="4th Generation";
1657 ipod->modelnum = 8;
1658 ipod->modelname = "ip4g";
1659 ipod->targetname = "ipod4gray";
1660 #ifdef WITH_BOOTOBJS
1661 ipod->bootloader = ipod4g;
1662 ipod->bootloader_len = LEN_ipod4g;
1663 #endif
1664 break;
1665 case 0x60:
1666 ipod->modelstr="Photo/Color";
1667 ipod->modelnum = 3;
1668 ipod->modelname = "ipco";
1669 ipod->targetname = "ipodcolor";
1670 #ifdef WITH_BOOTOBJS
1671 ipod->bootloader = ipodcolor;
1672 ipod->bootloader_len = LEN_ipodcolor;
1673 #endif
1674 break;
1675 case 0x70:
1676 ipod->modelstr="2nd Generation Mini";
1677 ipod->modelnum = 11;
1678 ipod->modelname = "mn2g";
1679 ipod->targetname = "ipodmini2g";
1680 #ifdef WITH_BOOTOBJS
1681 ipod->bootloader = ipodmini2g;
1682 ipod->bootloader_len = LEN_ipodmini2g;
1683 #endif
1684 break;
1685 case 0xc0:
1686 ipod->modelstr="1st Generation Nano";
1687 ipod->modelnum = 4;
1688 ipod->modelname = "nano";
1689 ipod->targetname = "ipodnano1g";
1690 #ifdef WITH_BOOTOBJS
1691 ipod->bootloader = ipodnano1g;
1692 ipod->bootloader_len = LEN_ipodnano1g;
1693 #endif
1694 break;
1695 case 0xb0:
1696 ipod->modelstr="Video (aka 5th Generation)";
1697 ipod->modelnum = 5;
1698 ipod->modelname = "ipvd";
1699 if(ipod->ramsize == 64) {
1700 ipod->targetname = "ipodvideo64mb";
1702 else {
1703 ipod->targetname = "ipodvideo";
1705 #ifdef WITH_BOOTOBJS
1706 ipod->bootloader = ipodvideo;
1707 ipod->bootloader_len = LEN_ipodvideo;
1708 #endif
1709 break;
1710 case 0x100:
1711 ipod->modelstr="2nd Generation Nano";
1712 ipod->modelnum = 62;
1713 ipod->modelname = "nn2x";
1714 ipod->targetname = "ipodnano2g";
1715 #ifdef WITH_BOOTOBJS
1716 ipod->bootloader = ipodnano2g;
1717 ipod->bootloader_len = LEN_ipodnano2g;
1718 #endif
1719 break;
1720 default:
1721 ipod->modelname = NULL;
1722 ipod->modelnum = 0;
1723 ipod->targetname = NULL;
1724 #ifdef WITH_BOOTOBJS
1725 ipod->bootloader = NULL;
1726 ipod->bootloader_len = 0;
1727 #endif
1728 return -1;
1730 return 0;
1733 /* returns number of found ipods or -1 if no ipods found and permission
1734 * for raw disc access was denied. */
1735 int ipod_scan(struct ipod_t* ipod)
1737 int i;
1738 int n = 0;
1739 int ipod_version;
1740 struct ipod_t ipod_found;
1741 int denied = 0;
1742 int result;
1744 printf("[INFO] Scanning disk devices...\n");
1746 for (i = 0; i <= 25 ; i++) {
1747 #ifdef __WIN32__
1748 sprintf(ipod->diskname,"\\\\.\\PhysicalDrive%d",i);
1749 #elif defined(linux) || defined (__linux)
1750 sprintf(ipod->diskname,"/dev/sd%c",'a'+i);
1751 #elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) \
1752 || defined(__bsdi__) || defined(__DragonFly__)
1753 sprintf(ipod->diskname,"/dev/da%d",i);
1754 #elif defined(__APPLE__) && defined(__MACH__)
1755 sprintf(ipod->diskname,"/dev/disk%d",i);
1756 #else
1757 #error No disk paths defined for this platform
1758 #endif
1759 if ((result = ipod_open(ipod, 1)) < 0) {
1760 if(result == -2) {
1761 denied++;
1763 ipod_close(ipod);
1764 continue;
1767 if (read_partinfo(ipod,1) < 0) {
1768 ipod_close(ipod);
1769 continue;
1772 if ((ipod->pinfo[0].start==0) || (ipod->pinfo[0].type != 0)) {
1773 ipod_close(ipod);
1774 continue;
1777 if (read_directory(ipod) < 0) {
1778 ipod_close(ipod);
1779 continue;
1782 ipod_version=(ipod->ipod_directory[ipod->ososimage].vers>>8);
1783 ipod->ramsize = 0;
1784 #ifdef __WIN32__
1785 /* Windows requires the ipod in R/W mode for SCSI Inquiry.
1786 * ipod_reopen_rw does unmount the player on OS X so do this on
1787 * W32 only during scanning. */
1788 ipod_reopen_rw(ipod);
1789 #endif
1790 ipod_get_xmlinfo(ipod);
1791 ipod_get_ramsize(ipod);
1792 if (getmodel(ipod,ipod_version) < 0) {
1793 ipod_close(ipod);
1794 continue;
1797 #ifdef __WIN32__
1798 printf("[INFO] Ipod found - %s (\"%s\") - disk device %d\n",
1799 ipod->modelstr,ipod->macpod ? "macpod" : "winpod",i);
1800 #else
1801 printf("[INFO] Ipod found - %s (\"%s\") - %s\n",
1802 ipod->modelstr,ipod->macpod ? "macpod" : "winpod",ipod->diskname);
1803 #endif
1804 n++;
1805 /* save the complete ipod_t structure for match. The for loop might
1806 * overwrite it, so we need to restore it later if only one found. */
1807 memcpy(&ipod_found, ipod, sizeof(struct ipod_t));
1808 ipod_close(ipod);
1811 if (n==1) {
1812 /* restore the ipod_t structure, it might have been overwritten */
1813 memcpy(ipod, &ipod_found, sizeof(struct ipod_t));
1815 else if(n == 0 && denied) {
1816 printf("[ERR] FATAL: Permission denied on %d device(s) and no ipod detected.\n", denied);
1817 #ifdef __WIN32__
1818 printf("[ERR] You need to run this program with administrator priviledges!\n");
1819 #else
1820 printf("[ERR] You need permissions for raw disc access for this program to work!\n");
1821 #endif
1823 return (n == 0 && denied) ? -1 : n;
1826 static void put_int32le(uint32_t x, unsigned char* p)
1828 p[0] = x & 0xff;
1829 p[1] = (x >> 8) & 0xff;
1830 p[2] = (x >> 16) & 0xff;
1831 p[3] = (x >> 24) & 0xff;
1834 int write_dos_partition_table(struct ipod_t* ipod)
1836 unsigned char* p;
1837 int i, n;
1838 uint32_t type;
1840 /* Only support 512-byte sectors at the moment */
1841 if ( ipod->sector_size != 512 )
1843 fprintf(stderr,"[ERR] Only ipods with 512 bytes per sector are supported.\n");
1844 return -1;
1847 /* Firstly zero the entire MBR */
1848 memset(ipod_sectorbuf, 0, ipod->sector_size);
1850 /* Now add the partition info */
1851 for (i=0; i < 4 ; i++)
1853 p = ipod_sectorbuf + 0x1be + i*16;
1855 /* Ensure first partition is type 0, and second is 0xb */
1856 if (i==0) { type = 0; }
1857 else if (i==1) { type = 0xb; }
1858 else { type = ipod->pinfo[i].type; }
1860 put_int32le(type, p + 4);
1861 put_int32le(ipod->pinfo[i].start, p + 8);
1862 put_int32le(ipod->pinfo[i].size, p + 12);
1865 /* Finally add the magic */
1866 ipod_sectorbuf[0x1fe] = 0x55;
1867 ipod_sectorbuf[0x1ff] = 0xaa;
1869 if (ipod_seek(ipod, 0) < 0) {
1870 fprintf(stderr,"[ERR] Seek failed writing MBR\n");
1871 return -1;
1874 /* Write MBR */
1875 if ((n = ipod_write(ipod, ipod_sectorbuf, ipod->sector_size)) < 0) {
1876 perror("[ERR] Write failed\n");
1877 return -1;
1880 return 0;
1883 /* Get the XML Device Information, as documented here:
1885 http://www.ipodlinux.org/wiki/Device_Information
1888 int ipod_get_xmlinfo(struct ipod_t* ipod)
1890 unsigned char hdr[255];
1891 unsigned char buf[255];
1892 char* p;
1893 int psize;
1894 int npages;
1895 int i;
1897 if (ipod_scsi_inquiry(ipod, 0xc0, buf, sizeof(buf)) < 0)
1899 fprintf(stderr,"[ERR] Sending SCSI Command failed.\n");
1900 return -1;
1903 /* Reading directly into hdr[] causes problems (for an unknown reason) on
1904 win32 */
1905 memcpy(hdr, buf, sizeof(hdr));
1907 npages = hdr[3];
1909 psize = npages * 0xf8; /* Hopefully this is enough. */
1911 ipod->xmlinfo = malloc(psize);
1912 ipod->xmlinfo_len = 0;
1914 if (ipod->xmlinfo == NULL) {
1915 fprintf(stderr,"[ERR] Could not allocate RAM for xmlinfo\n");
1916 return -1;
1919 p = ipod->xmlinfo;
1921 for (i=0; i < npages; i++) {
1922 if (ipod_scsi_inquiry(ipod, hdr[i+4], buf, sizeof(buf)) < 0) {
1923 fprintf(stderr,"[ERR] Sending SCSI Command failed.\n");
1924 return -1;
1927 if ((buf[3] + ipod->xmlinfo_len) > psize) {
1928 fprintf(stderr,"[ERR] Ran out of memory reading xmlinfo\n");
1929 free(ipod->xmlinfo);
1930 ipod->xmlinfo = NULL;
1931 ipod->xmlinfo_len = 0;
1932 return -1;
1935 memcpy(p, buf + 4, buf[3]);
1936 p += buf[3];
1937 ipod->xmlinfo_len += buf[3];
1940 /* NULL-terminate the XML info */
1941 *p = 0;
1943 fprintf(stderr,"[INFO] Read XML info (%d bytes)\n",ipod->xmlinfo_len);
1945 return 0;
1948 void ipod_get_ramsize(struct ipod_t* ipod)
1950 const char needle[] = "<key>RAM</key>\n<integer>";
1951 char* p;
1953 if (ipod->xmlinfo == NULL)
1954 return;
1956 p = strstr(ipod->xmlinfo, needle);
1958 if (p) {
1959 ipod->ramsize = atoi(p + sizeof(needle) - 1);
1963 #ifndef RBUTIL
1965 static inline uint32_t getuint32le(unsigned char* buf)
1967 int32_t res = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
1969 return res;
1972 /* testMarker and GetSecurityBlockKey based on code from BadBlocks and
1973 Kingstone, posted at http://ipodlinux.org/Flash_Decryption
1977 static bool testMarker(int marker)
1979 int mask, decrypt, temp1, temp2;
1981 mask = (marker&0xff)|((marker&0xff)<<8)|((marker&0xff)<<16)|((marker&0xff)<<24);
1982 decrypt = marker ^ mask;
1983 temp1=(int)((unsigned int)decrypt>>24);
1984 temp2=decrypt<<8;
1986 if (temp1==0)
1987 return false;
1989 temp2=(int)((unsigned int)temp2>>24);
1990 decrypt=decrypt<<16;
1991 decrypt=(int)((unsigned int)decrypt>>24);
1993 if ((temp1 < temp2) && (temp2 < decrypt))
1995 temp1 = temp1 & 0xf;
1996 temp2 = temp2 & 0xf;
1997 decrypt = decrypt & 0xf;
1999 if ((temp1 > temp2) && (temp2 > decrypt) && (decrypt != 0))
2001 return true;
2004 return false;
2007 static int GetSecurityBlockKey(unsigned char *data, unsigned char* this_key)
2009 int constant = 0x54c3a298;
2010 int key=0;
2011 int nkeys = 0;
2012 int aMarker=0;
2013 int pos=0;
2014 int c, count;
2015 int temp1;
2016 static const int offset[8]={0x5,0x25,0x6f,0x69,0x15,0x4d,0x40,0x34};
2018 for (c = 0; c < 8; c++)
2020 pos = offset[c]*4;
2021 aMarker = getuint32le(data + pos);
2023 if (testMarker(aMarker))
2025 if (c<7)
2026 pos =(offset[c+1]*4)+4;
2027 else
2028 pos =(offset[0]*4)+4;
2030 key=0;
2032 temp1=aMarker;
2034 for (count=0;count<2;count++){
2035 int word = getuint32le(data + pos);
2036 temp1 = aMarker;
2037 temp1 = temp1^word;
2038 temp1 = temp1^constant;
2039 key = temp1;
2040 pos = pos+4;
2042 int r1=0x6f;
2043 int r2=0;
2044 int r12;
2045 int r14;
2046 unsigned int r_tmp;
2048 for (count=2;count<128;count=count+2){
2049 r2=getuint32le(data+count*4);
2050 r12=getuint32le(data+(count*4)+4);
2051 r_tmp=(unsigned int)r12>>16;
2052 r14=r2 | ((int)r_tmp);
2053 r2=r2&0xffff;
2054 r2=r2 | r12;
2055 r1=r1^r14;
2056 r1=r1+r2;
2058 key=key^r1;
2060 // Invert key, little endian
2061 this_key[0] = key & 0xff;
2062 this_key[1] = (key >> 8) & 0xff;
2063 this_key[2] = (key >> 16) & 0xff;
2064 this_key[3] = (key >> 24) & 0xff;
2065 nkeys++;
2068 return nkeys;
2071 static int find_key(struct ipod_t* ipod, int aupd, unsigned char* key)
2073 int n;
2075 /* Firstly read the security block and find the RC4 key. This is
2076 in the sector preceeding the AUPD image. */
2078 fprintf(stderr, "[INFO] Reading security block at offset 0x%08x\n",ipod->ipod_directory[aupd].devOffset-ipod->sector_size);
2079 if (ipod_seek(ipod, ipod->fwoffset+ipod->ipod_directory[aupd].devOffset-ipod->sector_size) < 0) {
2080 return -1;
2083 if ((n = ipod_read(ipod, ipod_sectorbuf, 512)) < 0) {
2084 return -1;
2087 n = GetSecurityBlockKey(ipod_sectorbuf, key);
2089 if (n != 1)
2091 fprintf(stderr, "[ERR] %d keys found in security block, can not continue\n",n);
2092 return -1;
2095 return 0;
2098 int read_aupd(struct ipod_t* ipod, char* filename)
2100 int length;
2101 int i;
2102 int outfile;
2103 int n;
2104 int aupd;
2105 struct rc4_key_t rc4;
2106 unsigned char key[4];
2107 unsigned long chksum=0;
2109 aupd = 0;
2110 while ((aupd < ipod->nimages) && (ipod->ipod_directory[aupd].ftype != FTYPE_AUPD))
2112 aupd++;
2115 if (aupd == ipod->nimages)
2117 fprintf(stderr,"[ERR] No AUPD image in firmware partition.\n");
2118 return -1;
2121 length = ipod->ipod_directory[aupd].len;
2123 fprintf(stderr,"[INFO] Reading firmware (%d bytes)\n",length);
2125 if (find_key(ipod, aupd, key) < 0)
2127 return -1;
2130 fprintf(stderr, "[INFO] Decrypting AUPD image with key %02x%02x%02x%02x\n",key[0],key[1],key[2],key[3]);
2132 if (ipod_seek(ipod, ipod->fwoffset+ipod->ipod_directory[aupd].devOffset) < 0) {
2133 return -1;
2136 i = (length+ipod->sector_size-1) & ~(ipod->sector_size-1);
2138 if ((n = ipod_read(ipod,ipod_sectorbuf,i)) < 0) {
2139 return -1;
2142 if (n < i) {
2143 fprintf(stderr,"[ERR] Short read - requested %d bytes, received %d\n",
2144 i,n);
2145 return -1;
2148 /* Perform the decryption - this is standard (A)RC4 */
2149 matrixArc4Init(&rc4, key, 4);
2150 matrixArc4(&rc4, ipod_sectorbuf, ipod_sectorbuf, length);
2152 chksum = 0;
2153 for (i = 0; i < (int)length; i++) {
2154 /* add 8 unsigned bits but keep a 32 bit sum */
2155 chksum += ipod_sectorbuf[i];
2158 if (chksum != ipod->ipod_directory[aupd].chksum)
2160 fprintf(stderr,"[ERR] Decryption failed - checksum error\n");
2161 return -1;
2163 fprintf(stderr,"[INFO] Decrypted OK (checksum matches header)\n");
2165 outfile = open(filename,O_CREAT|O_TRUNC|O_WRONLY|O_BINARY,0666);
2166 if (outfile < 0) {
2167 fprintf(stderr,"[ERR] Couldn't open file %s\n",filename);
2168 return -1;
2171 n = write(outfile,ipod_sectorbuf,length);
2172 if (n != length) {
2173 fprintf(stderr,"[ERR] Write error - %d\n",n);
2175 close(outfile);
2177 return 0;
2180 int write_aupd(struct ipod_t* ipod, char* filename)
2182 unsigned int length;
2183 int i;
2184 int x;
2185 int n;
2186 int infile;
2187 int newsize;
2188 int aupd;
2189 unsigned long chksum=0;
2190 struct rc4_key_t rc4;
2191 unsigned char key[4];
2193 /* First check that the input file is the correct type for this ipod. */
2194 infile=open(filename,O_RDONLY);
2195 if (infile < 0) {
2196 fprintf(stderr,"[ERR] Couldn't open input file %s\n",filename);
2197 return -1;
2200 length = filesize(infile);
2201 newsize=(length+ipod->sector_size-1)&~(ipod->sector_size-1);
2203 fprintf(stderr,"[INFO] Padding input file from 0x%08x to 0x%08x bytes\n",
2204 length,newsize);
2206 if (newsize > BUFFER_SIZE) {
2207 fprintf(stderr,"[ERR] Input file too big for buffer\n");
2208 if (infile >= 0) close(infile);
2209 return -1;
2212 /* Find aupd image number */
2213 aupd = 0;
2214 while ((aupd < ipod->nimages) && (ipod->ipod_directory[aupd].ftype != FTYPE_AUPD))
2216 aupd++;
2219 if (aupd == ipod->nimages)
2221 fprintf(stderr,"[ERR] No AUPD image in firmware partition.\n");
2222 return -1;
2225 if (length != ipod->ipod_directory[aupd].len)
2227 fprintf(stderr,"[ERR] AUPD image (%d bytes) differs in size to %s (%d bytes).\n",
2228 ipod->ipod_directory[aupd].len, filename, length);
2229 return -1;
2232 if (find_key(ipod, aupd, key) < 0)
2234 return -1;
2237 fprintf(stderr, "[INFO] Encrypting AUPD image with key %02x%02x%02x%02x\n",key[0],key[1],key[2],key[3]);
2239 /* We now know we have enough space, so write it. */
2241 fprintf(stderr,"[INFO] Reading input file...\n");
2242 n = read(infile,ipod_sectorbuf,length);
2243 if (n < 0) {
2244 fprintf(stderr,"[ERR] Couldn't read input file\n");
2245 close(infile);
2246 return -1;
2248 close(infile);
2250 /* Pad the data with zeros */
2251 memset(ipod_sectorbuf+length,0,newsize-length);
2253 /* Calculate the new checksum (before we encrypt) */
2254 chksum = 0;
2255 for (i = 0; i < (int)length; i++) {
2256 /* add 8 unsigned bits but keep a 32 bit sum */
2257 chksum += ipod_sectorbuf[i];
2260 /* Perform the encryption - this is standard (A)RC4 */
2261 matrixArc4Init(&rc4, key, 4);
2262 matrixArc4(&rc4, ipod_sectorbuf, ipod_sectorbuf, length);
2264 if (ipod_seek(ipod, ipod->fwoffset+ipod->ipod_directory[aupd].devOffset) < 0) {
2265 fprintf(stderr,"[ERR] Seek failed\n");
2266 return -1;
2269 if ((n = ipod_write(ipod,ipod_sectorbuf,newsize)) < 0) {
2270 perror("[ERR] Write failed\n");
2271 return -1;
2274 if (n < newsize) {
2275 fprintf(stderr,"[ERR] Short write - requested %d bytes, received %d\n"
2276 ,newsize,n);
2277 return -1;
2279 fprintf(stderr,"[INFO] Wrote %d bytes to firmware partition\n",n);
2281 x = ipod->diroffset % ipod->sector_size;
2283 /* Read directory */
2284 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; }
2286 n=ipod_read(ipod, ipod_sectorbuf, ipod->sector_size);
2287 if (n < 0) { return -1; }
2289 /* Update checksum */
2290 fprintf(stderr,"[INFO] Updating checksum to 0x%08x (was 0x%08x)\n",(unsigned int)chksum,le2int(ipod_sectorbuf + x + aupd*40 + 28));
2291 int2le(chksum,ipod_sectorbuf+x+aupd*40+28);
2293 /* Write directory */
2294 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; }
2295 n=ipod_write(ipod, ipod_sectorbuf, ipod->sector_size);
2296 if (n < 0) { return -1; }
2298 return 0;
2301 #endif