summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDave Chapman <dave@dchapman.com>2006-12-13 09:02:18 +0000
committerDave Chapman <dave@dchapman.com>2006-12-13 09:02:18 +0000
commit4b7e1e09450b9132b2e30395d2cd73be618e1255 (patch)
treebd6bc4be393c8485e33f3624760ae37c526e2106
parent8a55822ae3e6150e57bd80fc225e196761453bfc (diff)
downloadrockbox-4b7e1e09450b9132b2e30395d2cd73be618e1255.tar.gz
rockbox-4b7e1e09450b9132b2e30395d2cd73be618e1255.zip
Work-in-progress towards a cross-platform ipodpatcher which will edit the firmware partition directly, incorporating the ipod_fw.c functionality. Tested successfully on win32 and Linux but it only lists the contents of the firmware partition at the moment - no actual reading or writing
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@11748 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--tools/ipodpatcher/Makefile11
-rw-r--r--tools/ipodpatcher/ipodio-posix.c96
-rw-r--r--tools/ipodpatcher/ipodio-win32.c190
-rw-r--r--tools/ipodpatcher/ipodio.h39
-rw-r--r--tools/ipodpatcher/ipodpatcher.c454
5 files changed, 618 insertions, 172 deletions
diff --git a/tools/ipodpatcher/Makefile b/tools/ipodpatcher/Makefile
index 6eb3dce75e..21994de754 100644
--- a/tools/ipodpatcher/Makefile
+++ b/tools/ipodpatcher/Makefile
@@ -1,8 +1,11 @@
1all: ipodpatcher.exe 1all: ipodpatcher
2 2
3ipodpatcher.exe: ipodpatcher.c 3ipodpatcher: ipodpatcher.c ipodio-posix.c parttypes.h
4 i586-mingw32msvc-gcc -Wall -o ipodpatcher.exe ipodpatcher.c 4 gcc -Wall -o ipodpatcher ipodpatcher.c ipodio-posix.c
5
6ipodpatcher.exe: ipodpatcher.c ipodio-win32.c parttypes.h
7 i586-mingw32msvc-gcc -Wall -o ipodpatcher.exe ipodpatcher.c ipodio-win32.c
5 i586-mingw32msvc-strip ipodpatcher.exe 8 i586-mingw32msvc-strip ipodpatcher.exe
6 9
7clean: 10clean:
8 rm -f ipodpatcher.exe *~ 11 rm -f ipodpatcher.exe ipodpatcher *~
diff --git a/tools/ipodpatcher/ipodio-posix.c b/tools/ipodpatcher/ipodio-posix.c
new file mode 100644
index 0000000000..cfded35390
--- /dev/null
+++ b/tools/ipodpatcher/ipodio-posix.c
@@ -0,0 +1,96 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2006 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 <sys/types.h>
26#include <sys/stat.h>
27
28#include "ipodio.h"
29
30void print_error(char* msg)
31{
32 perror(msg);
33}
34
35int ipod_open(HANDLE* dh, char* diskname, int* sector_size)
36{
37 *dh=open(diskname,O_RDONLY);
38 if (*dh < 0) {
39 perror(diskname);
40 return -1;
41 }
42
43 /* TODO: Detect sector size */
44 *sector_size = 512;
45
46 return 0;
47}
48
49
50int ipod_reopen_rw(HANDLE* dh, char* diskname)
51{
52 close(*dh);
53 *dh=open(diskname,O_RDWR);
54 if (*dh < 0) {
55 perror(diskname);
56 return -1;
57 }
58 return 0;
59}
60
61int ipod_close(HANDLE dh)
62{
63 close(dh);
64 return 0;
65}
66
67int ipod_alloc_buffer(unsigned char** sectorbuf, int bufsize)
68{
69 *sectorbuf=malloc(bufsize);
70 if (*sectorbuf == NULL) {
71 return -1;
72 }
73 return 0;
74}
75
76int ipod_seek(HANDLE dh, unsigned long pos)
77{
78 off_t res;
79
80 res = lseek(dh, pos, SEEK_SET);
81
82 if (res == -1) {
83 return -1;
84 }
85 return 0;
86}
87
88int ipod_read(HANDLE dh, unsigned char* buf, int nbytes)
89{
90 return read(dh, buf, nbytes);
91}
92
93int ipod_write(HANDLE dh, unsigned char* buf, int nbytes)
94{
95 return write(dh, buf, nbytes);
96}
diff --git a/tools/ipodpatcher/ipodio-win32.c b/tools/ipodpatcher/ipodio-win32.c
new file mode 100644
index 0000000000..4914e4b6cd
--- /dev/null
+++ b/tools/ipodpatcher/ipodio-win32.c
@@ -0,0 +1,190 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2006 Dave Chapman
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.
19 * See the file COPYING in the source tree root for full license agreement.
20 *
21 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
22 * KIND, either express or implied.
23 *
24 ****************************************************************************/
25
26#include <stdio.h>
27#include <unistd.h>
28#include <fcntl.h>
29#include <string.h>
30#include <stdlib.h>
31#include <sys/types.h>
32#include <sys/stat.h>
33#ifdef __WIN32__
34#include <windows.h>
35#include <winioctl.h>
36#endif
37
38#include "ipodio.h"
39
40static int lock_volume(HANDLE hDisk)
41{
42 DWORD dummy;
43
44 return DeviceIoControl(hDisk, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0,
45 &dummy, NULL);
46}
47
48static int unlock_volume(HANDLE hDisk)
49{
50 DWORD dummy;
51
52 return DeviceIoControl(hDisk, FSCTL_UNLOCK_VOLUME, NULL, 0, NULL, 0,
53 &dummy, NULL);
54}
55
56void print_error(char* msg)
57{
58 char* pMsgBuf;
59
60 printf(msg);
61 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
62 FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(),
63 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&pMsgBuf,
64 0, NULL);
65 printf(pMsgBuf);
66 LocalFree(pMsgBuf);
67}
68
69int ipod_open(HANDLE* dh, char* diskname, int* sector_size)
70{
71 DISK_GEOMETRY_EX diskgeometry_ex;
72 DISK_GEOMETRY diskgeometry;
73 unsigned long n;
74
75 *dh = CreateFile(diskname, GENERIC_READ,
76 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
77 FILE_FLAG_WRITE_THROUGH | FILE_FLAG_NO_BUFFERING, NULL);
78
79 if (*dh == INVALID_HANDLE_VALUE) {
80 print_error(" Error opening disk: ");
81 return -1;
82 }
83
84 if (!lock_volume(*dh)) {
85 print_error(" Error locking disk: ");
86 return -1;
87 }
88
89 if (!DeviceIoControl(*dh,
90 IOCTL_DISK_GET_DRIVE_GEOMETRY_EX,
91 NULL,
92 0,
93 &diskgeometry_ex,
94 sizeof(diskgeometry_ex),
95 &n,
96 NULL)) {
97 if (!DeviceIoControl(*dh,
98 IOCTL_DISK_GET_DRIVE_GEOMETRY,
99 NULL,
100 0,
101 &diskgeometry,
102 sizeof(diskgeometry),
103 &n,
104 NULL)) {
105 print_error(" Error reading disk geometry: ");
106 return -1;
107 } else {
108 *sector_size=diskgeometry.BytesPerSector;
109 }
110 } else {
111 *sector_size=diskgeometry_ex.Geometry.BytesPerSector;
112 }
113
114 return 0;
115}
116
117int ipod_reopen_rw(HANDLE* dh, char* diskname)
118{
119 /* Close existing file and re-open for writing */
120 unlock_volume(*dh);
121 CloseHandle(*dh);
122
123 *dh = CreateFile(diskname, GENERIC_WRITE,
124 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
125 FILE_FLAG_WRITE_THROUGH | FILE_FLAG_NO_BUFFERING, NULL);
126
127 if (*dh == INVALID_HANDLE_VALUE) {
128 print_error(" Error opening disk: ");
129 return -1;
130 }
131
132 if (!lock_volume(*dh)) {
133 print_error(" Error locking disk: ");
134 return -1;
135 }
136
137 return 0;
138}
139
140int ipod_close(HANDLE dh)
141{
142 unlock_volume(dh);
143 CloseHandle(dh);
144 return 0;
145}
146
147int ipod_alloc_buffer(unsigned char** sectorbuf, int bufsize)
148{
149 /* The ReadFile function requires a memory buffer aligned to a multiple of
150 the disk sector size. */
151 *sectorbuf = VirtualAlloc(NULL, bufsize, MEM_COMMIT, PAGE_READWRITE);
152 if (*sectorbuf == NULL) {
153 print_error(" Error allocating a buffer: ");
154 return -1;
155 }
156 return 0;
157}
158
159int ipod_seek(HANDLE dh, unsigned long pos)
160{
161 if (SetFilePointer(dh, pos, NULL, FILE_BEGIN)==0xffffffff) {
162 print_error(" Seek error ");
163 return -1;
164 }
165 return 0;
166}
167
168int ipod_read(HANDLE dh, unsigned char* buf, int nbytes)
169{
170 unsigned long count;
171
172 if (!ReadFile(dh, buf, nbytes, &count, NULL)) {
173 print_error(" Error reading from disk: ");
174 return -1;
175 }
176
177 return count;
178}
179
180int ipod_write(HANDLE dh, unsigned char* buf, int nbytes)
181{
182 unsigned long count;
183
184 if (!WriteFile(dh, buf, nbytes, &count, NULL)) {
185 print_error(" Error writing to disk: ");
186 return -1;
187 }
188
189 return count;
190}
diff --git a/tools/ipodpatcher/ipodio.h b/tools/ipodpatcher/ipodio.h
new file mode 100644
index 0000000000..8496766b76
--- /dev/null
+++ b/tools/ipodpatcher/ipodio.h
@@ -0,0 +1,39 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2006 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#ifndef __IPODIO_H
21#define __IPODIO_H
22
23#ifdef __WIN32__
24#include <windows.h>
25#else
26#define HANDLE int
27#define O_BINARY 0
28#endif
29
30void print_error(char* msg);
31int ipod_open(HANDLE* dh, char* diskname, int* sector_size);
32int ipod_reopen_rw(HANDLE* dh, char* diskname);
33int ipod_close(HANDLE dh);
34int ipod_seek(HANDLE dh, unsigned long pos);
35int ipod_read(HANDLE dh, unsigned char* buf, int nbytes);
36int ipod_write(HANDLE dh, unsigned char* buf, int nbytes);
37int ipod_alloc_buffer(unsigned char** sectorbuf, int bufsize);
38
39#endif
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 */
37static 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
42unsigned char* sectorbuf; 64unsigned char* sectorbuf;
43 65
44char* get_parttype(int pt) 66char* get_parttype(int pt)
@@ -57,35 +79,6 @@ char* get_parttype(int pt)
57 return unknown; 79 return unknown;
58} 80}
59 81
60void 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
73int 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
81int 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
89off_t filesize(int fd) { 82off_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
109struct partinfo { 98struct 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) \ 104int 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
111int 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
119void display_partinfo(struct partinfo* pinfo, int sector_size) 124void 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
133int read_partinfo(HANDLE dh, int sector_size, struct partinfo* pinfo) 144int 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
282void print_usage(void) { 296void 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
295enum { 325enum {
296 NONE, 326 NONE,
297 SHOW_INFO, 327 SHOW_INFO,
298 READ, 328 LIST_IMAGES
299 WRITE 329};
330
331char* ftypename[] = { "OSOS", "RSRC", "AUPD", "HIBE" };
332
333enum firmwaretype_t {
334 FTYPE_OSOS = 0,
335 FTYPE_RSRC,
336 FTYPE_AUPD,
337 FTYPE_HIBE
338};
339
340struct 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
352int 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
422int 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
302int main(int argc, char* argv[]) 466int 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(&sectorbuf,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, &sector_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}