diff options
Diffstat (limited to 'tools/ipodpatcher/ipodpatcher.c')
-rw-r--r-- | tools/ipodpatcher/ipodpatcher.c | 454 |
1 files changed, 286 insertions, 168 deletions
diff --git a/tools/ipodpatcher/ipodpatcher.c b/tools/ipodpatcher/ipodpatcher.c index 32c1291ab4..f965746282 100644 --- a/tools/ipodpatcher/ipodpatcher.c +++ b/tools/ipodpatcher/ipodpatcher.c | |||
@@ -9,12 +9,6 @@ | |||
9 | * | 9 | * |
10 | * Copyright (C) 2006 Dave Chapman | 10 | * Copyright (C) 2006 Dave Chapman |
11 | * | 11 | * |
12 | * error(), lock_volume() and unlock_volume() functions and inspiration taken | ||
13 | * from: | ||
14 | * RawDisk - Direct Disk Read/Write Access for NT/2000/XP | ||
15 | * Copyright (c) 2003 Jan Kiszka | ||
16 | * http://www.stud.uni-hannover.de/user/73174/RawDisk/ | ||
17 | * | ||
18 | * All files in this archive are subject to the GNU General Public License. | 12 | * All files in this archive are subject to the GNU General Public License. |
19 | * See the file COPYING in the source tree root for full license agreement. | 13 | * See the file COPYING in the source tree root for full license agreement. |
20 | * | 14 | * |
@@ -28,17 +22,45 @@ | |||
28 | #include <fcntl.h> | 22 | #include <fcntl.h> |
29 | #include <string.h> | 23 | #include <string.h> |
30 | #include <stdlib.h> | 24 | #include <stdlib.h> |
25 | #include <inttypes.h> | ||
31 | #include <sys/types.h> | 26 | #include <sys/types.h> |
32 | #include <sys/stat.h> | 27 | #include <sys/stat.h> |
33 | #include <windows.h> | ||
34 | #include <winioctl.h> | ||
35 | 28 | ||
36 | #include "parttypes.h" | 29 | #include "parttypes.h" |
30 | #include "ipodio.h" | ||
31 | |||
32 | #define VERSION "0.5" | ||
33 | |||
34 | //#define DEBUG | ||
35 | |||
36 | /* The following string appears at the start of the firmware partition */ | ||
37 | static const char *apple_stop_sign = "{{~~ /-----\\ "\ | ||
38 | "{{~~ / \\ "\ | ||
39 | "{{~~| | "\ | ||
40 | "{{~~| S T O P | "\ | ||
41 | "{{~~| | "\ | ||
42 | "{{~~ \\ / "\ | ||
43 | "{{~~ \\-----/ "\ | ||
44 | "Copyright(C) 200"\ | ||
45 | "1 Apple Computer"\ | ||
46 | ", Inc.----------"\ | ||
47 | "----------------"\ | ||
48 | "----------------"\ | ||
49 | "----------------"\ | ||
50 | "----------------"\ | ||
51 | "----------------"\ | ||
52 | "---------------"; | ||
53 | |||
54 | /* The maximum number of images in a firmware partition - a guess... */ | ||
55 | #define MAX_IMAGES 10 | ||
37 | 56 | ||
38 | /* Windows requires the buffer for disk I/O to be aligned in memory on a | 57 | /* Windows requires the buffer for disk I/O to be aligned in memory on a |
39 | multiple of the disk volume size - so we use a single global variable | 58 | multiple of the disk volume size - so we use a single global variable |
40 | and initialise it in main() | 59 | and initialise it with ipod_alloc_buf() |
41 | */ | 60 | */ |
61 | |||
62 | /* Size of buffer for disk I/O */ | ||
63 | #define BUFFER_SIZE 6*1024*1024 | ||
42 | unsigned char* sectorbuf; | 64 | unsigned char* sectorbuf; |
43 | 65 | ||
44 | char* get_parttype(int pt) | 66 | char* get_parttype(int pt) |
@@ -57,35 +79,6 @@ char* get_parttype(int pt) | |||
57 | return unknown; | 79 | return unknown; |
58 | } | 80 | } |
59 | 81 | ||
60 | void error(char* msg) | ||
61 | { | ||
62 | char* pMsgBuf; | ||
63 | |||
64 | printf(msg); | ||
65 | FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | | ||
66 | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(), | ||
67 | MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&pMsgBuf, | ||
68 | 0, NULL); | ||
69 | printf(pMsgBuf); | ||
70 | LocalFree(pMsgBuf); | ||
71 | } | ||
72 | |||
73 | int lock_volume(HANDLE hDisk) | ||
74 | { | ||
75 | DWORD dummy; | ||
76 | |||
77 | return DeviceIoControl(hDisk, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, | ||
78 | &dummy, NULL); | ||
79 | } | ||
80 | |||
81 | int unlock_volume(HANDLE hDisk) | ||
82 | { | ||
83 | DWORD dummy; | ||
84 | |||
85 | return DeviceIoControl(hDisk, FSCTL_UNLOCK_VOLUME, NULL, 0, NULL, 0, | ||
86 | &dummy, NULL); | ||
87 | } | ||
88 | |||
89 | off_t filesize(int fd) { | 82 | off_t filesize(int fd) { |
90 | struct stat buf; | 83 | struct stat buf; |
91 | 84 | ||
@@ -97,47 +90,67 @@ off_t filesize(int fd) { | |||
97 | } | 90 | } |
98 | } | 91 | } |
99 | 92 | ||
100 | |||
101 | /* Size of buffer for disk I/O */ | ||
102 | #define BUFFER_SIZE 32*1024 | ||
103 | |||
104 | /* Partition table parsing code taken from Rockbox */ | 93 | /* Partition table parsing code taken from Rockbox */ |
105 | 94 | ||
106 | #define MAX_SECTOR_SIZE 2048 | 95 | #define MAX_SECTOR_SIZE 2048 |
107 | #define SECTOR_SIZE 512 | 96 | #define SECTOR_SIZE 512 |
108 | 97 | ||
109 | struct partinfo { | 98 | struct partinfo_t { |
110 | unsigned long start; /* first sector (LBA) */ | 99 | unsigned long start; /* first sector (LBA) */ |
111 | unsigned long size; /* number of sectors */ | 100 | unsigned long size; /* number of sectors */ |
112 | unsigned char type; | 101 | unsigned char type; |
113 | }; | 102 | }; |
114 | 103 | ||
115 | #define BYTES2INT32(array,pos) \ | 104 | int static inline getint32le(unsigned char* buf) |
116 | ((long)array[pos] | ((long)array[pos+1] << 8 ) | \ | 105 | { |
106 | int32_t res = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; | ||
107 | |||
108 | return res; | ||
109 | } | ||
110 | |||
111 | int static inline getint16le(char* buf) | ||
112 | { | ||
113 | int16_t res = (buf[1] << 8) | buf[0]; | ||
114 | |||
115 | return res; | ||
116 | } | ||
117 | |||
118 | |||
119 | |||
120 | #define BYTES2INT32(array,pos)\ | ||
121 | ((long)array[pos] | ((long)array[pos+1] << 8 ) |\ | ||
117 | ((long)array[pos+2] << 16 ) | ((long)array[pos+3] << 24 )) | 122 | ((long)array[pos+2] << 16 ) | ((long)array[pos+3] << 24 )) |
118 | 123 | ||
119 | void display_partinfo(struct partinfo* pinfo, int sector_size) | 124 | void display_partinfo(struct partinfo_t* pinfo, int sector_size) |
120 | { | 125 | { |
121 | int i; | 126 | int i; |
122 | double sectors_per_MB = (1024.0*1024.0)/sector_size; | 127 | double sectors_per_MB = (1024.0*1024.0)/sector_size; |
123 | 128 | ||
124 | printf("Part Start Sector End Sector Size (MB) Type\n"); | 129 | printf("[INFO] Part Start Sector End Sector Size (MB) Type\n"); |
125 | for ( i = 0; i < 4; i++ ) { | 130 | for ( i = 0; i < 4; i++ ) { |
126 | if (pinfo[i].start != 0) { | 131 | if (pinfo[i].start != 0) { |
127 | printf(" %d %10ld %10ld %10.1f %s (0x%02x)\n",i,pinfo[i].start,pinfo[i].start+pinfo[i].size-1,pinfo[i].size/sectors_per_MB,get_parttype(pinfo[i].type),pinfo[i].type); | 132 | printf("[INFO] %d %10ld %10ld %10.1f %s (0x%02x)\n", |
133 | i, | ||
134 | pinfo[i].start, | ||
135 | pinfo[i].start+pinfo[i].size-1, | ||
136 | pinfo[i].size/sectors_per_MB, | ||
137 | get_parttype(pinfo[i].type), | ||
138 | pinfo[i].type); | ||
128 | } | 139 | } |
129 | } | 140 | } |
130 | } | 141 | } |
131 | 142 | ||
132 | 143 | ||
133 | int read_partinfo(HANDLE dh, int sector_size, struct partinfo* pinfo) | 144 | int read_partinfo(HANDLE dh, int sector_size, struct partinfo_t* pinfo) |
134 | { | 145 | { |
135 | int i; | 146 | int i; |
136 | unsigned char sector[MAX_SECTOR_SIZE]; | 147 | unsigned char sector[MAX_SECTOR_SIZE]; |
137 | unsigned long count; | 148 | unsigned long count; |
138 | 149 | ||
139 | if (!ReadFile(dh, sector, sector_size, &count, NULL)) { | 150 | count = ipod_read(dh,sector,sector_size); |
140 | error(" Error reading from disk: "); | 151 | |
152 | if (count <= 0) { | ||
153 | print_error(" Error reading from disk: "); | ||
141 | return -1; | 154 | return -1; |
142 | } | 155 | } |
143 | 156 | ||
@@ -180,8 +193,7 @@ int disk_read(HANDLE dh, int outfile,unsigned long start, unsigned long count, | |||
180 | 193 | ||
181 | fprintf(stderr,"[INFO] Seeking to sector %ld\n",start); | 194 | fprintf(stderr,"[INFO] Seeking to sector %ld\n",start); |
182 | 195 | ||
183 | if (SetFilePointer(dh, start*sector_size, NULL, FILE_BEGIN)==0xffffffff) { | 196 | if (ipod_seek(dh,start) < 0) { |
184 | error(" Seek error "); | ||
185 | return -1; | 197 | return -1; |
186 | } | 198 | } |
187 | 199 | ||
@@ -195,8 +207,9 @@ int disk_read(HANDLE dh, int outfile,unsigned long start, unsigned long count, | |||
195 | chunksize = bytesleft; | 207 | chunksize = bytesleft; |
196 | } | 208 | } |
197 | 209 | ||
198 | if (!ReadFile(dh, sectorbuf, chunksize, &n, NULL)) { | 210 | n = ipod_read(dh, sectorbuf, chunksize); |
199 | error("[ERR] read in disk_read"); | 211 | |
212 | if (n < 0) { | ||
200 | return -1; | 213 | return -1; |
201 | } | 214 | } |
202 | 215 | ||
@@ -233,8 +246,7 @@ int disk_write(HANDLE dh, int infile,unsigned long start, int sector_size) | |||
233 | int eof; | 246 | int eof; |
234 | int padding = 0; | 247 | int padding = 0; |
235 | 248 | ||
236 | if (SetFilePointer(dh, start*sector_size, NULL, FILE_BEGIN)==0xffffffff) { | 249 | if (ipod_seek(dh, start*sector_size) < 0) { |
237 | error(" Seek error "); | ||
238 | return -1; | 250 | return -1; |
239 | } | 251 | } |
240 | 252 | ||
@@ -260,8 +272,10 @@ int disk_write(HANDLE dh, int infile,unsigned long start, int sector_size) | |||
260 | 272 | ||
261 | bytesread += n; | 273 | bytesread += n; |
262 | 274 | ||
263 | if (!WriteFile(dh, sectorbuf, n, &res, NULL)) { | 275 | res = ipod_write(dh, sectorbuf,n); |
264 | error(" Error writing to disk: "); | 276 | |
277 | if (res < 0) { | ||
278 | print_error(" Error writing to disk: "); | ||
265 | fprintf(stderr,"Bytes written: %d\n",byteswritten); | 279 | fprintf(stderr,"Bytes written: %d\n",byteswritten); |
266 | return -1; | 280 | return -1; |
267 | } | 281 | } |
@@ -280,134 +294,229 @@ int disk_write(HANDLE dh, int infile,unsigned long start, int sector_size) | |||
280 | 294 | ||
281 | 295 | ||
282 | void print_usage(void) { | 296 | void print_usage(void) { |
283 | fprintf(stderr,"Usage: ipodpatcher [-i|r|w] DISKNO [file]\n"); | 297 | #ifdef __WIN32__ |
284 | fprintf(stderr," -i Display iPod's partition information (default)\n"); | 298 | fprintf(stderr,"Usage: ipodpatcher DISKNO [action]\n"); |
285 | fprintf(stderr," -r Read firmware partition to file\n"); | 299 | #else |
286 | fprintf(stderr," -w Write file to firmware partition\n"); | 300 | fprintf(stderr,"Usage: ipodpatcher device [action]\n"); |
301 | #endif | ||
302 | fprintf(stderr,"\n"); | ||
303 | fprintf(stderr,"Where [action] is one of:\n"); | ||
304 | #if 0 | ||
305 | fprintf(stderr," -e --extract-firmware filename.bin - extract firmware to a file\n"); | ||
306 | fprintf(stderr," -i --insert-firmware filename.bin - replace the firmware with the file\n"); | ||
307 | fprintf(stderr," -a --add-bootloader filename.bin - add a bootloader\n"); | ||
308 | fprintf(stderr," -r --remove-bootloader - remove a bootloader\n"); | ||
309 | #endif | ||
310 | fprintf(stderr," -l --list - list images in firmware partition\n"); | ||
287 | fprintf(stderr,"\n"); | 311 | fprintf(stderr,"\n"); |
312 | #ifdef __WIN32__ | ||
288 | fprintf(stderr,"DISKNO is the number (e.g. 2) Windows has assigned to your ipod's hard disk.\n"); | 313 | fprintf(stderr,"DISKNO is the number (e.g. 2) Windows has assigned to your ipod's hard disk.\n"); |
289 | fprintf(stderr,"The first hard disk in your computer (i.e. C:\\) will be disk0, the next disk\n"); | 314 | fprintf(stderr,"The first hard disk in your computer (i.e. C:\\) will be disk0, the next disk\n"); |
290 | fprintf(stderr,"will be disk 1 etc. ipodpatcher will refuse to access a disk unless it\n"); | 315 | fprintf(stderr,"will be disk 1 etc. ipodpatcher will refuse to access a disk unless it\n"); |
291 | fprintf(stderr,"can identify it as being an ipod.\n"); | 316 | fprintf(stderr,"can identify it as being an ipod.\n"); |
292 | fprintf(stderr,"\n"); | 317 | fprintf(stderr,"\n"); |
318 | #else | ||
319 | fprintf(stderr,"\"device\" is the device node (e.g. /dev/sda) assigned to your ipod.\n"); | ||
320 | fprintf(stderr,"ipodpatcher will refuse to access a disk unless it can identify it as being\n"); | ||
321 | fprintf(stderr,"an ipod.\n"); | ||
322 | #endif | ||
293 | } | 323 | } |
294 | 324 | ||
295 | enum { | 325 | enum { |
296 | NONE, | 326 | NONE, |
297 | SHOW_INFO, | 327 | SHOW_INFO, |
298 | READ, | 328 | LIST_IMAGES |
299 | WRITE | 329 | }; |
330 | |||
331 | char* ftypename[] = { "OSOS", "RSRC", "AUPD", "HIBE" }; | ||
332 | |||
333 | enum firmwaretype_t { | ||
334 | FTYPE_OSOS = 0, | ||
335 | FTYPE_RSRC, | ||
336 | FTYPE_AUPD, | ||
337 | FTYPE_HIBE | ||
338 | }; | ||
339 | |||
340 | struct ipod_directory_t { | ||
341 | enum firmwaretype_t ftype; | ||
342 | int id; | ||
343 | uint32_t devOffset; | ||
344 | uint32_t len; | ||
345 | uint32_t addr; | ||
346 | uint32_t entryOffset; | ||
347 | uint32_t chksum; | ||
348 | uint32_t vers; | ||
349 | uint32_t loadAddr; | ||
300 | }; | 350 | }; |
301 | 351 | ||
352 | int read_directory(HANDLE dh, int start, int sector_size, struct ipod_directory_t* ipod_directory) | ||
353 | { | ||
354 | int n; | ||
355 | int nimages; | ||
356 | off_t diroffset; | ||
357 | unsigned char* p; | ||
358 | |||
359 | /* Read firmware partition header (first 512 bytes of disk - but let's read a whole sector) */ | ||
360 | |||
361 | if (ipod_seek(dh, start) < 0) { return -1; } | ||
362 | |||
363 | n=ipod_read(dh, sectorbuf, sector_size); | ||
364 | if (n < 0) { return -1; } | ||
365 | |||
366 | if (memcmp(sectorbuf,apple_stop_sign,sizeof(apple_stop_sign))!=0) { | ||
367 | fprintf(stderr,"[ERR] Firmware partition doesn't contain Apple copyright, aborting."); | ||
368 | return -1; | ||
369 | } | ||
370 | |||
371 | if (memcmp(sectorbuf+0x100,"]ih[",4)!=0) { | ||
372 | fprintf(stderr,"[ERR] Bad firmware directory\n"); | ||
373 | return -1; | ||
374 | } | ||
375 | |||
376 | diroffset=getint32le(sectorbuf+0x104) + 0x200; | ||
377 | |||
378 | /* Read directory */ | ||
379 | if (ipod_seek(dh,start + diroffset) < 0) { return -1; } | ||
380 | |||
381 | n=ipod_read(dh, sectorbuf, sector_size); | ||
382 | if (n < 0) { return -1; } | ||
383 | |||
384 | nimages=0; | ||
385 | p = sectorbuf; | ||
386 | |||
387 | while ((nimages < MAX_IMAGES) && (p < (sectorbuf + 400)) && (memcmp(p,"!ATA",4)==0)) { | ||
388 | p+=4; | ||
389 | if (memcmp(p,"soso",4)==0) { | ||
390 | ipod_directory[nimages].ftype=FTYPE_OSOS; | ||
391 | } else if (memcmp(p,"crsr",4)==0) { | ||
392 | ipod_directory[nimages].ftype=FTYPE_RSRC; | ||
393 | } else if (memcmp(p,"dpua",4)==0) { | ||
394 | ipod_directory[nimages].ftype=FTYPE_AUPD; | ||
395 | } else if (memcmp(p,"ebih",4)==0) { | ||
396 | ipod_directory[nimages].ftype=FTYPE_HIBE; | ||
397 | } else { | ||
398 | fprintf(stderr,"[ERR] Unknown image type %c%c%c%c\n",p[0],p[1],p[2],p[3]); | ||
399 | } | ||
400 | p+=4; | ||
401 | ipod_directory[nimages].id=getint32le(p); | ||
402 | p+=4; | ||
403 | ipod_directory[nimages].devOffset=getint32le(p); | ||
404 | p+=4; | ||
405 | ipod_directory[nimages].len=getint32le(p); | ||
406 | p+=4; | ||
407 | ipod_directory[nimages].addr=getint32le(p); | ||
408 | p+=4; | ||
409 | ipod_directory[nimages].entryOffset=getint32le(p); | ||
410 | p+=4; | ||
411 | ipod_directory[nimages].chksum=getint32le(p); | ||
412 | p+=4; | ||
413 | ipod_directory[nimages].vers=getint32le(p); | ||
414 | p+=4; | ||
415 | ipod_directory[nimages].loadAddr=getint32le(p); | ||
416 | p+=4; | ||
417 | nimages++; | ||
418 | } | ||
419 | return nimages; | ||
420 | } | ||
421 | |||
422 | int list_images(int nimages, struct ipod_directory_t* ipod_directory) | ||
423 | { | ||
424 | int i; | ||
425 | |||
426 | #ifdef DEBUG | ||
427 | printf(" Type id devOffset len addr entryOffset chksum vers loadAddr\n"); | ||
428 | for (i = 0 ; i < nimages; i++) { | ||
429 | printf("%d - %s 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n",i, | ||
430 | ftypename[ipod_directory[i].ftype], | ||
431 | ipod_directory[i].id, | ||
432 | ipod_directory[i].devOffset, | ||
433 | ipod_directory[i].len, | ||
434 | ipod_directory[i].addr, | ||
435 | ipod_directory[i].entryOffset, | ||
436 | ipod_directory[i].chksum, | ||
437 | ipod_directory[i].vers, | ||
438 | ipod_directory[i].loadAddr); | ||
439 | } | ||
440 | #endif | ||
441 | |||
442 | printf("\n"); | ||
443 | printf("Listing firmware partition contents:\n"); | ||
444 | printf("\n"); | ||
445 | |||
446 | for (i = 0 ; i < nimages; i++) { | ||
447 | printf("Image %d:\n",i+1); | ||
448 | switch(ipod_directory[i].ftype) { | ||
449 | case FTYPE_OSOS: | ||
450 | if (ipod_directory[i].entryOffset==0) { | ||
451 | printf(" Main firmware - %d bytes\n",ipod_directory[i].len); | ||
452 | } else { | ||
453 | printf(" Main firmware - %d bytes\n",ipod_directory[i].entryOffset); | ||
454 | printf(" Third-party bootloader - %d bytes\n",ipod_directory[i].len-ipod_directory[i].entryOffset); | ||
455 | } | ||
456 | break; | ||
457 | default: | ||
458 | printf(" %s - %d bytes\n",ftypename[ipod_directory[i].ftype],ipod_directory[i].len); | ||
459 | } | ||
460 | } | ||
461 | printf("\n"); | ||
462 | |||
463 | return 0; | ||
464 | } | ||
465 | |||
302 | int main(int argc, char* argv[]) | 466 | int main(int argc, char* argv[]) |
303 | { | 467 | { |
304 | int i; | 468 | int i; |
305 | struct partinfo pinfo[4]; /* space for 4 partitions on 1 drive */ | 469 | int ipod_version; |
306 | int res; | 470 | struct partinfo_t pinfo[4]; /* space for 4 partitions on 1 drive */ |
307 | unsigned long n; | 471 | int nimages; |
308 | int outfile; | 472 | struct ipod_directory_t ipod_directory[MAX_IMAGES]; |
309 | int infile; | 473 | int action = SHOW_INFO; |
310 | int mode = SHOW_INFO; | ||
311 | int p = 0; | ||
312 | int diskno = -1; | ||
313 | int sector_size; | 474 | int sector_size; |
314 | DISK_GEOMETRY_EX diskgeometry_ex; | 475 | char devicename[4096]; |
315 | DISK_GEOMETRY diskgeometry; | ||
316 | char diskname[32]; | ||
317 | HANDLE dh; | 476 | HANDLE dh; |
318 | char* filename = NULL; | ||
319 | off_t inputsize; | ||
320 | 477 | ||
321 | fprintf(stderr,"ipodpatcher v0.4b - (C) Dave Chapman 2006\n"); | 478 | fprintf(stderr,"ipodpatcher v" VERSION " - (C) Dave Chapman 2006\n"); |
322 | fprintf(stderr,"This is free software; see the source for copying conditions. There is NO\n"); | 479 | fprintf(stderr,"This is free software; see the source for copying conditions. There is NO\n"); |
323 | fprintf(stderr,"warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"); | 480 | fprintf(stderr,"warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"); |
324 | 481 | ||
325 | if (argc <= 1) { | 482 | if (argc < 2) { |
326 | print_usage(); | 483 | print_usage(); |
327 | return 1; | 484 | return 1; |
328 | } | 485 | } |
329 | 486 | ||
330 | i = 1; | 487 | i = 1; |
488 | devicename[0]=0; | ||
489 | |||
490 | #ifdef __WIN32__ | ||
491 | snprintf(devicename,sizeof(devicename),"\\\\.\\PhysicalDrive%s",argv[1]); | ||
492 | #else | ||
493 | strncpy(devicename,argv[1],sizeof(devicename)); | ||
494 | #endif | ||
495 | |||
496 | i = 2; | ||
331 | while (i < argc) { | 497 | while (i < argc) { |
332 | if (strncmp(argv[i],"-i",2)==0) { | 498 | if ((strcmp(argv[i],"-l")==0) || (strcmp(argv[i],"--list")==0)) { |
333 | mode=SHOW_INFO; | 499 | action = LIST_IMAGES; |
334 | } else if (strncmp(argv[i],"-r",2)==0) { | 500 | i++; |
335 | mode = READ; | ||
336 | } else if (strncmp(argv[i],"-w",2)==0) { | ||
337 | mode = WRITE; | ||
338 | } else { | 501 | } else { |
339 | if (argv[i][0] == '-') { | 502 | print_usage(); return 1; |
340 | fprintf(stderr,"Unknown option %s\n",argv[i]); | ||
341 | return 1; | ||
342 | } else { | ||
343 | if (diskno == -1) { | ||
344 | diskno = atoi(argv[i]); | ||
345 | } else if (filename==NULL) { | ||
346 | filename = argv[i]; | ||
347 | } else { | ||
348 | fprintf(stderr,"Too many arguments: %s\n",argv[i]); | ||
349 | return 1; | ||
350 | } | ||
351 | } | ||
352 | } | 503 | } |
353 | i++; | ||
354 | } | 504 | } |
355 | 505 | ||
356 | if ((mode==NONE) || (diskno==-1) || ((mode!=SHOW_INFO) && (filename==NULL))) { | 506 | if (devicename[0]==0) { |
357 | print_usage(); | 507 | print_usage(); |
358 | return 1; | 508 | return 1; |
359 | } | 509 | } |
360 | 510 | ||
361 | snprintf(diskname,sizeof(diskname),"\\\\.\\PhysicalDrive%d",diskno); | 511 | if (ipod_alloc_buffer(§orbuf,BUFFER_SIZE) < 0) { |
362 | 512 | fprintf(stderr,"Failed to allocate memory buffer\n"); | |
363 | /* The ReadFile function requires a memory buffer aligned to a multiple of | ||
364 | the disk sector size. */ | ||
365 | sectorbuf = VirtualAlloc(NULL, BUFFER_SIZE, MEM_COMMIT, PAGE_READWRITE); | ||
366 | if (sectorbuf == NULL) { | ||
367 | error(" Error allocating a buffer: "); | ||
368 | return 2; | ||
369 | } | 513 | } |
370 | 514 | ||
371 | dh = CreateFile(diskname, GENERIC_READ, | 515 | if (ipod_open(&dh, devicename, §or_size) < 0) { |
372 | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, | 516 | return 1; |
373 | FILE_FLAG_WRITE_THROUGH | FILE_FLAG_NO_BUFFERING, NULL); | ||
374 | |||
375 | if (dh == INVALID_HANDLE_VALUE) { | ||
376 | error(" Error opening disk: "); | ||
377 | return 2; | ||
378 | } | ||
379 | |||
380 | if (!lock_volume(dh)) { | ||
381 | error(" Error locking disk: "); | ||
382 | return 2; | ||
383 | } | ||
384 | |||
385 | if (!DeviceIoControl(dh, | ||
386 | IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, | ||
387 | NULL, | ||
388 | 0, | ||
389 | &diskgeometry_ex, | ||
390 | sizeof(diskgeometry_ex), | ||
391 | &n, | ||
392 | NULL)) { | ||
393 | if (!DeviceIoControl(dh, | ||
394 | IOCTL_DISK_GET_DRIVE_GEOMETRY, | ||
395 | NULL, | ||
396 | 0, | ||
397 | &diskgeometry, | ||
398 | sizeof(diskgeometry), | ||
399 | &n, | ||
400 | NULL)) { | ||
401 | error(" Error reading disk geometry: "); | ||
402 | return 2; | ||
403 | } else { | ||
404 | sector_size=diskgeometry.BytesPerSector; | ||
405 | } | ||
406 | } else { | ||
407 | sector_size=diskgeometry_ex.Geometry.BytesPerSector; | ||
408 | } | 517 | } |
409 | 518 | ||
410 | fprintf(stderr,"[INFO] Reading partition table from %s\n",diskname); | 519 | fprintf(stderr,"[INFO] Reading partition table from %s\n",devicename); |
411 | fprintf(stderr,"[INFO] Sector size is %d bytes\n",sector_size); | 520 | fprintf(stderr,"[INFO] Sector size is %d bytes\n",sector_size); |
412 | 521 | ||
413 | if (read_partinfo(dh,sector_size,pinfo) < 0) { | 522 | if (read_partinfo(dh,sector_size,pinfo) < 0) { |
@@ -416,13 +525,35 @@ int main(int argc, char* argv[]) | |||
416 | 525 | ||
417 | display_partinfo(pinfo, sector_size); | 526 | display_partinfo(pinfo, sector_size); |
418 | 527 | ||
419 | if (pinfo[p].start==0) { | 528 | if (pinfo[0].start==0) { |
420 | fprintf(stderr,"[ERR] Specified partition (%d) does not exist:\n",p); | 529 | fprintf(stderr,"[ERR] No partition 0 on disk:\n"); |
421 | display_partinfo(pinfo, sector_size); | 530 | display_partinfo(pinfo, sector_size); |
422 | return 3; | 531 | return 3; |
423 | } | 532 | } |
424 | 533 | ||
425 | if (mode==READ) { | 534 | nimages=read_directory(dh, pinfo[0].start*sector_size, sector_size, ipod_directory); |
535 | if (nimages <= 0) { | ||
536 | fprintf(stderr,"[ERR] Failed to read firmware directory\n"); | ||
537 | return 1; | ||
538 | } | ||
539 | |||
540 | ipod_version=(ipod_directory[0].vers>>12) & 0x0f; | ||
541 | printf("[INFO] Ipod model: "); | ||
542 | switch (ipod_version) { | ||
543 | case 0x3: printf("3rd Generation\n"); break; | ||
544 | case 0x4: printf("1st Generation Mini\n"); break; | ||
545 | case 0x5: printf("4th Generation\n"); break; | ||
546 | case 0x6: printf("Photo/Color\n"); break; | ||
547 | case 0x7: printf("2nd Generation Mini\n"); break; | ||
548 | case 0xc: printf("1st Generation Nano\n"); break; | ||
549 | case 0xb: printf("Video (aka 5th Generation)\n"); break; | ||
550 | default: printf("UNKNOWN (Firmware version is %08x)\n",ipod_directory[0].vers); | ||
551 | } | ||
552 | |||
553 | if (action==LIST_IMAGES) { | ||
554 | list_images(nimages,ipod_directory); | ||
555 | #if 0 | ||
556 | } else if (mode==READ) { | ||
426 | outfile = open(filename,O_CREAT|O_WRONLY|O_BINARY,S_IREAD|S_IWRITE); | 557 | outfile = open(filename,O_CREAT|O_WRONLY|O_BINARY,S_IREAD|S_IWRITE); |
427 | if (outfile < 0) { | 558 | if (outfile < 0) { |
428 | perror(filename); | 559 | perror(filename); |
@@ -433,22 +564,8 @@ int main(int argc, char* argv[]) | |||
433 | 564 | ||
434 | close(outfile); | 565 | close(outfile); |
435 | } else if (mode==WRITE) { | 566 | } else if (mode==WRITE) { |
436 | /* Close existing file and re-open for writing */ | 567 | if (ipod_reopen_rw(&dh, devicename) < 0) { |
437 | unlock_volume(dh); | 568 | return 5; |
438 | CloseHandle(dh); | ||
439 | |||
440 | dh = CreateFile(diskname, GENERIC_WRITE, | ||
441 | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, | ||
442 | FILE_FLAG_WRITE_THROUGH | FILE_FLAG_NO_BUFFERING, NULL); | ||
443 | |||
444 | if (dh == INVALID_HANDLE_VALUE) { | ||
445 | error(" Error opening disk: "); | ||
446 | return 2; | ||
447 | } | ||
448 | |||
449 | if (!lock_volume(dh)) { | ||
450 | error(" Error locking disk: "); | ||
451 | return 2; | ||
452 | } | 569 | } |
453 | 570 | ||
454 | infile = open(filename,O_RDONLY|O_BINARY); | 571 | infile = open(filename,O_RDONLY|O_BINARY); |
@@ -469,9 +586,10 @@ int main(int argc, char* argv[]) | |||
469 | } | 586 | } |
470 | 587 | ||
471 | close(infile); | 588 | close(infile); |
589 | #endif | ||
472 | } | 590 | } |
473 | 591 | ||
474 | unlock_volume(dh); | 592 | ipod_close(dh); |
475 | CloseHandle(dh); | 593 | |
476 | return 0; | 594 | return 0; |
477 | } | 595 | } |