diff options
Diffstat (limited to 'rbutil/ipodpatcher')
-rw-r--r-- | rbutil/ipodpatcher/Makefile | 61 | ||||
-rw-r--r-- | rbutil/ipodpatcher/ipod2c.c | 139 | ||||
-rw-r--r-- | rbutil/ipodpatcher/ipodio-posix.c | 115 | ||||
-rw-r--r-- | rbutil/ipodpatcher/ipodio-win32.c | 190 | ||||
-rw-r--r-- | rbutil/ipodpatcher/ipodio.h | 89 | ||||
-rw-r--r-- | rbutil/ipodpatcher/ipodpatcher.c | 1261 | ||||
-rw-r--r-- | rbutil/ipodpatcher/ipodpatcher.h | 51 | ||||
-rw-r--r-- | rbutil/ipodpatcher/main.c | 429 | ||||
-rw-r--r-- | rbutil/ipodpatcher/parttypes.h | 109 |
9 files changed, 2444 insertions, 0 deletions
diff --git a/rbutil/ipodpatcher/Makefile b/rbutil/ipodpatcher/Makefile new file mode 100644 index 0000000000..f5a4d7cfb3 --- /dev/null +++ b/rbutil/ipodpatcher/Makefile | |||
@@ -0,0 +1,61 @@ | |||
1 | CFLAGS=-Wall | ||
2 | |||
3 | BOOT_H = ipod3g.h ipod4g.h ipodcolor.h ipodmini.h ipodmini2g.h ipodnano.h ipodvideo.h | ||
4 | |||
5 | # Uncomment the next two lines to build with embedded bootloaders and the | ||
6 | # --install option and interactive mode. You need the full set of Rockbox | ||
7 | # bootloaders in this directory - download them from | ||
8 | # http://download.rockbox.org/bootloader/ipod/bootloaders.zip | ||
9 | |||
10 | #BOOTSRC = ipod3g.c ipod4g.c ipodcolor.c ipodmini.c ipodmini2g.c ipodnano.c ipodvideo.c | ||
11 | #CFLAGS += -DWITH_BOOTOBJS | ||
12 | |||
13 | ifeq ($(findstring CYGWIN,$(shell uname)),CYGWIN) | ||
14 | OUTPUT=ipodpatcher.exe | ||
15 | CROSS= | ||
16 | CFLAGS+=-mno-cygwin | ||
17 | else | ||
18 | OUTPUT=ipodpatcher | ||
19 | CROSS=i586-mingw32msvc- | ||
20 | endif | ||
21 | |||
22 | NATIVECC = gcc | ||
23 | CC = $(CROSS)gcc | ||
24 | |||
25 | all: $(OUTPUT) | ||
26 | |||
27 | ipodpatcher: main.c ipodpatcher.c ipodio-posix.c parttypes.h $(BOOTSRC) | ||
28 | gcc $(CFLAGS) -o ipodpatcher main.c ipodpatcher.c ipodio-posix.c $(BOOTSRC) | ||
29 | strip ipodpatcher | ||
30 | |||
31 | ipodpatcher.exe: main.c ipodpatcher.c ipodio-win32.c parttypes.h $(BOOTSRC) | ||
32 | $(CC) $(CFLAGS) -o ipodpatcher.exe main.c ipodpatcher.c ipodio-win32.c $(BOOTSRC) | ||
33 | $(CROSS)strip ipodpatcher.exe | ||
34 | |||
35 | ipod2c: ipod2c.c | ||
36 | $(NATIVECC) $(CFLAGS) -o ipod2c ipod2c.c | ||
37 | |||
38 | ipod3g.c: bootloader-ipod3g.ipod ipod2c | ||
39 | ./ipod2c bootloader-ipod3g.ipod ipod3g | ||
40 | |||
41 | ipod4g.c: bootloader-ipod4g.ipod ipod2c | ||
42 | ./ipod2c bootloader-ipod4g.ipod ipod4g | ||
43 | |||
44 | ipodcolor.c: bootloader-ipodcolor.ipod ipod2c | ||
45 | ./ipod2c bootloader-ipodcolor.ipod ipodcolor | ||
46 | |||
47 | ipodmini.c: bootloader-ipodmini.ipod ipod2c | ||
48 | ./ipod2c bootloader-ipodmini.ipod ipodmini | ||
49 | |||
50 | ipodmini2g.c: bootloader-ipodmini2g.ipod ipod2c | ||
51 | ./ipod2c bootloader-ipodmini2g.ipod ipodmini2g | ||
52 | |||
53 | ipodnano.c: bootloader-ipodnano.ipod ipod2c | ||
54 | ./ipod2c bootloader-ipodnano.ipod ipodnano | ||
55 | |||
56 | ipodvideo.c: bootloader-ipodvideo.ipod ipod2c | ||
57 | ./ipod2c bootloader-ipodvideo.ipod ipodvideo | ||
58 | |||
59 | |||
60 | clean: | ||
61 | rm -f ipodpatcher.exe ipodpatcher ipod2c *~ $(BOOTSRC) $(BOOT_H) | ||
diff --git a/rbutil/ipodpatcher/ipod2c.c b/rbutil/ipodpatcher/ipod2c.c new file mode 100644 index 0000000000..af2e25dd09 --- /dev/null +++ b/rbutil/ipodpatcher/ipod2c.c | |||
@@ -0,0 +1,139 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id: ipodio-win32.c 12205 2007-02-05 01:20:20Z dave $ | ||
9 | * | ||
10 | * Copyright (C) 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 <string.h> | ||
22 | #include <sys/types.h> | ||
23 | #include <sys/stat.h> | ||
24 | #include <unistd.h> | ||
25 | #include <fcntl.h> | ||
26 | #include <stdlib.h> | ||
27 | |||
28 | #ifndef O_BINARY | ||
29 | #define O_BINARY 0 | ||
30 | #endif | ||
31 | |||
32 | static off_t filesize(int fd) | ||
33 | { | ||
34 | struct stat buf; | ||
35 | |||
36 | fstat(fd,&buf); | ||
37 | return buf.st_size; | ||
38 | } | ||
39 | |||
40 | static int write_cfile(unsigned char* buf, off_t len, char* cname) | ||
41 | { | ||
42 | char filename[256]; | ||
43 | FILE* fp; | ||
44 | int i; | ||
45 | |||
46 | snprintf(filename,256,"%s.c",cname); | ||
47 | |||
48 | fp = fopen(filename,"w+"); | ||
49 | if (fp == NULL) { | ||
50 | fprintf(stderr,"Couldn't open %s\n",filename); | ||
51 | return -1; | ||
52 | } | ||
53 | |||
54 | fprintf(fp,"/* Generated by ipod2c */\n\n"); | ||
55 | fprintf(fp,"unsigned char %s[] = {",cname); | ||
56 | |||
57 | for (i=0;i<len;i++) { | ||
58 | if ((i % 16) == 0) { | ||
59 | fprintf(fp,"\n "); | ||
60 | } | ||
61 | if (i == (len-1)) { | ||
62 | fprintf(fp,"0x%02x",buf[i]); | ||
63 | } else { | ||
64 | fprintf(fp,"0x%02x, ",buf[i]); | ||
65 | } | ||
66 | } | ||
67 | fprintf(fp,"\n};\n"); | ||
68 | |||
69 | fclose(fp); | ||
70 | return 0; | ||
71 | } | ||
72 | |||
73 | static int write_hfile(unsigned char* buf, off_t len, char* cname) | ||
74 | { | ||
75 | char filename[256]; | ||
76 | FILE* fp; | ||
77 | |||
78 | snprintf(filename,256,"%s.h",cname); | ||
79 | fp = fopen(filename,"w+"); | ||
80 | if (fp == NULL) { | ||
81 | fprintf(stderr,"Couldn't open %s\n",filename); | ||
82 | return -1; | ||
83 | } | ||
84 | |||
85 | fprintf(fp,"/* Generated by ipod2c */\n\n"); | ||
86 | fprintf(fp,"#define LEN_%s %d\n",cname,(int)len); | ||
87 | fprintf(fp,"extern unsigned char %s[];\n",cname); | ||
88 | fclose(fp); | ||
89 | return 0; | ||
90 | } | ||
91 | |||
92 | int main (int argc, char* argv[]) | ||
93 | { | ||
94 | char* infile; | ||
95 | char* cname; | ||
96 | int fd; | ||
97 | unsigned char* buf; | ||
98 | int len; | ||
99 | int n; | ||
100 | |||
101 | if (argc != 3) { | ||
102 | fprintf(stderr,"Usage: ipod2c file.bin cname\n"); | ||
103 | return 0; | ||
104 | } | ||
105 | |||
106 | infile=argv[1]; | ||
107 | cname=argv[2]; | ||
108 | |||
109 | fd = open(infile,O_RDONLY); | ||
110 | if (fd < 0) { | ||
111 | fprintf(stderr,"Can not open %s\n",infile); | ||
112 | return 0; | ||
113 | } | ||
114 | |||
115 | len = filesize(fd) - 8; | ||
116 | |||
117 | n = lseek(fd,8,SEEK_SET); | ||
118 | if (n != 8) { | ||
119 | fprintf(stderr,"Seek failed\n"); | ||
120 | return 0; | ||
121 | } | ||
122 | |||
123 | buf = malloc(len); | ||
124 | n = read(fd,buf,len); | ||
125 | if (n < len) { | ||
126 | fprintf(stderr,"Short read, aborting\n"); | ||
127 | return 0; | ||
128 | } | ||
129 | close(fd); | ||
130 | |||
131 | if (write_cfile(buf,len,cname) < 0) { | ||
132 | return -1; | ||
133 | } | ||
134 | if (write_hfile(buf,len,cname) < 0) { | ||
135 | return -1; | ||
136 | } | ||
137 | |||
138 | return 0; | ||
139 | } | ||
diff --git a/rbutil/ipodpatcher/ipodio-posix.c b/rbutil/ipodpatcher/ipodio-posix.c new file mode 100644 index 0000000000..365bc27291 --- /dev/null +++ b/rbutil/ipodpatcher/ipodio-posix.c | |||
@@ -0,0 +1,115 @@ | |||
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 <sys/types.h> | ||
26 | #include <sys/stat.h> | ||
27 | #include <sys/ioctl.h> | ||
28 | |||
29 | #if defined(linux) || defined (__linux) | ||
30 | #include <sys/mount.h> | ||
31 | #define IPOD_SECTORSIZE_IOCTL BLKSSZGET | ||
32 | #elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) \ | ||
33 | || defined(__bsdi__) || defined(__DragonFly__) | ||
34 | #include <sys/disk.h> | ||
35 | #define IPOD_SECTORSIZE_IOCTL DIOCGSECTORSIZE | ||
36 | #elif defined(__APPLE__) && defined(__MACH__) | ||
37 | #include <sys/disk.h> | ||
38 | #define IPOD_SECTORSIZE_IOCTL DKIOCGETBLOCKSIZE | ||
39 | #else | ||
40 | #error No sector-size detection implemented for this platform | ||
41 | #endif | ||
42 | |||
43 | #include "ipodio.h" | ||
44 | |||
45 | void print_error(char* msg) | ||
46 | { | ||
47 | perror(msg); | ||
48 | } | ||
49 | |||
50 | int ipod_open(struct ipod_t* ipod, int silent) | ||
51 | { | ||
52 | ipod->dh=open(ipod->diskname,O_RDONLY); | ||
53 | if (ipod->dh < 0) { | ||
54 | if (!silent) perror(ipod->diskname); | ||
55 | return -1; | ||
56 | } | ||
57 | |||
58 | if(ioctl(ipod->dh,IPOD_SECTORSIZE_IOCTL,&ipod->sector_size) < 0) { | ||
59 | ipod->sector_size=512; | ||
60 | if (!silent) { | ||
61 | fprintf(stderr,"[ERR] ioctl() call to get sector size failed, defaulting to %d\n" | ||
62 | ,ipod->sector_size); | ||
63 | } | ||
64 | } | ||
65 | return 0; | ||
66 | } | ||
67 | |||
68 | |||
69 | int ipod_reopen_rw(struct ipod_t* ipod) | ||
70 | { | ||
71 | close(ipod->dh); | ||
72 | ipod->dh=open(ipod->diskname,O_RDWR); | ||
73 | if (ipod->dh < 0) { | ||
74 | perror(ipod->diskname); | ||
75 | return -1; | ||
76 | } | ||
77 | return 0; | ||
78 | } | ||
79 | |||
80 | int ipod_close(struct ipod_t* ipod) | ||
81 | { | ||
82 | close(ipod->dh); | ||
83 | return 0; | ||
84 | } | ||
85 | |||
86 | int ipod_alloc_buffer(unsigned char** sectorbuf, int bufsize) | ||
87 | { | ||
88 | *sectorbuf=malloc(bufsize); | ||
89 | if (*sectorbuf == NULL) { | ||
90 | return -1; | ||
91 | } | ||
92 | return 0; | ||
93 | } | ||
94 | |||
95 | int ipod_seek(struct ipod_t* ipod, unsigned long pos) | ||
96 | { | ||
97 | off_t res; | ||
98 | |||
99 | res = lseek(ipod->dh, pos, SEEK_SET); | ||
100 | |||
101 | if (res == -1) { | ||
102 | return -1; | ||
103 | } | ||
104 | return 0; | ||
105 | } | ||
106 | |||
107 | int ipod_read(struct ipod_t* ipod, unsigned char* buf, int nbytes) | ||
108 | { | ||
109 | return read(ipod->dh, buf, nbytes); | ||
110 | } | ||
111 | |||
112 | int ipod_write(struct ipod_t* ipod, unsigned char* buf, int nbytes) | ||
113 | { | ||
114 | return write(ipod->dh, buf, nbytes); | ||
115 | } | ||
diff --git a/rbutil/ipodpatcher/ipodio-win32.c b/rbutil/ipodpatcher/ipodio-win32.c new file mode 100644 index 0000000000..83f00b8cd9 --- /dev/null +++ b/rbutil/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-2007 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 | |||
40 | static 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 | |||
48 | static 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 | |||
56 | void 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 | |||
69 | int ipod_open(struct ipod_t* ipod, int silent) | ||
70 | { | ||
71 | DISK_GEOMETRY_EX diskgeometry_ex; | ||
72 | DISK_GEOMETRY diskgeometry; | ||
73 | unsigned long n; | ||
74 | |||
75 | ipod->dh = CreateFile(ipod->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 (ipod->dh == INVALID_HANDLE_VALUE) { | ||
80 | if (!silent) print_error(" Error opening disk: "); | ||
81 | return -1; | ||
82 | } | ||
83 | |||
84 | if (!lock_volume(ipod->dh)) { | ||
85 | if (!silent) print_error(" Error locking disk: "); | ||
86 | return -1; | ||
87 | } | ||
88 | |||
89 | if (!DeviceIoControl(ipod->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(ipod->dh, | ||
98 | IOCTL_DISK_GET_DRIVE_GEOMETRY, | ||
99 | NULL, | ||
100 | 0, | ||
101 | &diskgeometry, | ||
102 | sizeof(diskgeometry), | ||
103 | &n, | ||
104 | NULL)) { | ||
105 | if (!silent) print_error(" Error reading disk geometry: "); | ||
106 | return -1; | ||
107 | } else { | ||
108 | ipod->sector_size=diskgeometry.BytesPerSector; | ||
109 | } | ||
110 | } else { | ||
111 | ipod->sector_size=diskgeometry_ex.Geometry.BytesPerSector; | ||
112 | } | ||
113 | |||
114 | return 0; | ||
115 | } | ||
116 | |||
117 | int ipod_reopen_rw(struct ipod_t* ipod) | ||
118 | { | ||
119 | /* Close existing file and re-open for writing */ | ||
120 | unlock_volume(ipod->dh); | ||
121 | CloseHandle(ipod->dh); | ||
122 | |||
123 | ipod->dh = CreateFile(ipod->diskname, GENERIC_READ | 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 (ipod->dh == INVALID_HANDLE_VALUE) { | ||
128 | print_error(" Error opening disk: "); | ||
129 | return -1; | ||
130 | } | ||
131 | |||
132 | if (!lock_volume(ipod->dh)) { | ||
133 | print_error(" Error locking disk: "); | ||
134 | return -1; | ||
135 | } | ||
136 | |||
137 | return 0; | ||
138 | } | ||
139 | |||
140 | int ipod_close(struct ipod_t* ipod) | ||
141 | { | ||
142 | unlock_volume(ipod->dh); | ||
143 | CloseHandle(ipod->dh); | ||
144 | return 0; | ||
145 | } | ||
146 | |||
147 | int 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 = (unsigned char*)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 | |||
159 | int ipod_seek(struct ipod_t* ipod, unsigned long pos) | ||
160 | { | ||
161 | if (SetFilePointer(ipod->dh, pos, NULL, FILE_BEGIN)==0xffffffff) { | ||
162 | print_error(" Seek error "); | ||
163 | return -1; | ||
164 | } | ||
165 | return 0; | ||
166 | } | ||
167 | |||
168 | int ipod_read(struct ipod_t* ipod, unsigned char* buf, int nbytes) | ||
169 | { | ||
170 | unsigned long count; | ||
171 | |||
172 | if (!ReadFile(ipod->dh, buf, nbytes, &count, NULL)) { | ||
173 | print_error(" Error reading from disk: "); | ||
174 | return -1; | ||
175 | } | ||
176 | |||
177 | return count; | ||
178 | } | ||
179 | |||
180 | int ipod_write(struct ipod_t* ipod, unsigned char* buf, int nbytes) | ||
181 | { | ||
182 | unsigned long count; | ||
183 | |||
184 | if (!WriteFile(ipod->dh, buf, nbytes, &count, NULL)) { | ||
185 | print_error(" Error writing to disk: "); | ||
186 | return -1; | ||
187 | } | ||
188 | |||
189 | return count; | ||
190 | } | ||
diff --git a/rbutil/ipodpatcher/ipodio.h b/rbutil/ipodpatcher/ipodio.h new file mode 100644 index 0000000000..d0641faa2b --- /dev/null +++ b/rbutil/ipodpatcher/ipodio.h | |||
@@ -0,0 +1,89 @@ | |||
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 | #ifndef __IPODIO_H | ||
21 | #define __IPODIO_H | ||
22 | |||
23 | #include <stdint.h> | ||
24 | |||
25 | #ifdef __WIN32__ | ||
26 | #include <windows.h> | ||
27 | #else | ||
28 | #define HANDLE int | ||
29 | #define O_BINARY 0 | ||
30 | #endif | ||
31 | |||
32 | /* The maximum number of images in a firmware partition - a guess... */ | ||
33 | #define MAX_IMAGES 10 | ||
34 | |||
35 | enum firmwaretype_t { | ||
36 | FTYPE_OSOS = 0, | ||
37 | FTYPE_RSRC, | ||
38 | FTYPE_AUPD, | ||
39 | FTYPE_HIBE | ||
40 | }; | ||
41 | |||
42 | struct ipod_directory_t { | ||
43 | enum firmwaretype_t ftype; | ||
44 | int id; | ||
45 | uint32_t devOffset; /* Offset of image relative to one sector into bootpart*/ | ||
46 | uint32_t len; | ||
47 | uint32_t addr; | ||
48 | uint32_t entryOffset; | ||
49 | uint32_t chksum; | ||
50 | uint32_t vers; | ||
51 | uint32_t loadAddr; | ||
52 | }; | ||
53 | |||
54 | struct partinfo_t { | ||
55 | unsigned long start; /* first sector (LBA) */ | ||
56 | unsigned long size; /* number of sectors */ | ||
57 | int type; | ||
58 | }; | ||
59 | |||
60 | struct ipod_t { | ||
61 | HANDLE dh; | ||
62 | char diskname[4096]; | ||
63 | int sector_size; | ||
64 | struct ipod_directory_t ipod_directory[MAX_IMAGES]; | ||
65 | int nimages; | ||
66 | off_t diroffset; | ||
67 | off_t start; /* Offset in bytes of firmware partition from start of disk */ | ||
68 | off_t fwoffset; /* Offset in bytes of start of firmware images from start of disk */ | ||
69 | struct partinfo_t pinfo[4]; | ||
70 | int modelnum; | ||
71 | char* modelname; | ||
72 | char* modelstr; | ||
73 | int macpod; | ||
74 | #ifdef WITH_BOOTOBJS | ||
75 | unsigned char* bootloader; | ||
76 | int bootloader_len; | ||
77 | #endif | ||
78 | }; | ||
79 | |||
80 | void print_error(char* msg); | ||
81 | int ipod_open(struct ipod_t* ipod, int silent); | ||
82 | int ipod_reopen_rw(struct ipod_t* ipod); | ||
83 | int ipod_close(struct ipod_t* ipod); | ||
84 | int ipod_seek(struct ipod_t* ipod, unsigned long pos); | ||
85 | int ipod_read(struct ipod_t* ipod, unsigned char* buf, int nbytes); | ||
86 | int ipod_write(struct ipod_t* ipod, unsigned char* buf, int nbytes); | ||
87 | int ipod_alloc_buffer(unsigned char** sectorbuf, int bufsize); | ||
88 | |||
89 | #endif | ||
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 | } | ||
diff --git a/rbutil/ipodpatcher/ipodpatcher.h b/rbutil/ipodpatcher/ipodpatcher.h new file mode 100644 index 0000000000..c533f4c2dc --- /dev/null +++ b/rbutil/ipodpatcher/ipodpatcher.h | |||
@@ -0,0 +1,51 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id: ipodpatcher.c 12237 2007-02-08 21:31:38Z dave $ | ||
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 | #ifndef _IPODPATCHER_H | ||
21 | #define _IPODPATCHER_H | ||
22 | |||
23 | #include "ipodio.h" | ||
24 | |||
25 | /* Size of buffer for disk I/O - 8MB is large enough for any version | ||
26 | of the Apple firmware, but not the Nano's RSRC image. */ | ||
27 | #define BUFFER_SIZE 8*1024*1024 | ||
28 | extern unsigned char* sectorbuf; | ||
29 | |||
30 | #define FILETYPE_DOT_IPOD 0 | ||
31 | #define FILETYPE_DOT_BIN 1 | ||
32 | #ifdef WITH_BOOTOBJS | ||
33 | #define FILETYPE_INTERNAL 2 | ||
34 | #endif | ||
35 | |||
36 | void display_partinfo(struct ipod_t* ipod); | ||
37 | int read_partinfo(struct ipod_t* ipod, int silent); | ||
38 | int read_partition(struct ipod_t* ipod, int outfile); | ||
39 | int write_partition(struct ipod_t* ipod, int infile); | ||
40 | int diskmove(struct ipod_t* ipod, int delta); | ||
41 | int add_bootloader(struct ipod_t* ipod, char* filename, int type); | ||
42 | int delete_bootloader(struct ipod_t* ipod); | ||
43 | int write_firmware(struct ipod_t* ipod, char* filename, int type); | ||
44 | int read_firmware(struct ipod_t* ipod, char* filename); | ||
45 | int read_directory(struct ipod_t* ipod); | ||
46 | int list_images(struct ipod_t* ipod); | ||
47 | int getmodel(struct ipod_t* ipod, int ipod_version); | ||
48 | int ipod_scan(struct ipod_t* ipod); | ||
49 | off_t filesize(int fd); | ||
50 | |||
51 | #endif | ||
diff --git a/rbutil/ipodpatcher/main.c b/rbutil/ipodpatcher/main.c new file mode 100644 index 0000000000..d183b9bc52 --- /dev/null +++ b/rbutil/ipodpatcher/main.c | |||
@@ -0,0 +1,429 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id: ipodpatcher.c 12237 2007-02-08 21:31:38Z dave $ | ||
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 "ipodpatcher.h" | ||
30 | #include "ipodio.h" | ||
31 | |||
32 | #define VERSION "0.8 with r12194-070204 bootloaders" | ||
33 | |||
34 | int verbose = 0; | ||
35 | |||
36 | enum { | ||
37 | NONE, | ||
38 | #ifdef WITH_BOOTOBJS | ||
39 | INSTALL, | ||
40 | #endif | ||
41 | INTERACTIVE, | ||
42 | SHOW_INFO, | ||
43 | LIST_IMAGES, | ||
44 | DELETE_BOOTLOADER, | ||
45 | ADD_BOOTLOADER, | ||
46 | READ_FIRMWARE, | ||
47 | WRITE_FIRMWARE, | ||
48 | READ_PARTITION, | ||
49 | WRITE_PARTITION | ||
50 | }; | ||
51 | |||
52 | void print_macpod_warning(void) | ||
53 | { | ||
54 | printf("[INFO] ************************************************************************\n"); | ||
55 | printf("[INFO] *** WARNING FOR ROCKBOX USERS\n"); | ||
56 | printf("[INFO] *** You must convert this ipod to FAT32 format (aka a \"winpod\")\n"); | ||
57 | printf("[INFO] *** if you want to run Rockbox. Rockbox WILL NOT work on this ipod.\n"); | ||
58 | printf("[INFO] *** See http://www.rockbox.org/twiki/bin/view/Main/IpodConversionToFAT32\n"); | ||
59 | printf("[INFO] ************************************************************************\n"); | ||
60 | } | ||
61 | |||
62 | void print_usage(void) | ||
63 | { | ||
64 | fprintf(stderr,"Usage: ipodpatcher --scan\n"); | ||
65 | #ifdef __WIN32__ | ||
66 | fprintf(stderr," or ipodpatcher [DISKNO] [action]\n"); | ||
67 | #else | ||
68 | fprintf(stderr," or ipodpatcher [device] [action]\n"); | ||
69 | #endif | ||
70 | fprintf(stderr,"\n"); | ||
71 | fprintf(stderr,"Where [action] is one of the following options:\n"); | ||
72 | #ifdef WITH_BOOTOBJS | ||
73 | fprintf(stderr," --install\n"); | ||
74 | #endif | ||
75 | fprintf(stderr," -l, --list\n"); | ||
76 | fprintf(stderr," -r, --read-partition bootpartition.bin\n"); | ||
77 | fprintf(stderr," -w, --write-partition bootpartition.bin\n"); | ||
78 | fprintf(stderr," -rf, --read-firmware filename.ipod\n"); | ||
79 | fprintf(stderr," -wf, --write-firmware filename.ipod\n"); | ||
80 | fprintf(stderr," -wfb, --write-firmware-bin filename.bin\n"); | ||
81 | fprintf(stderr," -a, --add-bootloader filename.ipod\n"); | ||
82 | fprintf(stderr," -ab, --add-bootloader-bin filename.bin\n"); | ||
83 | fprintf(stderr," -d, --delete-bootloader\n"); | ||
84 | fprintf(stderr,"\n"); | ||
85 | |||
86 | #ifdef __WIN32__ | ||
87 | fprintf(stderr,"DISKNO is the number (e.g. 2) Windows has assigned to your ipod's hard disk.\n"); | ||
88 | fprintf(stderr,"The first hard disk in your computer (i.e. C:\\) will be disk 0, the next disk\n"); | ||
89 | fprintf(stderr,"will be disk 1 etc. ipodpatcher will refuse to access a disk unless it\n"); | ||
90 | fprintf(stderr,"can identify it as being an ipod.\n"); | ||
91 | fprintf(stderr,"\n"); | ||
92 | #else | ||
93 | #if defined(linux) || defined (__linux) | ||
94 | fprintf(stderr,"\"device\" is the device node (e.g. /dev/sda) assigned to your ipod.\n"); | ||
95 | #elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) | ||
96 | fprintf(stderr,"\"device\" is the device node (e.g. /dev/da1) assigned to your ipod.\n"); | ||
97 | #elif defined(__APPLE__) && defined(__MACH__) | ||
98 | fprintf(stderr,"\"device\" is the device node (e.g. /dev/disk1) assigned to your ipod.\n"); | ||
99 | #endif | ||
100 | fprintf(stderr,"ipodpatcher will refuse to access a disk unless it can identify it as being\n"); | ||
101 | fprintf(stderr,"an ipod.\n"); | ||
102 | #endif | ||
103 | } | ||
104 | |||
105 | int main(int argc, char* argv[]) | ||
106 | { | ||
107 | #ifdef WITH_BOOTOBJS | ||
108 | char yesno[4]; | ||
109 | #endif | ||
110 | int i; | ||
111 | int n; | ||
112 | int infile, outfile; | ||
113 | unsigned int inputsize; | ||
114 | char* filename; | ||
115 | int action = SHOW_INFO; | ||
116 | int type; | ||
117 | struct ipod_t ipod; | ||
118 | |||
119 | fprintf(stderr,"ipodpatcher v" VERSION " - (C) Dave Chapman 2006-2007\n"); | ||
120 | fprintf(stderr,"This is free software; see the source for copying conditions. There is NO\n"); | ||
121 | fprintf(stderr,"warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"); | ||
122 | |||
123 | if ((argc > 1) && ((strcmp(argv[1],"-h")==0) || (strcmp(argv[1],"--help")==0))) { | ||
124 | print_usage(); | ||
125 | return 1; | ||
126 | } | ||
127 | |||
128 | if (ipod_alloc_buffer(§orbuf,BUFFER_SIZE) < 0) { | ||
129 | fprintf(stderr,"Failed to allocate memory buffer\n"); | ||
130 | } | ||
131 | |||
132 | if ((argc > 1) && (strcmp(argv[1],"--scan")==0)) { | ||
133 | if (ipod_scan(&ipod) == 0) | ||
134 | fprintf(stderr,"[ERR] No ipods found.\n"); | ||
135 | return 0; | ||
136 | } | ||
137 | |||
138 | /* If the first parameter doesn't start with -, then we interpret it as a device */ | ||
139 | if ((argc > 1) && (argv[1][0] != '-')) { | ||
140 | ipod.diskname[0]=0; | ||
141 | #ifdef __WIN32__ | ||
142 | snprintf(ipod.diskname,sizeof(ipod.diskname),"\\\\.\\PhysicalDrive%s",argv[1]); | ||
143 | #else | ||
144 | strncpy(ipod.diskname,argv[1],sizeof(ipod.diskname)); | ||
145 | #endif | ||
146 | i = 2; | ||
147 | } else { | ||
148 | /* Autoscan for ipods */ | ||
149 | n = ipod_scan(&ipod); | ||
150 | if (n==0) { | ||
151 | fprintf(stderr,"[ERR] No ipods found, aborting\n"); | ||
152 | fprintf(stderr,"[ERR] Please connect your ipod and ensure it is in disk mode\n"); | ||
153 | #if defined(__APPLE__) && defined(__MACH__) | ||
154 | fprintf(stderr,"[ERR] Also ensure that itunes is closed, and that your ipod is not mounted.\n"); | ||
155 | #elif !defined(__WIN32__) | ||
156 | if (geteuid()!=0) { | ||
157 | fprintf(stderr,"[ERR] You may also need to run ipodpatcher as root.\n"); | ||
158 | } | ||
159 | #endif | ||
160 | fprintf(stderr,"[ERR] Please refer to the Rockbox manual if you continue to have problems.\n"); | ||
161 | } else if (n > 1) { | ||
162 | fprintf(stderr,"[ERR] %d ipods found, aborting\n",n); | ||
163 | fprintf(stderr,"[ERR] Please connect only one ipod and re-run ipodpatcher.\n"); | ||
164 | } | ||
165 | |||
166 | if (n != 1) { | ||
167 | #ifdef WITH_BOOTOBJS | ||
168 | if (argc==1) { | ||
169 | printf("\nPress ENTER to exit ipodpatcher :"); | ||
170 | fgets(yesno,4,stdin); | ||
171 | } | ||
172 | #endif | ||
173 | return 0; | ||
174 | } | ||
175 | |||
176 | i = 1; | ||
177 | } | ||
178 | |||
179 | #ifdef WITH_BOOTOBJS | ||
180 | action = INTERACTIVE; | ||
181 | #else | ||
182 | action = NONE; | ||
183 | #endif | ||
184 | |||
185 | while (i < argc) { | ||
186 | if ((strcmp(argv[i],"-l")==0) || (strcmp(argv[i],"--list")==0)) { | ||
187 | action = LIST_IMAGES; | ||
188 | i++; | ||
189 | #ifdef WITH_BOOTOBJS | ||
190 | } else if (strcmp(argv[i],"--install")==0) { | ||
191 | action = INSTALL; | ||
192 | i++; | ||
193 | #endif | ||
194 | } else if ((strcmp(argv[i],"-d")==0) || | ||
195 | (strcmp(argv[i],"--delete-bootloader")==0)) { | ||
196 | action = DELETE_BOOTLOADER; | ||
197 | i++; | ||
198 | } else if ((strcmp(argv[i],"-a")==0) || | ||
199 | (strcmp(argv[i],"--add-bootloader")==0)) { | ||
200 | action = ADD_BOOTLOADER; | ||
201 | type = FILETYPE_DOT_IPOD; | ||
202 | i++; | ||
203 | if (i == argc) { print_usage(); return 1; } | ||
204 | filename=argv[i]; | ||
205 | i++; | ||
206 | } else if ((strcmp(argv[i],"-ab")==0) || | ||
207 | (strcmp(argv[i],"--add-bootloader-bin")==0)) { | ||
208 | action = ADD_BOOTLOADER; | ||
209 | type = FILETYPE_DOT_BIN; | ||
210 | i++; | ||
211 | if (i == argc) { print_usage(); return 1; } | ||
212 | filename=argv[i]; | ||
213 | i++; | ||
214 | } else if ((strcmp(argv[i],"-rf")==0) || | ||
215 | (strcmp(argv[i],"--read-firmware")==0)) { | ||
216 | action = READ_FIRMWARE; | ||
217 | i++; | ||
218 | if (i == argc) { print_usage(); return 1; } | ||
219 | filename=argv[i]; | ||
220 | i++; | ||
221 | } else if ((strcmp(argv[i],"-wf")==0) || | ||
222 | (strcmp(argv[i],"--write-firmware")==0)) { | ||
223 | action = WRITE_FIRMWARE; | ||
224 | type = FILETYPE_DOT_IPOD; | ||
225 | i++; | ||
226 | if (i == argc) { print_usage(); return 1; } | ||
227 | filename=argv[i]; | ||
228 | i++; | ||
229 | } else if ((strcmp(argv[i],"-wfb")==0) || | ||
230 | (strcmp(argv[i],"--write-firmware-bin")==0)) { | ||
231 | action = WRITE_FIRMWARE; | ||
232 | type = FILETYPE_DOT_BIN; | ||
233 | i++; | ||
234 | if (i == argc) { print_usage(); return 1; } | ||
235 | filename=argv[i]; | ||
236 | i++; | ||
237 | } else if ((strcmp(argv[i],"-r")==0) || | ||
238 | (strcmp(argv[i],"--read-partition")==0)) { | ||
239 | action = READ_PARTITION; | ||
240 | i++; | ||
241 | if (i == argc) { print_usage(); return 1; } | ||
242 | filename=argv[i]; | ||
243 | i++; | ||
244 | } else if ((strcmp(argv[i],"-w")==0) || | ||
245 | (strcmp(argv[i],"--write-partition")==0)) { | ||
246 | action = WRITE_PARTITION; | ||
247 | i++; | ||
248 | if (i == argc) { print_usage(); return 1; } | ||
249 | filename=argv[i]; | ||
250 | i++; | ||
251 | } else if ((strcmp(argv[i],"-v")==0) || | ||
252 | (strcmp(argv[i],"--verbose")==0)) { | ||
253 | verbose++; | ||
254 | i++; | ||
255 | } else { | ||
256 | print_usage(); return 1; | ||
257 | } | ||
258 | } | ||
259 | |||
260 | if (ipod.diskname[0]==0) { | ||
261 | print_usage(); | ||
262 | return 1; | ||
263 | } | ||
264 | |||
265 | if (ipod_open(&ipod, 0) < 0) { | ||
266 | return 1; | ||
267 | } | ||
268 | |||
269 | fprintf(stderr,"[INFO] Reading partition table from %s\n",ipod.diskname); | ||
270 | fprintf(stderr,"[INFO] Sector size is %d bytes\n",ipod.sector_size); | ||
271 | |||
272 | if (read_partinfo(&ipod,0) < 0) { | ||
273 | return 2; | ||
274 | } | ||
275 | |||
276 | display_partinfo(&ipod); | ||
277 | |||
278 | if (ipod.pinfo[0].start==0) { | ||
279 | fprintf(stderr,"[ERR] No partition 0 on disk:\n"); | ||
280 | display_partinfo(&ipod); | ||
281 | return 3; | ||
282 | } | ||
283 | |||
284 | read_directory(&ipod); | ||
285 | |||
286 | if (ipod.nimages <= 0) { | ||
287 | fprintf(stderr,"[ERR] Failed to read firmware directory - nimages=%d\n",ipod.nimages); | ||
288 | return 1; | ||
289 | } | ||
290 | |||
291 | if (getmodel(&ipod,(ipod.ipod_directory[0].vers>>8)) < 0) { | ||
292 | fprintf(stderr,"[ERR] Unknown version number in firmware (%08x)\n", | ||
293 | ipod.ipod_directory[0].vers); | ||
294 | return -1; | ||
295 | } | ||
296 | |||
297 | printf("[INFO] Ipod model: %s (\"%s\")\n",ipod.modelstr, | ||
298 | ipod.macpod ? "macpod" : "winpod"); | ||
299 | |||
300 | if (ipod.macpod) { | ||
301 | print_macpod_warning(); | ||
302 | } | ||
303 | |||
304 | if (action==LIST_IMAGES) { | ||
305 | list_images(&ipod); | ||
306 | #ifdef WITH_BOOTOBJS | ||
307 | } else if (action==INTERACTIVE) { | ||
308 | |||
309 | printf("Do you wish to install the rockbox bootloader? (y/n) :"); | ||
310 | if (fgets(yesno,4,stdin)) { | ||
311 | if (yesno[0]=='y') { | ||
312 | if (ipod_reopen_rw(&ipod) < 0) { | ||
313 | return 5; | ||
314 | } | ||
315 | |||
316 | if (add_bootloader(&ipod, NULL, FILETYPE_INTERNAL)==0) { | ||
317 | fprintf(stderr,"[INFO] Bootloader installed successfully.\n"); | ||
318 | } else { | ||
319 | fprintf(stderr,"[ERR] --install failed.\n"); | ||
320 | } | ||
321 | } | ||
322 | } | ||
323 | #endif | ||
324 | } else if (action==DELETE_BOOTLOADER) { | ||
325 | if (ipod_reopen_rw(&ipod) < 0) { | ||
326 | return 5; | ||
327 | } | ||
328 | |||
329 | if (ipod.ipod_directory[0].entryOffset==0) { | ||
330 | fprintf(stderr,"[ERR] No bootloader detected.\n"); | ||
331 | } else { | ||
332 | if (delete_bootloader(&ipod)==0) { | ||
333 | fprintf(stderr,"[INFO] Bootloader removed.\n"); | ||
334 | } else { | ||
335 | fprintf(stderr,"[ERR] --delete-bootloader failed.\n"); | ||
336 | } | ||
337 | } | ||
338 | } else if (action==ADD_BOOTLOADER) { | ||
339 | if (ipod_reopen_rw(&ipod) < 0) { | ||
340 | return 5; | ||
341 | } | ||
342 | |||
343 | if (add_bootloader(&ipod, filename, type)==0) { | ||
344 | fprintf(stderr,"[INFO] Bootloader %s written to device.\n",filename); | ||
345 | } else { | ||
346 | fprintf(stderr,"[ERR] --add-bootloader failed.\n"); | ||
347 | } | ||
348 | #ifdef WITH_BOOTOBJS | ||
349 | } else if (action==INSTALL) { | ||
350 | if (ipod_reopen_rw(&ipod) < 0) { | ||
351 | return 5; | ||
352 | } | ||
353 | |||
354 | if (add_bootloader(&ipod, NULL, FILETYPE_INTERNAL)==0) { | ||
355 | fprintf(stderr,"[INFO] Bootloader installed successfully.\n"); | ||
356 | } else { | ||
357 | fprintf(stderr,"[ERR] --install failed.\n"); | ||
358 | } | ||
359 | #endif | ||
360 | } else if (action==WRITE_FIRMWARE) { | ||
361 | if (ipod_reopen_rw(&ipod) < 0) { | ||
362 | return 5; | ||
363 | } | ||
364 | |||
365 | if (write_firmware(&ipod, filename,type)==0) { | ||
366 | fprintf(stderr,"[INFO] Firmware %s written to device.\n",filename); | ||
367 | } else { | ||
368 | fprintf(stderr,"[ERR] --write-firmware failed.\n"); | ||
369 | } | ||
370 | } else if (action==READ_FIRMWARE) { | ||
371 | if (read_firmware(&ipod, filename)==0) { | ||
372 | fprintf(stderr,"[INFO] Firmware read to file %s.\n",filename); | ||
373 | } else { | ||
374 | fprintf(stderr,"[ERR] --read-firmware failed.\n"); | ||
375 | } | ||
376 | } else if (action==READ_PARTITION) { | ||
377 | outfile = open(filename,O_CREAT|O_TRUNC|O_WRONLY|O_BINARY,S_IREAD|S_IWRITE); | ||
378 | if (outfile < 0) { | ||
379 | perror(filename); | ||
380 | return 4; | ||
381 | } | ||
382 | |||
383 | if (read_partition(&ipod, outfile) < 0) { | ||
384 | fprintf(stderr,"[ERR] --read-partition failed.\n"); | ||
385 | } else { | ||
386 | fprintf(stderr,"[INFO] Partition extracted to %s.\n",filename); | ||
387 | } | ||
388 | close(outfile); | ||
389 | } else if (action==WRITE_PARTITION) { | ||
390 | if (ipod_reopen_rw(&ipod) < 0) { | ||
391 | return 5; | ||
392 | } | ||
393 | |||
394 | infile = open(filename,O_RDONLY|O_BINARY); | ||
395 | if (infile < 0) { | ||
396 | perror(filename); | ||
397 | return 2; | ||
398 | } | ||
399 | |||
400 | /* Check filesize is <= partition size */ | ||
401 | inputsize=filesize(infile); | ||
402 | if (inputsize > 0) { | ||
403 | if (inputsize <= (ipod.pinfo[0].size*ipod.sector_size)) { | ||
404 | fprintf(stderr,"[INFO] Input file is %u bytes\n",inputsize); | ||
405 | if (write_partition(&ipod,infile) < 0) { | ||
406 | fprintf(stderr,"[ERR] --write-partition failed.\n"); | ||
407 | } else { | ||
408 | fprintf(stderr,"[INFO] %s restored to partition\n",filename); | ||
409 | } | ||
410 | } else { | ||
411 | fprintf(stderr,"[ERR] File is too large for firmware partition, aborting.\n"); | ||
412 | } | ||
413 | } | ||
414 | |||
415 | close(infile); | ||
416 | } | ||
417 | |||
418 | ipod_close(&ipod); | ||
419 | |||
420 | #ifdef WITH_BOOTOBJS | ||
421 | if (action==INTERACTIVE) { | ||
422 | printf("Press ENTER to exit ipodpatcher :"); | ||
423 | fgets(yesno,4,stdin); | ||
424 | } | ||
425 | #endif | ||
426 | |||
427 | |||
428 | return 0; | ||
429 | } | ||
diff --git a/rbutil/ipodpatcher/parttypes.h b/rbutil/ipodpatcher/parttypes.h new file mode 100644 index 0000000000..f8de303553 --- /dev/null +++ b/rbutil/ipodpatcher/parttypes.h | |||
@@ -0,0 +1,109 @@ | |||
1 | /* DOS partition types - taken from fdisk */ | ||
2 | |||
3 | struct parttype { | ||
4 | unsigned char type; | ||
5 | char *name; | ||
6 | }; | ||
7 | |||
8 | struct parttype parttypes[] = { | ||
9 | {0x00, "Empty"}, | ||
10 | {0x01, "FAT12"}, | ||
11 | {0x02, "XENIX root"}, | ||
12 | {0x03, "XENIX usr"}, | ||
13 | {0x04, "FAT16 <32M"}, | ||
14 | {0x05, "Extended"}, /* DOS 3.3+ extended partition */ | ||
15 | {0x06, "FAT16"}, /* DOS 16-bit >=32M */ | ||
16 | {0x07, "HPFS/NTFS"}, /* OS/2 IFS, eg, HPFS or NTFS or QNX */ | ||
17 | {0x08, "AIX"}, /* AIX boot (AIX -- PS/2 port) or SplitDrive */ | ||
18 | {0x09, "AIX bootable"}, /* AIX data or Coherent */ | ||
19 | {0x0a, "OS/2 Boot Manager"},/* OS/2 Boot Manager */ | ||
20 | {0x0b, "W95 FAT32"}, | ||
21 | {0x0c, "W95 FAT32 (LBA)"},/* LBA really is `Extended Int 13h' */ | ||
22 | {0x0e, "W95 FAT16 (LBA)"}, | ||
23 | {0x0f, "W95 Ext'd (LBA)"}, | ||
24 | {0x10, "OPUS"}, | ||
25 | {0x11, "Hidden FAT12"}, | ||
26 | {0x12, "Compaq diagnostics"}, | ||
27 | {0x14, "Hidden FAT16 <32M"}, | ||
28 | {0x16, "Hidden FAT16"}, | ||
29 | {0x17, "Hidden HPFS/NTFS"}, | ||
30 | {0x18, "AST SmartSleep"}, | ||
31 | {0x1b, "Hidden W95 FAT32"}, | ||
32 | {0x1c, "Hidden W95 FAT32 (LBA)"}, | ||
33 | {0x1e, "Hidden W95 FAT16 (LBA)"}, | ||
34 | {0x24, "NEC DOS"}, | ||
35 | {0x39, "Plan 9"}, | ||
36 | {0x3c, "PartitionMagic recovery"}, | ||
37 | {0x40, "Venix 80286"}, | ||
38 | {0x41, "PPC PReP Boot"}, | ||
39 | {0x42, "SFS"}, | ||
40 | {0x4d, "QNX4.x"}, | ||
41 | {0x4e, "QNX4.x 2nd part"}, | ||
42 | {0x4f, "QNX4.x 3rd part"}, | ||
43 | {0x50, "OnTrack DM"}, | ||
44 | {0x51, "OnTrack DM6 Aux1"}, /* (or Novell) */ | ||
45 | {0x52, "CP/M"}, /* CP/M or Microport SysV/AT */ | ||
46 | {0x53, "OnTrack DM6 Aux3"}, | ||
47 | {0x54, "OnTrackDM6"}, | ||
48 | {0x55, "EZ-Drive"}, | ||
49 | {0x56, "Golden Bow"}, | ||
50 | {0x5c, "Priam Edisk"}, | ||
51 | {0x61, "SpeedStor"}, | ||
52 | {0x63, "GNU HURD or SysV"}, /* GNU HURD or Mach or Sys V/386 (such as ISC UNIX) */ | ||
53 | {0x64, "Novell Netware 286"}, | ||
54 | {0x65, "Novell Netware 386"}, | ||
55 | {0x70, "DiskSecure Multi-Boot"}, | ||
56 | {0x75, "PC/IX"}, | ||
57 | {0x80, "Old Minix"}, /* Minix 1.4a and earlier */ | ||
58 | {0x81, "Minix / old Linux"},/* Minix 1.4b and later */ | ||
59 | {0x82, "Linux swap / Solaris"}, | ||
60 | {0x83, "Linux"}, | ||
61 | {0x84, "OS/2 hidden C: drive"}, | ||
62 | {0x85, "Linux extended"}, | ||
63 | {0x86, "NTFS volume set"}, | ||
64 | {0x87, "NTFS volume set"}, | ||
65 | {0x88, "Linux plaintext"}, | ||
66 | {0x8e, "Linux LVM"}, | ||
67 | {0x93, "Amoeba"}, | ||
68 | {0x94, "Amoeba BBT"}, /* (bad block table) */ | ||
69 | {0x9f, "BSD/OS"}, /* BSDI */ | ||
70 | {0xa0, "IBM Thinkpad hibernation"}, | ||
71 | {0xa5, "FreeBSD"}, /* various BSD flavours */ | ||
72 | {0xa6, "OpenBSD"}, | ||
73 | {0xa7, "NeXTSTEP"}, | ||
74 | {0xa8, "Darwin UFS"}, | ||
75 | {0xa9, "NetBSD"}, | ||
76 | {0xab, "Darwin boot"}, | ||
77 | {0xb7, "BSDI fs"}, | ||
78 | {0xb8, "BSDI swap"}, | ||
79 | {0xbb, "Boot Wizard hidden"}, | ||
80 | {0xbe, "Solaris boot"}, | ||
81 | {0xbf, "Solaris"}, | ||
82 | {0xc1, "DRDOS/sec (FAT-12)"}, | ||
83 | {0xc4, "DRDOS/sec (FAT-16 < 32M)"}, | ||
84 | {0xc6, "DRDOS/sec (FAT-16)"}, | ||
85 | {0xc7, "Syrinx"}, | ||
86 | {0xda, "Non-FS data"}, | ||
87 | {0xdb, "CP/M / CTOS / ..."},/* CP/M or Concurrent CP/M or | ||
88 | Concurrent DOS or CTOS */ | ||
89 | {0xde, "Dell Utility"}, /* Dell PowerEdge Server utilities */ | ||
90 | {0xdf, "BootIt"}, /* BootIt EMBRM */ | ||
91 | {0xe1, "DOS access"}, /* DOS access or SpeedStor 12-bit FAT | ||
92 | extended partition */ | ||
93 | {0xe3, "DOS R/O"}, /* DOS R/O or SpeedStor */ | ||
94 | {0xe4, "SpeedStor"}, /* SpeedStor 16-bit FAT extended | ||
95 | partition < 1024 cyl. */ | ||
96 | {0xeb, "BeOS fs"}, | ||
97 | {0xee, "EFI GPT"}, /* Intel EFI GUID Partition Table */ | ||
98 | {0xef, "EFI (FAT-12/16/32)"},/* Intel EFI System Partition */ | ||
99 | {0xf0, "Linux/PA-RISC boot"},/* Linux/PA-RISC boot loader */ | ||
100 | {0xf1, "SpeedStor"}, | ||
101 | {0xf4, "SpeedStor"}, /* SpeedStor large partition */ | ||
102 | {0xf2, "DOS secondary"}, /* DOS 3.3+ secondary */ | ||
103 | {0xfd, "Linux raid autodetect"},/* New (2.2.x) raid partition with | ||
104 | autodetect using persistent | ||
105 | superblock */ | ||
106 | {0xfe, "LANstep"}, /* SpeedStor >1024 cyl. or LANstep */ | ||
107 | {0xff, "BBT"}, /* Xenix Bad Block Table */ | ||
108 | { 0, 0 } | ||
109 | }; | ||