summaryrefslogtreecommitdiff
path: root/rbutil/sansapatcher
diff options
context:
space:
mode:
Diffstat (limited to 'rbutil/sansapatcher')
-rw-r--r--rbutil/sansapatcher/Makefile44
-rw-r--r--rbutil/sansapatcher/main.c293
-rw-r--r--rbutil/sansapatcher/sansaio-posix.c115
-rw-r--r--rbutil/sansapatcher/sansaio-win32.c196
-rw-r--r--rbutil/sansapatcher/sansaio.h74
-rw-r--r--rbutil/sansapatcher/sansapatcher.c702
-rw-r--r--rbutil/sansapatcher/sansapatcher.h45
7 files changed, 1469 insertions, 0 deletions
diff --git a/rbutil/sansapatcher/Makefile b/rbutil/sansapatcher/Makefile
new file mode 100644
index 0000000000..17b3fb0047
--- /dev/null
+++ b/rbutil/sansapatcher/Makefile
@@ -0,0 +1,44 @@
1CFLAGS=-Wall -D_LARGEFILE64_SOURCE
2
3ifeq ($(findstring CYGWIN,$(shell uname)),CYGWIN)
4OUTPUT=sansapatcher.exe
5CROSS=
6CFLAGS+=-mno-cygwin
7else
8OUTPUT=sansapatcher
9CROSS=i586-mingw32msvc-
10endif
11
12NATIVECC = gcc
13CC = $(CROSS)gcc
14
15all: $(OUTPUT)
16
17sansapatcher: main.c sansapatcher.c sansaio-posix.c parttypes.h bootimg.c
18 gcc $(CFLAGS) -o sansapatcher main.c sansapatcher.c sansaio-posix.c bootimg.c
19 strip sansapatcher
20
21sansapatcher.exe: main.c sansapatcher.c sansaio-win32.c parttypes.h bootimg.c
22 $(CC) $(CFLAGS) -o sansapatcher.exe main.c sansapatcher.c sansaio-win32.c bootimg.c
23 $(CROSS)strip sansapatcher.exe
24
25sansapatcher-mac: sansapatcher-i386 sansapatcher-ppc
26 lipo -create sansapatcher-ppc sansapatcher-i386 -output sansapatcher-mac
27
28sansapatcher-i386: main.c sansapatcher.c sansaio-posix.c parttypes.h bootimg.c
29 gcc -isysroot /Developer/SDKs/MacOSX10.4u.sdk -o bin/i386/program -arch i386 $(CFLAGS) -o sansapatcher-i386 main.c sansapatcher.c sansaio-posix.c bootimg.c
30 strip sansapatcher-i386
31
32sansapatcher-ppc: main.c sansapatcher.c sansaio-posix.c parttypes.h bootimg.c
33 gcc -arch ppc $(CFLAGS) -o sansapatcher-ppc main.c sansapatcher.c sansaio-posix.c bootimg.c
34 strip sansapatcher-ppc
35
36#mi42c: mi42c.c
37# $(NATIVECC) $(CFLAGS) -o mi42c mi42c.c
38
39#bootimg.c: PP5022.mi4 mi42c
40# ./mi42c PP5022.mi4 bootimg
41
42clean:
43 rm -f sansapatcher.exe sansapatcher-mac sansapatcher-i386 sansapatcher-ppc sansapatcher mi42c *~
44#bootimg.c bootimg.h
diff --git a/rbutil/sansapatcher/main.c b/rbutil/sansapatcher/main.c
new file mode 100644
index 0000000000..4e1e2dc120
--- /dev/null
+++ b/rbutil/sansapatcher/main.c
@@ -0,0 +1,293 @@
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 "sansapatcher.h"
30#include "sansaio.h"
31
32#define VERSION "0.1"
33
34int verbose = 0;
35
36enum {
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
52void print_usage(void)
53{
54 fprintf(stderr,"Usage: sansapatcher --scan\n");
55#ifdef __WIN32__
56 fprintf(stderr," or sansapatcher [DISKNO] [action]\n");
57#else
58 fprintf(stderr," or sansapatcher [device] [action]\n");
59#endif
60 fprintf(stderr,"\n");
61 fprintf(stderr,"Where [action] is one of the following options:\n");
62#ifdef WITH_BOOTOBJS
63 fprintf(stderr," --install\n");
64#endif
65 fprintf(stderr," -l, --list\n");
66 fprintf(stderr," -rf, --read-firmware filename.mi4\n");
67 fprintf(stderr," -a, --add-bootloader filename.mi4\n");
68 fprintf(stderr," -d, --delete-bootloader\n");
69 fprintf(stderr,"\n");
70
71#ifdef __WIN32__
72 fprintf(stderr,"DISKNO is the number (e.g. 2) Windows has assigned to your sansa's hard disk.\n");
73 fprintf(stderr,"The first hard disk in your computer (i.e. C:\\) will be disk 0, the next disk\n");
74 fprintf(stderr,"will be disk 1 etc. sansapatcher will refuse to access a disk unless it\n");
75 fprintf(stderr,"can identify it as being an E200.\n");
76 fprintf(stderr,"\n");
77#else
78#if defined(linux) || defined (__linux)
79 fprintf(stderr,"\"device\" is the device node (e.g. /dev/sda) assigned to your sansa.\n");
80#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
81 fprintf(stderr,"\"device\" is the device node (e.g. /dev/da1) assigned to your sansa.\n");
82#elif defined(__APPLE__) && defined(__MACH__)
83 fprintf(stderr,"\"device\" is the device node (e.g. /dev/disk1) assigned to your sansa.\n");
84#endif
85 fprintf(stderr,"sansapatcher will refuse to access a disk unless it can identify it as being\n");
86 fprintf(stderr,"an E200.\n");
87#endif
88}
89
90void display_partinfo(struct sansa_t* sansa)
91{
92 int i;
93 double sectors_per_MB = (1024.0*1024.0)/sansa->sector_size;
94
95 printf("[INFO] Part Start Sector End Sector Size (MB) Type\n");
96 for ( i = 0; i < 4; i++ ) {
97 if (sansa->pinfo[i].start != 0) {
98 printf("[INFO] %d %10ld %10ld %10.1f %s (0x%02x)\n",
99 i,
100 sansa->pinfo[i].start,
101 sansa->pinfo[i].start+sansa->pinfo[i].size-1,
102 sansa->pinfo[i].size/sectors_per_MB,
103 get_parttype(sansa->pinfo[i].type),
104 sansa->pinfo[i].type);
105 }
106 }
107}
108
109
110int main(int argc, char* argv[])
111{
112#ifdef WITH_BOOTOBJS
113 char yesno[4];
114#endif
115 int i;
116 int n;
117 char* filename;
118 int action = SHOW_INFO;
119 int type;
120 struct sansa_t sansa;
121
122 fprintf(stderr,"sansapatcher v" VERSION " - (C) Dave Chapman 2006-2007\n");
123 fprintf(stderr,"This is free software; see the source for copying conditions. There is NO\n");
124 fprintf(stderr,"warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n");
125
126 if ((argc > 1) && ((strcmp(argv[1],"-h")==0) || (strcmp(argv[1],"--help")==0))) {
127 print_usage();
128 return 1;
129 }
130
131 if (sansa_alloc_buffer(&sectorbuf,BUFFER_SIZE) < 0) {
132 fprintf(stderr,"Failed to allocate memory buffer\n");
133 }
134
135 if ((argc > 1) && (strcmp(argv[1],"--scan")==0)) {
136 if (sansa_scan(&sansa) == 0)
137 fprintf(stderr,"[ERR] No E200s found.\n");
138 return 0;
139 }
140
141 /* If the first parameter doesn't start with -, then we interpret it as a device */
142 if ((argc > 1) && (argv[1][0] != '-')) {
143 sansa.diskname[0]=0;
144#ifdef __WIN32__
145 snprintf(sansa.diskname,sizeof(sansa.diskname),"\\\\.\\PhysicalDrive%s",argv[1]);
146#else
147 strncpy(sansa.diskname,argv[1],sizeof(sansa.diskname));
148#endif
149 i = 2;
150 } else {
151 /* Autoscan for E200s */
152 n = sansa_scan(&sansa);
153 if (n==0) {
154 fprintf(stderr,"[ERR] No E200s found, aborting\n");
155 fprintf(stderr,"[ERR] Please connect your sansa and ensure it is in UMS mode\n");
156#if defined(__APPLE__) && defined(__MACH__)
157 fprintf(stderr,"[ERR] Also ensure that your E200's main partition is not mounted.\n");
158#elif !defined(__WIN32__)
159 if (geteuid()!=0) {
160 fprintf(stderr,"[ERR] You may also need to run sansapatcher as root.\n");
161 }
162#endif
163 fprintf(stderr,"[ERR] Please refer to the Rockbox manual if you continue to have problems.\n");
164 } else if (n > 1) {
165 fprintf(stderr,"[ERR] %d E200s found, aborting\n",n);
166 fprintf(stderr,"[ERR] Please connect only one E200 and re-run sansapatcher.\n");
167 }
168
169 if (n != 1) {
170#ifdef WITH_BOOTOBJS
171 if (argc==1) {
172 printf("\nPress ENTER to exit sansapatcher :");
173 fgets(yesno,4,stdin);
174 }
175#endif
176 return 0;
177 }
178
179 i = 1;
180 }
181
182#ifdef WITH_BOOTOBJS
183 action = INTERACTIVE;
184#else
185 action = NONE;
186#endif
187
188 while (i < argc) {
189 if ((strcmp(argv[i],"-l")==0) || (strcmp(argv[i],"--list")==0)) {
190 action = LIST_IMAGES;
191 i++;
192#ifdef WITH_BOOTOBJS
193 } else if (strcmp(argv[i],"--install")==0) {
194 action = INSTALL;
195 i++;
196#endif
197 } else if ((strcmp(argv[i],"-d")==0) ||
198 (strcmp(argv[i],"--delete-bootloader")==0)) {
199 action = DELETE_BOOTLOADER;
200 i++;
201 } else if ((strcmp(argv[i],"-a")==0) ||
202 (strcmp(argv[i],"--add-bootloader")==0)) {
203 action = ADD_BOOTLOADER;
204 type = FILETYPE_MI4;
205 i++;
206 if (i == argc) { print_usage(); return 1; }
207 filename=argv[i];
208 i++;
209 } else if ((strcmp(argv[i],"-rf")==0) ||
210 (strcmp(argv[i],"--read-firmware")==0)) {
211 action = READ_FIRMWARE;
212 i++;
213 if (i == argc) { print_usage(); return 1; }
214 filename=argv[i];
215 i++;
216 }
217 }
218
219 if (sansa.diskname[0]==0) {
220 print_usage();
221 return 1;
222 }
223
224 if (sansa_open(&sansa, 0) < 0) {
225 return 1;
226 }
227
228 fprintf(stderr,"[INFO] Reading partition table from %s\n",sansa.diskname);
229 fprintf(stderr,"[INFO] Sector size is %d bytes\n",sansa.sector_size);
230
231 if (read_partinfo(&sansa,0) < 0) {
232 return 2;
233 }
234
235 display_partinfo(&sansa);
236
237 i = is_e200(&sansa);
238 if (i < 0) {
239 fprintf(stderr,"[ERR] Disk is not an E200 (%d), aborting.\n",i);
240 return 3;
241 }
242
243 if (sansa.hasoldbootloader) {
244 printf("[ERR] ************************************************************************\n");
245 printf("[ERR] *** OLD ROCKBOX INSTALLATION DETECTED, ABORTING.\n");
246 printf("[ERR] *** You must reinstall the original Sansa firmware before running\n");
247 printf("[ERR] *** sansapatcher for the first time.\n");
248 printf("[ERR] *** See http://www.rockbox.org/twiki/bin/view/Main/SansaE200Install\n");
249 printf("[ERR] ************************************************************************\n");
250 return 4;
251 }
252
253 if (action==LIST_IMAGES) {
254 list_images(&sansa);
255 } else if (action==READ_FIRMWARE) {
256 if (read_firmware(&sansa, filename)==0) {
257 fprintf(stderr,"[INFO] Firmware read to file %s.\n",filename);
258 } else {
259 fprintf(stderr,"[ERR] --read-firmware failed.\n");
260 }
261 } else if (action==ADD_BOOTLOADER) {
262 if (sansa_reopen_rw(&sansa) < 0) {
263 return 5;
264 }
265
266 if (add_bootloader(&sansa, filename, type)==0) {
267 fprintf(stderr,"[INFO] Bootloader %s written to device.\n",filename);
268 } else {
269 fprintf(stderr,"[ERR] --add-bootloader failed.\n");
270 }
271 } else if (action==DELETE_BOOTLOADER) {
272 if (sansa_reopen_rw(&sansa) < 0) {
273 return 5;
274 }
275
276 if (delete_bootloader(&sansa)==0) {
277 fprintf(stderr,"[INFO] Bootloader removed successfully.\n");
278 } else {
279 fprintf(stderr,"[ERR] --delete-bootloader failed.\n");
280 }
281 }
282
283 sansa_close(&sansa);
284
285#ifdef WITH_BOOTOBJS
286 if (action==INTERACTIVE) {
287 printf("Press ENTER to exit sansapatcher :");
288 fgets(yesno,4,stdin);
289 }
290#endif
291
292 return 0;
293}
diff --git a/rbutil/sansapatcher/sansaio-posix.c b/rbutil/sansapatcher/sansaio-posix.c
new file mode 100644
index 0000000000..a8d529c20b
--- /dev/null
+++ b/rbutil/sansapatcher/sansaio-posix.c
@@ -0,0 +1,115 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id: ipodio-posix.c 12263 2007-02-10 19:49:43Z 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 <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 SANSA_SECTORSIZE_IOCTL BLKSSZGET
32#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) \
33 || defined(__bsdi__) || defined(__DragonFly__)
34#include <sys/disk.h>
35#define SANSA_SECTORSIZE_IOCTL DIOCGSECTORSIZE
36#elif defined(__APPLE__) && defined(__MACH__)
37#include <sys/disk.h>
38#define SANSA_SECTORSIZE_IOCTL DKIOCGETBLOCKSIZE
39#else
40 #error No sector-size detection implemented for this platform
41#endif
42
43#include "sansaio.h"
44
45void print_error(char* msg)
46{
47 perror(msg);
48}
49
50int sansa_open(struct sansa_t* sansa, int silent)
51{
52 sansa->dh=open(sansa->diskname,O_RDONLY);
53 if (sansa->dh < 0) {
54 if (!silent) perror(sansa->diskname);
55 return -1;
56 }
57
58 if(ioctl(sansa->dh,SANSA_SECTORSIZE_IOCTL,&sansa->sector_size) < 0) {
59 sansa->sector_size=512;
60 if (!silent) {
61 fprintf(stderr,"[ERR] ioctl() call to get sector size failed, defaulting to %d\n"
62 ,sansa->sector_size);
63 }
64 }
65 return 0;
66}
67
68
69int sansa_reopen_rw(struct sansa_t* sansa)
70{
71 close(sansa->dh);
72 sansa->dh=open(sansa->diskname,O_RDWR);
73 if (sansa->dh < 0) {
74 perror(sansa->diskname);
75 return -1;
76 }
77 return 0;
78}
79
80int sansa_close(struct sansa_t* sansa)
81{
82 close(sansa->dh);
83 return 0;
84}
85
86int sansa_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
95int sansa_seek(struct sansa_t* sansa, loff_t pos)
96{
97 off_t res;
98
99 res = lseek64(sansa->dh, pos, SEEK_SET);
100
101 if (res == -1) {
102 return -1;
103 }
104 return 0;
105}
106
107int sansa_read(struct sansa_t* sansa, unsigned char* buf, int nbytes)
108{
109 return read(sansa->dh, buf, nbytes);
110}
111
112int sansa_write(struct sansa_t* sansa, unsigned char* buf, int nbytes)
113{
114 return write(sansa->dh, buf, nbytes);
115}
diff --git a/rbutil/sansapatcher/sansaio-win32.c b/rbutil/sansapatcher/sansaio-win32.c
new file mode 100644
index 0000000000..315b379a28
--- /dev/null
+++ b/rbutil/sansapatcher/sansaio-win32.c
@@ -0,0 +1,196 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id: ipodio-win32.c 12263 2007-02-10 19:49:43Z dave $
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 "sansaio.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 sansa_open(struct sansa_t* sansa, int silent)
70{
71 DISK_GEOMETRY_EX diskgeometry_ex;
72 DISK_GEOMETRY diskgeometry;
73 unsigned long n;
74
75 sansa->dh = CreateFile(sansa->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 (sansa->dh == INVALID_HANDLE_VALUE) {
80 if (!silent) print_error(" Error opening disk: ");
81 return -1;
82 }
83
84 if (!lock_volume(sansa->dh)) {
85 if (!silent) print_error(" Error locking disk: ");
86 return -1;
87 }
88
89 if (!DeviceIoControl(sansa->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(sansa->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 sansa->sector_size=diskgeometry.BytesPerSector;
109 }
110 } else {
111 sansa->sector_size=diskgeometry_ex.Geometry.BytesPerSector;
112 }
113
114 return 0;
115}
116
117int sansa_reopen_rw(struct sansa_t* sansa)
118{
119 /* Close existing file and re-open for writing */
120 unlock_volume(sansa->dh);
121 CloseHandle(sansa->dh);
122
123 sansa->dh = CreateFile(sansa->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 (sansa->dh == INVALID_HANDLE_VALUE) {
128 print_error(" Error opening disk: ");
129 return -1;
130 }
131
132 if (!lock_volume(sansa->dh)) {
133 print_error(" Error locking disk: ");
134 return -1;
135 }
136
137 return 0;
138}
139
140int sansa_close(struct sansa_t* sansa)
141{
142 unlock_volume(sansa->dh);
143 CloseHandle(sansa->dh);
144 return 0;
145}
146
147int sansa_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
159int sansa_seek(struct sansa_t* sansa, loff_t pos)
160{
161 LARGE_INTEGER li;
162
163 li.QuadPart = pos;
164
165 li.LowPart = SetFilePointer (sansa->dh, li.LowPart, &li.HighPart, FILE_BEGIN);
166
167 if (li.LowPart == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) {
168 print_error(" Seek error ");
169 return -1;
170 }
171 return 0;
172}
173
174int sansa_read(struct sansa_t* sansa, unsigned char* buf, int nbytes)
175{
176 unsigned long count;
177
178 if (!ReadFile(sansa->dh, buf, nbytes, &count, NULL)) {
179 print_error(" Error reading from disk: ");
180 return -1;
181 }
182
183 return count;
184}
185
186int sansa_write(struct sansa_t* sansa, unsigned char* buf, int nbytes)
187{
188 unsigned long count;
189
190 if (!WriteFile(sansa->dh, buf, nbytes, &count, NULL)) {
191 print_error(" Error writing to disk: ");
192 return -1;
193 }
194
195 return count;
196}
diff --git a/rbutil/sansapatcher/sansaio.h b/rbutil/sansapatcher/sansaio.h
new file mode 100644
index 0000000000..246400c51c
--- /dev/null
+++ b/rbutil/sansapatcher/sansaio.h
@@ -0,0 +1,74 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id: ipodio.h 12339 2007-02-16 20:45:00Z 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 __SANSAIO_H
21#define __SANSAIO_H
22
23#include <stdint.h>
24#include <unistd.h>
25
26#ifdef __WIN32__
27#include <windows.h>
28#define loff_t int64_t
29#else
30#define HANDLE int
31#define O_BINARY 0
32
33/* Only Linux seems to need lseek64 and loff_t */
34#if !defined(linux) && defined (__linux)
35#define loff_t off_t
36#define lseek64 lseek
37#endif
38
39#endif
40
41struct partinfo_t {
42 unsigned long start; /* first sector (LBA) */
43 unsigned long size; /* number of sectors */
44 int type;
45};
46
47struct mi4header_t {
48 uint32_t version;
49 uint32_t length;
50 uint32_t crc32;
51 uint32_t enctype;
52 uint32_t mi4size;
53 uint32_t plaintext;
54};
55
56struct sansa_t {
57 HANDLE dh;
58 char diskname[4096];
59 int sector_size;
60 struct partinfo_t pinfo[4];
61 int hasoldbootloader;
62 loff_t start; /* Offset in bytes of firmware partition from start of disk */
63};
64
65void print_error(char* msg);
66int sansa_open(struct sansa_t* sansa, int silent);
67int sansa_reopen_rw(struct sansa_t* sansa);
68int sansa_close(struct sansa_t* sansa);
69int sansa_seek(struct sansa_t* sansa, loff_t pos);
70int sansa_read(struct sansa_t* sansa, unsigned char* buf, int nbytes);
71int sansa_write(struct sansa_t* sansa, unsigned char* buf, int nbytes);
72int sansa_alloc_buffer(unsigned char** sectorbuf, int bufsize);
73
74#endif
diff --git a/rbutil/sansapatcher/sansapatcher.c b/rbutil/sansapatcher/sansapatcher.c
new file mode 100644
index 0000000000..190cf09452
--- /dev/null
+++ b/rbutil/sansapatcher/sansapatcher.c
@@ -0,0 +1,702 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id: ipodpatcher.c 12264 2007-02-10 20:09:23Z 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 "parttypes.h"
30#include "sansaio.h"
31#include "sansapatcher.h"
32#include "bootimg.h"
33
34/* The offset of the MI4 image header in the firmware partition */
35#define PPMI_OFFSET 0x80000
36
37extern int verbose;
38
39/* Windows requires the buffer for disk I/O to be aligned in memory on a
40 multiple of the disk volume size - so we use a single global variable
41 and initialise it with sansa_alloc_buf() in main().
42*/
43
44unsigned char* sectorbuf;
45
46char* get_parttype(int pt)
47{
48 int i;
49 static char unknown[]="Unknown";
50
51 if (pt == -1) {
52 return "HFS/HFS+";
53 }
54
55 i=0;
56 while (parttypes[i].name != NULL) {
57 if (parttypes[i].type == pt) {
58 return (parttypes[i].name);
59 }
60 i++;
61 }
62
63 return unknown;
64}
65
66off_t filesize(int fd) {
67 struct stat buf;
68
69 if (fstat(fd,&buf) < 0) {
70 perror("[ERR] Checking filesize of input file");
71 return -1;
72 } else {
73 return(buf.st_size);
74 }
75}
76
77/* Partition table parsing code taken from Rockbox */
78
79#define MAX_SECTOR_SIZE 2048
80#define SECTOR_SIZE 512
81
82unsigned short static inline le2ushort(unsigned char* buf)
83{
84 unsigned short res = (buf[1] << 8) | buf[0];
85
86 return res;
87}
88
89int static inline le2int(unsigned char* buf)
90{
91 int32_t res = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
92
93 return res;
94}
95
96int static inline be2int(unsigned char* buf)
97{
98 int32_t res = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
99
100 return res;
101}
102
103int static inline getint16le(char* buf)
104{
105 int16_t res = (buf[1] << 8) | buf[0];
106
107 return res;
108}
109
110void static inline short2le(unsigned short val, unsigned char* addr)
111{
112 addr[0] = val & 0xFF;
113 addr[1] = (val >> 8) & 0xff;
114}
115
116void static inline int2le(unsigned int val, unsigned char* addr)
117{
118 addr[0] = val & 0xFF;
119 addr[1] = (val >> 8) & 0xff;
120 addr[2] = (val >> 16) & 0xff;
121 addr[3] = (val >> 24) & 0xff;
122}
123
124void int2be(unsigned int val, unsigned char* addr)
125{
126 addr[0] = (val >> 24) & 0xff;
127 addr[1] = (val >> 16) & 0xff;
128 addr[2] = (val >> 8) & 0xff;
129 addr[3] = val & 0xFF;
130}
131
132
133#define BYTES2INT32(array,pos)\
134 ((long)array[pos] | ((long)array[pos+1] << 8 ) |\
135 ((long)array[pos+2] << 16 ) | ((long)array[pos+3] << 24 ))
136
137int read_partinfo(struct sansa_t* sansa, int silent)
138{
139 int i;
140 unsigned long count;
141
142 count = sansa_read(sansa,sectorbuf, sansa->sector_size);
143
144 if (count <= 0) {
145 print_error(" Error reading from disk: ");
146 return -1;
147 }
148
149 if ((sectorbuf[510] == 0x55) && (sectorbuf[511] == 0xaa)) {
150 /* parse partitions */
151 for ( i = 0; i < 4; i++ ) {
152 unsigned char* ptr = sectorbuf + 0x1be + 16*i;
153 sansa->pinfo[i].type = ptr[4];
154 sansa->pinfo[i].start = BYTES2INT32(ptr, 8);
155 sansa->pinfo[i].size = BYTES2INT32(ptr, 12);
156
157 /* extended? */
158 if ( sansa->pinfo[i].type == 5 ) {
159 /* not handled yet */
160 }
161 }
162 } else if ((sectorbuf[0] == 'E') && (sectorbuf[1] == 'R')) {
163 if (!silent) fprintf(stderr,"[ERR] Bad boot sector signature\n");
164 return -1;
165 }
166
167 /* Calculate the starting position of the firmware partition */
168 sansa->start = (loff_t)sansa->pinfo[1].start*(loff_t)sansa->sector_size;
169 return 0;
170}
171
172
173/*
174 * CRC32 implementation taken from:
175 *
176 * efone - Distributed internet phone system.
177 *
178 * (c) 1999,2000 Krzysztof Dabrowski
179 * (c) 1999,2000 ElysiuM deeZine
180 *
181 * This program is free software; you can redistribute it and/or
182 * modify it under the terms of the GNU General Public License
183 * as published by the Free Software Foundation; either version
184 * 2 of the License, or (at your option) any later version.
185 *
186 */
187
188/* crc_tab[] -- this crcTable is being build by chksum_crc32GenTab().
189 * so make sure, you call it before using the other
190 * functions!
191 */
192static unsigned int crc_tab[256];
193
194/* chksum_crc() -- to a given block, this one calculates the
195 * crc32-checksum until the length is
196 * reached. the crc32-checksum will be
197 * the result.
198 */
199static unsigned int chksum_crc32 (unsigned char *block, unsigned int length)
200{
201 register unsigned long crc;
202 unsigned long i;
203
204 crc = 0;
205 for (i = 0; i < length; i++)
206 {
207 crc = ((crc >> 8) & 0x00FFFFFF) ^ crc_tab[(crc ^ *block++) & 0xFF];
208 }
209 return (crc);
210}
211
212/* chksum_crc32gentab() -- to a global crc_tab[256], this one will
213 * calculate the crcTable for crc32-checksums.
214 * it is generated to the polynom [..]
215 */
216
217static void chksum_crc32gentab (void)
218{
219 unsigned long crc, poly;
220 int i, j;
221
222 poly = 0xEDB88320L;
223 for (i = 0; i < 256; i++)
224 {
225 crc = i;
226 for (j = 8; j > 0; j--)
227 {
228 if (crc & 1)
229 {
230 crc = (crc >> 1) ^ poly;
231 }
232 else
233 {
234 crc >>= 1;
235 }
236 }
237 crc_tab[i] = crc;
238 }
239}
240
241/* Known keys for Sansa E200 firmwares: */
242#define NUM_KEYS 2
243static uint32_t keys[][4] = {
244 { 0xe494e96e, 0x3ee32966, 0x6f48512b, 0xa93fbb42 }, /* "sansa" */
245 { 0xd7b10538, 0xc662945b, 0x1b3fce68, 0xf389c0e6 }, /* "sansa_gh" */
246};
247
248/*
249
250tea_decrypt() from http://en.wikipedia.org/wiki/Tiny_Encryption_Algorithm
251
252"Following is an adaptation of the reference encryption and decryption
253routines in C, released into the public domain by David Wheeler and
254Roger Needham:"
255
256*/
257
258/* NOTE: The mi4 version of TEA uses a different initial value to sum compared
259 to the reference implementation and the main loop is 8 iterations, not
260 32.
261*/
262
263void tea_decrypt(uint32_t* v0, uint32_t* v1, uint32_t* k) {
264 uint32_t sum=0xF1BBCDC8, i; /* set up */
265 uint32_t delta=0x9E3779B9; /* a key schedule constant */
266 uint32_t k0=k[0], k1=k[1], k2=k[2], k3=k[3]; /* cache key */
267 for(i=0; i<8; i++) { /* basic cycle start */
268 *v1 -= ((*v0<<4) + k2) ^ (*v0 + sum) ^ ((*v0>>5) + k3);
269 *v0 -= ((*v1<<4) + k0) ^ (*v1 + sum) ^ ((*v1>>5) + k1);
270 sum -= delta; /* end cycle */
271 }
272}
273
274/* mi4 files are encrypted in 64-bit blocks (two little-endian 32-bit
275 integers) and the key is incremented after each block
276 */
277
278void tea_decrypt_buf(unsigned char* src, unsigned char* dest, size_t n, uint32_t * key)
279{
280 uint32_t v0, v1;
281 int i;
282
283 for (i = 0; i < (n / 8); i++) {
284 v0 = le2int(src);
285 v1 = le2int(src+4);
286
287 tea_decrypt(&v0, &v1, key);
288
289 int2le(v0, dest);
290 int2le(v1, dest+4);
291
292 src += 8;
293 dest += 8;
294
295 /* Now increment the key */
296 key[0]++;
297 if (key[0]==0) {
298 key[1]++;
299 if (key[1]==0) {
300 key[2]++;
301 if (key[2]==0) {
302 key[3]++;
303 }
304 }
305 }
306 }
307}
308
309static int get_mi4header(unsigned char* buf,struct mi4header_t* mi4header)
310{
311 if (memcmp(buf,"PPOS",4)!=0)
312 return -1;
313
314 mi4header->version = le2int(buf+0x04);
315 mi4header->length = le2int(buf+0x08);
316 mi4header->crc32 = le2int(buf+0x0c);
317 mi4header->enctype = le2int(buf+0x10);
318 mi4header->mi4size = le2int(buf+0x14);
319 mi4header->plaintext = le2int(buf+0x18);
320
321 return 0;
322}
323
324static int set_mi4header(unsigned char* buf,struct mi4header_t* mi4header)
325{
326 if (memcmp(buf,"PPOS",4)!=0)
327 return -1;
328
329 int2le(mi4header->version ,buf+0x04);
330 int2le(mi4header->length ,buf+0x08);
331 int2le(mi4header->crc32 ,buf+0x0c);
332 int2le(mi4header->enctype ,buf+0x10);
333 int2le(mi4header->mi4size ,buf+0x14);
334 int2le(mi4header->plaintext ,buf+0x18);
335
336 return 0;
337}
338
339int sansa_seek_and_read(struct sansa_t* sansa, loff_t pos, unsigned char* buf, int nbytes)
340{
341 int n;
342
343 if (sansa_seek(sansa, pos) < 0) {
344 return -1;
345 }
346
347 if ((n = sansa_read(sansa,buf,nbytes)) < 0) {
348 return -1;
349 }
350
351 if (n < nbytes) {
352 fprintf(stderr,"[ERR] Short read - requested %d bytes, received %d\n",
353 nbytes,n);
354 return -1;
355 }
356
357 return 0;
358}
359
360
361/* We identify an E200 based on the following criteria:
362
363 1) Exactly two partitions;
364 2) First partition is type "W95 FAT32" (0x0b);
365 3) Second partition is type "OS/2 hidden C: drive" (0x84);
366 4) The "PPBL" string appears at offset 0 in the 2nd partition;
367 5) The "PPMI" string appears at offset PPMI_OFFSET in the 2nd partition.
368*/
369
370int is_e200(struct sansa_t* sansa)
371{
372 struct mi4header_t mi4header;
373
374 /* Check partition layout */
375
376 if ((sansa->pinfo[0].type != 0x0b) || (sansa->pinfo[1].type != 0x84) ||
377 (sansa->pinfo[2].type != 0x00) || (sansa->pinfo[3].type != 0x00)) {
378 /* Bad partition layout, abort */
379 return -1;
380 }
381
382 /* Check Bootloader header */
383 if (sansa_seek_and_read(sansa, sansa->start, sectorbuf, 0x200) < 0) {
384 return -2;
385 }
386 if (memcmp(sectorbuf,"PPBL",4)!=0) {
387 /* No bootloader header, abort */
388 return -4;
389 }
390
391 /* Check Main firmware header */
392 if (sansa_seek_and_read(sansa, sansa->start+PPMI_OFFSET, sectorbuf, 0x200) < 0) {
393 fprintf(stderr,"[ERR] Seek to 0x%08x in is_e200 failed.\n",
394 (unsigned int)(sansa->start+PPMI_OFFSET));
395 return -5;
396 }
397 if (memcmp(sectorbuf,"PPMI",4)!=0) {
398 /* No bootloader header, abort */
399 return -7;
400 }
401
402 /* Check main mi4 file header */
403 if (sansa_seek_and_read(sansa, sansa->start+PPMI_OFFSET+0x200, sectorbuf, 0x200) < 0) {
404 fprintf(stderr,"[ERR] Seek to 0x%08x in is_e200 failed.\n",
405 (unsigned int)(sansa->start+PPMI_OFFSET+0x200));
406 return -5;
407 }
408
409 if (get_mi4header(sectorbuf,&mi4header) < 0) {
410 fprintf(stderr,"[ERR] Invalid mi4header\n");
411 return -6;
412 }
413
414 if ((mi4header.mi4size < 100000) &&
415 (memcmp(sectorbuf+0x1f8,"RBBL",4)!=0)) {
416 sansa->hasoldbootloader = 1;
417 } else {
418 sansa->hasoldbootloader = 0;
419 }
420
421 return 0;
422}
423
424int sansa_scan(struct sansa_t* sansa)
425{
426 int i;
427 int n = 0;
428 char last_disk[4096];
429
430 printf("[INFO] Scanning disk devices...\n");
431
432 for (i = 0; i <= 25 ; i++) {
433#ifdef __WIN32__
434 sprintf(sansa->diskname,"\\\\.\\PhysicalDrive%d",i);
435#elif defined(linux) || defined (__linux)
436 sprintf(sansa->diskname,"/dev/sd%c",'a'+i);
437#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) \
438 || defined(__bsdi__) || defined(__DragonFly__)
439 sprintf(sansa->diskname,"/dev/da%d",i);
440#elif defined(__APPLE__) && defined(__MACH__)
441 sprintf(sansa->diskname,"/dev/disk%d",i);
442#else
443 #error No disk paths defined for this platform
444#endif
445 if (sansa_open(sansa, 1) < 0) {
446 continue;
447 }
448
449 if (read_partinfo(sansa,1) < 0) {
450 continue;
451 }
452
453 if (is_e200(sansa) < 0) {
454 continue;
455 }
456
457#ifdef __WIN32__
458 printf("[INFO] E200 found - disk device %d\n",i);
459#else
460 printf("[INFO] E200 found - %s\n",sansa->diskname);
461#endif
462 n++;
463 strcpy(last_disk,sansa->diskname);
464 sansa_close(sansa);
465 }
466
467 if (n==1) {
468 /* Remember the disk name */
469 strcpy(sansa->diskname,last_disk);
470 }
471 return n;
472}
473
474int load_original_firmware(struct sansa_t* sansa, unsigned char* buf, struct mi4header_t* mi4header)
475{
476 int ppmi_length;
477 int n;
478 unsigned char* tmpbuf;
479 int i;
480 int key_found;
481
482 /* Read 512 bytes from PPMI_OFFSET - the PPMI header plus the mi4 header */
483 if (sansa_seek_and_read(sansa, sansa->start + PPMI_OFFSET, buf, 512) < 0) {
484 return -1;
485 }
486
487 /* No need to check PPMI magic - it's done during init to confirm
488 this is an E200 */
489 ppmi_length = le2int(buf+4);
490
491 /* Firstly look for an original firmware after the first image */
492 if (sansa_seek_and_read(sansa, sansa->start + PPMI_OFFSET + 0x200 + ppmi_length, buf, 512) < 0) {
493 return -1;
494 }
495
496 if (get_mi4header(buf,mi4header)==0) {
497 /* We have a valid MI4 file after a bootloader, so we use this. */
498 if ((n = sansa_seek_and_read(sansa,
499 sansa->start + PPMI_OFFSET + 0x200 + ppmi_length,
500 buf, mi4header->mi4size)) < 0) {
501 return -1;
502 }
503 } else {
504 /* No valid MI4 file, so read the first image. */
505 if ((n = sansa_seek_and_read(sansa,
506 sansa->start + PPMI_OFFSET + 0x200,
507 buf, ppmi_length)) < 0) {
508 return -1;
509 }
510 }
511
512 get_mi4header(buf,mi4header);
513
514#if 0
515 printf("mi4header->version =0x%08x\n",mi4header->version);
516 printf("mi4header->length =0x%08x\n",mi4header->length);
517 printf("mi4header->crc32 =0x%08x\n",mi4header->crc32);
518 printf("mi4header->enctype =0x%08x\n",mi4header->enctype);
519 printf("mi4header->mi4size =0x%08x\n",mi4header->mi4size);
520 printf("mi4header->plaintext =0x%08x\n",mi4header->plaintext);
521#endif
522
523 /* Decrypt anything that needs decrypting. */
524 if (mi4header->plaintext < mi4header->mi4size - 0x200) {
525 /* TODO: Check different keys */
526 tmpbuf=malloc(mi4header->mi4size-(mi4header->plaintext+0x200));
527 if (tmpbuf==NULL) {
528 fprintf(stderr,"[ERR] Can not allocate memory\n");
529 return -1;
530 }
531
532 key_found=0;
533 for (i=0; i < NUM_KEYS && !key_found ; i++) {
534 tea_decrypt_buf(buf+(mi4header->plaintext+0x200),
535 tmpbuf,
536 mi4header->mi4size-(mi4header->plaintext+0x200),
537 keys[i]);
538 key_found = (le2int(tmpbuf+mi4header->length-mi4header->plaintext-4) == 0xaa55aa55);
539 }
540
541 if (key_found) {
542printf("Key found - %d\n",i);
543 memcpy(buf+(mi4header->plaintext+0x200),tmpbuf,mi4header->mi4size-(mi4header->plaintext+0x200));
544 free(tmpbuf);
545 } else {
546 fprintf(stderr,"[ERR] Failed to decrypt image, aborting\n");
547 free(tmpbuf);
548 return -1;
549 }
550 }
551
552 /* Increase plaintext value to full file */
553 mi4header->plaintext = mi4header->mi4size - 0x200;
554
555 /* Update CRC checksum */
556 chksum_crc32gentab ();
557 mi4header->crc32 = chksum_crc32(buf+0x200,mi4header->mi4size-0x200);
558
559 set_mi4header(buf,mi4header);
560
561 return 0;
562}
563
564int read_firmware(struct sansa_t* sansa, char* filename)
565{
566 int res;
567 int outfile;
568 struct mi4header_t mi4header;
569
570 res = load_original_firmware(sansa,sectorbuf,&mi4header);
571 if (res < 0)
572 return res;
573
574 outfile = open(filename,O_CREAT|O_TRUNC|O_WRONLY|O_BINARY,0666);
575 if (outfile < 0) {
576 fprintf(stderr,"[ERR] Couldn't open file %s\n",filename);
577 return -1;
578 }
579
580 write(outfile,sectorbuf,mi4header.mi4size);
581 close(outfile);
582
583 return 0;
584}
585
586
587int add_bootloader(struct sansa_t* sansa, char* filename, int type)
588{
589 int res;
590 int infile;
591 int bl_length;
592 struct mi4header_t mi4header;
593 int n;
594 int length;
595
596 /* Step 1 - read bootloader into RAM. */
597 infile=open(filename,O_RDONLY|O_BINARY);
598 if (infile < 0) {
599 fprintf(stderr,"[ERR] Couldn't open input file %s\n",filename);
600 return -1;
601 }
602
603 bl_length = filesize(infile);
604
605 /* Create PPMI header */
606 memset(sectorbuf,0,0x200);
607 memcpy(sectorbuf,"PPMI",4);
608 int2le(bl_length, sectorbuf+4);
609 int2le(0x00020000, sectorbuf+8);
610
611 /* Read bootloader into sectorbuf+0x200 */
612 n = read(infile,sectorbuf+0x200,bl_length);
613 if (n < bl_length) {
614 fprintf(stderr,"[ERR] Short read - requested %d bytes, received %d\n"
615 ,bl_length,n);
616 return -1;
617 }
618
619 /* Load original firmware from Sansa to the space after the bootloader */
620 res = load_original_firmware(sansa,sectorbuf+0x200+bl_length,&mi4header);
621 if (res < 0)
622 return res;
623
624 /* Now write the whole thing back to the Sansa */
625
626 if (sansa_seek(sansa, sansa->start+PPMI_OFFSET) < 0) {
627 fprintf(stderr,"[ERR] Seek to 0x%08x in add_bootloader failed.\n",
628 (unsigned int)(sansa->start+PPMI_OFFSET));
629 return -5;
630 }
631
632 length = 0x200 + bl_length + mi4header.mi4size;
633
634 n=sansa_write(sansa, sectorbuf, length);
635 if (n < length) {
636 fprintf(stderr,"[ERR] Short write in add_bootloader\n");
637 return -6;
638 }
639
640 return 0;
641}
642
643int delete_bootloader(struct sansa_t* sansa)
644{
645 int res;
646 struct mi4header_t mi4header;
647 int n;
648 int length;
649
650 /* Load original firmware from Sansa to sectorbuf+0x200 */
651 res = load_original_firmware(sansa,sectorbuf+0x200,&mi4header);
652 if (res < 0)
653 return res;
654
655 /* Create PPMI header */
656 memset(sectorbuf,0,0x200);
657 memcpy(sectorbuf,"PPMI",4);
658 int2le(mi4header.mi4size, sectorbuf+4);
659 int2le(0x00020000, sectorbuf+8);
660
661 /* Now write the whole thing back to the Sansa */
662
663 if (sansa_seek(sansa, sansa->start+PPMI_OFFSET) < 0) {
664 fprintf(stderr,"[ERR] Seek to 0x%08x in add_bootloader failed.\n",
665 (unsigned int)(sansa->start+PPMI_OFFSET));
666 return -5;
667 }
668
669 length = 0x200 + mi4header.mi4size;
670
671 n=sansa_write(sansa, sectorbuf, length);
672 if (n < length) {
673 fprintf(stderr,"[ERR] Short write in delete_bootloader\n");
674 return -6;
675 }
676
677 return 0;
678}
679
680void list_images(struct sansa_t* sansa)
681{
682 struct mi4header_t mi4header;
683 loff_t ppmi_length;
684
685 /* Check Main firmware header */
686 if (sansa_seek_and_read(sansa, sansa->start+PPMI_OFFSET, sectorbuf, 0x200) < 0) {
687 return;
688 }
689
690 ppmi_length = le2int(sectorbuf+4);
691
692 printf("[INFO] Image 1 - %llu bytes\n",ppmi_length);
693
694 /* Look for an original firmware after the first image */
695 if (sansa_seek_and_read(sansa, sansa->start + PPMI_OFFSET + 0x200 + ppmi_length, sectorbuf, 512) < 0) {
696 return;
697 }
698
699 if (get_mi4header(sectorbuf,&mi4header)==0) {
700 printf("[INFO] Image 2 - %d bytes\n",mi4header.mi4size);
701 }
702}
diff --git a/rbutil/sansapatcher/sansapatcher.h b/rbutil/sansapatcher/sansapatcher.h
new file mode 100644
index 0000000000..7a2345f34a
--- /dev/null
+++ b/rbutil/sansapatcher/sansapatcher.h
@@ -0,0 +1,45 @@
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 "sansaio.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
28extern unsigned char* sectorbuf;
29
30#define FILETYPE_MI4 0
31#ifdef WITH_BOOTOBJS
32 #define FILETYPE_INTERNAL 1
33#endif
34
35char* get_parttype(int pt);
36int read_partinfo(struct sansa_t* sansa, int silent);
37off_t filesize(int fd);
38int is_e200(struct sansa_t* sansa);
39int sansa_scan(struct sansa_t* sansa);
40int read_firmware(struct sansa_t* sansa, char* filename);
41int add_bootloader(struct sansa_t* sansa, char* filename, int type);
42int delete_bootloader(struct sansa_t* sansa);
43void list_images(struct sansa_t* sansa);
44
45#endif