diff options
Diffstat (limited to 'rbutil/ipodpatcher/ipodpatcher.c')
-rw-r--r-- | rbutil/ipodpatcher/ipodpatcher.c | 1261 |
1 files changed, 1261 insertions, 0 deletions
diff --git a/rbutil/ipodpatcher/ipodpatcher.c b/rbutil/ipodpatcher/ipodpatcher.c new file mode 100644 index 0000000000..6c60bae38d --- /dev/null +++ b/rbutil/ipodpatcher/ipodpatcher.c | |||
@@ -0,0 +1,1261 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2006-2007 Dave Chapman | ||
11 | * | ||
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. | ||
14 | * | ||
15 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
16 | * KIND, either express or implied. | ||
17 | * | ||
18 | ****************************************************************************/ | ||
19 | |||
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> | ||
28 | |||
29 | #include "parttypes.h" | ||
30 | #include "ipodio.h" | ||
31 | #include "ipodpatcher.h" | ||
32 | |||
33 | #ifdef WITH_BOOTOBJS | ||
34 | #include "ipod3g.h" | ||
35 | #include "ipod4g.h" | ||
36 | #include "ipodmini.h" | ||
37 | #include "ipodmini2g.h" | ||
38 | #include "ipodcolor.h" | ||
39 | #include "ipodnano.h" | ||
40 | #include "ipodvideo.h" | ||
41 | #endif | ||
42 | |||
43 | extern int verbose; | ||
44 | |||
45 | unsigned char* sectorbuf; | ||
46 | |||
47 | /* The following string appears at the start of the firmware partition */ | ||
48 | static const char *apple_stop_sign = "{{~~ /-----\\ "\ | ||
49 | "{{~~ / \\ "\ | ||
50 | "{{~~| | "\ | ||
51 | "{{~~| S T O P | "\ | ||
52 | "{{~~| | "\ | ||
53 | "{{~~ \\ / "\ | ||
54 | "{{~~ \\-----/ "\ | ||
55 | "Copyright(C) 200"\ | ||
56 | "1 Apple Computer"\ | ||
57 | ", Inc.----------"\ | ||
58 | "----------------"\ | ||
59 | "----------------"\ | ||
60 | "----------------"\ | ||
61 | "----------------"\ | ||
62 | "----------------"\ | ||
63 | "---------------"; | ||
64 | |||
65 | /* Windows requires the buffer for disk I/O to be aligned in memory on a | ||
66 | multiple of the disk volume size - so we use a single global variable | ||
67 | and initialise it with ipod_alloc_buf() | ||
68 | */ | ||
69 | |||
70 | char* get_parttype(int pt) | ||
71 | { | ||
72 | int i; | ||
73 | static char unknown[]="Unknown"; | ||
74 | |||
75 | if (pt == -1) { | ||
76 | return "HFS/HFS+"; | ||
77 | } | ||
78 | |||
79 | i=0; | ||
80 | while (parttypes[i].name != NULL) { | ||
81 | if (parttypes[i].type == pt) { | ||
82 | return (parttypes[i].name); | ||
83 | } | ||
84 | i++; | ||
85 | } | ||
86 | |||
87 | return unknown; | ||
88 | } | ||
89 | |||
90 | off_t filesize(int fd) { | ||
91 | struct stat buf; | ||
92 | |||
93 | if (fstat(fd,&buf) < 0) { | ||
94 | perror("[ERR] Checking filesize of input file"); | ||
95 | return -1; | ||
96 | } else { | ||
97 | return(buf.st_size); | ||
98 | } | ||
99 | } | ||
100 | |||
101 | /* Partition table parsing code taken from Rockbox */ | ||
102 | |||
103 | #define MAX_SECTOR_SIZE 2048 | ||
104 | #define SECTOR_SIZE 512 | ||
105 | |||
106 | unsigned short static inline le2ushort(unsigned char* buf) | ||
107 | { | ||
108 | unsigned short res = (buf[1] << 8) | buf[0]; | ||
109 | |||
110 | return res; | ||
111 | } | ||
112 | |||
113 | int static inline le2int(unsigned char* buf) | ||
114 | { | ||
115 | int32_t res = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; | ||
116 | |||
117 | return res; | ||
118 | } | ||
119 | |||
120 | int static inline be2int(unsigned char* buf) | ||
121 | { | ||
122 | int32_t res = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; | ||
123 | |||
124 | return res; | ||
125 | } | ||
126 | |||
127 | int static inline getint16le(char* buf) | ||
128 | { | ||
129 | int16_t res = (buf[1] << 8) | buf[0]; | ||
130 | |||
131 | return res; | ||
132 | } | ||
133 | |||
134 | void static inline short2le(unsigned short val, unsigned char* addr) | ||
135 | { | ||
136 | addr[0] = val & 0xFF; | ||
137 | addr[1] = (val >> 8) & 0xff; | ||
138 | } | ||
139 | |||
140 | void static inline int2le(unsigned int val, unsigned char* addr) | ||
141 | { | ||
142 | addr[0] = val & 0xFF; | ||
143 | addr[1] = (val >> 8) & 0xff; | ||
144 | addr[2] = (val >> 16) & 0xff; | ||
145 | addr[3] = (val >> 24) & 0xff; | ||
146 | } | ||
147 | |||
148 | void int2be(unsigned int val, unsigned char* addr) | ||
149 | { | ||
150 | addr[0] = (val >> 24) & 0xff; | ||
151 | addr[1] = (val >> 16) & 0xff; | ||
152 | addr[2] = (val >> 8) & 0xff; | ||
153 | addr[3] = val & 0xFF; | ||
154 | } | ||
155 | |||
156 | |||
157 | #define BYTES2INT32(array,pos)\ | ||
158 | ((long)array[pos] | ((long)array[pos+1] << 8 ) |\ | ||
159 | ((long)array[pos+2] << 16 ) | ((long)array[pos+3] << 24 )) | ||
160 | |||
161 | void display_partinfo(struct ipod_t* ipod) | ||
162 | { | ||
163 | int i; | ||
164 | double sectors_per_MB = (1024.0*1024.0)/ipod->sector_size; | ||
165 | |||
166 | printf("[INFO] Part Start Sector End Sector Size (MB) Type\n"); | ||
167 | for ( i = 0; i < 4; i++ ) { | ||
168 | if (ipod->pinfo[i].start != 0) { | ||
169 | printf("[INFO] %d %10ld %10ld %10.1f %s (0x%02x)\n", | ||
170 | i, | ||
171 | ipod->pinfo[i].start, | ||
172 | ipod->pinfo[i].start+ipod->pinfo[i].size-1, | ||
173 | ipod->pinfo[i].size/sectors_per_MB, | ||
174 | get_parttype(ipod->pinfo[i].type), | ||
175 | ipod->pinfo[i].type); | ||
176 | } | ||
177 | } | ||
178 | } | ||
179 | |||
180 | int read_partinfo(struct ipod_t* ipod, int silent) | ||
181 | { | ||
182 | int i; | ||
183 | unsigned long count; | ||
184 | |||
185 | count = ipod_read(ipod,sectorbuf, ipod->sector_size); | ||
186 | |||
187 | if (count <= 0) { | ||
188 | print_error(" Error reading from disk: "); | ||
189 | return -1; | ||
190 | } | ||
191 | |||
192 | if ((sectorbuf[510] == 0x55) && (sectorbuf[511] == 0xaa)) { | ||
193 | /* DOS partition table */ | ||
194 | if ((memcmp(§orbuf[71],"iPod",4) != 0) && | ||
195 | (memcmp(§orbuf[0x40],"This is your Apple iPod. You probably do not want to boot from it!",66) != 0) ) { | ||
196 | if (!silent) fprintf(stderr,"[ERR] Drive is not an iPod, aborting\n"); | ||
197 | return -1; | ||
198 | } | ||
199 | |||
200 | ipod->macpod = 0; | ||
201 | /* parse partitions */ | ||
202 | for ( i = 0; i < 4; i++ ) { | ||
203 | unsigned char* ptr = sectorbuf + 0x1be + 16*i; | ||
204 | ipod->pinfo[i].type = ptr[4]; | ||
205 | ipod->pinfo[i].start = BYTES2INT32(ptr, 8); | ||
206 | ipod->pinfo[i].size = BYTES2INT32(ptr, 12); | ||
207 | |||
208 | /* extended? */ | ||
209 | if ( ipod->pinfo[i].type == 5 ) { | ||
210 | /* not handled yet */ | ||
211 | } | ||
212 | } | ||
213 | } else if ((sectorbuf[0] == 'E') && (sectorbuf[1] == 'R')) { | ||
214 | /* Apple Partition Map */ | ||
215 | |||
216 | /* APM parsing code based on the check_mac_partitions() function in | ||
217 | ipodloader2 - written by Thomas Tempelmann and released | ||
218 | under the GPL. */ | ||
219 | |||
220 | int blkNo = 1; | ||
221 | int partBlkCount = 1; | ||
222 | int partBlkSizMul = sectorbuf[2] / 2; | ||
223 | |||
224 | int pmMapBlkCnt; /* # of blks in partition map */ | ||
225 | int pmPyPartStart; /* physical start blk of partition */ | ||
226 | int pmPartBlkCnt; /* # of blks in this partition */ | ||
227 | int i = 0; | ||
228 | |||
229 | ipod->macpod = 1; | ||
230 | |||
231 | memset(ipod->pinfo,0,sizeof(ipod->pinfo)); | ||
232 | |||
233 | while (blkNo <= partBlkCount) { | ||
234 | if (ipod_seek(ipod, blkNo * partBlkSizMul * 512) < 0) { | ||
235 | fprintf(stderr,"[ERR] Seek failed whilst reading APM\n"); | ||
236 | return -1; | ||
237 | } | ||
238 | |||
239 | count = ipod_read(ipod, sectorbuf, ipod->sector_size); | ||
240 | |||
241 | if (count <= 0) { | ||
242 | print_error(" Error reading from disk: "); | ||
243 | return -1; | ||
244 | } | ||
245 | |||
246 | /* see if it's a partition entry */ | ||
247 | if ((sectorbuf[0] != 'P') || (sectorbuf[1] != 'M')) { | ||
248 | /* end of partition table -> leave the loop */ | ||
249 | break; | ||
250 | } | ||
251 | |||
252 | /* Extract the interesting entries */ | ||
253 | pmMapBlkCnt = be2int(sectorbuf + 4); | ||
254 | pmPyPartStart = be2int(sectorbuf + 8); | ||
255 | pmPartBlkCnt = be2int(sectorbuf + 12); | ||
256 | |||
257 | /* update the number of part map blocks */ | ||
258 | partBlkCount = pmMapBlkCnt; | ||
259 | |||
260 | if (strncmp((char*)(sectorbuf + 48), "Apple_MDFW", 32)==0) { | ||
261 | /* A Firmware partition */ | ||
262 | ipod->pinfo[i].start = pmPyPartStart; | ||
263 | ipod->pinfo[i].size = pmPartBlkCnt; | ||
264 | ipod->pinfo[i].type = 0; | ||
265 | i++; | ||
266 | } else if (strncmp((char*)(sectorbuf + 48), "Apple_HFS", 32)==0) { | ||
267 | /* A HFS partition */ | ||
268 | ipod->pinfo[i].start = pmPyPartStart; | ||
269 | ipod->pinfo[i].size = pmPartBlkCnt; | ||
270 | ipod->pinfo[i].type = -1; | ||
271 | i++; | ||
272 | } | ||
273 | |||
274 | blkNo++; /* read next partition map entry */ | ||
275 | } | ||
276 | } else { | ||
277 | if (!silent) fprintf(stderr,"[ERR] Bad boot sector signature\n"); | ||
278 | return -1; | ||
279 | } | ||
280 | |||
281 | ipod->start = ipod->pinfo[0].start*ipod->sector_size; | ||
282 | return 0; | ||
283 | } | ||
284 | |||
285 | int read_partition(struct ipod_t* ipod, int outfile) | ||
286 | { | ||
287 | int res; | ||
288 | unsigned long n; | ||
289 | int bytesleft; | ||
290 | int chunksize; | ||
291 | int count = ipod->pinfo[0].size; | ||
292 | |||
293 | if (ipod_seek(ipod, ipod->start) < 0) { | ||
294 | return -1; | ||
295 | } | ||
296 | |||
297 | fprintf(stderr,"[INFO] Writing %d sectors to output file\n",count); | ||
298 | |||
299 | bytesleft = count * ipod->sector_size; | ||
300 | while (bytesleft > 0) { | ||
301 | if (bytesleft > BUFFER_SIZE) { | ||
302 | chunksize = BUFFER_SIZE; | ||
303 | } else { | ||
304 | chunksize = bytesleft; | ||
305 | } | ||
306 | |||
307 | n = ipod_read(ipod, sectorbuf, chunksize); | ||
308 | |||
309 | if (n < 0) { | ||
310 | return -1; | ||
311 | } | ||
312 | |||
313 | if (n < chunksize) { | ||
314 | fprintf(stderr, | ||
315 | "[ERR] Short read in disk_read() - requested %d, got %lu\n", | ||
316 | chunksize,n); | ||
317 | return -1; | ||
318 | } | ||
319 | |||
320 | bytesleft -= n; | ||
321 | |||
322 | res = write(outfile,sectorbuf,n); | ||
323 | |||
324 | if (res < 0) { | ||
325 | perror("[ERR] write in disk_read"); | ||
326 | return -1; | ||
327 | } | ||
328 | |||
329 | if (res != n) { | ||
330 | fprintf(stderr, | ||
331 | "Short write - requested %lu, received %d - aborting.\n",n,res); | ||
332 | return -1; | ||
333 | } | ||
334 | } | ||
335 | |||
336 | fprintf(stderr,"[INFO] Done.\n"); | ||
337 | return 0; | ||
338 | } | ||
339 | |||
340 | int write_partition(struct ipod_t* ipod, int infile) | ||
341 | { | ||
342 | unsigned long res; | ||
343 | int n; | ||
344 | int bytesread; | ||
345 | int byteswritten = 0; | ||
346 | int eof; | ||
347 | int padding = 0; | ||
348 | |||
349 | if (ipod_seek(ipod, ipod->start) < 0) { | ||
350 | return -1; | ||
351 | } | ||
352 | |||
353 | fprintf(stderr,"[INFO] Writing input file to device\n"); | ||
354 | bytesread = 0; | ||
355 | eof = 0; | ||
356 | while (!eof) { | ||
357 | n = read(infile,sectorbuf,BUFFER_SIZE); | ||
358 | |||
359 | if (n < 0) { | ||
360 | perror("[ERR] read in disk_write"); | ||
361 | return -1; | ||
362 | } | ||
363 | |||
364 | if (n < BUFFER_SIZE) { | ||
365 | eof = 1; | ||
366 | /* We need to pad the last write to a multiple of SECTOR_SIZE */ | ||
367 | if ((n % ipod->sector_size) != 0) { | ||
368 | padding = (ipod->sector_size-(n % ipod->sector_size)); | ||
369 | n += padding; | ||
370 | } | ||
371 | } | ||
372 | |||
373 | bytesread += n; | ||
374 | |||
375 | res = ipod_write(ipod, sectorbuf, n); | ||
376 | |||
377 | if (res < 0) { | ||
378 | print_error(" Error writing to disk: "); | ||
379 | fprintf(stderr,"Bytes written: %d\n",byteswritten); | ||
380 | return -1; | ||
381 | } | ||
382 | |||
383 | if (res != n) { | ||
384 | fprintf(stderr,"[ERR] Short write - requested %d, received %lu - aborting.\n",n,res); | ||
385 | return -1; | ||
386 | } | ||
387 | |||
388 | byteswritten += res; | ||
389 | } | ||
390 | |||
391 | fprintf(stderr,"[INFO] Wrote %d bytes plus %d bytes padding.\n", | ||
392 | byteswritten-padding,padding); | ||
393 | return 0; | ||
394 | } | ||
395 | |||
396 | char* ftypename[] = { "OSOS", "RSRC", "AUPD", "HIBE" }; | ||
397 | |||
398 | int diskmove(struct ipod_t* ipod, int delta) | ||
399 | { | ||
400 | int src_start; | ||
401 | int src_end; | ||
402 | int bytesleft; | ||
403 | int chunksize; | ||
404 | int i; | ||
405 | int n; | ||
406 | |||
407 | src_start = ipod->ipod_directory[1].devOffset + ipod->sector_size; | ||
408 | src_end = (ipod->ipod_directory[ipod->nimages-1].devOffset + ipod->sector_size + | ||
409 | ipod->ipod_directory[ipod->nimages-1].len + | ||
410 | (ipod->sector_size-1)) & ~(ipod->sector_size-1); | ||
411 | bytesleft = src_end - src_start; | ||
412 | |||
413 | if (verbose) { | ||
414 | fprintf(stderr,"[INFO] Need to move images 2-%d forward %08x bytes\n", ipod->nimages,delta); | ||
415 | fprintf(stderr,"[VERB] src_start = %08x\n",src_start); | ||
416 | fprintf(stderr,"[VERB] src_end = %08x\n",src_end); | ||
417 | fprintf(stderr,"[VERB] dest_start = %08x\n",src_start+delta); | ||
418 | fprintf(stderr,"[VERB] dest_end = %08x\n",src_end+delta); | ||
419 | fprintf(stderr,"[VERB] bytes to copy = %08x\n",bytesleft); | ||
420 | } | ||
421 | |||
422 | while (bytesleft > 0) { | ||
423 | if (bytesleft <= BUFFER_SIZE) { | ||
424 | chunksize = bytesleft; | ||
425 | } else { | ||
426 | chunksize = BUFFER_SIZE; | ||
427 | } | ||
428 | |||
429 | if (verbose) { | ||
430 | fprintf(stderr,"[VERB] Copying %08x bytes from %08x to %08x (absolute %08x to %08x)\n", | ||
431 | chunksize, | ||
432 | src_end-chunksize, | ||
433 | src_end-chunksize+delta, | ||
434 | (unsigned int)(ipod->start+src_end-chunksize), | ||
435 | (unsigned int)(ipod->start+src_end-chunksize+delta)); | ||
436 | } | ||
437 | |||
438 | |||
439 | if (ipod_seek(ipod, ipod->start+src_end-chunksize) < 0) { | ||
440 | fprintf(stderr,"[ERR] Seek failed\n"); | ||
441 | return -1; | ||
442 | } | ||
443 | |||
444 | if ((n = ipod_read(ipod,sectorbuf,chunksize)) < 0) { | ||
445 | perror("[ERR] Write failed\n"); | ||
446 | return -1; | ||
447 | } | ||
448 | |||
449 | if (n < chunksize) { | ||
450 | fprintf(stderr,"[ERR] Short read - requested %d bytes, received %d\n", | ||
451 | i,n); | ||
452 | return -1; | ||
453 | } | ||
454 | |||
455 | if (ipod_seek(ipod, ipod->start+src_end-chunksize+delta) < 0) { | ||
456 | fprintf(stderr,"[ERR] Seek failed\n"); | ||
457 | return -1; | ||
458 | } | ||
459 | |||
460 | if ((n = ipod_write(ipod,sectorbuf,chunksize)) < 0) { | ||
461 | perror("[ERR] Write failed\n"); | ||
462 | return -1; | ||
463 | } | ||
464 | |||
465 | if (n < chunksize) { | ||
466 | fprintf(stderr,"[ERR] Short write - requested %d bytes, received %d\n" | ||
467 | ,i,n); | ||
468 | return -1; | ||
469 | } | ||
470 | |||
471 | src_end -= chunksize; | ||
472 | bytesleft -= chunksize; | ||
473 | } | ||
474 | |||
475 | return 0; | ||
476 | } | ||
477 | |||
478 | int add_bootloader(struct ipod_t* ipod, char* filename, int type) | ||
479 | { | ||
480 | int length; | ||
481 | int i; | ||
482 | int x; | ||
483 | int n; | ||
484 | int infile; | ||
485 | int paddedlength; | ||
486 | int entryOffset; | ||
487 | int delta = 0; | ||
488 | unsigned long chksum=0; | ||
489 | unsigned long filechksum=0; | ||
490 | unsigned char header[8]; /* Header for .ipod file */ | ||
491 | unsigned char* bootloader_buf; | ||
492 | |||
493 | /* Calculate the position in the OSOS image where our bootloader will go. */ | ||
494 | if (ipod->ipod_directory[0].entryOffset>0) { | ||
495 | /* Keep the same entryOffset */ | ||
496 | entryOffset = ipod->ipod_directory[0].entryOffset; | ||
497 | } else { | ||
498 | entryOffset = (ipod->ipod_directory[0].len+ipod->sector_size-1)&~(ipod->sector_size-1); | ||
499 | } | ||
500 | |||
501 | #ifdef WITH_BOOTOBJS | ||
502 | if (type == FILETYPE_INTERNAL) { | ||
503 | fprintf(stderr,"[INFO] Using internal bootloader - %d bytes\n",ipod->bootloader_len); | ||
504 | memcpy(sectorbuf+entryOffset,ipod->bootloader,ipod->bootloader_len); | ||
505 | length = ipod->bootloader_len; | ||
506 | paddedlength=(ipod->bootloader_len+ipod->sector_size-1)&~(ipod->sector_size-1); | ||
507 | } | ||
508 | else | ||
509 | #endif | ||
510 | { | ||
511 | infile=open(filename,O_RDONLY); | ||
512 | if (infile < 0) { | ||
513 | fprintf(stderr,"[ERR] Couldn't open input file %s\n",filename); | ||
514 | return -1; | ||
515 | } | ||
516 | |||
517 | if (type==FILETYPE_DOT_IPOD) { | ||
518 | /* First check that the input file is the correct type for this ipod. */ | ||
519 | n = read(infile,header,8); | ||
520 | if (n < 8) { | ||
521 | fprintf(stderr,"[ERR] Failed to read header from %s\n",filename); | ||
522 | close(infile); | ||
523 | return -1; | ||
524 | } | ||
525 | |||
526 | if (memcmp(header+4, ipod->modelname,4)!=0) { | ||
527 | fprintf(stderr,"[ERR] Model name in input file (%c%c%c%c) doesn't match ipod model (%s)\n", | ||
528 | header[4],header[5],header[6],header[7], ipod->modelname); | ||
529 | close(infile); | ||
530 | return -1; | ||
531 | } | ||
532 | |||
533 | filechksum = be2int(header); | ||
534 | |||
535 | length=filesize(infile)-8; | ||
536 | } else { | ||
537 | length=filesize(infile); | ||
538 | } | ||
539 | paddedlength=(length+ipod->sector_size-1)&~(ipod->sector_size-1); | ||
540 | |||
541 | bootloader_buf = malloc(length); | ||
542 | if (bootloader_buf == NULL) { | ||
543 | fprintf(stderr,"[ERR] Can not allocate memory for bootlaoder\n"); | ||
544 | } | ||
545 | /* Now read our bootloader - we need to check it before modifying the partition*/ | ||
546 | n = read(infile,bootloader_buf,length); | ||
547 | close(infile); | ||
548 | |||
549 | if (n < 0) { | ||
550 | fprintf(stderr,"[ERR] Couldn't read input file\n"); | ||
551 | return -1; | ||
552 | } | ||
553 | |||
554 | if (type==FILETYPE_DOT_IPOD) { | ||
555 | /* Calculate and confirm bootloader checksum */ | ||
556 | chksum = ipod->modelnum; | ||
557 | for (i = 0; i < length; i++) { | ||
558 | /* add 8 unsigned bits but keep a 32 bit sum */ | ||
559 | chksum += bootloader_buf[i]; | ||
560 | } | ||
561 | |||
562 | if (chksum == filechksum) { | ||
563 | fprintf(stderr,"[INFO] Checksum OK in %s\n",filename); | ||
564 | } else { | ||
565 | fprintf(stderr,"[ERR] Checksum in %s failed check\n",filename); | ||
566 | return -1; | ||
567 | } | ||
568 | } | ||
569 | } | ||
570 | |||
571 | if (entryOffset+paddedlength > BUFFER_SIZE) { | ||
572 | fprintf(stderr,"[ERR] Input file too big for buffer\n"); | ||
573 | return -1; | ||
574 | } | ||
575 | |||
576 | if (verbose) { | ||
577 | fprintf(stderr,"[VERB] Original firmware begins at 0x%08x\n", ipod->ipod_directory[0].devOffset + ipod->sector_size); | ||
578 | fprintf(stderr,"[VERB] New entryOffset will be 0x%08x\n",entryOffset); | ||
579 | fprintf(stderr,"[VERB] End of bootloader will be at 0x%08x\n",entryOffset+paddedlength); | ||
580 | } | ||
581 | |||
582 | /* Check if we have enough space */ | ||
583 | /* TODO: Check the size of the partition. */ | ||
584 | if (ipod->nimages > 1) { | ||
585 | if ((ipod->ipod_directory[0].devOffset+entryOffset+paddedlength) > | ||
586 | ipod->ipod_directory[1].devOffset) { | ||
587 | fprintf(stderr,"[INFO] Moving images to create room for new firmware...\n"); | ||
588 | delta = ipod->ipod_directory[0].devOffset + entryOffset+paddedlength | ||
589 | - ipod->ipod_directory[1].devOffset; | ||
590 | |||
591 | if (diskmove(ipod, delta) < 0) { | ||
592 | fprintf(stderr,"[ERR] Image movement failed.\n"); | ||
593 | return -1; | ||
594 | } | ||
595 | } | ||
596 | } | ||
597 | |||
598 | |||
599 | /* We have moved the partitions, now we can write our bootloader */ | ||
600 | |||
601 | /* Firstly read the original firmware into sectorbuf */ | ||
602 | fprintf(stderr,"[INFO] Reading original firmware...\n"); | ||
603 | if (ipod_seek(ipod, ipod->fwoffset+ipod->ipod_directory[0].devOffset) < 0) { | ||
604 | fprintf(stderr,"[ERR] Seek failed\n"); | ||
605 | return -1; | ||
606 | } | ||
607 | |||
608 | if ((n = ipod_read(ipod,sectorbuf,entryOffset)) < 0) { | ||
609 | perror("[ERR] Read failed\n"); | ||
610 | return -1; | ||
611 | } | ||
612 | |||
613 | if (n < entryOffset) { | ||
614 | fprintf(stderr,"[ERR] Short read - requested %d bytes, received %d\n" | ||
615 | ,i,n); | ||
616 | return -1; | ||
617 | } | ||
618 | |||
619 | #ifdef WITH_BOOTOBJS | ||
620 | if (type == FILETYPE_INTERNAL) { | ||
621 | memcpy(sectorbuf+entryOffset,ipod->bootloader,ipod->bootloader_len); | ||
622 | } | ||
623 | else | ||
624 | #endif | ||
625 | { | ||
626 | memcpy(sectorbuf+entryOffset,bootloader_buf,length); | ||
627 | free(bootloader_buf); | ||
628 | } | ||
629 | |||
630 | /* Calculate new checksum for combined image */ | ||
631 | chksum = 0; | ||
632 | for (i=0;i<entryOffset + length; i++) { | ||
633 | chksum += sectorbuf[i]; | ||
634 | } | ||
635 | |||
636 | /* Now write the combined firmware image to the disk */ | ||
637 | |||
638 | if (ipod_seek(ipod, ipod->fwoffset+ipod->ipod_directory[0].devOffset) < 0) { | ||
639 | fprintf(stderr,"[ERR] Seek failed\n"); | ||
640 | return -1; | ||
641 | } | ||
642 | |||
643 | if ((n = ipod_write(ipod,sectorbuf,entryOffset+paddedlength)) < 0) { | ||
644 | perror("[ERR] Write failed\n"); | ||
645 | return -1; | ||
646 | } | ||
647 | |||
648 | if (n < (entryOffset+paddedlength)) { | ||
649 | fprintf(stderr,"[ERR] Short read - requested %d bytes, received %d\n" | ||
650 | ,i,n); | ||
651 | return -1; | ||
652 | } | ||
653 | |||
654 | fprintf(stderr,"[INFO] Wrote %d bytes to firmware partition\n",entryOffset+paddedlength); | ||
655 | |||
656 | x = ipod->diroffset % ipod->sector_size; | ||
657 | |||
658 | /* Read directory */ | ||
659 | if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { | ||
660 | fprintf(stderr,"[ERR] Seek failed\n"); | ||
661 | return -1; | ||
662 | } | ||
663 | |||
664 | n=ipod_read(ipod, sectorbuf, ipod->sector_size); | ||
665 | if (n < 0) { | ||
666 | fprintf(stderr,"[ERR] Directory read failed\n"); | ||
667 | return -1; | ||
668 | } | ||
669 | |||
670 | /* Update entries for image 0 */ | ||
671 | int2le(entryOffset+length,sectorbuf+x+16); | ||
672 | int2le(entryOffset,sectorbuf+x+24); | ||
673 | int2le(chksum,sectorbuf+x+28); | ||
674 | int2le(0xffffffff,sectorbuf+x+36); /* loadAddr */ | ||
675 | |||
676 | /* Update devOffset entries for other images, if we have moved them */ | ||
677 | if (delta > 0) { | ||
678 | for (i=1;i<ipod->nimages;i++) { | ||
679 | int2le(le2int(sectorbuf+x+i*40+12)+delta,sectorbuf+x+i*40+12); | ||
680 | } | ||
681 | } | ||
682 | |||
683 | /* Write directory */ | ||
684 | if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { | ||
685 | fprintf(stderr,"[ERR] Seek to %d failed\n", (int)(ipod->start+ipod->diroffset-x)); | ||
686 | return -1; | ||
687 | } | ||
688 | n=ipod_write(ipod, sectorbuf, ipod->sector_size); | ||
689 | if (n < 0) { | ||
690 | fprintf(stderr,"[ERR] Directory write failed\n"); | ||
691 | return -1; | ||
692 | } | ||
693 | |||
694 | return 0; | ||
695 | } | ||
696 | |||
697 | int delete_bootloader(struct ipod_t* ipod) | ||
698 | { | ||
699 | int length; | ||
700 | int i; | ||
701 | int x; | ||
702 | int n; | ||
703 | unsigned long chksum=0; /* 32 bit checksum - Rockbox .ipod style*/ | ||
704 | |||
705 | /* Removing the bootloader involves adjusting the "length", | ||
706 | "chksum" and "entryOffset" values in the osos image's directory | ||
707 | entry. */ | ||
708 | |||
709 | /* Firstly check we have a bootloader... */ | ||
710 | |||
711 | if (ipod->ipod_directory[0].entryOffset == 0) { | ||
712 | fprintf(stderr,"[ERR] No bootloader found.\n"); | ||
713 | return -1; | ||
714 | } | ||
715 | |||
716 | length = ipod->ipod_directory[0].entryOffset; | ||
717 | |||
718 | /* Read the firmware so we can calculate the checksum */ | ||
719 | fprintf(stderr,"[INFO] Reading firmware (%d bytes)\n",length); | ||
720 | |||
721 | if (ipod_seek(ipod, ipod->fwoffset+ipod->ipod_directory[0].devOffset) < 0) { | ||
722 | return -1; | ||
723 | } | ||
724 | |||
725 | i = (length+ipod->sector_size-1) & ~(ipod->sector_size-1); | ||
726 | fprintf(stderr,"[INFO] Padding read from 0x%08x to 0x%08x bytes\n", | ||
727 | length,i); | ||
728 | |||
729 | if ((n = ipod_read(ipod,sectorbuf,i)) < 0) { | ||
730 | return -1; | ||
731 | } | ||
732 | |||
733 | if (n < i) { | ||
734 | fprintf(stderr,"[ERR] Short read - requested %d bytes, received %d\n", | ||
735 | i,n); | ||
736 | return -1; | ||
737 | } | ||
738 | |||
739 | chksum = 0; | ||
740 | for (i = 0; i < length; i++) { | ||
741 | /* add 8 unsigned bits but keep a 32 bit sum */ | ||
742 | chksum += sectorbuf[i]; | ||
743 | } | ||
744 | |||
745 | /* Now write back the updated directory entry */ | ||
746 | |||
747 | fprintf(stderr,"[INFO] Updating firmware checksum\n"); | ||
748 | |||
749 | x = ipod->diroffset % ipod->sector_size; | ||
750 | |||
751 | /* Read directory */ | ||
752 | if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; } | ||
753 | |||
754 | n=ipod_read(ipod, sectorbuf, ipod->sector_size); | ||
755 | if (n < 0) { return -1; } | ||
756 | |||
757 | /* Update entries for image 0 */ | ||
758 | int2le(length,sectorbuf+x+16); | ||
759 | int2le(0,sectorbuf+x+24); | ||
760 | int2le(chksum,sectorbuf+x+28); | ||
761 | |||
762 | /* Write directory */ | ||
763 | if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; } | ||
764 | n=ipod_write(ipod, sectorbuf, ipod->sector_size); | ||
765 | if (n < 0) { return -1; } | ||
766 | |||
767 | return 0; | ||
768 | } | ||
769 | |||
770 | int write_firmware(struct ipod_t* ipod, char* filename, int type) | ||
771 | { | ||
772 | int length; | ||
773 | int i; | ||
774 | int x; | ||
775 | int n; | ||
776 | int infile; | ||
777 | int newsize; | ||
778 | int bytesavailable; | ||
779 | unsigned long chksum=0; | ||
780 | unsigned long filechksum=0; | ||
781 | unsigned char header[8]; /* Header for .ipod file */ | ||
782 | |||
783 | /* First check that the input file is the correct type for this ipod. */ | ||
784 | infile=open(filename,O_RDONLY); | ||
785 | if (infile < 0) { | ||
786 | fprintf(stderr,"[ERR] Couldn't open input file %s\n",filename); | ||
787 | return -1; | ||
788 | } | ||
789 | |||
790 | if (type==FILETYPE_DOT_IPOD) { | ||
791 | n = read(infile,header,8); | ||
792 | if (n < 8) { | ||
793 | fprintf(stderr,"[ERR] Failed to read header from %s\n",filename); | ||
794 | close(infile); | ||
795 | return -1; | ||
796 | } | ||
797 | |||
798 | if (memcmp(header+4, ipod->modelname,4)!=0) { | ||
799 | fprintf(stderr,"[ERR] Model name in input file (%c%c%c%c) doesn't match ipod model (%s)\n", | ||
800 | header[4],header[5],header[6],header[7], ipod->modelname); | ||
801 | close(infile); | ||
802 | return -1; | ||
803 | } | ||
804 | |||
805 | filechksum = be2int(header); | ||
806 | |||
807 | length = filesize(infile)-8; | ||
808 | } else { | ||
809 | length = filesize(infile); | ||
810 | } | ||
811 | newsize=(length+ipod->sector_size-1)&~(ipod->sector_size-1); | ||
812 | |||
813 | fprintf(stderr,"[INFO] Padding input file from 0x%08x to 0x%08x bytes\n", | ||
814 | length,newsize); | ||
815 | |||
816 | if (newsize > BUFFER_SIZE) { | ||
817 | fprintf(stderr,"[ERR] Input file too big for buffer\n"); | ||
818 | close(infile); | ||
819 | return -1; | ||
820 | } | ||
821 | |||
822 | /* Check if we have enough space */ | ||
823 | /* TODO: Check the size of the partition. */ | ||
824 | if (ipod->nimages > 1) { | ||
825 | bytesavailable=ipod->ipod_directory[1].devOffset-ipod->ipod_directory[0].devOffset; | ||
826 | if (bytesavailable < newsize) { | ||
827 | fprintf(stderr,"[INFO] Moving images to create room for new firmware...\n"); | ||
828 | |||
829 | /* TODO: Implement image movement */ | ||
830 | fprintf(stderr,"[ERR] Image movement not yet implemented.\n"); | ||
831 | close(infile); | ||
832 | return -1; | ||
833 | } | ||
834 | } | ||
835 | |||
836 | fprintf(stderr,"[INFO] Reading input file...\n"); | ||
837 | /* We now know we have enough space, so write it. */ | ||
838 | memset(sectorbuf+length,0,newsize-length); | ||
839 | n = read(infile,sectorbuf,length); | ||
840 | if (n < 0) { | ||
841 | fprintf(stderr,"[ERR] Couldn't read input file\n"); | ||
842 | close(infile); | ||
843 | return -1; | ||
844 | } | ||
845 | close(infile); | ||
846 | |||
847 | if (type==FILETYPE_DOT_IPOD) { | ||
848 | chksum = ipod->modelnum; | ||
849 | for (i = 0; i < length; i++) { | ||
850 | /* add 8 unsigned bits but keep a 32 bit sum */ | ||
851 | chksum += sectorbuf[i]; | ||
852 | } | ||
853 | |||
854 | if (chksum == filechksum) { | ||
855 | fprintf(stderr,"[INFO] Checksum OK in %s\n",filename); | ||
856 | } else { | ||
857 | fprintf(stderr,"[ERR] Checksum in %s failed check\n",filename); | ||
858 | return -1; | ||
859 | } | ||
860 | } | ||
861 | |||
862 | if (ipod_seek(ipod, ipod->fwoffset+ipod->ipod_directory[0].devOffset) < 0) { | ||
863 | fprintf(stderr,"[ERR] Seek failed\n"); | ||
864 | return -1; | ||
865 | } | ||
866 | |||
867 | if ((n = ipod_write(ipod,sectorbuf,newsize)) < 0) { | ||
868 | perror("[ERR] Write failed\n"); | ||
869 | return -1; | ||
870 | } | ||
871 | |||
872 | if (n < newsize) { | ||
873 | fprintf(stderr,"[ERR] Short write - requested %d bytes, received %d\n" | ||
874 | ,i,n); | ||
875 | return -1; | ||
876 | } | ||
877 | fprintf(stderr,"[INFO] Wrote %d bytes to firmware partition\n",n); | ||
878 | |||
879 | /* Now we need to update the "len", "entryOffset" and "chksum" fields */ | ||
880 | chksum = 0; | ||
881 | for (i = 0; i < length; i++) { | ||
882 | /* add 8 unsigned bits but keep a 32 bit sum */ | ||
883 | chksum += sectorbuf[i]; | ||
884 | } | ||
885 | |||
886 | x = ipod->diroffset % ipod->sector_size; | ||
887 | |||
888 | /* Read directory */ | ||
889 | if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; } | ||
890 | |||
891 | n=ipod_read(ipod, sectorbuf, ipod->sector_size); | ||
892 | if (n < 0) { return -1; } | ||
893 | |||
894 | /* Update entries for image 0 */ | ||
895 | int2le(length,sectorbuf+x+16); | ||
896 | int2le(0,sectorbuf+x+24); | ||
897 | int2le(chksum,sectorbuf+x+28); | ||
898 | |||
899 | /* Write directory */ | ||
900 | if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; } | ||
901 | n=ipod_write(ipod, sectorbuf, ipod->sector_size); | ||
902 | if (n < 0) { return -1; } | ||
903 | |||
904 | return 0; | ||
905 | } | ||
906 | |||
907 | int read_firmware(struct ipod_t* ipod, char* filename) | ||
908 | { | ||
909 | int length; | ||
910 | int i; | ||
911 | int outfile; | ||
912 | int n; | ||
913 | unsigned long chksum=0; /* 32 bit checksum - Rockbox .ipod style*/ | ||
914 | unsigned char header[8]; /* Header for .ipod file */ | ||
915 | |||
916 | if (ipod->ipod_directory[0].entryOffset != 0) { | ||
917 | /* We have a bootloader... */ | ||
918 | length = ipod->ipod_directory[0].entryOffset; | ||
919 | } else { | ||
920 | length = ipod->ipod_directory[0].len; | ||
921 | } | ||
922 | |||
923 | fprintf(stderr,"[INFO] Reading firmware (%d bytes)\n",length); | ||
924 | |||
925 | if (ipod_seek(ipod, ipod->fwoffset+ipod->ipod_directory[0].devOffset) < 0) { | ||
926 | return -1; | ||
927 | } | ||
928 | |||
929 | i = (length+ipod->sector_size-1) & ~(ipod->sector_size-1); | ||
930 | fprintf(stderr,"[INFO] Padding read from 0x%08x to 0x%08x bytes\n", | ||
931 | length,i); | ||
932 | |||
933 | if ((n = ipod_read(ipod,sectorbuf,i)) < 0) { | ||
934 | return -1; | ||
935 | } | ||
936 | |||
937 | if (n < i) { | ||
938 | fprintf(stderr,"[ERR] Short read - requested %d bytes, received %d\n", | ||
939 | i,n); | ||
940 | return -1; | ||
941 | } | ||
942 | |||
943 | chksum = ipod->modelnum; | ||
944 | for (i = 0; i < length; i++) { | ||
945 | /* add 8 unsigned bits but keep a 32 bit sum */ | ||
946 | chksum += sectorbuf[i]; | ||
947 | } | ||
948 | |||
949 | int2be(chksum,header); | ||
950 | memcpy(header+4, ipod->modelname,4); | ||
951 | |||
952 | outfile = open(filename,O_CREAT|O_TRUNC|O_WRONLY|O_BINARY,0666); | ||
953 | if (outfile < 0) { | ||
954 | fprintf(stderr,"[ERR] Couldn't open file %s\n",filename); | ||
955 | return -1; | ||
956 | } | ||
957 | |||
958 | write(outfile,header,8); | ||
959 | write(outfile,sectorbuf,length); | ||
960 | close(outfile); | ||
961 | |||
962 | return 0; | ||
963 | } | ||
964 | |||
965 | int read_directory(struct ipod_t* ipod) | ||
966 | { | ||
967 | int n; | ||
968 | int x; | ||
969 | unsigned char* p; | ||
970 | unsigned short version; | ||
971 | |||
972 | ipod->nimages=0; | ||
973 | |||
974 | /* Read firmware partition header (first 512 bytes of disk - but | ||
975 | let's read a whole sector) */ | ||
976 | |||
977 | if (ipod_seek(ipod, ipod->start) < 0) { | ||
978 | fprintf(stderr,"[ERR] Seek to 0x%08x in read_directory() failed.\n", | ||
979 | (unsigned int)(ipod->start)); | ||
980 | return -1; | ||
981 | } | ||
982 | |||
983 | n=ipod_read(ipod, sectorbuf, ipod->sector_size); | ||
984 | if (n < 0) { | ||
985 | fprintf(stderr,"[ERR] ipod_read(ipod,buf,0x%08x) failed in read_directory()\n", ipod->sector_size); | ||
986 | return -1; | ||
987 | } | ||
988 | |||
989 | if (memcmp(sectorbuf,apple_stop_sign,sizeof(apple_stop_sign))!=0) { | ||
990 | fprintf(stderr,"[ERR] Firmware partition doesn't contain Apple copyright, aborting.\n"); | ||
991 | return -1; | ||
992 | } | ||
993 | |||
994 | if (memcmp(sectorbuf+0x100,"]ih[",4)!=0) { | ||
995 | fprintf(stderr,"[ERR] Bad firmware directory\n"); | ||
996 | return -1; | ||
997 | } | ||
998 | |||
999 | version = le2ushort(sectorbuf+0x10a); | ||
1000 | if ((version != 2) && (version != 3)) { | ||
1001 | fprintf(stderr,"[ERR] Unknown firmware format version %04x\n", | ||
1002 | version); | ||
1003 | } | ||
1004 | ipod->diroffset=le2int(sectorbuf+0x104) + 0x200; | ||
1005 | |||
1006 | /* diroffset may not be sector-aligned */ | ||
1007 | x = ipod->diroffset % ipod->sector_size; | ||
1008 | |||
1009 | /* Read directory */ | ||
1010 | if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { | ||
1011 | fprintf(stderr,"[ERR] Seek to diroffset (%08x) failed.\n",(unsigned)ipod->diroffset); | ||
1012 | return -1; | ||
1013 | } | ||
1014 | |||
1015 | n=ipod_read(ipod, sectorbuf, ipod->sector_size); | ||
1016 | if (n < 0) { | ||
1017 | fprintf(stderr,"[ERR] Read of directory failed.\n"); | ||
1018 | return -1; | ||
1019 | } | ||
1020 | |||
1021 | p = sectorbuf + x; | ||
1022 | |||
1023 | while ((ipod->nimages < MAX_IMAGES) && (p < (sectorbuf + x + 400)) && | ||
1024 | (memcmp(p,"!ATA",4)==0)) { | ||
1025 | p+=4; | ||
1026 | if (memcmp(p,"soso",4)==0) { | ||
1027 | ipod->ipod_directory[ipod->nimages].ftype=FTYPE_OSOS; | ||
1028 | } else if (memcmp(p,"crsr",4)==0) { | ||
1029 | ipod->ipod_directory[ipod->nimages].ftype=FTYPE_RSRC; | ||
1030 | } else if (memcmp(p,"dpua",4)==0) { | ||
1031 | ipod->ipod_directory[ipod->nimages].ftype=FTYPE_AUPD; | ||
1032 | } else if (memcmp(p,"ebih",4)==0) { | ||
1033 | ipod->ipod_directory[ipod->nimages].ftype=FTYPE_HIBE; | ||
1034 | } else { | ||
1035 | fprintf(stderr,"[ERR] Unknown image type %c%c%c%c\n", | ||
1036 | p[0],p[1],p[2],p[3]); | ||
1037 | } | ||
1038 | p+=4; | ||
1039 | ipod->ipod_directory[ipod->nimages].id=le2int(p); | ||
1040 | p+=4; | ||
1041 | ipod->ipod_directory[ipod->nimages].devOffset=le2int(p); | ||
1042 | p+=4; | ||
1043 | ipod->ipod_directory[ipod->nimages].len=le2int(p); | ||
1044 | p+=4; | ||
1045 | ipod->ipod_directory[ipod->nimages].addr=le2int(p); | ||
1046 | p+=4; | ||
1047 | ipod->ipod_directory[ipod->nimages].entryOffset=le2int(p); | ||
1048 | p+=4; | ||
1049 | ipod->ipod_directory[ipod->nimages].chksum=le2int(p); | ||
1050 | p+=4; | ||
1051 | ipod->ipod_directory[ipod->nimages].vers=le2int(p); | ||
1052 | p+=4; | ||
1053 | ipod->ipod_directory[ipod->nimages].loadAddr=le2int(p); | ||
1054 | p+=4; | ||
1055 | ipod->nimages++; | ||
1056 | } | ||
1057 | |||
1058 | if ((ipod->nimages > 1) && (version==2)) { | ||
1059 | /* The 3g firmware image doesn't appear to have a version, so | ||
1060 | let's make one up... Note that this is never written back to the | ||
1061 | ipod, so it's OK to do. */ | ||
1062 | |||
1063 | if (ipod->ipod_directory[0].vers == 0) { ipod->ipod_directory[0].vers = 3; } | ||
1064 | |||
1065 | ipod->fwoffset = ipod->start; | ||
1066 | } else { | ||
1067 | ipod->fwoffset = ipod->start + ipod->sector_size; | ||
1068 | } | ||
1069 | |||
1070 | return 0; | ||
1071 | } | ||
1072 | |||
1073 | int list_images(struct ipod_t* ipod) | ||
1074 | { | ||
1075 | int i; | ||
1076 | |||
1077 | if (verbose) { | ||
1078 | printf(" Type id devOffset len addr entryOffset chksum vers loadAddr devOffset+len\n"); | ||
1079 | for (i = 0 ; i < ipod->nimages; i++) { | ||
1080 | printf("%d - %s 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n",i, | ||
1081 | ftypename[ipod->ipod_directory[i].ftype], | ||
1082 | ipod->ipod_directory[i].id, | ||
1083 | ipod->ipod_directory[i].devOffset, | ||
1084 | ipod->ipod_directory[i].len, | ||
1085 | ipod->ipod_directory[i].addr, | ||
1086 | ipod->ipod_directory[i].entryOffset, | ||
1087 | ipod->ipod_directory[i].chksum, | ||
1088 | ipod->ipod_directory[i].vers, | ||
1089 | ipod->ipod_directory[i].loadAddr, | ||
1090 | ipod->ipod_directory[i].devOffset+((ipod->ipod_directory[i].len+ipod->sector_size-1)&~(ipod->sector_size-1))); | ||
1091 | } | ||
1092 | } | ||
1093 | |||
1094 | printf("\n"); | ||
1095 | printf("Listing firmware partition contents:\n"); | ||
1096 | printf("\n"); | ||
1097 | |||
1098 | for (i = 0 ; i < ipod->nimages; i++) { | ||
1099 | printf("Image %d:\n",i+1); | ||
1100 | switch(ipod->ipod_directory[i].ftype) { | ||
1101 | case FTYPE_OSOS: | ||
1102 | if (ipod->ipod_directory[i].entryOffset==0) { | ||
1103 | printf(" Main firmware - %d bytes\n", | ||
1104 | ipod->ipod_directory[i].len); | ||
1105 | } else { | ||
1106 | printf(" Main firmware - %d bytes\n", | ||
1107 | ipod->ipod_directory[i].entryOffset); | ||
1108 | printf(" Third-party bootloader - %d bytes\n", | ||
1109 | ipod->ipod_directory[i].len-ipod->ipod_directory[i].entryOffset); | ||
1110 | } | ||
1111 | break; | ||
1112 | default: | ||
1113 | printf(" %s - %d bytes\n", | ||
1114 | ftypename[ipod->ipod_directory[i].ftype], | ||
1115 | ipod->ipod_directory[i].len); | ||
1116 | } | ||
1117 | } | ||
1118 | printf("\n"); | ||
1119 | |||
1120 | return 0; | ||
1121 | } | ||
1122 | |||
1123 | int getmodel(struct ipod_t* ipod, int ipod_version) | ||
1124 | { | ||
1125 | switch (ipod_version) { | ||
1126 | case 0x02: | ||
1127 | ipod->modelstr="3rd Generation"; | ||
1128 | ipod->modelnum = 7; | ||
1129 | ipod->modelname = "ip3g"; | ||
1130 | #ifdef WITH_BOOTOBJS | ||
1131 | ipod->bootloader = ipod3g; | ||
1132 | ipod->bootloader_len = LEN_ipod3g; | ||
1133 | #endif | ||
1134 | break; | ||
1135 | case 0x40: | ||
1136 | ipod->modelstr="1st Generation Mini"; | ||
1137 | ipod->modelnum = 9; | ||
1138 | ipod->modelname = "mini"; | ||
1139 | #ifdef WITH_BOOTOBJS | ||
1140 | ipod->bootloader = ipodmini; | ||
1141 | ipod->bootloader_len = LEN_ipodmini; | ||
1142 | #endif | ||
1143 | break; | ||
1144 | case 0x50: | ||
1145 | ipod->modelstr="4th Generation"; | ||
1146 | ipod->modelnum = 8; | ||
1147 | ipod->modelname = "ip4g"; | ||
1148 | #ifdef WITH_BOOTOBJS | ||
1149 | ipod->bootloader = ipod4g; | ||
1150 | ipod->bootloader_len = LEN_ipod4g; | ||
1151 | #endif | ||
1152 | break; | ||
1153 | case 0x60: | ||
1154 | ipod->modelstr="Photo/Color"; | ||
1155 | ipod->modelnum = 3; | ||
1156 | ipod->modelname = "ipco"; | ||
1157 | #ifdef WITH_BOOTOBJS | ||
1158 | ipod->bootloader = ipodcolor; | ||
1159 | ipod->bootloader_len = LEN_ipodcolor; | ||
1160 | #endif | ||
1161 | break; | ||
1162 | case 0x70: | ||
1163 | ipod->modelstr="2nd Generation Mini"; | ||
1164 | ipod->modelnum = 11; | ||
1165 | ipod->modelname = "mn2g"; | ||
1166 | #ifdef WITH_BOOTOBJS | ||
1167 | ipod->bootloader = ipodmini2g; | ||
1168 | ipod->bootloader_len = LEN_ipodmini2g; | ||
1169 | #endif | ||
1170 | break; | ||
1171 | case 0xc0: | ||
1172 | ipod->modelstr="1st Generation Nano"; | ||
1173 | ipod->modelnum = 4; | ||
1174 | ipod->modelname = "nano"; | ||
1175 | #ifdef WITH_BOOTOBJS | ||
1176 | ipod->bootloader = ipodnano; | ||
1177 | ipod->bootloader_len = LEN_ipodnano; | ||
1178 | #endif | ||
1179 | break; | ||
1180 | case 0xb0: | ||
1181 | ipod->modelstr="Video (aka 5th Generation)"; | ||
1182 | ipod->modelnum = 5; | ||
1183 | ipod->modelname = "ipvd"; | ||
1184 | #ifdef WITH_BOOTOBJS | ||
1185 | ipod->bootloader = ipodvideo; | ||
1186 | ipod->bootloader_len = LEN_ipodvideo; | ||
1187 | #endif | ||
1188 | break; | ||
1189 | default: | ||
1190 | ipod->modelname = NULL; | ||
1191 | ipod->modelnum = 0; | ||
1192 | #ifdef WITH_BOOTOBJS | ||
1193 | ipod->bootloader = NULL; | ||
1194 | ipod->bootloader_len = 0; | ||
1195 | #endif | ||
1196 | return -1; | ||
1197 | } | ||
1198 | return 0; | ||
1199 | } | ||
1200 | |||
1201 | int ipod_scan(struct ipod_t* ipod) | ||
1202 | { | ||
1203 | int i; | ||
1204 | int n = 0; | ||
1205 | int ipod_version; | ||
1206 | char last_ipod[4096]; | ||
1207 | |||
1208 | printf("[INFO] Scanning disk devices...\n"); | ||
1209 | |||
1210 | for (i = 0; i <= 25 ; i++) { | ||
1211 | #ifdef __WIN32__ | ||
1212 | sprintf(ipod->diskname,"\\\\.\\PhysicalDrive%d",i); | ||
1213 | #elif defined(linux) || defined (__linux) | ||
1214 | sprintf(ipod->diskname,"/dev/sd%c",'a'+i); | ||
1215 | #elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) \ | ||
1216 | || defined(__bsdi__) || defined(__DragonFly__) | ||
1217 | sprintf(ipod->diskname,"/dev/da%d",i); | ||
1218 | #elif defined(__APPLE__) && defined(__MACH__) | ||
1219 | sprintf(ipod->diskname,"/dev/disk%d",i); | ||
1220 | #else | ||
1221 | #error No disk paths defined for this platform | ||
1222 | #endif | ||
1223 | if (ipod_open(ipod, 1) < 0) { | ||
1224 | continue; | ||
1225 | } | ||
1226 | |||
1227 | if (read_partinfo(ipod,1) < 0) { | ||
1228 | continue; | ||
1229 | } | ||
1230 | |||
1231 | if ((ipod->pinfo[0].start==0) || (ipod->pinfo[0].type != 0)) { | ||
1232 | continue; | ||
1233 | } | ||
1234 | |||
1235 | if (read_directory(ipod) < 0) { | ||
1236 | continue; | ||
1237 | } | ||
1238 | |||
1239 | ipod_version=(ipod->ipod_directory[0].vers>>8); | ||
1240 | if (getmodel(ipod,ipod_version) < 0) { | ||
1241 | continue; | ||
1242 | } | ||
1243 | |||
1244 | #ifdef __WIN32__ | ||
1245 | printf("[INFO] Ipod found - %s (\"%s\") - disk device %d\n", | ||
1246 | ipod->modelstr,ipod->macpod ? "macpod" : "winpod",i); | ||
1247 | #else | ||
1248 | printf("[INFO] Ipod found - %s (\"%s\") - %s\n", | ||
1249 | ipod->modelstr,ipod->macpod ? "macpod" : "winpod",ipod->diskname); | ||
1250 | #endif | ||
1251 | n++; | ||
1252 | strcpy(last_ipod,ipod->diskname); | ||
1253 | ipod_close(ipod); | ||
1254 | } | ||
1255 | |||
1256 | if (n==1) { | ||
1257 | /* Remember the disk name */ | ||
1258 | strcpy(ipod->diskname,last_ipod); | ||
1259 | } | ||
1260 | return n; | ||
1261 | } | ||