summaryrefslogtreecommitdiff
path: root/utils/ipodpatcher
diff options
context:
space:
mode:
Diffstat (limited to 'utils/ipodpatcher')
-rw-r--r--utils/ipodpatcher/Makefile53
-rw-r--r--utils/ipodpatcher/arc4.c108
-rw-r--r--utils/ipodpatcher/arc4.h47
-rw-r--r--utils/ipodpatcher/fat32format.c530
-rw-r--r--utils/ipodpatcher/ipodio-posix.c409
-rw-r--r--utils/ipodpatcher/ipodio-win32-scsi.c147
-rw-r--r--utils/ipodpatcher/ipodio-win32.c226
-rw-r--r--utils/ipodpatcher/ipodio.h115
-rw-r--r--utils/ipodpatcher/ipodpatcher.c2350
-rw-r--r--utils/ipodpatcher/ipodpatcher.h84
-rw-r--r--utils/ipodpatcher/ipodpatcher.manifest13
-rw-r--r--utils/ipodpatcher/ipodpatcher.pro47
-rw-r--r--utils/ipodpatcher/ipodpatcher.rc1
-rw-r--r--utils/ipodpatcher/main.c622
-rw-r--r--utils/ipodpatcher/parttypes.h109
15 files changed, 4861 insertions, 0 deletions
diff --git a/utils/ipodpatcher/Makefile b/utils/ipodpatcher/Makefile
new file mode 100644
index 0000000000..4254995d22
--- /dev/null
+++ b/utils/ipodpatcher/Makefile
@@ -0,0 +1,53 @@
1# __________ __ ___.
2# Open \______ \ ____ ____ | | _\_ |__ _______ ___
3# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
4# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
5# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
6# \/ \/ \/ \/ \/
7# $Id$
8#
9
10CFLAGS += -Wall -W
11
12# Build with "make BOOTOBJS=1" to build with embedded bootloaders and the
13# --install option and interactive mode. You need the full set of Rockbox
14# bootloaders in this directory - download them from
15# http://download.rockbox.org/bootloader/ipod/bootloaders.zip
16
17# Releases of ipodpatcher are created with "make RELEASE=1". This
18# enables BOOTOBJS and uses the VERSION string defined in main.c
19ifdef RELEASE
20CFLAGS += -DRELEASE
21BOOTOBJS=1
22endif
23
24ifdef BOOTOBJS
25BOOTSRC = ipod1g2g.c ipod3g.c ipod4g.c ipodcolor.c ipodmini1g.c \
26 ipodmini2g.c ipodnano1g.c ipodvideo.c ipodnano2g.c
27CFLAGS += -DWITH_BOOTOBJS
28endif
29
30# additional frameworks to link on on OS X
31LDOPTS_OSX = -framework CoreFoundation -framework IOKit
32
33LIBSOURCES = ipodpatcher.c fat32format.c arc4.c \
34 ipodio-posix.c ipodio-win32-scsi.c ipodio-win32.c
35SOURCES = main.c $(BOOTSRC)
36ipodpatcher: SOURCES+= ipodio-posix.c
37
38OUTPUT = ipodpatcher
39include ../libtools.make
40
41ipodpatcher.exe: $(OBJDIR)ipodpatcher-rc.o
42$(OBJDIR)ipodpatcher-rc.o: ipodpatcher.rc ipodpatcher.manifest
43 @echo WINDRES $(notdir $<)
44 $(SILENT)$(CROSS)$(WINDRES) -i $< -o $@
45
46%.c: bootloader-%.ipod $(BIN2C)
47 @echo BIN2C $<
48 $(SILENT)$(BIN2C) -i $< $*
49
50%.c: bootloader-%.ipodx $(BIN2C)
51 @echo BIN2C $<
52 $(SILENT)$(BIN2C) -i $< $*
53
diff --git a/utils/ipodpatcher/arc4.c b/utils/ipodpatcher/arc4.c
new file mode 100644
index 0000000000..75b1862b89
--- /dev/null
+++ b/utils/ipodpatcher/arc4.c
@@ -0,0 +1,108 @@
1/*
2 * arc4.c
3 * Release $Name: MATRIXSSL_1_8_3_OPEN $
4 *
5 * ARC4 stream cipher implementation
6 */
7/*
8 * Copyright (c) PeerSec Networks, 2002-2007. All Rights Reserved.
9 * The latest version of this code is available at http://www.matrixssl.org
10 *
11 * This software is open source; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This General Public License does NOT permit incorporating this software
17 * into proprietary programs. If you are unable to comply with the GPL, a
18 * commercial license for this software may be purchased from PeerSec Networks
19 * at http://www.peersec.com
20 *
21 * This program is distributed in WITHOUT ANY WARRANTY; without even the
22 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
23 * See the GNU General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 * http://www.gnu.org/copyleft/gpl.html
29 */
30/******************************************************************************/
31
32#include "arc4.h"
33
34/*
35 Some accounts, such as O'Reilly's Secure Programming Cookbook say that no
36 more than 2^30 bytes should be processed without rekeying, so we
37 enforce that limit here. FYI, this is equal to 1GB of data transferred.
38*/
39#define ARC4_MAX_BYTES 0x40000000
40
41/******************************************************************************/
42/*
43 SSL_RSA_WITH_RC4_* cipher callbacks
44 */
45void matrixArc4Init(struct rc4_key_t *ctx, unsigned char *key, int32_t keylen)
46{
47 unsigned char index1, index2, tmp, *state;
48 int16_t counter;
49
50 ctx->byteCount = 0;
51 state = &ctx->state[0];
52
53 for (counter = 0; counter < 256; counter++) {
54 state[counter] = (unsigned char)counter;
55 }
56 ctx->x = 0;
57 ctx->y = 0;
58 index1 = 0;
59 index2 = 0;
60
61 for (counter = 0; counter < 256; counter++) {
62 index2 = (key[index1] + state[counter] + index2) & 0xff;
63
64 tmp = state[counter];
65 state[counter] = state[index2];
66 state[index2] = tmp;
67
68 index1 = (index1 + 1) % keylen;
69 }
70}
71
72int32_t matrixArc4(struct rc4_key_t *ctx, unsigned char *in,
73 unsigned char *out, int32_t len)
74{
75 unsigned char x, y, *state, xorIndex, tmp;
76 int counter; /* NOTE BY DAVE CHAPMAN: This was a short in
77 the original code, which caused a segfault
78 when attempting to process data > 32767
79 bytes. */
80
81 ctx->byteCount += len;
82 if (ctx->byteCount > ARC4_MAX_BYTES) {
83 return -1;
84 }
85
86 x = ctx->x;
87 y = ctx->y;
88 state = &ctx->state[0];
89 for (counter = 0; counter < len; counter++) {
90 x = (x + 1) & 0xff;
91 y = (state[x] + y) & 0xff;
92
93 tmp = state[x];
94 state[x] = state[y];
95 state[y] = tmp;
96
97 xorIndex = (state[x] + state[y]) & 0xff;
98
99 tmp = in[counter];
100 tmp ^= state[xorIndex];
101 out[counter] = tmp;
102 }
103 ctx->x = x;
104 ctx->y = y;
105 return len;
106}
107
108/*****************************************************************************/
diff --git a/utils/ipodpatcher/arc4.h b/utils/ipodpatcher/arc4.h
new file mode 100644
index 0000000000..8bff0e2dc1
--- /dev/null
+++ b/utils/ipodpatcher/arc4.h
@@ -0,0 +1,47 @@
1/*
2 arc4.h - based on matrixssl-1-8-3-open
3
4*/
5
6/*
7 * Copyright (c) PeerSec Networks, 2002-2007. All Rights Reserved.
8 * The latest version of this code is available at http://www.matrixssl.org
9 *
10 * This software is open source; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This General Public License does NOT permit incorporating this software
16 * into proprietary programs. If you are unable to comply with the GPL, a
17 * commercial license for this software may be purchased from PeerSec Networks
18 * at http://www.peersec.com
19 *
20 * This program is distributed in WITHOUT ANY WARRANTY; without even the
21 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
22 * See the GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 * http://www.gnu.org/copyleft/gpl.html
28 */
29/*****************************************************************************/
30
31#ifndef _ARC4_H
32
33#include <stdint.h>
34
35struct rc4_key_t
36{
37 unsigned char state[256];
38 uint32_t byteCount;
39 unsigned char x;
40 unsigned char y;
41};
42
43void matrixArc4Init(struct rc4_key_t *ctx, unsigned char *key, int32_t keylen);
44int32_t matrixArc4(struct rc4_key_t *ctx, unsigned char *in,
45 unsigned char *out, int32_t len);
46
47#endif
diff --git a/utils/ipodpatcher/fat32format.c b/utils/ipodpatcher/fat32format.c
new file mode 100644
index 0000000000..7ee8021cbf
--- /dev/null
+++ b/utils/ipodpatcher/fat32format.c
@@ -0,0 +1,530 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 *
11 * FAT32 formatting functions. Based on:
12 *
13 * Fat32 formatter version 1.03
14 * (c) Tom Thornhill 2005
15 * This software is covered by the GPL.
16 * By using this tool, you agree to absolve Ridgecrop of an liabilities for
17 * lost data.
18 * Please backup any data you value before using this tool.
19 *
20 *
21 * Modified June 2007 by Dave Chapman for use in ipodpatcher
22 *
23 *
24 * This program is free software; you can redistribute it and/or
25 * modify it under the terms of the GNU General Public License
26 * as published by the Free Software Foundation; either version 2
27 * of the License, or (at your option) any later version.
28 *
29 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
30 * KIND, either express or implied.
31 *
32 ****************************************************************************/
33
34#include <stdio.h>
35#include <stdlib.h>
36#include <string.h>
37#include <stdbool.h>
38#include <stdint.h>
39#include <inttypes.h>
40
41#include "ipodio.h"
42
43static inline uint16_t swap16(uint16_t value)
44{
45 return (value >> 8) | (value << 8);
46}
47
48static inline uint32_t swap32(uint32_t value)
49{
50 uint32_t hi = swap16(value >> 16);
51 uint32_t lo = swap16(value & 0xffff);
52 return (lo << 16) | hi;
53}
54
55/* The following functions are not the most efficient, but are
56 self-contained and don't require needing to know endianness of CPU
57 at compile-time.
58
59 Note that htole16/htole32 exist on some platforms, so for
60 simplicity we use different names.
61
62*/
63
64static uint16_t rb_htole16(uint16_t x)
65{
66 uint16_t test = 0x1234;
67 unsigned char* p = (unsigned char*)&test;
68
69 if (p[0]==0x12) {
70 /* Big-endian */
71 return swap16(x);
72 } else {
73 return x;
74 }
75}
76
77static uint32_t rb_htole32(uint32_t x)
78{
79 uint32_t test = 0x12345678;
80 unsigned char* p = (unsigned char*)&test;
81
82 if (p[0]==0x12) {
83 /* Big-endian */
84 return swap32(x);
85 } else {
86 return x;
87 }
88}
89
90
91/* TODO: Pass these as parameters to the various create_ functions */
92
93/* can be zero for default or 1,2,4,8,16,32 or 64 */
94static int sectors_per_cluster = 0;
95
96/* Recommended values */
97static uint32_t ReservedSectCount = 32;
98static uint32_t NumFATs = 2;
99static uint32_t BackupBootSect = 6;
100static uint32_t VolumeId=0; /* calculated before format */
101
102/* Calculated later */
103static uint32_t FatSize=0;
104static uint32_t BytesPerSect=0;
105static uint32_t SectorsPerCluster=0;
106static uint32_t TotalSectors=0;
107static uint32_t SystemAreaSize=0;
108static uint32_t UserAreaSize=0;
109static uint8_t VolId[12] = "NO NAME ";
110
111
112struct FAT_BOOTSECTOR32
113{
114 /* Common fields. */
115 uint8_t sJmpBoot[3];
116 char sOEMName[8];
117 uint16_t wBytsPerSec;
118 uint8_t bSecPerClus;
119 uint16_t wRsvdSecCnt;
120 uint8_t bNumFATs;
121 uint16_t wRootEntCnt;
122 uint16_t wTotSec16; /* if zero, use dTotSec32 instead */
123 uint8_t bMedia;
124 uint16_t wFATSz16;
125 uint16_t wSecPerTrk;
126 uint16_t wNumHeads;
127 uint32_t dHiddSec;
128 uint32_t dTotSec32;
129
130 /* Fat 32/16 only */
131 uint32_t dFATSz32;
132 uint16_t wExtFlags;
133 uint16_t wFSVer;
134 uint32_t dRootClus;
135 uint16_t wFSInfo;
136 uint16_t wBkBootSec;
137 uint8_t Reserved[12];
138 uint8_t bDrvNum;
139 uint8_t Reserved1;
140 uint8_t bBootSig; /* == 0x29 if next three fields are ok */
141 uint32_t dBS_VolID;
142 uint8_t sVolLab[11];
143 uint8_t sBS_FilSysType[8];
144} __attribute__((packed));
145
146struct FAT_FSINFO {
147 uint32_t dLeadSig; // 0x41615252
148 uint8_t sReserved1[480]; // zeros
149 uint32_t dStrucSig; // 0x61417272
150 uint32_t dFree_Count; // 0xFFFFFFFF
151 uint32_t dNxt_Free; // 0xFFFFFFFF
152 uint8_t sReserved2[12]; // zeros
153 uint32_t dTrailSig; // 0xAA550000
154} __attribute__((packed));
155
156
157/* Write "count" zero sectors, starting at sector "sector" */
158static int zero_sectors(struct ipod_t* ipod, uint64_t sector, int count)
159{
160 int n;
161
162 if (ipod_seek(ipod, sector * ipod->sector_size) < 0) {
163 fprintf(stderr,"[ERR] Seek failed\n");
164 return -1;
165 }
166
167 memset(ipod->sectorbuf, 0, 128 * ipod->sector_size);
168
169 /* Write 128 sectors at a time */
170 while (count) {
171 if (count >= 128)
172 n = 128;
173 else
174 n = count;
175
176 if (ipod_write(ipod,n * ipod->sector_size) < 0) {
177 perror("[ERR] Write failed in zero_sectors\n");
178 return -1;
179 }
180
181 count -= n;
182 }
183
184 return 0;
185}
186
187
188/*
18928.2 CALCULATING THE VOLUME SERIAL NUMBER
190
191For example, say a disk was formatted on 26 Dec 95 at 9:55 PM and 41.94
192seconds. DOS takes the date and time just before it writes it to the
193disk.
194
195Low order word is calculated: Volume Serial Number is:
196 Month & Day 12/26 0c1ah
197 Sec & Hundrenths 41:94 295eh 3578:1d02
198 -----
199 3578h
200
201High order word is calculated:
202 Hours & Minutes 21:55 1537h
203 Year 1995 07cbh
204 -----
205 1d02h
206*/
207static uint32_t get_volume_id ( )
208{
209 /* TODO */
210#if 0
211 SYSTEMTIME s;
212 uint32_t d;
213 uint16_t lo,hi,tmp;
214
215 GetLocalTime( &s );
216
217 lo = s.wDay + ( s.wMonth << 8 );
218 tmp = (s.wMilliseconds/10) + (s.wSecond << 8 );
219 lo += tmp;
220
221 hi = s.wMinute + ( s.wHour << 8 );
222 hi += s.wYear;
223
224 d = lo + (hi << 16);
225 return(d);
226#endif
227 return(0);
228}
229
230/*
231This is the Microsoft calculation from FATGEN
232
233 uint32_t RootDirSectors = 0;
234 uint32_t TmpVal1, TmpVal2, FATSz;
235
236 TmpVal1 = DskSize - ( ReservedSecCnt + RootDirSectors);
237 TmpVal2 = (256 * SecPerClus) + NumFATs;
238 TmpVal2 = TmpVal2 / 2;
239 FATSz = (TmpVal1 + (TmpVal2 - 1)) / TmpVal2;
240
241 return( FatSz );
242*/
243
244
245static uint32_t get_fat_size_sectors(uint32_t DskSize, uint32_t ReservedSecCnt,
246 uint32_t SecPerClus, uint32_t NumFATs,
247 uint32_t BytesPerSect)
248{
249 uint64_t Numerator, Denominator;
250 uint64_t FatElementSize = 4;
251 uint64_t FatSz;
252
253 /* This is based on
254 http://hjem.get2net.dk/rune_moeller_barnkob/filesystems/fat.html
255 I've made the obvious changes for FAT32
256 */
257
258 Numerator = FatElementSize * ( DskSize - ReservedSecCnt );
259 Denominator = ( SecPerClus * BytesPerSect ) + ( FatElementSize * NumFATs );
260 FatSz = Numerator / Denominator;
261
262 /* round up */
263 FatSz += 1;
264
265 return((uint32_t)FatSz);
266}
267
268static uint8_t get_spc(uint32_t ClusterSizeKB, uint32_t BytesPerSect)
269{
270 uint32_t spc = ( ClusterSizeKB * 1024 ) / BytesPerSect;
271 return( (uint8_t) spc );
272}
273
274static uint8_t get_sectors_per_cluster(uint32_t DiskSizeSectors,
275 uint32_t BytesPerSect)
276{
277 uint8_t ret = 0x01; /* 1 sector per cluster */
278 uint64_t DiskSizeBytes = (uint64_t)DiskSizeSectors * (uint64_t)BytesPerSect;
279 int64_t DiskSizeMB = DiskSizeBytes / ( 1024*1024 );
280
281 /* 512 MB to 8,191 MB 4 KB */
282 if ( DiskSizeMB > 512 )
283 ret = get_spc( 4, BytesPerSect ); /* ret = 0x8; */
284
285 /* 8,192 MB to 16,383 MB 8 KB */
286 if ( DiskSizeMB > 8192 )
287 ret = get_spc( 8, BytesPerSect ); /* ret = 0x10; */
288
289 /* 16,384 MB to 32,767 MB 16 KB */
290 if ( DiskSizeMB > 16384 )
291 ret = get_spc( 16, BytesPerSect ); /* ret = 0x20; */
292
293 /* Larger than 32,768 MB 32 KB */
294 if ( DiskSizeMB > 32768 )
295 ret = get_spc( 32, BytesPerSect ); /* ret = 0x40; */
296
297 return( ret );
298
299}
300
301static void create_boot_sector(unsigned char* buf,
302 struct ipod_t* ipod, int partition)
303{
304 struct FAT_BOOTSECTOR32* pFAT32BootSect = (struct FAT_BOOTSECTOR32*)buf;
305
306 /* fill out the boot sector and fs info */
307 pFAT32BootSect->sJmpBoot[0]=0xEB;
308 pFAT32BootSect->sJmpBoot[1]=0x5A;
309 pFAT32BootSect->sJmpBoot[2]=0x90;
310 memcpy(pFAT32BootSect->sOEMName, "MSWIN4.1", 8 );
311 pFAT32BootSect->wBytsPerSec = rb_htole16(BytesPerSect);
312 pFAT32BootSect->bSecPerClus = SectorsPerCluster ;
313 pFAT32BootSect->wRsvdSecCnt = rb_htole16(ReservedSectCount);
314 pFAT32BootSect->bNumFATs = NumFATs;
315 pFAT32BootSect->wRootEntCnt = rb_htole16(0);
316 pFAT32BootSect->wTotSec16 = rb_htole16(0);
317 pFAT32BootSect->bMedia = 0xF8;
318 pFAT32BootSect->wFATSz16 = rb_htole16(0);
319 pFAT32BootSect->wSecPerTrk = rb_htole16(ipod->sectors_per_track);
320 pFAT32BootSect->wNumHeads = rb_htole16(ipod->num_heads);
321 pFAT32BootSect->dHiddSec = rb_htole16(ipod->pinfo[partition].start);
322 pFAT32BootSect->dTotSec32 = rb_htole32(TotalSectors);
323 pFAT32BootSect->dFATSz32 = rb_htole32(FatSize);
324 pFAT32BootSect->wExtFlags = rb_htole16(0);
325 pFAT32BootSect->wFSVer = rb_htole16(0);
326 pFAT32BootSect->dRootClus = rb_htole32(2);
327 pFAT32BootSect->wFSInfo = rb_htole16(1);
328 pFAT32BootSect->wBkBootSec = rb_htole16(BackupBootSect);
329 pFAT32BootSect->bDrvNum = 0x80;
330 pFAT32BootSect->Reserved1 = 0;
331 pFAT32BootSect->bBootSig = 0x29;
332 pFAT32BootSect->dBS_VolID = rb_htole32(VolumeId);
333 memcpy(pFAT32BootSect->sVolLab, VolId, 11);
334 memcpy(pFAT32BootSect->sBS_FilSysType, "FAT32 ", 8 );
335
336 buf[510] = 0x55;
337 buf[511] = 0xaa;
338}
339
340static void create_fsinfo(unsigned char* buf)
341{
342 struct FAT_FSINFO* pFAT32FsInfo = (struct FAT_FSINFO*)buf;
343
344 /* FSInfo sect */
345 pFAT32FsInfo->dLeadSig = rb_htole32(0x41615252);
346 pFAT32FsInfo->dStrucSig = rb_htole32(0x61417272);
347 pFAT32FsInfo->dFree_Count = rb_htole32((uint32_t) -1);
348 pFAT32FsInfo->dNxt_Free = rb_htole32((uint32_t) -1);
349 pFAT32FsInfo->dTrailSig = rb_htole32(0xaa550000);
350 pFAT32FsInfo->dFree_Count = rb_htole32((UserAreaSize/SectorsPerCluster)-1);
351
352 /* clusters 0-1 reserved, we used cluster 2 for the root dir */
353 pFAT32FsInfo->dNxt_Free = rb_htole32(3);
354}
355
356static void create_firstfatsector(unsigned char* buf)
357{
358 uint32_t* p = (uint32_t*)buf; /* We know the buffer is aligned */
359
360 /* First FAT Sector */
361 p[0] = rb_htole32(0x0ffffff8); /* Reserved cluster 1 media id in low byte */
362 p[1] = rb_htole32(0x0fffffff); /* Reserved cluster 2 EOC */
363 p[2] = rb_htole32(0x0fffffff); /* end of cluster chain for root dir */
364}
365
366int format_partition(struct ipod_t* ipod, int partition)
367{
368 uint32_t i;
369 uint64_t qTotalSectors=0;
370 uint64_t FatNeeded;
371
372 VolumeId = get_volume_id( );
373
374 /* Only support hard disks at the moment */
375 if ( ipod->sector_size != 512 )
376 {
377 fprintf(stderr,"[ERR] Only disks with 512 bytes per sector are supported.\n");
378 return -1;
379 }
380 BytesPerSect = ipod->sector_size;
381
382 /* Checks on Disk Size */
383 qTotalSectors = ipod->pinfo[partition].size;
384
385 /* low end limit - 65536 sectors */
386 if ( qTotalSectors < 65536 )
387 {
388 /* I suspect that most FAT32 implementations would mount this
389 volume just fine, but the spec says that we shouldn't do
390 this, so we won't */
391
392 fprintf(stderr,"[ERR] This drive is too small for FAT32 - there must be at least 64K clusters\n" );
393 return -1;
394 }
395
396 if ( qTotalSectors >= 0xffffffff )
397 {
398 /* This is a more fundamental limitation on FAT32 - the total
399 sector count in the root dir is 32bit. With a bit of
400 creativity, FAT32 could be extended to handle at least 2^28
401 clusters There would need to be an extra field in the
402 FSInfo sector, and the old sector count could be set to
403 0xffffffff. This is non standard though, the Windows FAT
404 driver FASTFAT.SYS won't understand this. Perhaps a future
405 version of FAT32 and FASTFAT will handle this. */
406
407 fprintf(stderr,"[ERR] This drive is too big for FAT32 - max 2TB supported\n");
408 }
409
410 if ( sectors_per_cluster ) {
411 SectorsPerCluster = sectors_per_cluster;
412 } else {
413 SectorsPerCluster = get_sectors_per_cluster(ipod->pinfo[partition].size,
414 BytesPerSect );
415 }
416
417 TotalSectors = (uint32_t) qTotalSectors;
418
419 FatSize = get_fat_size_sectors(TotalSectors, ReservedSectCount,
420 SectorsPerCluster, NumFATs, BytesPerSect );
421
422 UserAreaSize = TotalSectors - ReservedSectCount - (NumFATs*FatSize);
423
424 /* First zero out ReservedSect + FatSize * NumFats + SectorsPerCluster */
425 SystemAreaSize = (ReservedSectCount+(NumFATs*FatSize) + SectorsPerCluster);
426
427 /* Work out the Cluster count */
428 FatNeeded = UserAreaSize/SectorsPerCluster;
429
430 /* check for a cluster count of >2^28, since the upper 4 bits of
431 the cluster values in the FAT are reserved. */
432 if (FatNeeded > 0x0FFFFFFF) {
433 fprintf(stderr,"[ERR] This drive has more than 2^28 clusters, try to specify a larger cluster size\n" );
434 return -1;
435 }
436
437 /* Sanity check, make sure the fat is big enough.
438 Convert the cluster count into a Fat sector count, and check
439 the fat size value we calculated earlier is OK. */
440
441 FatNeeded *=4;
442 FatNeeded += (BytesPerSect-1);
443 FatNeeded /= BytesPerSect;
444
445 if ( FatNeeded > FatSize ) {
446 fprintf(stderr,"[ERR] Drive too big to format\n");
447 return -1;
448 }
449
450 /*
451 Write boot sector, fats
452 Sector 0 Boot Sector
453 Sector 1 FSInfo
454 Sector 2 More boot code - we write zeros here
455 Sector 3 unused
456 Sector 4 unused
457 Sector 5 unused
458 Sector 6 Backup boot sector
459 Sector 7 Backup FSInfo sector
460 Sector 8 Backup 'more boot code'
461 zero'd sectors upto ReservedSectCount
462 FAT1 ReservedSectCount to ReservedSectCount + FatSize
463 ...
464 FATn ReservedSectCount to ReservedSectCount + FatSize
465 RootDir - allocated to cluster2
466 */
467
468 fprintf(stderr,"[INFO] Heads - %d, sectors/track = %d\n",ipod->num_heads,ipod->sectors_per_track);
469 fprintf(stderr,"[INFO] Size : %" PRIu64 "GB %u sectors\n",
470 ((uint64_t)ipod->pinfo[partition].size * (uint64_t)ipod->sector_size) / (1000*1000*1000), TotalSectors );
471 fprintf(stderr,"[INFO] %d Bytes Per Sector, Cluster size %d bytes\n", BytesPerSect, SectorsPerCluster*BytesPerSect );
472 fprintf(stderr,"[INFO] Volume ID is %x:%x\n", VolumeId>>16, VolumeId&0xffff );
473 fprintf(stderr,"[INFO] %d Reserved Sectors, %d Sectors per FAT, %d fats\n", ReservedSectCount, FatSize, NumFATs );
474 fprintf (stderr,"[INFO] %d Total clusters\n", UserAreaSize/SectorsPerCluster );
475
476 fprintf(stderr,"[INFO] Formatting partition %d:...\n",partition);
477
478 /* Once zero_sectors has run, any data on the drive is basically lost... */
479 fprintf(stderr,"[INFO] Clearing out %d sectors for Reserved sectors, fats and root cluster...\n", SystemAreaSize );
480
481 zero_sectors(ipod, ipod->pinfo[partition].start, SystemAreaSize);
482
483 fprintf(stderr,"[INFO] Initialising reserved sectors and FATs...\n" );
484
485 /* Create the boot sector structure */
486 create_boot_sector(ipod->sectorbuf, ipod, partition);
487 create_fsinfo(ipod->sectorbuf + 512);
488
489 /* Write boot sector and fsinfo at start of partition */
490 if (ipod_seek(ipod, ipod->pinfo[partition].start * ipod->sector_size) < 0) {
491 fprintf(stderr,"[ERR] Seek failed\n");
492 return -1;
493 }
494 if (ipod_write(ipod,512 * 2) < 0) {
495 perror("[ERR] Write failed (first copy of bootsect/fsinfo)\n");
496 return -1;
497 }
498
499 /* Write backup copy of boot sector and fsinfo */
500 if (ipod_seek(ipod, (ipod->pinfo[partition].start + BackupBootSect) * ipod->sector_size) < 0) {
501 fprintf(stderr,"[ERR] Seek failed\n");
502 return -1;
503 }
504 if (ipod_write(ipod,512 * 2) < 0) {
505 perror("[ERR] Write failed (first copy of bootsect/fsinfo)\n");
506 return -1;
507 }
508
509 /* Create the first FAT sector */
510 create_firstfatsector(ipod->sectorbuf);
511
512 /* Write the first fat sector in the right places */
513 for ( i=0; i<NumFATs; i++ ) {
514 int SectorStart = ReservedSectCount + (i * FatSize );
515
516 if (ipod_seek(ipod, (ipod->pinfo[partition].start + SectorStart) * ipod->sector_size) < 0) {
517 fprintf(stderr,"[ERR] Seek failed\n");
518 return -1;
519 }
520
521 if (ipod_write(ipod,512) < 0) {
522 perror("[ERR] Write failed (first copy of bootsect/fsinfo)\n");
523 return -1;
524 }
525 }
526
527 fprintf(stderr,"[INFO] Format successful\n");
528
529 return 0;
530}
diff --git a/utils/ipodpatcher/ipodio-posix.c b/utils/ipodpatcher/ipodio-posix.c
new file mode 100644
index 0000000000..9b386d994f
--- /dev/null
+++ b/utils/ipodpatcher/ipodio-posix.c
@@ -0,0 +1,409 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2006-2007 Dave Chapman
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#if !defined(_WIN32) /* all non-Windows platforms are considered POSIX. */
23
24#include <stdio.h>
25#include <unistd.h>
26#include <fcntl.h>
27#include <string.h>
28#include <stdlib.h>
29#include <sys/types.h>
30#include <sys/stat.h>
31#include <sys/ioctl.h>
32#include <errno.h>
33
34#include "ipodio.h"
35
36#if defined(linux) || defined (__linux)
37#include <sys/mount.h>
38#include <linux/hdreg.h>
39#include <scsi/scsi_ioctl.h>
40#include <scsi/sg.h>
41
42#define IPOD_SECTORSIZE_IOCTL BLKSSZGET
43
44static void get_geometry(struct ipod_t* ipod)
45{
46 struct hd_geometry geometry;
47
48 if (!ioctl(ipod->dh, HDIO_GETGEO, &geometry)) {
49 /* never use geometry.cylinders - it is truncated */
50 ipod->num_heads = geometry.heads;
51 ipod->sectors_per_track = geometry.sectors;
52 } else {
53 ipod->num_heads = 0;
54 ipod->sectors_per_track = 0;
55 }
56}
57
58/* Linux SCSI Inquiry code based on the documentation and example code from
59 http://www.ibm.com/developerworks/linux/library/l-scsi-api/index.html
60*/
61
62int ipod_scsi_inquiry(struct ipod_t* ipod, int page_code,
63 unsigned char* buf, int bufsize)
64{
65 unsigned char cdb[6];
66 struct sg_io_hdr hdr;
67 unsigned char sense_buffer[255];
68
69 memset(&hdr, 0, sizeof(hdr));
70
71 hdr.interface_id = 'S'; /* this is the only choice we have! */
72 hdr.flags = SG_FLAG_LUN_INHIBIT; /* this would put the LUN to 2nd byte of cdb*/
73
74 /* Set xfer data */
75 hdr.dxferp = buf;
76 hdr.dxfer_len = bufsize;
77
78 /* Set sense data */
79 hdr.sbp = sense_buffer;
80 hdr.mx_sb_len = sizeof(sense_buffer);
81
82 /* Set the cdb format */
83 cdb[0] = 0x12;
84 cdb[1] = 1; /* Enable Vital Product Data (EVPD) */
85 cdb[2] = page_code & 0xff;
86 cdb[3] = 0;
87 cdb[4] = 0xff;
88 cdb[5] = 0; /* For control filed, just use 0 */
89
90 hdr.dxfer_direction = SG_DXFER_FROM_DEV;
91 hdr.cmdp = cdb;
92 hdr.cmd_len = 6;
93
94 int ret = ioctl(ipod->dh, SG_IO, &hdr);
95
96 if (ret < 0) {
97 return -1;
98 } else {
99 return 0;
100 }
101}
102
103#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) \
104 || defined(__bsdi__) || defined(__DragonFly__)
105#include <sys/disk.h>
106#define IPOD_SECTORSIZE_IOCTL DIOCGSECTORSIZE
107
108/* TODO: Implement this function for BSD */
109static void get_geometry(struct ipod_t* ipod)
110{
111 /* Are these universal for all ipods? */
112 ipod->num_heads = 255;
113 ipod->sectors_per_track = 63;
114}
115
116int ipod_scsi_inquiry(struct ipod_t* ipod, int page_code,
117 unsigned char* buf, int bufsize)
118{
119 /* TODO: Implement for BSD */
120 (void)ipod;
121 (void)page_code;
122 (void)buf;
123 (void)bufsize;
124 return -1;
125}
126
127#elif defined(__APPLE__) && defined(__MACH__)
128/* OS X IOKit includes don't like VERSION being defined! */
129#undef VERSION
130#include <sys/disk.h>
131#include <CoreFoundation/CoreFoundation.h>
132#include <IOKit/IOKitLib.h>
133#include <IOKit/scsi/SCSITaskLib.h>
134#include <IOKit/scsi/SCSICommandOperationCodes.h>
135#define IPOD_SECTORSIZE_IOCTL DKIOCGETBLOCKSIZE
136
137/* TODO: Implement this function for Mac OS X */
138static void get_geometry(struct ipod_t* ipod)
139{
140 /* Are these universal for all ipods? */
141 ipod->num_heads = 255;
142 ipod->sectors_per_track = 63;
143}
144
145int ipod_scsi_inquiry(struct ipod_t* ipod, int page_code,
146 unsigned char* buf, int bufsize)
147{
148 /* OS X doesn't allow to simply send out a SCSI inquiry request but
149 * requires registering an interface handler first.
150 * Currently this is done on each inquiry request which is somewhat
151 * inefficient but the current ipodpatcher API doesn't really fit here.
152 * Based on the documentation in Apple's document
153 * "SCSI Architecture Model Device Interface Guide".
154 *
155 * WARNING: this code currently doesn't take the selected device into
156 * account. It simply looks for an Ipod on the system and uses
157 * the first match.
158 */
159 (void)ipod;
160 int result = 0;
161 /* first, create a dictionary to match the device. This is needed to get the
162 * service. */
163 CFMutableDictionaryRef match_dict;
164 match_dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, NULL, NULL);
165 if(match_dict == NULL)
166 return -1;
167
168 /* set value to match. In case of the Ipod this is "iPodUserClientDevice". */
169 CFMutableDictionaryRef sub_dict;
170 sub_dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, NULL, NULL);
171 if(sub_dict == NULL)
172 return -1;
173 CFDictionarySetValue(sub_dict, CFSTR(kIOPropertySCSITaskDeviceCategory),
174 CFSTR("iPodUserClientDevice"));
175 CFDictionarySetValue(match_dict, CFSTR(kIOPropertyMatchKey), sub_dict);
176
177 /* get an iterator for searching for the service. */
178 kern_return_t kr;
179 io_iterator_t iterator = IO_OBJECT_NULL;
180 /* get matching services from IO registry. Consumes one reference to
181 * the dictionary, so no need to release that. */
182 kr = IOServiceGetMatchingServices(kIOMasterPortDefault, match_dict, &iterator);
183
184 if(!iterator | (kr != kIOReturnSuccess))
185 return -1;
186
187 /* get interface and obtain exclusive access */
188 SInt32 score;
189 HRESULT herr;
190 kern_return_t err;
191 IOCFPlugInInterface **plugin_interface = NULL;
192 SCSITaskDeviceInterface **interface = NULL;
193 io_service_t device = IO_OBJECT_NULL;
194 device = IOIteratorNext(iterator);
195
196 err = IOCreatePlugInInterfaceForService(device, kIOSCSITaskDeviceUserClientTypeID,
197 kIOCFPlugInInterfaceID, &plugin_interface,
198 &score);
199
200 if(err != noErr) {
201 return -1;
202 }
203 /* query the plugin interface for task interface */
204 herr = (*plugin_interface)->QueryInterface(plugin_interface,
205 CFUUIDGetUUIDBytes(kIOSCSITaskDeviceInterfaceID), (LPVOID*)&interface);
206 if(herr != S_OK) {
207 IODestroyPlugInInterface(plugin_interface);
208 return -1;
209 }
210
211 err = (*interface)->ObtainExclusiveAccess(interface);
212 if(err != noErr) {
213 (*interface)->Release(interface);
214 IODestroyPlugInInterface(plugin_interface);
215 return -1;
216 }
217
218 /* do the inquiry */
219 SCSITaskInterface **task = NULL;
220
221 task = (*interface)->CreateSCSITask(interface);
222 if(task != NULL) {
223 kern_return_t err;
224 SCSITaskStatus task_status;
225 IOVirtualRange* range;
226 SCSI_Sense_Data sense_data;
227 SCSICommandDescriptorBlock cdb;
228 UInt64 transfer_count = 0;
229 memset(buf, 0, bufsize);
230 /* allocate virtual range for buffer. */
231 range = (IOVirtualRange*) malloc(sizeof(IOVirtualRange));
232 memset(&sense_data, 0, sizeof(sense_data));
233 memset(cdb, 0, sizeof(cdb));
234 /* set up range. address is buffer address, length is request size. */
235 range->address = (IOVirtualAddress)buf;
236 range->length = bufsize;
237 /* setup CDB */
238 cdb[0] = 0x12; /* inquiry */
239 cdb[1] = 1;
240 cdb[2] = page_code;
241 cdb[4] = bufsize;
242
243 /* set cdb in task */
244 err = (*task)->SetCommandDescriptorBlock(task, cdb, kSCSICDBSize_6Byte);
245 if(err != kIOReturnSuccess) {
246 result = -1;
247 goto cleanup;
248 }
249 err = (*task)->SetScatterGatherEntries(task, range, 1, bufsize,
250 kSCSIDataTransfer_FromTargetToInitiator);
251 if(err != kIOReturnSuccess) {
252 result = -1;
253 goto cleanup;
254 }
255 /* set timeout */
256 err = (*task)->SetTimeoutDuration(task, 10000);
257 if(err != kIOReturnSuccess) {
258 result = -1;
259 goto cleanup;
260 }
261
262 /* request data */
263 err = (*task)->ExecuteTaskSync(task, &sense_data, &task_status, &transfer_count);
264 if(err != kIOReturnSuccess) {
265 result = -1;
266 goto cleanup;
267 }
268 /* cleanup */
269 free(range);
270
271 /* release task interface */
272 (*task)->Release(task);
273 }
274 else {
275 result = -1;
276 }
277cleanup:
278 /* cleanup interface */
279 (*interface)->ReleaseExclusiveAccess(interface);
280 (*interface)->Release(interface);
281 IODestroyPlugInInterface(plugin_interface);
282
283 return result;
284}
285
286#else
287 #error No sector-size detection implemented for this platform
288#endif
289
290#if defined(__APPLE__) && defined(__MACH__)
291static int ipod_unmount(struct ipod_t* ipod)
292{
293 char cmd[4096];
294 int res;
295
296 sprintf(cmd, "/usr/sbin/diskutil unmount \"%ss2\"",ipod->diskname);
297 fprintf(stderr,"[INFO] ");
298 res = system(cmd);
299
300 if (res==0) {
301 return 0;
302 } else {
303 perror("Unmount failed");
304 return -1;
305 }
306}
307#endif
308
309void ipod_print_error(char* msg)
310{
311 perror(msg);
312}
313
314int ipod_open(struct ipod_t* ipod, int silent)
315{
316 ipod->dh=open(ipod->diskname,O_RDONLY);
317 if (ipod->dh < 0) {
318 if (!silent) perror(ipod->diskname);
319 if(errno == EACCES) return -2;
320 else return -1;
321 }
322
323 /* Read information about the disk */
324
325 if(ioctl(ipod->dh,IPOD_SECTORSIZE_IOCTL,&ipod->sector_size) < 0) {
326 ipod->sector_size=512;
327 if (!silent) {
328 fprintf(stderr,"[ERR] ioctl() call to get sector size failed, defaulting to %d\n"
329 ,ipod->sector_size);
330 }
331 }
332
333 get_geometry(ipod);
334
335 return 0;
336}
337
338
339int ipod_reopen_rw(struct ipod_t* ipod)
340{
341#if defined(__APPLE__) && defined(__MACH__)
342 if (ipod_unmount(ipod) < 0)
343 return -1;
344#endif
345
346 close(ipod->dh);
347 ipod->dh=open(ipod->diskname,O_RDWR);
348 if (ipod->dh < 0) {
349 perror(ipod->diskname);
350 return -1;
351 }
352 return 0;
353}
354
355int ipod_close(struct ipod_t* ipod)
356{
357 close(ipod->dh);
358 return 0;
359}
360
361int ipod_alloc_buffer(struct ipod_t* ipod, int bufsize)
362{
363 ipod->sectorbuf = malloc(bufsize);
364 if (ipod->sectorbuf== NULL) {
365 return -1;
366 }
367 return 0;
368}
369
370int ipod_dealloc_buffer(struct ipod_t* ipod)
371{
372 if (ipod->sectorbuf == NULL) {
373 return -1;
374 }
375 free(ipod->sectorbuf);
376 ipod->sectorbuf = NULL;
377 return 0;
378}
379
380int ipod_seek(struct ipod_t* ipod, unsigned long pos)
381{
382 off_t res;
383
384 res = lseek(ipod->dh, pos, SEEK_SET);
385
386 if (res == -1) {
387 return -1;
388 }
389 return 0;
390}
391
392ssize_t ipod_read(struct ipod_t* ipod, int nbytes)
393{
394 if(ipod->sectorbuf == NULL) {
395 return -1;
396 }
397 return read(ipod->dh, ipod->sectorbuf, nbytes);
398}
399
400ssize_t ipod_write(struct ipod_t* ipod, int nbytes)
401{
402 if(ipod->sectorbuf == NULL) {
403 return -1;
404 }
405 return write(ipod->dh, ipod->sectorbuf, nbytes);
406}
407
408#endif
409
diff --git a/utils/ipodpatcher/ipodio-win32-scsi.c b/utils/ipodpatcher/ipodio-win32-scsi.c
new file mode 100644
index 0000000000..16460cfba3
--- /dev/null
+++ b/utils/ipodpatcher/ipodio-win32-scsi.c
@@ -0,0 +1,147 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2009 Dave Chapman
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 *
21 * Based on the getCapsUsingSCSIPassThrough() function from "cddrv.cpp":
22 * - http://www.farmanager.com/svn/trunk/unicode_far/cddrv.cpp
23 *
24 * Copyright (c) 1996 Eugene Roshal
25 * Copyright (c) 2000 Far Group
26 * All rights reserved.
27 *
28 * Redistribution and use in source and binary forms, with or without
29 * modification, are permitted provided that the following conditions
30 * are met:
31 * 1. Redistributions of source code must retain the above copyright
32 * notice, this list of conditions and the following disclaimer.
33 * 2. Redistributions in binary form must reproduce the above copyright
34 * notice, this list of conditions and the following disclaimer in the
35 * documentation and/or other materials provided with the distribution.
36 * 3. The name of the authors may not be used to endorse or promote products
37 * derived from this software without specific prior written permission.
38 *
39 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
40 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
41 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
42 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
43 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
44 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
45 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
46 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
47 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
48 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
49 *
50 ****************************************************************************/
51
52#if defined(_WIN32)
53#include <windows.h>
54#include <stddef.h>
55#include <stdio.h>
56
57#include "ipodio.h"
58
59/* from ddk/ntddscsi.h */
60#define SCSI_IOCTL_DATA_OUT 0
61#define SCSI_IOCTL_DATA_IN 1
62#define SCSI_IOCTL_DATA_UNSPECIFIED 2
63
64#define IOCTL_SCSI_PASS_THROUGH \
65 CTL_CODE(FILE_DEVICE_CONTROLLER, 0x0401, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
66
67typedef struct _SCSI_PASS_THROUGH {
68 USHORT Length;
69 UCHAR ScsiStatus;
70 UCHAR PathId;
71 UCHAR TargetId;
72 UCHAR Lun;
73 UCHAR CdbLength;
74 UCHAR SenseInfoLength;
75 UCHAR DataIn;
76 ULONG DataTransferLength;
77 ULONG TimeOutValue;
78 ULONG_PTR DataBufferOffset;
79 ULONG SenseInfoOffset;
80 UCHAR Cdb[16];
81} SCSI_PASS_THROUGH, *PSCSI_PASS_THROUGH;
82
83typedef struct _SCSI_PASS_THROUGH_WITH_BUFFERS {
84 SCSI_PASS_THROUGH Spt;
85 ULONG Filler; /* realign buffers to double word boundary */
86 UCHAR SenseBuf[32];
87 UCHAR DataBuf[512];
88} SCSI_PASS_THROUGH_WITH_BUFFERS, *PSCSI_PASS_THROUGH_WITH_BUFFERS;
89
90int ipod_scsi_inquiry(struct ipod_t* ipod, int page_code,
91 unsigned char* buf, int bufsize)
92{
93 SCSI_PASS_THROUGH_WITH_BUFFERS sptwb;
94 ULONG length;
95 DWORD returned;
96 BOOL status;
97
98 if (bufsize > 255) {
99 fprintf(stderr,"[ERR] Invalid bufsize in ipod_scsi_inquiry\n");
100 return -1;
101 }
102
103 memset(&sptwb, 0, sizeof(sptwb));
104
105 sptwb.Spt.Length = sizeof(SCSI_PASS_THROUGH);
106 sptwb.Spt.PathId = 0;
107 sptwb.Spt.TargetId = 1;
108 sptwb.Spt.Lun = 0;
109 sptwb.Spt.CdbLength = 6;
110 sptwb.Spt.SenseInfoLength = 32; /* sbuf size */;
111 sptwb.Spt.DataIn = SCSI_IOCTL_DATA_IN;
112 sptwb.Spt.DataTransferLength = bufsize;
113 sptwb.Spt.TimeOutValue = 2; /* 2 seconds */
114 sptwb.Spt.DataBufferOffset = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS, DataBuf);
115 sptwb.Spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS, SenseBuf);
116 length = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS, DataBuf) +
117 sptwb.Spt.DataTransferLength;
118
119 /* Set cdb info */
120 sptwb.Spt.Cdb[0] = 0x12; /* SCSI Inquiry */
121 sptwb.Spt.Cdb[1] = 1;
122 sptwb.Spt.Cdb[2] = page_code;
123 sptwb.Spt.Cdb[3] = 0;
124 sptwb.Spt.Cdb[4] = bufsize;
125 sptwb.Spt.Cdb[5] = 0;
126
127 status = DeviceIoControl(ipod->dh,
128 IOCTL_SCSI_PASS_THROUGH,
129 &sptwb,
130 sizeof(SCSI_PASS_THROUGH),
131 &sptwb,
132 length,
133 &returned,
134 FALSE);
135
136 if (status) {
137 /* W32 sometimes returns more bytes with additional garbage.
138 * Make sure to not copy that garbage. */
139 memcpy(buf, sptwb.DataBuf,
140 (DWORD)bufsize >= returned ? returned : (DWORD)bufsize);
141 return 0;
142 } else {
143 return -1;
144 }
145}
146#endif
147
diff --git a/utils/ipodpatcher/ipodio-win32.c b/utils/ipodpatcher/ipodio-win32.c
new file mode 100644
index 0000000000..cea218774a
--- /dev/null
+++ b/utils/ipodpatcher/ipodio-win32.c
@@ -0,0 +1,226 @@
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 * This program is free software; you can redistribute it and/or
19 * modify it under the terms of the GNU General Public License
20 * as published by the Free Software Foundation; either version 2
21 * of the License, or (at your option) any later version.
22 *
23 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
24 * KIND, either express or implied.
25 *
26 ****************************************************************************/
27
28#if defined(_WIN32)
29
30#include <stdio.h>
31#include <unistd.h>
32#include <fcntl.h>
33#include <string.h>
34#include <stdlib.h>
35#include <sys/types.h>
36#include <sys/stat.h>
37#include <windows.h>
38#include <stddef.h>
39#include <winioctl.h>
40
41#include "ipodio.h"
42
43static int lock_volume(HANDLE hDisk)
44{
45 DWORD dummy;
46
47 return DeviceIoControl(hDisk, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0,
48 &dummy, NULL);
49}
50
51static int unlock_volume(HANDLE hDisk)
52{
53 DWORD dummy;
54
55 return DeviceIoControl(hDisk, FSCTL_UNLOCK_VOLUME, NULL, 0, NULL, 0,
56 &dummy, NULL);
57}
58
59void ipod_print_error(char* msg)
60{
61 LPSTR pMsgBuf = NULL;
62
63 printf(msg);
64 FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
65 FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(),
66 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), pMsgBuf,
67 0, NULL);
68 printf(pMsgBuf);
69 LocalFree(pMsgBuf);
70}
71
72int ipod_open(struct ipod_t* ipod, int silent)
73{
74 DISK_GEOMETRY_EX diskgeometry_ex;
75 DISK_GEOMETRY diskgeometry;
76 unsigned long n;
77
78 ipod->dh = CreateFileA(ipod->diskname, GENERIC_READ,
79 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
80 FILE_FLAG_WRITE_THROUGH | FILE_FLAG_NO_BUFFERING, NULL);
81
82 if (ipod->dh == INVALID_HANDLE_VALUE) {
83 if (!silent) ipod_print_error(" Error opening disk: ");
84 if(GetLastError() == ERROR_ACCESS_DENIED)
85 return -2;
86 else
87 return -1;
88 }
89
90 if (!lock_volume(ipod->dh)) {
91 if (!silent) ipod_print_error(" Error locking disk: ");
92 return -1;
93 }
94
95 /* Defaults */
96 ipod->num_heads = 0;
97 ipod->sectors_per_track = 0;
98
99 if (!DeviceIoControl(ipod->dh,
100 IOCTL_DISK_GET_DRIVE_GEOMETRY_EX,
101 NULL,
102 0,
103 &diskgeometry_ex,
104 sizeof(diskgeometry_ex),
105 &n,
106 NULL)) {
107 if (!DeviceIoControl(ipod->dh,
108 IOCTL_DISK_GET_DRIVE_GEOMETRY,
109 NULL,
110 0,
111 &diskgeometry,
112 sizeof(diskgeometry),
113 &n,
114 NULL)) {
115 if (!silent) ipod_print_error(" Error reading disk geometry: ");
116 return -1;
117 } else {
118 ipod->sector_size = diskgeometry.BytesPerSector;
119 ipod->num_heads = diskgeometry.TracksPerCylinder;
120 ipod->sectors_per_track = diskgeometry.SectorsPerTrack;
121 }
122 } else {
123 ipod->sector_size = diskgeometry_ex.Geometry.BytesPerSector;
124 ipod->num_heads = diskgeometry_ex.Geometry.TracksPerCylinder;
125 ipod->sectors_per_track = diskgeometry_ex.Geometry.SectorsPerTrack;
126 }
127
128 return 0;
129}
130
131int ipod_reopen_rw(struct ipod_t* ipod)
132{
133 /* Close existing file and re-open for writing */
134 unlock_volume(ipod->dh);
135 CloseHandle(ipod->dh);
136
137 ipod->dh = CreateFileA(ipod->diskname, GENERIC_READ | GENERIC_WRITE,
138 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
139 FILE_FLAG_WRITE_THROUGH | FILE_FLAG_NO_BUFFERING, NULL);
140
141 if (ipod->dh == INVALID_HANDLE_VALUE) {
142 ipod_print_error(" Error opening disk: ");
143 return -1;
144 }
145
146 if (!lock_volume(ipod->dh)) {
147 ipod_print_error(" Error locking disk: ");
148 return -1;
149 }
150
151 return 0;
152}
153
154int ipod_close(struct ipod_t* ipod)
155{
156 unlock_volume(ipod->dh);
157 CloseHandle(ipod->dh);
158 return 0;
159}
160
161int ipod_alloc_buffer(struct ipod_t* ipod, int bufsize)
162{
163 /* The ReadFile function requires a memory buffer aligned to a multiple of
164 the disk sector size. */
165 ipod->sectorbuf = (unsigned char*)VirtualAlloc(NULL, bufsize, MEM_COMMIT, PAGE_READWRITE);
166 if (ipod->sectorbuf== NULL) {
167 ipod_print_error(" Error allocating a buffer: ");
168 return -1;
169 }
170 return 0;
171}
172
173int ipod_dealloc_buffer(struct ipod_t* ipod)
174{
175 if (ipod->sectorbuf == NULL) {
176 return -1;
177 }
178 if(!VirtualFree(ipod->sectorbuf, 0, MEM_RELEASE)) {
179 ipod_print_error(" Error releasing buffer ");
180 return -1;
181 }
182 ipod->sectorbuf = NULL;
183 return 0;
184}
185
186int ipod_seek(struct ipod_t* ipod, unsigned long pos)
187{
188 if (SetFilePointer(ipod->dh, pos, NULL, FILE_BEGIN)==0xffffffff) {
189 ipod_print_error(" Seek error ");
190 return -1;
191 }
192 return 0;
193}
194
195ssize_t ipod_read(struct ipod_t* ipod, int nbytes)
196{
197 unsigned long count;
198
199 if(ipod->sectorbuf == NULL) {
200 return -1;
201 }
202 if (!ReadFile(ipod->dh, ipod->sectorbuf, nbytes, &count, NULL)) {
203 ipod_print_error(" Error reading from disk: ");
204 return -1;
205 }
206
207 return count;
208}
209
210ssize_t ipod_write(struct ipod_t* ipod, int nbytes)
211{
212 unsigned long count;
213
214 if(ipod->sectorbuf == NULL) {
215 return -1;
216 }
217 if (!WriteFile(ipod->dh, ipod->sectorbuf, nbytes, &count, NULL)) {
218 ipod_print_error(" Error writing to disk: ");
219 return -1;
220 }
221
222 return count;
223}
224
225#endif
226
diff --git a/utils/ipodpatcher/ipodio.h b/utils/ipodpatcher/ipodio.h
new file mode 100644
index 0000000000..4f1a35dd09
--- /dev/null
+++ b/utils/ipodpatcher/ipodio.h
@@ -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 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#ifndef __IPODIO_H
23#define __IPODIO_H
24
25#include <stdint.h>
26#if !defined(_WIN32)
27#include <unistd.h>
28#elif defined(_MSC_VER)
29/* MSVC uses a different name for ssize_t */
30#define ssize_t SSIZE_T
31#endif
32
33#if defined(__WIN32__) || defined(_WIN32)
34#include <windows.h>
35#else
36#define HANDLE int
37#define O_BINARY 0
38#endif
39
40/* The maximum number of images in a firmware partition - a guess... */
41#define MAX_IMAGES 10
42
43enum firmwaretype_t {
44 FTYPE_OSOS = 0,
45 FTYPE_RSRC,
46 FTYPE_AUPD,
47 FTYPE_HIBE,
48 FTYPE_OSBK
49};
50
51struct ipod_directory_t {
52 enum firmwaretype_t ftype;
53 int id;
54 uint32_t devOffset; /* Offset of image relative to one sector into bootpart*/
55 uint32_t len;
56 uint32_t addr;
57 uint32_t entryOffset;
58 uint32_t chksum;
59 uint32_t vers;
60 uint32_t loadAddr;
61};
62
63/* A fake partition type - DOS partition tables can't include HFS partitions */
64#define PARTTYPE_HFS 0xffff
65
66struct partinfo_t {
67 uint32_t start; /* first sector (LBA) */
68 uint32_t size; /* number of sectors */
69 uint32_t type;
70};
71
72struct ipod_t {
73 unsigned char* sectorbuf;
74 HANDLE dh;
75 char diskname[4096];
76 int sector_size;
77 int sectors_per_track;
78 int num_heads;
79 struct ipod_directory_t ipod_directory[MAX_IMAGES];
80 int nimages;
81 int ososimage;
82 off_t diroffset;
83 off_t start; /* Offset in bytes of firmware partition from start of disk */
84 off_t fwoffset; /* Offset in bytes of start of firmware images from start of disk */
85 struct partinfo_t pinfo[4];
86 int modelnum;
87 char* modelname;
88 char* modelstr;
89 char* targetname;
90 int macpod;
91 char* xmlinfo; /* The XML Device Information (if available) */
92 int xmlinfo_len;
93 int ramsize; /* The amount of RAM in the ipod (if available) */
94#ifdef WITH_BOOTOBJS
95 unsigned char* bootloader;
96 int bootloader_len;
97#endif
98};
99
100void ipod_print_error(char* msg);
101int ipod_open(struct ipod_t* ipod, int silent);
102int ipod_reopen_rw(struct ipod_t* ipod);
103int ipod_close(struct ipod_t* ipod);
104int ipod_seek(struct ipod_t* ipod, unsigned long pos);
105int ipod_scsi_inquiry(struct ipod_t* ipod, int page_code,
106 unsigned char* buf, int bufsize);
107ssize_t ipod_read(struct ipod_t* ipod, int nbytes);
108ssize_t ipod_write(struct ipod_t* ipod, int nbytes);
109int ipod_alloc_buffer(struct ipod_t* ipod, int bufsize);
110int ipod_dealloc_buffer(struct ipod_t* ipod);
111
112/* In fat32format.c */
113int format_partition(struct ipod_t* ipod, int partition);
114
115#endif
diff --git a/utils/ipodpatcher/ipodpatcher.c b/utils/ipodpatcher/ipodpatcher.c
new file mode 100644
index 0000000000..e047e52abe
--- /dev/null
+++ b/utils/ipodpatcher/ipodpatcher.c
@@ -0,0 +1,2350 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2006-2007 Dave Chapman
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include <stdio.h>
23#include <unistd.h>
24#include <fcntl.h>
25#include <string.h>
26#include <stdlib.h>
27#include <inttypes.h>
28#include <stdbool.h>
29#include <sys/types.h>
30#include <sys/stat.h>
31
32#include "parttypes.h"
33#include "ipodio.h"
34#include "ipodpatcher.h"
35
36#ifdef WITH_BOOTOBJS
37#include "ipod1g2g.h"
38#include "ipod3g.h"
39#include "ipod4g.h"
40#include "ipodmini1g.h"
41#include "ipodmini2g.h"
42#include "ipodcolor.h"
43#include "ipodnano1g.h"
44#include "ipodvideo.h"
45#include "ipodnano2g.h"
46#endif
47
48#ifndef RBUTIL
49#include "arc4.h"
50#endif
51
52int ipod_verbose = 0;
53
54
55/* The following string appears at the start of the firmware partition */
56static const char apple_stop_sign[] = "{{~~ /-----\\ "\
57 "{{~~ / \\ "\
58 "{{~~| | "\
59 "{{~~| S T O P | "\
60 "{{~~| | "\
61 "{{~~ \\ / "\
62 "{{~~ \\-----/ "\
63 "Copyright(C) 200"\
64 "1 Apple Computer"\
65 ", Inc.----------"\
66 "----------------"\
67 "----------------"\
68 "----------------"\
69 "----------------"\
70 "----------------"\
71 "---------------";
72
73/* Windows requires the buffer for disk I/O to be aligned in memory on a
74 multiple of the disk volume size - so we use a single global variable
75 and initialise it with ipod_alloc_buf()
76*/
77
78char* get_parttype(unsigned int pt)
79{
80 int i;
81 static char unknown[]="Unknown";
82
83 if (pt == PARTTYPE_HFS) {
84 return "HFS/HFS+";
85 }
86
87 i=0;
88 while (parttypes[i].name != NULL) {
89 if (parttypes[i].type == pt) {
90 return (parttypes[i].name);
91 }
92 i++;
93 }
94
95 return unknown;
96}
97
98off_t filesize(int fd) {
99 struct stat buf;
100
101 if (fstat(fd,&buf) < 0) {
102 perror("[ERR] Checking filesize of input file");
103 return -1;
104 } else {
105 return(buf.st_size);
106 }
107}
108
109/* Partition table parsing code taken from Rockbox */
110
111#define MAX_SECTOR_SIZE 2048
112#define SECTOR_SIZE 512
113
114static inline unsigned short le2ushort(unsigned char* buf)
115{
116 unsigned short res = (buf[1] << 8) | buf[0];
117
118 return res;
119}
120
121static inline int le2int(unsigned char* buf)
122{
123 int32_t res = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
124
125 return res;
126}
127
128static inline int be2int(unsigned char* buf)
129{
130 int32_t res = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
131
132 return res;
133}
134
135static inline int getint16le(char* buf)
136{
137 int16_t res = (buf[1] << 8) | buf[0];
138
139 return res;
140}
141
142static inline void short2le(unsigned short val, unsigned char* addr)
143{
144 addr[0] = val & 0xFF;
145 addr[1] = (val >> 8) & 0xff;
146}
147
148static inline void int2le(unsigned int val, unsigned char* addr)
149{
150 addr[0] = val & 0xFF;
151 addr[1] = (val >> 8) & 0xff;
152 addr[2] = (val >> 16) & 0xff;
153 addr[3] = (val >> 24) & 0xff;
154}
155
156static inline void int2be(unsigned int val, unsigned char* addr)
157{
158 addr[0] = (val >> 24) & 0xff;
159 addr[1] = (val >> 16) & 0xff;
160 addr[2] = (val >> 8) & 0xff;
161 addr[3] = val & 0xFF;
162}
163
164
165#define BYTES2INT32(array,pos)\
166 ((long)array[pos] | ((long)array[pos+1] << 8 ) |\
167 ((long)array[pos+2] << 16 ) | ((long)array[pos+3] << 24 ))
168
169int read_partinfo(struct ipod_t* ipod, int silent)
170{
171 int i;
172 unsigned long count;
173
174 if(ipod->sectorbuf == NULL) {
175 fprintf(stderr,"[ERR] Buffer not initialized.");
176 return -1;
177 }
178
179 count = ipod_read(ipod,ipod->sector_size);
180
181 if (count <= 0) {
182 ipod_print_error(" Error reading from disk: ");
183 return -1;
184 }
185
186 memset(ipod->pinfo, 0, sizeof(ipod->pinfo));
187
188 if ((ipod->sectorbuf[510] == 0x55) && (ipod->sectorbuf[511] == 0xaa)) {
189 /* DOS partition table */
190 ipod->macpod = 0;
191 /* parse partitions */
192 for ( i = 0; i < 4; i++ ) {
193 unsigned char* ptr = ipod->sectorbuf + 0x1be + 16*i;
194 ipod->pinfo[i].type = ptr[4];
195 ipod->pinfo[i].start = BYTES2INT32(ptr, 8);
196 ipod->pinfo[i].size = BYTES2INT32(ptr, 12);
197
198 /* extended? */
199 if ( ipod->pinfo[i].type == 5 ) {
200 /* not handled yet */
201 }
202 }
203 } else if ((ipod->sectorbuf[0] == 'E') && (ipod->sectorbuf[1] == 'R')) {
204 /* Apple Partition Map */
205
206 /* APM parsing code based on the check_mac_partitions() function in
207 ipodloader2 - written by Thomas Tempelmann and released
208 under the GPL. */
209
210 int blkNo = 1;
211 int partBlkCount = 1;
212 int partBlkSizMul = ipod->sectorbuf[2] / 2;
213
214 int pmMapBlkCnt; /* # of blks in partition map */
215 int pmPyPartStart; /* physical start blk of partition */
216 int pmPartBlkCnt; /* # of blks in this partition */
217 int i = 0;
218
219 ipod->macpod = 1;
220
221 memset(ipod->pinfo,0,sizeof(ipod->pinfo));
222
223 while (blkNo <= partBlkCount) {
224 if (ipod_seek(ipod, blkNo * partBlkSizMul * 512) < 0) {
225 fprintf(stderr,"[ERR] Seek failed whilst reading APM\n");
226 return -1;
227 }
228
229 count = ipod_read(ipod, ipod->sector_size);
230
231 if (count <= 0) {
232 ipod_print_error(" Error reading from disk: ");
233 return -1;
234 }
235
236 /* see if it's a partition entry */
237 if ((ipod->sectorbuf[0] != 'P') || (ipod->sectorbuf[1] != 'M')) {
238 /* end of partition table -> leave the loop */
239 break;
240 }
241
242 /* Extract the interesting entries */
243 pmMapBlkCnt = be2int(ipod->sectorbuf + 4);
244 pmPyPartStart = be2int(ipod->sectorbuf + 8);
245 pmPartBlkCnt = be2int(ipod->sectorbuf + 12);
246
247 /* update the number of part map blocks */
248 partBlkCount = pmMapBlkCnt;
249
250 if (strncmp((char*)(ipod->sectorbuf + 48), "Apple_MDFW", 32)==0) {
251 /* A Firmware partition */
252 ipod->pinfo[i].start = pmPyPartStart;
253 ipod->pinfo[i].size = pmPartBlkCnt;
254 ipod->pinfo[i].type = 0;
255 i++;
256 } else if (strncmp((char*)(ipod->sectorbuf + 48), "Apple_HFS", 32)==0) {
257 /* A HFS partition */
258 ipod->pinfo[i].start = pmPyPartStart;
259 ipod->pinfo[i].size = pmPartBlkCnt;
260 ipod->pinfo[i].type = PARTTYPE_HFS;
261 i++;
262 }
263
264 blkNo++; /* read next partition map entry */
265 }
266 } else {
267 if (!silent) fprintf(stderr,"[ERR] Bad boot sector signature\n");
268 return -1;
269 }
270
271 /* Check that the partition table looks like an ipod:
272 1) Partition 1 is of type 0 (Empty) but isn't empty.
273 2) Partition 2 is of type 0xb or 0xc (winpod) or -1 (macpod)
274 */
275 if ((ipod->pinfo[0].type != 0) || (ipod->pinfo[0].size == 0) ||
276 ((ipod->pinfo[1].type != 0xb) && (ipod->pinfo[1].type != 0xc) &&
277 (ipod->pinfo[1].type != PARTTYPE_HFS))) {
278 if (!silent) fprintf(stderr,"[ERR] Partition layout is not an ipod\n");
279 return -1;
280 }
281
282 ipod->start = ipod->pinfo[0].start*ipod->sector_size;
283 return 0;
284}
285
286int read_partition(struct ipod_t* ipod, int outfile)
287{
288 int res;
289 ssize_t n;
290 int bytesleft;
291 int chunksize;
292 int count = ipod->pinfo[0].size;
293
294 if (ipod_seek(ipod, ipod->start) < 0) {
295 return -1;
296 }
297 if(ipod->sectorbuf == NULL) {
298 fprintf(stderr,"[ERR] Buffer not initialized.");
299 return -1;
300 }
301
302 fprintf(stderr,"[INFO] Writing %d sectors to output file\n",count);
303
304 bytesleft = count * ipod->sector_size;
305 while (bytesleft > 0) {
306 if (bytesleft > BUFFER_SIZE) {
307 chunksize = BUFFER_SIZE;
308 } else {
309 chunksize = bytesleft;
310 }
311
312 n = ipod_read(ipod, chunksize);
313
314 if (n < 0) {
315 return -1;
316 }
317
318 if (n < chunksize) {
319 fprintf(stderr,
320 "[ERR] Short read in disk_read() - requested %d, got %d\n",
321 chunksize,(int)n);
322 return -1;
323 }
324
325 bytesleft -= n;
326
327 res = write(outfile,ipod->sectorbuf,n);
328
329 if (res < 0) {
330 perror("[ERR] write in disk_read");
331 return -1;
332 }
333
334 if (res != n) {
335 fprintf(stderr,
336 "Short write - requested %d, received %d - aborting.\n",(int)n,res);
337 return -1;
338 }
339 }
340
341 fprintf(stderr,"[INFO] Done.\n");
342 return 0;
343}
344
345int write_partition(struct ipod_t* ipod, int infile)
346{
347 ssize_t res;
348 int n;
349 int bytesread;
350 int byteswritten = 0;
351 int eof;
352 int padding = 0;
353
354 if (ipod_seek(ipod, ipod->start) < 0) {
355 return -1;
356 }
357 if(ipod->sectorbuf == NULL) {
358 fprintf(stderr,"[ERR] Buffer not initialized.");
359 return -1;
360 }
361
362 fprintf(stderr,"[INFO] Writing input file to device\n");
363 bytesread = 0;
364 eof = 0;
365 while (!eof) {
366 n = read(infile,ipod->sectorbuf,BUFFER_SIZE);
367
368 if (n < 0) {
369 perror("[ERR] read in disk_write");
370 return -1;
371 }
372
373 if (n < BUFFER_SIZE) {
374 eof = 1;
375 /* We need to pad the last write to a multiple of SECTOR_SIZE */
376 if ((n % ipod->sector_size) != 0) {
377 padding = (ipod->sector_size-(n % ipod->sector_size));
378 n += padding;
379 }
380 }
381
382 bytesread += n;
383
384 res = ipod_write(ipod, n);
385
386 if (res < 0) {
387 ipod_print_error(" Error writing to disk: ");
388 fprintf(stderr,"Bytes written: %d\n",byteswritten);
389 return -1;
390 }
391
392 if (res != n) {
393 fprintf(stderr,"[ERR] Short write - requested %d, received %d - aborting.\n",n,(int)res);
394 return -1;
395 }
396
397 byteswritten += res;
398 }
399
400 fprintf(stderr,"[INFO] Wrote %d bytes plus %d bytes padding.\n",
401 byteswritten-padding,padding);
402 return 0;
403}
404
405char* ftypename[] = { "OSOS", "RSRC", "AUPD", "HIBE", "OSBK" };
406
407int diskmove(struct ipod_t* ipod, int delta)
408{
409 int src_start;
410 int src_end;
411 int bytesleft;
412 int chunksize;
413 int n;
414
415 src_start = ipod->ipod_directory[1].devOffset;
416 src_end = (ipod->ipod_directory[ipod->nimages-1].devOffset + ipod->sector_size +
417 ipod->ipod_directory[ipod->nimages-1].len +
418 (ipod->sector_size-1)) & ~(ipod->sector_size-1);
419 bytesleft = src_end - src_start;
420
421 if (ipod_verbose) {
422 fprintf(stderr,"[INFO] Need to move images 2-%d forward %08x bytes\n", ipod->nimages,delta);
423 fprintf(stderr,"[VERB] src_start = %08x\n",src_start);
424 fprintf(stderr,"[VERB] src_end = %08x\n",src_end);
425 fprintf(stderr,"[VERB] dest_start = %08x\n",src_start+delta);
426 fprintf(stderr,"[VERB] dest_end = %08x\n",src_end+delta);
427 fprintf(stderr,"[VERB] bytes to copy = %08x\n",bytesleft);
428 }
429
430 while (bytesleft > 0) {
431 if (bytesleft <= BUFFER_SIZE) {
432 chunksize = bytesleft;
433 } else {
434 chunksize = BUFFER_SIZE;
435 }
436
437 if (ipod_verbose) {
438 fprintf(stderr,"[VERB] Copying %08x bytes from %08x to %08x (absolute %08x to %08x)\n",
439 chunksize,
440 src_end-chunksize,
441 src_end-chunksize+delta,
442 (unsigned int)(ipod->start+src_end-chunksize),
443 (unsigned int)(ipod->start+src_end-chunksize+delta));
444 }
445
446
447 if (ipod_seek(ipod, ipod->start+src_end-chunksize) < 0) {
448 fprintf(stderr,"[ERR] Seek failed\n");
449 return -1;
450 }
451
452 if ((n = ipod_read(ipod,chunksize)) < 0) {
453 perror("[ERR] Write failed\n");
454 return -1;
455 }
456
457 if (n < chunksize) {
458 fprintf(stderr,"[ERR] Short read - requested %d bytes, received %d\n",
459 chunksize,n);
460 return -1;
461 }
462
463 if (ipod_seek(ipod, ipod->start+src_end-chunksize+delta) < 0) {
464 fprintf(stderr,"[ERR] Seek failed\n");
465 return -1;
466 }
467
468 if ((n = ipod_write(ipod,chunksize)) < 0) {
469 perror("[ERR] Write failed\n");
470 return -1;
471 }
472
473 if (n < chunksize) {
474 fprintf(stderr,"[ERR] Short write - requested %d bytes, received %d\n"
475 ,chunksize,n);
476 return -1;
477 }
478
479 src_end -= chunksize;
480 bytesleft -= chunksize;
481 }
482
483 return 0;
484}
485
486static int rename_image(struct ipod_t* ipod, char* from, char* to)
487{
488 int n;
489 int x;
490 int found;
491 int i;
492 unsigned char* p;
493
494 /* diroffset may not be sector-aligned */
495 x = ipod->diroffset % ipod->sector_size;
496
497 if(ipod->sectorbuf == NULL) {
498 fprintf(stderr,"[ERR] Buffer not initialized.");
499 return -1;
500 }
501 /* Read directory */
502 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) {
503 fprintf(stderr,"[ERR] Seek to diroffset (%08x) failed.\n",(unsigned)ipod->diroffset);
504 return -1;
505 }
506
507 n=ipod_read(ipod, ipod->sector_size);
508 if (n < 0) {
509 fprintf(stderr,"[ERR] Read of directory failed.\n");
510 return -1;
511 }
512
513 p = ipod->sectorbuf + x;
514
515 /* A hack to detect 2nd gen Nanos - maybe there is a better way? */
516 if (p[0] == 0)
517 {
518 /* Adjust diroffset */
519 ipod->diroffset += ipod->sector_size - x;
520
521 n=ipod_read(ipod, ipod->sector_size);
522 if (n < 0) {
523 fprintf(stderr,"[ERR] Read of directory failed.\n");
524 return -1;
525 }
526 p = ipod->sectorbuf;
527 }
528
529 found = 0;
530 for (i=0 ; !found && i < MAX_IMAGES; i++) {
531 if (memcmp(p + 4, from, 4) == 0) {
532 memcpy(p + 4, to, 4);
533
534 found = 1;
535 }
536 p += 40;
537 }
538
539 if (!found) {
540 fprintf(stderr,"[ERR] Unexpected error - no \"%s\" image!\n", from);
541 return -1;
542 }
543
544 /* Write directory back to disk */
545 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) {
546 fprintf(stderr,"[ERR] Seek to diroffset (%08x) failed.\n",(unsigned)ipod->diroffset);
547 return -1;
548 }
549
550 n=ipod_write(ipod, ipod->sector_size);
551 if (n < 0) {
552 fprintf(stderr,"[ERR] Write of directory failed in rename_image.\n");
553 return -1;
554 }
555
556 return 0;
557}
558
559static int delete_image(struct ipod_t* ipod, char* name)
560{
561 int n;
562 int x;
563 int found;
564 int i;
565 unsigned char* p;
566
567 /* diroffset may not be sector-aligned */
568 x = ipod->diroffset % ipod->sector_size;
569
570 /* Read directory */
571 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) {
572 fprintf(stderr,"[ERR] Seek to diroffset (%08x) failed.\n",(unsigned)ipod->diroffset);
573 return -1;
574 }
575
576 n=ipod_read(ipod, ipod->sector_size);
577 if (n < 0) {
578 fprintf(stderr,"[ERR] Read of directory failed.\n");
579 return -1;
580 }
581
582 p = ipod->sectorbuf + x;
583
584 /* A hack to detect 2nd gen Nanos - maybe there is a better way? */
585 if (p[0] == 0)
586 {
587 /* Adjust diroffset */
588 ipod->diroffset += ipod->sector_size - x;
589
590 n=ipod_read(ipod, ipod->sector_size);
591 if (n < 0) {
592 fprintf(stderr,"[ERR] Read of directory failed.\n");
593 return -1;
594 }
595 p = ipod->sectorbuf;
596 }
597
598 found = 0;
599 for (i=0 ; !found && i < MAX_IMAGES; i++) {
600 if (memcmp(p + 4, name, 4) == 0) {
601 memset(p, 0, 40); /* Delete directory entry */
602 found = 1;
603 }
604 p += 40;
605 }
606
607 if (!found) {
608 fprintf(stderr,"[ERR] Unexpected error - no \"%s\" image!\n", name);
609 return -1;
610 }
611
612 /* Write directory back to disk */
613 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) {
614 fprintf(stderr,"[ERR] Seek to diroffset (%08x) failed.\n",(unsigned)ipod->diroffset);
615 return -1;
616 }
617
618 n=ipod_write(ipod, ipod->sector_size);
619 if (n < 0) {
620 fprintf(stderr,"[ERR] Write of directory failed in delete_image.\n");
621 return -1;
622 }
623
624 return 0;
625}
626
627int add_new_image(struct ipod_t* ipod, char* imagename, char* filename, int type)
628{
629 int length;
630 int found;
631 int i;
632 int x;
633 int n;
634 int infile;
635 int newsize;
636 unsigned long chksum=0;
637 unsigned long filechksum=0;
638 unsigned long offset;
639 unsigned char header[8]; /* Header for .ipod file */
640 unsigned char* p;
641
642 if(ipod->sectorbuf == NULL) {
643 fprintf(stderr,"[ERR] Buffer not initialized.");
644 return -1;
645 }
646#ifdef WITH_BOOTOBJS
647 if (type == FILETYPE_INTERNAL) {
648 fprintf(stderr,"[INFO] Using internal bootloader - %d bytes\n",ipod->bootloader_len);
649 length = ipod->bootloader_len;
650 infile = -1;
651 }
652 else
653#endif
654 {
655 /* First check that the input file is the correct type for this ipod. */
656 infile=open(filename,O_RDONLY);
657 if (infile < 0) {
658 fprintf(stderr,"[ERR] Couldn't open input file %s\n",filename);
659 return -1;
660 }
661
662 if (type==FILETYPE_DOT_IPOD) {
663 n = read(infile,header,8);
664 if (n < 8) {
665 fprintf(stderr,"[ERR] Failed to read header from %s\n",filename);
666 close(infile);
667 return -1;
668 }
669
670 if (memcmp(header+4, ipod->modelname,4)!=0) {
671 fprintf(stderr,"[ERR] Model name in input file (%c%c%c%c) doesn't match ipod model (%s)\n",
672 header[4],header[5],header[6],header[7], ipod->modelname);
673 close(infile);
674 return -1;
675 }
676
677 filechksum = be2int(header);
678
679 length = filesize(infile)-8;
680 } else {
681 length = filesize(infile);
682 }
683 }
684
685 newsize=(length+ipod->sector_size-1)&~(ipod->sector_size-1);
686
687 fprintf(stderr,"[INFO] Padding input file from 0x%08x to 0x%08x bytes\n",
688 length,newsize);
689
690 if (newsize > BUFFER_SIZE) {
691 fprintf(stderr,"[ERR] Input file too big for buffer\n");
692 if (infile >= 0) close(infile);
693 return -1;
694 }
695
696 /* TODO: Check if we have enough space in the partition for the new image */
697
698#ifdef WITH_BOOTOBJS
699 if (type == FILETYPE_INTERNAL) {
700 memcpy(ipod->sectorbuf,ipod->bootloader,ipod->bootloader_len);
701 }
702 else
703#endif
704 {
705 fprintf(stderr,"[INFO] Reading input file...\n");
706
707 n = read(infile,ipod->sectorbuf,length);
708 if (n < 0) {
709 fprintf(stderr,"[ERR] Couldn't read input file\n");
710 close(infile);
711 return -1;
712 }
713 close(infile);
714 }
715
716 /* Pad the data with zeros */
717 memset(ipod->sectorbuf+length,0,newsize-length);
718
719 if (type==FILETYPE_DOT_IPOD) {
720 chksum = ipod->modelnum;
721 for (i = 0; i < length; i++) {
722 /* add 8 unsigned bits but keep a 32 bit sum */
723 chksum += ipod->sectorbuf[i];
724 }
725
726 if (chksum == filechksum) {
727 fprintf(stderr,"[INFO] Checksum OK in %s\n",filename);
728 } else {
729 fprintf(stderr,"[ERR] Checksum in %s failed check\n",filename);
730 return -1;
731 }
732 }
733
734
735 offset = ipod->fwoffset + ipod->ipod_directory[ipod->nimages - 1].devOffset +
736 ipod->ipod_directory[ipod->nimages - 1].len + ipod->sector_size;
737
738 /* 2nd Gen Nano has encrypted firmware, and the sector
739 preceeding the firmware contains hashes that need to be
740 preserved. Nano 2G images include these extra 2048 (0x800)
741 bytes
742 */
743 if (ipod_seek(ipod, offset - (ipod->modelnum == 62 ? 0x800 : 0)) < 0) {
744 fprintf(stderr,"[ERR] Seek failed\n");
745 return -1;
746 }
747
748 if ((n = ipod_write(ipod,newsize)) < 0) {
749 perror("[ERR] Write failed\n");
750 return -1;
751 }
752
753 if (n < newsize) {
754 fprintf(stderr,"[ERR] Short write - requested %d bytes, received %d\n"
755 ,newsize,n);
756 return -1;
757 }
758 fprintf(stderr,"[INFO] Wrote %d bytes to firmware partition\n",n);
759
760 /* Now we need to create a new directory entry
761
762 NOTE: On the Nano 2G, the checksum is the checksum of the
763 unencrypted firmware. But this isn't checked by the NOR
764 bootloader (there are cryptographic hashes in the
765 firmware itself), so it doesn't matter that this is
766 wrong.
767 */
768 chksum = 0;
769 for (i = 0; i < length; i++) {
770 /* add 8 unsigned bits but keep a 32 bit sum */
771 chksum += ipod->sectorbuf[i];
772 }
773
774 x = ipod->diroffset % ipod->sector_size;
775
776 /* Read directory */
777 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; }
778
779 n=ipod_read(ipod, ipod->sector_size);
780 if (n < 0) { return -1; }
781
782 /* Create a new directory entry */
783
784 /* Copy OSOS or OSBK details - we assume one of them exists */
785 p = ipod->sectorbuf + x;
786 found = 0;
787 for (i = 0; !found && i < ipod->nimages; i++) {
788 if ((memcmp(p + 4, "soso", 4)==0) || (memcmp(p + 4, "kbso", 4)==0)) {
789 found = 1;
790 } else {
791 p += 40;
792 }
793 }
794
795 if (!found) {
796 fprintf(stderr,"[ERR] No OSOS or OSBK image to copy directory from\n");
797 return -1;
798 }
799
800 /* Copy directory image */
801 memcpy(ipod->sectorbuf + x + (ipod->nimages * 40), p, 40);
802 p = ipod->sectorbuf + x + (ipod->nimages * 40);
803
804 /* Modify directory. */
805 memcpy(p + 4, imagename, 4);
806 int2le(offset - ipod->fwoffset, p + 12); /* devOffset */
807 int2le(length - (ipod->modelnum==62 ? 0x800: 0), p + 16); /* len */
808 int2le(chksum, p + 28); /* checksum */
809
810 /* Write directory */
811 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; }
812 n=ipod_write(ipod, ipod->sector_size);
813 if (n < 0) { return -1; }
814
815 return 0;
816}
817
818
819int ipod_has_bootloader(struct ipod_t* ipod)
820{
821 /* The 2nd gen Nano is installed differently */
822 if (ipod->modelnum == 62) {
823 int i;
824 int has_osbk = 0;
825 /* Check if we have an OSBK image */
826 for (i = 0; i < ipod->nimages; i++) {
827 if (ipod->ipod_directory[i].ftype==FTYPE_OSBK) {
828 has_osbk = 1;
829 }
830 }
831 return has_osbk;
832 }
833 else {
834 return (ipod->ipod_directory[0].entryOffset != 0);
835 }
836}
837
838
839/*
840 Bootloader installation on the Nano2G consists of renaming the
841 OSOS image to OSBK and then writing the Rockbox bootloader as a
842 new OSOS image.
843
844 Maybe this approach can/should be adapted for other ipods, as it
845 prevents the Apple bootloader loading the original firmware into
846 RAM along with the Rockbox bootloader (and hence will give a
847 faster boot when the user just wants to start Rockbox).
848
849*/
850
851static int add_bootloader_nano2g(struct ipod_t* ipod, char* filename, int type)
852{
853 /* Check if we already have an OSBK image */
854 if (ipod_has_bootloader(ipod) == 0) {
855 /* First-time install - rename OSOS to OSBK and create new OSOS for bootloader */
856 fprintf(stderr,"[INFO] Creating OSBK backup image of original firmware\n");
857
858 if (rename_image(ipod, "soso", "kbso") < 0) {
859 fprintf(stderr,"[ERR] Could not rename OSOS image\n");
860 return -1;
861 }
862
863 /* Add our bootloader as a brand new image */
864 return add_new_image(ipod, "soso", filename, type);
865 } else {
866 /* This is an update, just replace OSOS with our bootloader */
867
868 return write_firmware(ipod, filename, type);
869 }
870}
871
872
873static int delete_bootloader_nano2g(struct ipod_t* ipod)
874{
875 /* Check if we have an OSBK image */
876 if (ipod_has_bootloader(ipod) == 0) {
877 fprintf(stderr,"[ERR] No OSBK image found - nothing to uninstall\n");
878 return -1;
879 } else {
880 /* Delete our bootloader image */
881 if (delete_image(ipod, "soso") < 0) {
882 fprintf(stderr,"[WARN] Could not delete OSOS image\n");
883 } else {
884 fprintf(stderr,"[INFO] OSOS image deleted\n");
885 }
886
887 if (rename_image(ipod, "kbso", "soso") < 0) {
888 fprintf(stderr,"[ERR] Could not rename OSBK image\n");
889 return -1;
890 }
891
892
893 fprintf(stderr,"[INFO] OSBK image renamed to OSOS - bootloader uninstalled.\n");
894 return 0;
895 }
896}
897
898
899int add_bootloader(struct ipod_t* ipod, char* filename, int type)
900{
901 int length;
902 int i;
903 int x;
904 int n;
905 int infile;
906 int paddedlength;
907 int entryOffset;
908 int delta = 0;
909 unsigned long chksum=0;
910 unsigned long filechksum=0;
911 unsigned char header[8]; /* Header for .ipod file */
912 unsigned char* bootloader_buf;
913
914 /* The 2nd gen Nano is installed differently */
915 if (ipod->modelnum == 62) {
916 return add_bootloader_nano2g(ipod, filename, type);
917 }
918 if(ipod->sectorbuf == NULL) {
919 fprintf(stderr,"[ERR] Buffer not initialized.");
920 return -1;
921 }
922
923 /* Calculate the position in the OSOS image where our bootloader will go. */
924 if (ipod->ipod_directory[0].entryOffset>0) {
925 /* Keep the same entryOffset */
926 entryOffset = ipod->ipod_directory[0].entryOffset;
927 } else {
928 entryOffset = (ipod->ipod_directory[0].len+ipod->sector_size-1)&~(ipod->sector_size-1);
929 }
930
931#ifdef WITH_BOOTOBJS
932 if (type == FILETYPE_INTERNAL) {
933 fprintf(stderr,"[INFO] Using internal bootloader - %d bytes\n",ipod->bootloader_len);
934 memcpy(ipod->sectorbuf+entryOffset,ipod->bootloader,ipod->bootloader_len);
935 length = ipod->bootloader_len;
936 paddedlength=(ipod->bootloader_len+ipod->sector_size-1)&~(ipod->sector_size-1);
937 }
938 else
939#endif
940 {
941 infile=open(filename,O_RDONLY);
942 if (infile < 0) {
943 fprintf(stderr,"[ERR] Couldn't open input file %s\n",filename);
944 return -1;
945 }
946
947 if (type==FILETYPE_DOT_IPOD) {
948 /* First check that the input file is the correct type for this ipod. */
949 n = read(infile,header,8);
950 if (n < 8) {
951 fprintf(stderr,"[ERR] Failed to read header from %s\n",filename);
952 close(infile);
953 return -1;
954 }
955
956 if (memcmp(header+4, ipod->modelname,4)!=0) {
957 fprintf(stderr,"[ERR] Model name in input file (%c%c%c%c) doesn't match ipod model (%s)\n",
958 header[4],header[5],header[6],header[7], ipod->modelname);
959 close(infile);
960 return -1;
961 }
962
963 filechksum = be2int(header);
964
965 length=filesize(infile)-8;
966 } else {
967 length=filesize(infile);
968 }
969 paddedlength=(length+ipod->sector_size-1)&~(ipod->sector_size-1);
970
971 bootloader_buf = malloc(length);
972 if (bootloader_buf == NULL) {
973 fprintf(stderr,"[ERR] Can not allocate memory for bootloader\n");
974 return -1;
975 }
976 /* Now read our bootloader - we need to check it before modifying the partition*/
977 n = read(infile,bootloader_buf,length);
978 close(infile);
979
980 if (n < 0) {
981 fprintf(stderr,"[ERR] Couldn't read input file\n");
982 return -1;
983 }
984
985 if (type==FILETYPE_DOT_IPOD) {
986 /* Calculate and confirm bootloader checksum */
987 chksum = ipod->modelnum;
988 for (i = 0; i < length; i++) {
989 /* add 8 unsigned bits but keep a 32 bit sum */
990 chksum += bootloader_buf[i];
991 }
992
993 if (chksum == filechksum) {
994 fprintf(stderr,"[INFO] Checksum OK in %s\n",filename);
995 } else {
996 fprintf(stderr,"[ERR] Checksum in %s failed check\n",filename);
997 return -1;
998 }
999 }
1000 }
1001
1002 if (entryOffset+paddedlength > BUFFER_SIZE) {
1003 fprintf(stderr,"[ERR] Input file too big for buffer\n");
1004 return -1;
1005 }
1006
1007 if (ipod_verbose) {
1008 fprintf(stderr,"[VERB] Original firmware begins at 0x%08x\n", ipod->ipod_directory[0].devOffset + ipod->sector_size);
1009 fprintf(stderr,"[VERB] New entryOffset will be 0x%08x\n",entryOffset);
1010 fprintf(stderr,"[VERB] End of bootloader will be at 0x%08x\n",entryOffset+paddedlength);
1011 }
1012
1013 /* Check if we have enough space */
1014 /* TODO: Check the size of the partition. */
1015 if (ipod->nimages > 1) {
1016 if ((ipod->ipod_directory[0].devOffset+entryOffset+paddedlength) >
1017 ipod->ipod_directory[1].devOffset) {
1018 fprintf(stderr,"[INFO] Moving images to create room for new firmware...\n");
1019 delta = ipod->ipod_directory[0].devOffset + entryOffset+paddedlength
1020 - ipod->ipod_directory[1].devOffset + ipod->sector_size;
1021
1022 if (diskmove(ipod, delta) < 0) {
1023 fprintf(stderr,"[ERR] Image movement failed.\n");
1024 return -1;
1025 }
1026 }
1027 }
1028
1029
1030 /* We have moved the partitions, now we can write our bootloader */
1031
1032 /* Firstly read the original firmware into ipod->sectorbuf */
1033 fprintf(stderr,"[INFO] Reading original firmware...\n");
1034 if (ipod_seek(ipod, ipod->fwoffset+ipod->ipod_directory[0].devOffset) < 0) {
1035 fprintf(stderr,"[ERR] Seek failed\n");
1036 return -1;
1037 }
1038
1039 if ((n = ipod_read(ipod,entryOffset)) < 0) {
1040 perror("[ERR] Read failed\n");
1041 return -1;
1042 }
1043
1044 if (n < entryOffset) {
1045 fprintf(stderr,"[ERR] Short read - requested %d bytes, received %d\n"
1046 ,entryOffset,n);
1047 return -1;
1048 }
1049
1050#ifdef WITH_BOOTOBJS
1051 if (type == FILETYPE_INTERNAL) {
1052 memcpy(ipod->sectorbuf+entryOffset,ipod->bootloader,ipod->bootloader_len);
1053 }
1054 else
1055#endif
1056 {
1057 memcpy(ipod->sectorbuf+entryOffset,bootloader_buf,length);
1058 free(bootloader_buf);
1059 }
1060
1061 /* Calculate new checksum for combined image */
1062 chksum = 0;
1063 for (i=0;i<entryOffset + length; i++) {
1064 chksum += ipod->sectorbuf[i];
1065 }
1066
1067 /* Now write the combined firmware image to the disk */
1068
1069 if (ipod_seek(ipod, ipod->fwoffset+ipod->ipod_directory[0].devOffset) < 0) {
1070 fprintf(stderr,"[ERR] Seek failed\n");
1071 return -1;
1072 }
1073
1074 if ((n = ipod_write(ipod,entryOffset+paddedlength)) < 0) {
1075 perror("[ERR] Write failed\n");
1076 return -1;
1077 }
1078
1079 if (n < (entryOffset+paddedlength)) {
1080 fprintf(stderr,"[ERR] Short read - requested %d bytes, received %d\n"
1081 ,entryOffset+paddedlength,n);
1082 return -1;
1083 }
1084
1085 fprintf(stderr,"[INFO] Wrote %d bytes to firmware partition\n",entryOffset+paddedlength);
1086
1087 x = ipod->diroffset % ipod->sector_size;
1088
1089 /* Read directory */
1090 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) {
1091 fprintf(stderr,"[ERR] Seek failed\n");
1092 return -1;
1093 }
1094
1095 n=ipod_read(ipod, ipod->sector_size);
1096 if (n < 0) {
1097 fprintf(stderr,"[ERR] Directory read failed\n");
1098 return -1;
1099 }
1100
1101 /* Update entries for image 0 */
1102 int2le(entryOffset+length,ipod->sectorbuf+x+16);
1103 int2le(entryOffset,ipod->sectorbuf+x+24);
1104 int2le(chksum,ipod->sectorbuf+x+28);
1105 int2le(0xffffffff,ipod->sectorbuf+x+36); /* loadAddr */
1106
1107 /* Update devOffset entries for other images, if we have moved them */
1108 if (delta > 0) {
1109 for (i=1;i<ipod->nimages;i++) {
1110 int2le(le2int(ipod->sectorbuf+x+i*40+12)+delta,ipod->sectorbuf+x+i*40+12);
1111 }
1112 }
1113
1114 /* Write directory */
1115 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) {
1116 fprintf(stderr,"[ERR] Seek to %d failed\n", (int)(ipod->start+ipod->diroffset-x));
1117 return -1;
1118 }
1119 n=ipod_write(ipod, ipod->sector_size);
1120 if (n < 0) {
1121 fprintf(stderr,"[ERR] Directory write failed\n");
1122 return -1;
1123 }
1124
1125 return 0;
1126}
1127
1128int delete_bootloader(struct ipod_t* ipod)
1129{
1130 int length;
1131 int i;
1132 int x;
1133 int n;
1134 unsigned long chksum=0; /* 32 bit checksum - Rockbox .ipod style*/
1135
1136 /* The 2nd gen Nano is installed differently */
1137 if (ipod->modelnum == 62) {
1138 return delete_bootloader_nano2g(ipod);
1139 }
1140 if(ipod->sectorbuf == NULL) {
1141 fprintf(stderr,"[ERR] Buffer not initialized.");
1142 return -1;
1143 }
1144
1145 /* Removing the bootloader involves adjusting the "length",
1146 "chksum" and "entryOffset" values in the osos image's directory
1147 entry. */
1148
1149 /* Firstly check we have a bootloader... */
1150
1151 if (ipod_has_bootloader(ipod) == 0) {
1152 fprintf(stderr,"[ERR] No bootloader found.\n");
1153 return -1;
1154 }
1155
1156 length = ipod->ipod_directory[0].entryOffset;
1157
1158 /* Read the firmware so we can calculate the checksum */
1159 fprintf(stderr,"[INFO] Reading firmware (%d bytes)\n",length);
1160
1161 if (ipod_seek(ipod, ipod->fwoffset+ipod->ipod_directory[0].devOffset) < 0) {
1162 return -1;
1163 }
1164
1165 i = (length+ipod->sector_size-1) & ~(ipod->sector_size-1);
1166 fprintf(stderr,"[INFO] Padding read from 0x%08x to 0x%08x bytes\n",
1167 length,i);
1168
1169 if ((n = ipod_read(ipod,i)) < 0) {
1170 return -1;
1171 }
1172
1173 if (n < i) {
1174 fprintf(stderr,"[ERR] Short read - requested %d bytes, received %d\n",
1175 i,n);
1176 return -1;
1177 }
1178
1179 chksum = 0;
1180 for (i = 0; i < length; i++) {
1181 /* add 8 unsigned bits but keep a 32 bit sum */
1182 chksum += ipod->sectorbuf[i];
1183 }
1184
1185 /* Now write back the updated directory entry */
1186
1187 fprintf(stderr,"[INFO] Updating firmware checksum\n");
1188
1189 x = ipod->diroffset % ipod->sector_size;
1190
1191 /* Read directory */
1192 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; }
1193
1194 n=ipod_read(ipod, ipod->sector_size);
1195 if (n < 0) { return -1; }
1196
1197 /* Update entries for image 0 */
1198 int2le(length,ipod->sectorbuf+x+16);
1199 int2le(0,ipod->sectorbuf+x+24);
1200 int2le(chksum,ipod->sectorbuf+x+28);
1201
1202 /* Write directory */
1203 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; }
1204 n=ipod_write(ipod, ipod->sector_size);
1205 if (n < 0) { return -1; }
1206
1207 return 0;
1208}
1209
1210int write_firmware(struct ipod_t* ipod, char* filename, int type)
1211{
1212 int length;
1213 int i;
1214 int x;
1215 int n;
1216 int infile;
1217 int newsize;
1218 int bytesavailable;
1219 unsigned long chksum=0;
1220 unsigned long filechksum=0;
1221 unsigned long offset;
1222 unsigned char header[8]; /* Header for .ipod file */
1223 unsigned char* p;
1224
1225 if(ipod->sectorbuf == NULL) {
1226 fprintf(stderr,"[ERR] Buffer not initialized.");
1227 return -1;
1228 }
1229#ifdef WITH_BOOTOBJS
1230 if (type == FILETYPE_INTERNAL) {
1231 fprintf(stderr,"[INFO] Using internal bootloader - %d bytes\n",ipod->bootloader_len);
1232 length = ipod->bootloader_len;
1233 infile = -1;
1234 }
1235 else
1236#endif
1237 {
1238 /* First check that the input file is the correct type for this ipod. */
1239 infile=open(filename,O_RDONLY);
1240 if (infile < 0) {
1241 fprintf(stderr,"[ERR] Couldn't open input file %s\n",filename);
1242 return -1;
1243 }
1244
1245 if (type==FILETYPE_DOT_IPOD) {
1246 n = read(infile,header,8);
1247 if (n < 8) {
1248 fprintf(stderr,"[ERR] Failed to read header from %s\n",filename);
1249 close(infile);
1250 return -1;
1251 }
1252
1253 if (memcmp(header+4, ipod->modelname,4)!=0) {
1254 fprintf(stderr,"[ERR] Model name in input file (%c%c%c%c) doesn't match ipod model (%s)\n",
1255 header[4],header[5],header[6],header[7], ipod->modelname);
1256 close(infile);
1257 return -1;
1258 }
1259
1260 filechksum = be2int(header);
1261
1262 length = filesize(infile)-8;
1263 } else {
1264 length = filesize(infile);
1265 }
1266 }
1267
1268 newsize=(length+ipod->sector_size-1)&~(ipod->sector_size-1);
1269
1270 fprintf(stderr,"[INFO] Padding input file from 0x%08x to 0x%08x bytes\n",
1271 length,newsize);
1272
1273 if (newsize > BUFFER_SIZE) {
1274 fprintf(stderr,"[ERR] Input file too big for buffer\n");
1275 if (infile >= 0) close(infile);
1276 return -1;
1277 }
1278
1279 /* Check if we have enough space */
1280 /* TODO: Check the size of the partition. */
1281 if (ipod->nimages > 1) {
1282 bytesavailable=ipod->ipod_directory[1].devOffset-ipod->ipod_directory[0].devOffset;
1283 if (bytesavailable < newsize) {
1284 fprintf(stderr,"[INFO] Moving images to create room for new firmware...\n");
1285
1286 /* TODO: Implement image movement */
1287 fprintf(stderr,"[ERR] Image movement not yet implemented.\n");
1288 close(infile);
1289 return -1;
1290 }
1291 }
1292
1293#ifdef WITH_BOOTOBJS
1294 if (type == FILETYPE_INTERNAL) {
1295 memcpy(ipod->sectorbuf,ipod->bootloader,ipod->bootloader_len);
1296 }
1297 else
1298#endif
1299 {
1300 fprintf(stderr,"[INFO] Reading input file...\n");
1301 /* We now know we have enough space, so write it. */
1302 n = read(infile,ipod->sectorbuf,length);
1303 if (n < 0) {
1304 fprintf(stderr,"[ERR] Couldn't read input file\n");
1305 close(infile);
1306 return -1;
1307 }
1308 close(infile);
1309 }
1310
1311 /* Pad the data with zeros */
1312 memset(ipod->sectorbuf+length,0,newsize-length);
1313
1314 if (type==FILETYPE_DOT_IPOD) {
1315 chksum = ipod->modelnum;
1316 for (i = 0; i < length; i++) {
1317 /* add 8 unsigned bits but keep a 32 bit sum */
1318 chksum += ipod->sectorbuf[i];
1319 }
1320
1321 if (chksum == filechksum) {
1322 fprintf(stderr,"[INFO] Checksum OK in %s\n",filename);
1323 } else {
1324 fprintf(stderr,"[ERR] Checksum in %s failed check\n",filename);
1325 return -1;
1326 }
1327 }
1328
1329
1330 offset = ipod->fwoffset+ipod->ipod_directory[ipod->ososimage].devOffset;
1331
1332 if (ipod->modelnum==62) {
1333
1334 /* 2nd Gen Nano has encrypted firmware, and the sector
1335 preceeding the firmware contains hashes that need to be
1336 preserved. Nano 2G images include these extra 2048 (0x800)
1337 bytes
1338 */
1339
1340 offset -= 0x800;
1341
1342 /* TODO: The above checks need to take into account this 0x800 bytes */
1343 }
1344
1345 if (ipod_seek(ipod, offset) < 0) {
1346 fprintf(stderr,"[ERR] Seek failed\n");
1347 return -1;
1348 }
1349
1350 if ((n = ipod_write(ipod,newsize)) < 0) {
1351 perror("[ERR] Write failed\n");
1352 return -1;
1353 }
1354
1355 if (n < newsize) {
1356 fprintf(stderr,"[ERR] Short write - requested %d bytes, received %d\n"
1357 ,newsize,n);
1358 return -1;
1359 }
1360 fprintf(stderr,"[INFO] Wrote %d bytes to firmware partition\n",n);
1361
1362 /* Now we need to update the "len", "entryOffset" and "chksum" fields
1363
1364 NOTE: On the Nano 2G, the checksum is the checksum of the
1365 unencrypted firmware. But this isn't checked by the NOR
1366 bootloader (there are cryptographic hashes in the
1367 firmware itself), so it doesn't matter that this is
1368 wrong.
1369 */
1370 chksum = 0;
1371 for (i = 0; i < length; i++) {
1372 /* add 8 unsigned bits but keep a 32 bit sum */
1373 chksum += ipod->sectorbuf[i];
1374 }
1375
1376 x = ipod->diroffset % ipod->sector_size;
1377
1378 /* Read directory */
1379 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; }
1380
1381 n=ipod_read(ipod, ipod->sector_size);
1382 if (n < 0) { return -1; }
1383
1384 /* Update entries for image */
1385 p = ipod->sectorbuf + x + (ipod->ososimage * 40);
1386 int2le(length - (ipod->modelnum==62 ? 0x800: 0), p + 16);
1387 int2le(0, p + 24);
1388 int2le(chksum, p + 28);
1389
1390 /* Write directory */
1391 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; }
1392 n=ipod_write(ipod, ipod->sector_size);
1393 if (n < 0) { return -1; }
1394
1395 return 0;
1396}
1397
1398int read_firmware(struct ipod_t* ipod, char* filename, int type)
1399{
1400 int length;
1401 int i;
1402 int outfile;
1403 int n;
1404 unsigned long offset;
1405 unsigned long chksum=0; /* 32 bit checksum - Rockbox .ipod style*/
1406 unsigned char header[8]; /* Header for .ipod file */
1407
1408 if(ipod->sectorbuf == NULL) {
1409 fprintf(stderr,"[ERR] Buffer not initialized.");
1410 return -1;
1411 }
1412 if (ipod->ipod_directory[ipod->ososimage].entryOffset != 0) {
1413 /* We have a bootloader... */
1414 length = ipod->ipod_directory[ipod->ososimage].entryOffset;
1415 } else {
1416 length = ipod->ipod_directory[ipod->ososimage].len;
1417 }
1418
1419 fprintf(stderr,"[INFO] Reading firmware (%d bytes)\n",length);
1420
1421 offset = ipod->fwoffset + ipod->ipod_directory[ipod->ososimage].devOffset;
1422 i = (length+ipod->sector_size-1) & ~(ipod->sector_size-1);
1423 fprintf(stderr,"[INFO] Padding read from 0x%08x to 0x%08x bytes\n",
1424 length,i);
1425
1426 if (ipod->modelnum==62) {
1427 /* 2nd Gen Nano has encrypted firmware, and we need to dump the
1428 sector preceeding the image - it contains hashes */
1429 offset -= 0x800;
1430 length += 0x800;
1431 i += 0x800;
1432 }
1433
1434 if (ipod_seek(ipod, offset)) {
1435 return -1;
1436 }
1437
1438 if ((n = ipod_read(ipod,i)) < 0) {
1439 return -1;
1440 }
1441
1442 if (n < i) {
1443 fprintf(stderr,"[ERR] Short read - requested %d bytes, received %d\n",
1444 i,n);
1445 return -1;
1446 }
1447
1448 outfile = open(filename,O_CREAT|O_TRUNC|O_WRONLY|O_BINARY,0666);
1449 if (outfile < 0) {
1450 fprintf(stderr,"[ERR] Couldn't open file %s\n",filename);
1451 return -1;
1452 }
1453
1454 if (type == FILETYPE_DOT_IPOD) {
1455 chksum = ipod->modelnum;
1456 for (i = 0; i < length; i++) {
1457 /* add 8 unsigned bits but keep a 32 bit sum */
1458 chksum += ipod->sectorbuf[i];
1459 }
1460
1461 int2be(chksum,header);
1462 memcpy(header+4, ipod->modelname,4);
1463
1464 n = write(outfile,header,8);
1465 if (n != 8) {
1466 fprintf(stderr,"[ERR] Write error - %d\n",n);
1467 }
1468 }
1469
1470 n = write(outfile,ipod->sectorbuf,length);
1471 if (n != length) {
1472 fprintf(stderr,"[ERR] Write error - %d\n",n);
1473 }
1474 close(outfile);
1475
1476 return 0;
1477}
1478
1479int read_directory(struct ipod_t* ipod)
1480{
1481 ssize_t n;
1482 int x;
1483 unsigned char* p;
1484 unsigned short version;
1485
1486 ipod->nimages=0;
1487
1488 /* Read firmware partition header (first 512 bytes of disk - but
1489 let's read a whole sector) */
1490
1491 if (ipod_seek(ipod, ipod->start) < 0) {
1492 fprintf(stderr,"[ERR] Seek to 0x%08x in read_directory() failed.\n",
1493 (unsigned int)(ipod->start));
1494 return -1;
1495 }
1496
1497 n=ipod_read(ipod, ipod->sector_size);
1498 if (n < 0) {
1499 fprintf(stderr,"[ERR] ipod_read(ipod,0x%08x) failed in read_directory()\n", ipod->sector_size);
1500 return -1;
1501 }
1502
1503 if (memcmp(ipod->sectorbuf,apple_stop_sign,sizeof(apple_stop_sign))!=0) {
1504 fprintf(stderr,"[ERR] Firmware partition doesn't contain Apple copyright, aborting.\n");
1505 return -1;
1506 }
1507
1508 if (memcmp(ipod->sectorbuf+0x100,"]ih[",4)!=0) {
1509 fprintf(stderr,"[ERR] Bad firmware directory\n");
1510 return -1;
1511 }
1512
1513 version = le2ushort(ipod->sectorbuf+0x10a);
1514 if ((version != 2) && (version != 3)) {
1515 fprintf(stderr,"[ERR] Unknown firmware format version %04x\n",
1516 version);
1517 }
1518 ipod->diroffset=le2int(ipod->sectorbuf+0x104) + 0x200;
1519
1520 /* diroffset may not be sector-aligned */
1521 x = ipod->diroffset % ipod->sector_size;
1522
1523 /* Read directory */
1524 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) {
1525 fprintf(stderr,"[ERR] Seek to diroffset (%08x) failed.\n",(unsigned)ipod->diroffset);
1526 return -1;
1527 }
1528
1529 n=ipod_read(ipod, ipod->sector_size);
1530 if (n < 0) {
1531 fprintf(stderr,"[ERR] Read of directory failed.\n");
1532 return -1;
1533 }
1534
1535 p = ipod->sectorbuf + x;
1536
1537 /* A hack to detect 2nd gen Nanos - maybe there is a better way? */
1538 if (p[0] == 0)
1539 {
1540 /* Adjust diroffset */
1541 ipod->diroffset += ipod->sector_size - x;
1542
1543 n=ipod_read(ipod, ipod->sector_size);
1544 if (n < 0) {
1545 fprintf(stderr,"[ERR] Read of directory failed.\n");
1546 return -1;
1547 }
1548 p = ipod->sectorbuf;
1549 }
1550
1551 ipod->ososimage = -1;
1552 while ((ipod->nimages < MAX_IMAGES) && (p < (ipod->sectorbuf + x + 400)) &&
1553 ((memcmp(p,"!ATA",4)==0) || (memcmp(p,"DNAN",4)==0))) {
1554 p+=4;
1555 if (memcmp(p,"soso",4)==0) {
1556 ipod->ipod_directory[ipod->nimages].ftype=FTYPE_OSOS;
1557 ipod->ososimage = ipod->nimages;
1558 } else if (memcmp(p,"crsr",4)==0) {
1559 ipod->ipod_directory[ipod->nimages].ftype=FTYPE_RSRC;
1560 } else if (memcmp(p,"dpua",4)==0) {
1561 ipod->ipod_directory[ipod->nimages].ftype=FTYPE_AUPD;
1562 } else if (memcmp(p,"kbso",4)==0) {
1563 ipod->ipod_directory[ipod->nimages].ftype=FTYPE_OSBK;
1564 } else if (memcmp(p,"ebih",4)==0) {
1565 ipod->ipod_directory[ipod->nimages].ftype=FTYPE_HIBE;
1566 } else {
1567 fprintf(stderr,"[ERR] Unknown image type %c%c%c%c\n",
1568 p[0],p[1],p[2],p[3]);
1569 }
1570 p+=4;
1571 ipod->ipod_directory[ipod->nimages].id=le2int(p);
1572 p+=4;
1573 ipod->ipod_directory[ipod->nimages].devOffset=le2int(p);
1574 p+=4;
1575 ipod->ipod_directory[ipod->nimages].len=le2int(p);
1576 p+=4;
1577 ipod->ipod_directory[ipod->nimages].addr=le2int(p);
1578 p+=4;
1579 ipod->ipod_directory[ipod->nimages].entryOffset=le2int(p);
1580 p+=4;
1581 ipod->ipod_directory[ipod->nimages].chksum=le2int(p);
1582 p+=4;
1583 ipod->ipod_directory[ipod->nimages].vers=le2int(p);
1584 p+=4;
1585 ipod->ipod_directory[ipod->nimages].loadAddr=le2int(p);
1586 p+=4;
1587 ipod->nimages++;
1588 }
1589
1590 if (ipod->ososimage < 0) {
1591 fprintf(stderr,"[ERR] No OSOS image found.\n");
1592 return -1;
1593 }
1594
1595 if ((ipod->nimages > 1) && (version==2)) {
1596 /* The 3g firmware image doesn't appear to have a version, so
1597 let's make one up... Note that this is never written back to the
1598 ipod, so it's OK to do. */
1599
1600 if (ipod->ipod_directory[ipod->ososimage].vers == 0) { ipod->ipod_directory[ipod->ososimage].vers = 3; }
1601
1602 ipod->fwoffset = ipod->start;
1603 } else {
1604 ipod->fwoffset = ipod->start + ipod->sector_size;
1605 }
1606
1607 return 0;
1608}
1609
1610int list_images(struct ipod_t* ipod)
1611{
1612 int i;
1613
1614 if (ipod_verbose) {
1615 printf(" Type id devOffset len addr entryOffset chksum vers loadAddr devOffset+len\n");
1616 for (i = 0 ; i < ipod->nimages; i++) {
1617 printf("%d - %s 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n",i,
1618 ftypename[ipod->ipod_directory[i].ftype],
1619 ipod->ipod_directory[i].id,
1620 ipod->ipod_directory[i].devOffset,
1621 ipod->ipod_directory[i].len,
1622 ipod->ipod_directory[i].addr,
1623 ipod->ipod_directory[i].entryOffset,
1624 ipod->ipod_directory[i].chksum,
1625 ipod->ipod_directory[i].vers,
1626 ipod->ipod_directory[i].loadAddr,
1627 ipod->ipod_directory[i].devOffset+((ipod->ipod_directory[i].len+ipod->sector_size-1)&~(ipod->sector_size-1)));
1628 }
1629 }
1630
1631 printf("\n");
1632 printf("Listing firmware partition contents:\n");
1633 printf("\n");
1634
1635 for (i = 0 ; i < ipod->nimages; i++) {
1636 printf("Image %d:\n",i+1);
1637 switch(ipod->ipod_directory[i].ftype) {
1638 case FTYPE_OSOS:
1639 if (ipod->ipod_directory[i].entryOffset==0) {
1640 printf(" Main firmware - %d bytes\n",
1641 ipod->ipod_directory[i].len);
1642 } else {
1643 printf(" Main firmware - %d bytes\n",
1644 ipod->ipod_directory[i].entryOffset);
1645 printf(" Third-party bootloader - %d bytes\n",
1646 ipod->ipod_directory[i].len-ipod->ipod_directory[i].entryOffset);
1647 }
1648 break;
1649 default:
1650 printf(" %s - %d bytes\n",
1651 ftypename[ipod->ipod_directory[i].ftype],
1652 ipod->ipod_directory[i].len);
1653 }
1654 }
1655 printf("\n");
1656
1657 return 0;
1658}
1659
1660int getmodel(struct ipod_t* ipod, int ipod_version)
1661{
1662 switch (ipod_version) {
1663 case 0x01:
1664 ipod->modelstr="1st or 2nd Generation";
1665 ipod->modelnum = 19;
1666 ipod->modelname = "1g2g";
1667 ipod->targetname = "ipod1g2g";
1668#ifdef WITH_BOOTOBJS
1669 ipod->bootloader = ipod1g2g;
1670 ipod->bootloader_len = LEN_ipod1g2g;
1671#endif
1672 break;
1673 case 0x02:
1674 ipod->modelstr="3rd Generation";
1675 ipod->modelnum = 7;
1676 ipod->modelname = "ip3g";
1677 ipod->targetname = "ipod3g";
1678#ifdef WITH_BOOTOBJS
1679 ipod->bootloader = ipod3g;
1680 ipod->bootloader_len = LEN_ipod3g;
1681#endif
1682 break;
1683 case 0x40:
1684 ipod->modelstr="1st Generation Mini";
1685 ipod->modelnum = 9;
1686 ipod->modelname = "mini";
1687 ipod->targetname = "ipodmini1g";
1688#ifdef WITH_BOOTOBJS
1689 ipod->bootloader = ipodmini1g;
1690 ipod->bootloader_len = LEN_ipodmini1g;
1691#endif
1692 break;
1693 case 0x50:
1694 ipod->modelstr="4th Generation";
1695 ipod->modelnum = 8;
1696 ipod->modelname = "ip4g";
1697 ipod->targetname = "ipod4gray";
1698#ifdef WITH_BOOTOBJS
1699 ipod->bootloader = ipod4g;
1700 ipod->bootloader_len = LEN_ipod4g;
1701#endif
1702 break;
1703 case 0x60:
1704 ipod->modelstr="Photo/Color";
1705 ipod->modelnum = 3;
1706 ipod->modelname = "ipco";
1707 ipod->targetname = "ipodcolor";
1708#ifdef WITH_BOOTOBJS
1709 ipod->bootloader = ipodcolor;
1710 ipod->bootloader_len = LEN_ipodcolor;
1711#endif
1712 break;
1713 case 0x70:
1714 ipod->modelstr="2nd Generation Mini";
1715 ipod->modelnum = 11;
1716 ipod->modelname = "mn2g";
1717 ipod->targetname = "ipodmini2g";
1718#ifdef WITH_BOOTOBJS
1719 ipod->bootloader = ipodmini2g;
1720 ipod->bootloader_len = LEN_ipodmini2g;
1721#endif
1722 break;
1723 case 0xc0:
1724 ipod->modelstr="1st Generation Nano";
1725 ipod->modelnum = 4;
1726 ipod->modelname = "nano";
1727 ipod->targetname = "ipodnano1g";
1728#ifdef WITH_BOOTOBJS
1729 ipod->bootloader = ipodnano1g;
1730 ipod->bootloader_len = LEN_ipodnano1g;
1731#endif
1732 break;
1733 case 0xb0:
1734 ipod->modelstr="Video (aka 5th Generation)";
1735 ipod->modelnum = 5;
1736 ipod->modelname = "ipvd";
1737 ipod->targetname = "ipodvideo";
1738#ifdef WITH_BOOTOBJS
1739 ipod->bootloader = ipodvideo;
1740 ipod->bootloader_len = LEN_ipodvideo;
1741#endif
1742 break;
1743 case 0x100:
1744 ipod->modelstr="2nd Generation Nano";
1745 ipod->modelnum = 62;
1746 ipod->modelname = "nn2x";
1747 ipod->targetname = "ipodnano2g";
1748#ifdef WITH_BOOTOBJS
1749 ipod->bootloader = ipodnano2g;
1750 ipod->bootloader_len = LEN_ipodnano2g;
1751#endif
1752 break;
1753 default:
1754 ipod->modelname = NULL;
1755 ipod->modelnum = 0;
1756 ipod->targetname = NULL;
1757#ifdef WITH_BOOTOBJS
1758 ipod->bootloader = NULL;
1759 ipod->bootloader_len = 0;
1760#endif
1761 return -1;
1762 }
1763 return 0;
1764}
1765
1766/* returns number of found ipods or -1 if no ipods found and permission
1767 * for raw disc access was denied. */
1768int ipod_scan(struct ipod_t* ipod)
1769{
1770 int i;
1771 int n = 0;
1772 int ipod_version;
1773 struct ipod_t ipod_found;
1774 int denied = 0;
1775 int result;
1776
1777 printf("[INFO] Scanning disk devices...\n");
1778
1779 for (i = 0; i <= 25 ; i++) {
1780#ifdef __WIN32__
1781 sprintf(ipod->diskname,"\\\\.\\PhysicalDrive%d",i);
1782#elif defined(linux) || defined (__linux)
1783 sprintf(ipod->diskname,"/dev/sd%c",'a'+i);
1784#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) \
1785 || defined(__bsdi__) || defined(__DragonFly__)
1786 sprintf(ipod->diskname,"/dev/da%d",i);
1787#elif defined(__APPLE__) && defined(__MACH__)
1788 sprintf(ipod->diskname,"/dev/disk%d",i);
1789#else
1790 #error No disk paths defined for this platform
1791#endif
1792 if ((result = ipod_open(ipod, 1)) < 0) {
1793 if(result == -2) {
1794 denied++;
1795 }
1796 ipod_close(ipod);
1797 continue;
1798 }
1799
1800 if (read_partinfo(ipod,1) < 0) {
1801 ipod_close(ipod);
1802 continue;
1803 }
1804
1805 if ((ipod->pinfo[0].start==0) || (ipod->pinfo[0].type != 0)) {
1806 ipod_close(ipod);
1807 continue;
1808 }
1809
1810 if (read_directory(ipod) < 0) {
1811 ipod_close(ipod);
1812 continue;
1813 }
1814
1815 ipod_version=(ipod->ipod_directory[ipod->ososimage].vers>>8);
1816 ipod->ramsize = 0;
1817#ifdef __WIN32__
1818 /* Windows requires the ipod in R/W mode for SCSI Inquiry.
1819 * ipod_reopen_rw does unmount the player on OS X so do this on
1820 * W32 only during scanning. */
1821 ipod_reopen_rw(ipod);
1822#endif
1823 ipod_get_xmlinfo(ipod);
1824 ipod_get_ramsize(ipod);
1825 if (getmodel(ipod,ipod_version) < 0) {
1826 ipod_close(ipod);
1827 continue;
1828 }
1829
1830#ifdef __WIN32__
1831 printf("[INFO] Ipod found - %s (\"%s\") - disk device %d\n",
1832 ipod->modelstr,ipod->macpod ? "macpod" : "winpod",i);
1833#else
1834 printf("[INFO] Ipod found - %s (\"%s\") - %s\n",
1835 ipod->modelstr,ipod->macpod ? "macpod" : "winpod",ipod->diskname);
1836#endif
1837 n++;
1838 /* save the complete ipod_t structure for match. The for loop might
1839 * overwrite it, so we need to restore it later if only one found. */
1840 memcpy(&ipod_found, ipod, sizeof(struct ipod_t));
1841 ipod_close(ipod);
1842 }
1843
1844 if (n==1) {
1845 /* restore the ipod_t structure, it might have been overwritten */
1846 memcpy(ipod, &ipod_found, sizeof(struct ipod_t));
1847 }
1848 else if(n == 0 && denied) {
1849 printf("[ERR] FATAL: Permission denied on %d device(s) and no ipod detected.\n", denied);
1850#ifdef __WIN32__
1851 printf("[ERR] You need to run this program with administrator priviledges!\n");
1852#else
1853 printf("[ERR] You need permissions for raw disc access for this program to work!\n");
1854#endif
1855 }
1856 return (n == 0 && denied) ? -1 : n;
1857}
1858
1859static void put_int32le(uint32_t x, unsigned char* p)
1860{
1861 p[0] = x & 0xff;
1862 p[1] = (x >> 8) & 0xff;
1863 p[2] = (x >> 16) & 0xff;
1864 p[3] = (x >> 24) & 0xff;
1865}
1866
1867int write_dos_partition_table(struct ipod_t* ipod)
1868{
1869 unsigned char* p;
1870 int i, n;
1871 uint32_t type;
1872
1873 /* Only support 512-byte sectors at the moment */
1874 if ( ipod->sector_size != 512 )
1875 {
1876 fprintf(stderr,"[ERR] Only ipods with 512 bytes per sector are supported.\n");
1877 return -1;
1878 }
1879 if(ipod->sectorbuf == NULL) {
1880 fprintf(stderr,"[ERR] Buffer not initialized.");
1881 return -1;
1882 }
1883
1884 /* Firstly zero the entire MBR */
1885 memset(ipod->sectorbuf, 0, ipod->sector_size);
1886
1887 /* Now add the partition info */
1888 for (i=0; i < 4 ; i++)
1889 {
1890 p = ipod->sectorbuf + 0x1be + i*16;
1891
1892 /* Ensure first partition is type 0, and second is 0xb */
1893 if (i==0) { type = 0; }
1894 else if (i==1) { type = 0xb; }
1895 else { type = ipod->pinfo[i].type; }
1896
1897 put_int32le(type, p + 4);
1898 put_int32le(ipod->pinfo[i].start, p + 8);
1899 put_int32le(ipod->pinfo[i].size, p + 12);
1900 }
1901
1902 /* Finally add the magic */
1903 ipod->sectorbuf[0x1fe] = 0x55;
1904 ipod->sectorbuf[0x1ff] = 0xaa;
1905
1906 if (ipod_seek(ipod, 0) < 0) {
1907 fprintf(stderr,"[ERR] Seek failed writing MBR\n");
1908 return -1;
1909 }
1910
1911 /* Write MBR */
1912 if ((n = ipod_write(ipod, ipod->sector_size)) < 0) {
1913 perror("[ERR] Write failed\n");
1914 return -1;
1915 }
1916
1917 return 0;
1918}
1919
1920/* Get the XML Device Information, as documented here:
1921
1922 http://www.ipodlinux.org/wiki/Device_Information
1923*/
1924
1925int ipod_get_xmlinfo(struct ipod_t* ipod)
1926{
1927 unsigned char hdr[255];
1928 unsigned char buf[255];
1929 char* p;
1930 int psize;
1931 int npages;
1932 int i;
1933
1934 if (ipod_scsi_inquiry(ipod, 0xc0, buf, sizeof(buf)) < 0)
1935 {
1936 fprintf(stderr,"[ERR] Sending SCSI Command failed.\n");
1937 return -1;
1938 }
1939
1940 /* Reading directly into hdr[] causes problems (for an unknown reason) on
1941 win32 */
1942 memcpy(hdr, buf, sizeof(hdr));
1943
1944 npages = hdr[3];
1945
1946 psize = npages * 0xf8; /* Hopefully this is enough. */
1947
1948 ipod->xmlinfo = malloc(psize);
1949 ipod->xmlinfo_len = 0;
1950
1951 if (ipod->xmlinfo == NULL) {
1952 fprintf(stderr,"[ERR] Could not allocate RAM for xmlinfo\n");
1953 return -1;
1954 }
1955
1956 p = ipod->xmlinfo;
1957
1958 for (i=0; i < npages; i++) {
1959 if (ipod_scsi_inquiry(ipod, hdr[i+4], buf, sizeof(buf)) < 0) {
1960 fprintf(stderr,"[ERR] Sending SCSI Command failed.\n");
1961 return -1;
1962 }
1963
1964 if ((buf[3] + ipod->xmlinfo_len) > psize) {
1965 fprintf(stderr,"[ERR] Ran out of memory reading xmlinfo\n");
1966 free(ipod->xmlinfo);
1967 ipod->xmlinfo = NULL;
1968 ipod->xmlinfo_len = 0;
1969 return -1;
1970 }
1971
1972 memcpy(p, buf + 4, buf[3]);
1973 p += buf[3];
1974 ipod->xmlinfo_len += buf[3];
1975 }
1976
1977 /* NULL-terminate the XML info */
1978 *p = 0;
1979
1980 fprintf(stderr,"[INFO] Read XML info (%d bytes)\n",ipod->xmlinfo_len);
1981
1982 return 0;
1983}
1984
1985void ipod_get_ramsize(struct ipod_t* ipod)
1986{
1987 const char needle[] = "<key>RAM</key>\n<integer>";
1988 char* p;
1989
1990 if (ipod->xmlinfo == NULL)
1991 return;
1992
1993 p = strstr(ipod->xmlinfo, needle);
1994
1995 if (p) {
1996 ipod->ramsize = atoi(p + sizeof(needle) - 1);
1997 }
1998}
1999
2000#ifndef RBUTIL
2001
2002static inline uint32_t getuint32le(unsigned char* buf)
2003{
2004 int32_t res = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
2005
2006 return res;
2007}
2008
2009/* testMarker and GetSecurityBlockKey based on code from BadBlocks and
2010 Kingstone, posted at http://ipodlinux.org/Flash_Decryption
2011
2012*/
2013
2014static bool testMarker(int marker)
2015{
2016 int mask, decrypt, temp1, temp2;
2017
2018 mask = (marker&0xff)|((marker&0xff)<<8)|((marker&0xff)<<16)|((marker&0xff)<<24);
2019 decrypt = marker ^ mask;
2020 temp1=(int)((unsigned int)decrypt>>24);
2021 temp2=decrypt<<8;
2022
2023 if (temp1==0)
2024 return false;
2025
2026 temp2=(int)((unsigned int)temp2>>24);
2027 decrypt=decrypt<<16;
2028 decrypt=(int)((unsigned int)decrypt>>24);
2029
2030 if ((temp1 < temp2) && (temp2 < decrypt))
2031 {
2032 temp1 = temp1 & 0xf;
2033 temp2 = temp2 & 0xf;
2034 decrypt = decrypt & 0xf;
2035
2036 if ((temp1 > temp2) && (temp2 > decrypt) && (decrypt != 0))
2037 {
2038 return true;
2039 }
2040 }
2041 return false;
2042}
2043
2044static int GetSecurityBlockKey(unsigned char *data, unsigned char* this_key)
2045{
2046 int constant = 0x54c3a298;
2047 int key=0;
2048 int nkeys = 0;
2049 int aMarker=0;
2050 int pos=0;
2051 int c, count;
2052 int temp1;
2053 static const int offset[8]={0x5,0x25,0x6f,0x69,0x15,0x4d,0x40,0x34};
2054
2055 for (c = 0; c < 8; c++)
2056 {
2057 pos = offset[c]*4;
2058 aMarker = getuint32le(data + pos);
2059
2060 if (testMarker(aMarker))
2061 {
2062 if (c<7)
2063 pos =(offset[c+1]*4)+4;
2064 else
2065 pos =(offset[0]*4)+4;
2066
2067 key=0;
2068
2069 temp1=aMarker;
2070
2071 for (count=0;count<2;count++){
2072 int word = getuint32le(data + pos);
2073 temp1 = aMarker;
2074 temp1 = temp1^word;
2075 temp1 = temp1^constant;
2076 key = temp1;
2077 pos = pos+4;
2078 }
2079 int r1=0x6f;
2080 int r2=0;
2081 int r12;
2082 int r14;
2083 unsigned int r_tmp;
2084
2085 for (count=2;count<128;count=count+2){
2086 r2=getuint32le(data+count*4);
2087 r12=getuint32le(data+(count*4)+4);
2088 r_tmp=(unsigned int)r12>>16;
2089 r14=r2 | ((int)r_tmp);
2090 r2=r2&0xffff;
2091 r2=r2 | r12;
2092 r1=r1^r14;
2093 r1=r1+r2;
2094 }
2095 key=key^r1;
2096
2097 // Invert key, little endian
2098 this_key[0] = key & 0xff;
2099 this_key[1] = (key >> 8) & 0xff;
2100 this_key[2] = (key >> 16) & 0xff;
2101 this_key[3] = (key >> 24) & 0xff;
2102 nkeys++;
2103 }
2104 }
2105 return nkeys;
2106}
2107
2108static int find_key(struct ipod_t* ipod, int aupd, unsigned char* key)
2109{
2110 int n;
2111
2112 /* Firstly read the security block and find the RC4 key. This is
2113 in the sector preceeding the AUPD image. */
2114
2115 if(ipod->sectorbuf == NULL) {
2116 fprintf(stderr,"[ERR] Buffer not initialized.");
2117 return -1;
2118 }
2119 fprintf(stderr, "[INFO] Reading security block at offset 0x%08x\n",ipod->ipod_directory[aupd].devOffset-ipod->sector_size);
2120 if (ipod_seek(ipod, ipod->fwoffset+ipod->ipod_directory[aupd].devOffset-ipod->sector_size) < 0) {
2121 return -1;
2122 }
2123
2124 if ((n = ipod_read(ipod, 512)) < 0) {
2125 return -1;
2126 }
2127
2128 n = GetSecurityBlockKey(ipod->sectorbuf, key);
2129
2130 if (n != 1)
2131 {
2132 fprintf(stderr, "[ERR] %d keys found in security block, can not continue\n",n);
2133 return -1;
2134 }
2135
2136 return 0;
2137}
2138
2139int read_aupd(struct ipod_t* ipod, char* filename)
2140{
2141 int length;
2142 int i;
2143 int outfile;
2144 int n;
2145 int aupd;
2146 struct rc4_key_t rc4;
2147 unsigned char key[4];
2148 unsigned long chksum=0;
2149
2150 if(ipod->sectorbuf == NULL) {
2151 fprintf(stderr,"[ERR] Buffer not initialized.");
2152 return -1;
2153 }
2154 aupd = 0;
2155 while ((aupd < ipod->nimages) && (ipod->ipod_directory[aupd].ftype != FTYPE_AUPD))
2156 {
2157 aupd++;
2158 }
2159
2160 if (aupd == ipod->nimages)
2161 {
2162 fprintf(stderr,"[ERR] No AUPD image in firmware partition.\n");
2163 return -1;
2164 }
2165
2166 length = ipod->ipod_directory[aupd].len;
2167
2168 fprintf(stderr,"[INFO] Reading firmware (%d bytes)\n",length);
2169
2170 if (find_key(ipod, aupd, key) < 0)
2171 {
2172 return -1;
2173 }
2174
2175 fprintf(stderr, "[INFO] Decrypting AUPD image with key %02x%02x%02x%02x\n",key[0],key[1],key[2],key[3]);
2176
2177 if (ipod_seek(ipod, ipod->fwoffset+ipod->ipod_directory[aupd].devOffset) < 0) {
2178 return -1;
2179 }
2180
2181 i = (length+ipod->sector_size-1) & ~(ipod->sector_size-1);
2182
2183 if ((n = ipod_read(ipod,i)) < 0) {
2184 return -1;
2185 }
2186
2187 if (n < i) {
2188 fprintf(stderr,"[ERR] Short read - requested %d bytes, received %d\n",
2189 i,n);
2190 return -1;
2191 }
2192
2193 /* Perform the decryption - this is standard (A)RC4 */
2194 matrixArc4Init(&rc4, key, 4);
2195 matrixArc4(&rc4, ipod->sectorbuf, ipod->sectorbuf, length);
2196
2197 chksum = 0;
2198 for (i = 0; i < (int)length; i++) {
2199 /* add 8 unsigned bits but keep a 32 bit sum */
2200 chksum += ipod->sectorbuf[i];
2201 }
2202
2203 if (chksum != ipod->ipod_directory[aupd].chksum)
2204 {
2205 fprintf(stderr,"[ERR] Decryption failed - checksum error\n");
2206 return -1;
2207 }
2208 fprintf(stderr,"[INFO] Decrypted OK (checksum matches header)\n");
2209
2210 outfile = open(filename,O_CREAT|O_TRUNC|O_WRONLY|O_BINARY,0666);
2211 if (outfile < 0) {
2212 fprintf(stderr,"[ERR] Couldn't open file %s\n",filename);
2213 return -1;
2214 }
2215
2216 n = write(outfile,ipod->sectorbuf,length);
2217 if (n != length) {
2218 fprintf(stderr,"[ERR] Write error - %d\n",n);
2219 }
2220 close(outfile);
2221
2222 return 0;
2223}
2224
2225int write_aupd(struct ipod_t* ipod, char* filename)
2226{
2227 unsigned int length;
2228 int i;
2229 int x;
2230 int n;
2231 int infile;
2232 int newsize;
2233 int aupd;
2234 unsigned long chksum=0;
2235 struct rc4_key_t rc4;
2236 unsigned char key[4];
2237
2238 if(ipod->sectorbuf == NULL) {
2239 fprintf(stderr,"[ERR] Buffer not initialized.");
2240 return -1;
2241 }
2242 /* First check that the input file is the correct type for this ipod. */
2243 infile=open(filename,O_RDONLY);
2244 if (infile < 0) {
2245 fprintf(stderr,"[ERR] Couldn't open input file %s\n",filename);
2246 return -1;
2247 }
2248
2249 length = filesize(infile);
2250 newsize=(length+ipod->sector_size-1)&~(ipod->sector_size-1);
2251
2252 fprintf(stderr,"[INFO] Padding input file from 0x%08x to 0x%08x bytes\n",
2253 length,newsize);
2254
2255 if (newsize > BUFFER_SIZE) {
2256 fprintf(stderr,"[ERR] Input file too big for buffer\n");
2257 if (infile >= 0) close(infile);
2258 return -1;
2259 }
2260
2261 /* Find aupd image number */
2262 aupd = 0;
2263 while ((aupd < ipod->nimages) && (ipod->ipod_directory[aupd].ftype != FTYPE_AUPD))
2264 {
2265 aupd++;
2266 }
2267
2268 if (aupd == ipod->nimages)
2269 {
2270 fprintf(stderr,"[ERR] No AUPD image in firmware partition.\n");
2271 return -1;
2272 }
2273
2274 if (length != ipod->ipod_directory[aupd].len)
2275 {
2276 fprintf(stderr,"[ERR] AUPD image (%d bytes) differs in size to %s (%d bytes).\n",
2277 ipod->ipod_directory[aupd].len, filename, length);
2278 return -1;
2279 }
2280
2281 if (find_key(ipod, aupd, key) < 0)
2282 {
2283 return -1;
2284 }
2285
2286 fprintf(stderr, "[INFO] Encrypting AUPD image with key %02x%02x%02x%02x\n",key[0],key[1],key[2],key[3]);
2287
2288 /* We now know we have enough space, so write it. */
2289
2290 fprintf(stderr,"[INFO] Reading input file...\n");
2291 n = read(infile,ipod->sectorbuf,length);
2292 if (n < 0) {
2293 fprintf(stderr,"[ERR] Couldn't read input file\n");
2294 close(infile);
2295 return -1;
2296 }
2297 close(infile);
2298
2299 /* Pad the data with zeros */
2300 memset(ipod->sectorbuf+length,0,newsize-length);
2301
2302 /* Calculate the new checksum (before we encrypt) */
2303 chksum = 0;
2304 for (i = 0; i < (int)length; i++) {
2305 /* add 8 unsigned bits but keep a 32 bit sum */
2306 chksum += ipod->sectorbuf[i];
2307 }
2308
2309 /* Perform the encryption - this is standard (A)RC4 */
2310 matrixArc4Init(&rc4, key, 4);
2311 matrixArc4(&rc4, ipod->sectorbuf, ipod->sectorbuf, length);
2312
2313 if (ipod_seek(ipod, ipod->fwoffset+ipod->ipod_directory[aupd].devOffset) < 0) {
2314 fprintf(stderr,"[ERR] Seek failed\n");
2315 return -1;
2316 }
2317
2318 if ((n = ipod_write(ipod,newsize)) < 0) {
2319 perror("[ERR] Write failed\n");
2320 return -1;
2321 }
2322
2323 if (n < newsize) {
2324 fprintf(stderr,"[ERR] Short write - requested %d bytes, received %d\n"
2325 ,newsize,n);
2326 return -1;
2327 }
2328 fprintf(stderr,"[INFO] Wrote %d bytes to firmware partition\n",n);
2329
2330 x = ipod->diroffset % ipod->sector_size;
2331
2332 /* Read directory */
2333 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; }
2334
2335 n=ipod_read(ipod, ipod->sector_size);
2336 if (n < 0) { return -1; }
2337
2338 /* Update checksum */
2339 fprintf(stderr,"[INFO] Updating checksum to 0x%08x (was 0x%08x)\n",(unsigned int)chksum,le2int(ipod->sectorbuf + x + aupd*40 + 28));
2340 int2le(chksum,ipod->sectorbuf+x+aupd*40+28);
2341
2342 /* Write directory */
2343 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; }
2344 n=ipod_write(ipod, ipod->sector_size);
2345 if (n < 0) { return -1; }
2346
2347 return 0;
2348}
2349
2350#endif
diff --git a/utils/ipodpatcher/ipodpatcher.h b/utils/ipodpatcher/ipodpatcher.h
new file mode 100644
index 0000000000..2cd2331666
--- /dev/null
+++ b/utils/ipodpatcher/ipodpatcher.h
@@ -0,0 +1,84 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2006-2007 Dave Chapman
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#ifndef IPODPATCHER_H
23#define IPODPATCHER_H
24
25#ifdef __cplusplus
26extern "C" {
27#endif
28
29#include "ipodio.h"
30
31/* exit codes */
32#define IPOD_OK 0
33#define IPOD_WRONG_ARGUMENTS 1
34#define IPOD_OPEN_INFILE_FAILED 2
35#define IPOD_PARTITION_ERROR 3
36#define IPOD_OPEN_OUTFILE_FAILED 4
37#define IPOD_CANNOT_REOPEN 5
38#define IPOD_ACCESS_DENIED 10
39#define IPOD_NOT_FOUND 11
40#define IPOD_WRONG_DEVICE_COUNT 12
41#define IPOD_IMAGE_ERROR 13
42#define IPOD_DUMP_FAILED 14
43#define IPOD_MULTIPLE_DEVICES 15
44#define IPOD_WRONG_TYPE 16
45#define IPOD_UNKNOWN_FW_VERSION -1
46
47/* Size of buffer for disk I/O - 8MB is large enough for any version
48 of the Apple firmware, but not the Nano's RSRC image. */
49#define BUFFER_SIZE 8*1024*1024
50
51extern int ipod_verbose;
52
53#define FILETYPE_DOT_IPOD 0
54#define FILETYPE_DOT_BIN 1
55#ifdef WITH_BOOTOBJS
56 #define FILETYPE_INTERNAL 2
57#endif
58
59char* get_parttype(unsigned int pt);
60int read_partinfo(struct ipod_t* ipod, int silent);
61int read_partition(struct ipod_t* ipod, int outfile);
62int write_partition(struct ipod_t* ipod, int infile);
63int diskmove(struct ipod_t* ipod, int delta);
64int add_bootloader(struct ipod_t* ipod, char* filename, int type);
65int delete_bootloader(struct ipod_t* ipod);
66int write_firmware(struct ipod_t* ipod, char* filename, int type);
67int read_firmware(struct ipod_t* ipod, char* filename, int type);
68int read_directory(struct ipod_t* ipod);
69int list_images(struct ipod_t* ipod);
70int getmodel(struct ipod_t* ipod, int ipod_version);
71int ipod_scan(struct ipod_t* ipod);
72int write_dos_partition_table(struct ipod_t* ipod);
73int ipod_get_xmlinfo(struct ipod_t* ipod);
74void ipod_get_ramsize(struct ipod_t* ipod);
75int read_aupd(struct ipod_t* ipod, char* filename);
76int write_aupd(struct ipod_t* ipod, char* filename);
77off_t filesize(int fd);
78int ipod_has_bootloader(struct ipod_t* ipod);
79
80#ifdef __cplusplus
81}
82#endif
83#endif
84
diff --git a/utils/ipodpatcher/ipodpatcher.manifest b/utils/ipodpatcher/ipodpatcher.manifest
new file mode 100644
index 0000000000..695ecb26ea
--- /dev/null
+++ b/utils/ipodpatcher/ipodpatcher.manifest
@@ -0,0 +1,13 @@
1<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
2<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
3 <assemblyIdentity version="1.0.0.0" processorArchitecture="X86" name="ipodpatcher.exe" type="win32"/>
4
5 <!-- Identify the application security requirements. -->
6 <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
7 <security>
8 <requestedPrivileges>
9 <requestedExecutionLevel level="requireAdministrator"/>
10 </requestedPrivileges>
11 </security>
12 </trustInfo>
13</assembly>
diff --git a/utils/ipodpatcher/ipodpatcher.pro b/utils/ipodpatcher/ipodpatcher.pro
new file mode 100644
index 0000000000..fac1e35f00
--- /dev/null
+++ b/utils/ipodpatcher/ipodpatcher.pro
@@ -0,0 +1,47 @@
1#
2# __________ __ ___.
3# Open \______ \ ____ ____ | | _\_ |__ _______ ___
4# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7# \/ \/ \/ \/ \/
8#
9# All files in this archive are subject to the GNU General Public License.
10# See the file COPYING in the source tree root for full license agreement.
11#
12# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
13# KIND, either express or implied.
14#
15
16TEMPLATE = app
17TARGET = ipodpatcher
18QT -= core
19
20SOURCES += \
21 main.c \
22 ipodpatcher.c \
23 ipodio-posix.c \
24 ipodio-win32-scsi.c \
25 ipodio-win32.c \
26 fat32format.c \
27 arc4.c \
28
29HEADERS += \
30 arc4.h \
31 ipodio.h \
32 ipodpatcher.h \
33 parttypes.h \
34
35DEFINES += RELEASE=1 _LARGEFILE64_SOURCE
36
37RC_FILE = ipodpatcher.rc
38
39macx {
40 LIBS += -framework CoreFoundation -framework IOKit
41}
42
43
44unix {
45 target.path = /usr/local/bin
46 INSTALLS += target
47}
diff --git a/utils/ipodpatcher/ipodpatcher.rc b/utils/ipodpatcher/ipodpatcher.rc
new file mode 100644
index 0000000000..e440b51271
--- /dev/null
+++ b/utils/ipodpatcher/ipodpatcher.rc
@@ -0,0 +1 @@
1 24 MOVEABLE PURE "ipodpatcher.manifest"
diff --git a/utils/ipodpatcher/main.c b/utils/ipodpatcher/main.c
new file mode 100644
index 0000000000..7b0a909178
--- /dev/null
+++ b/utils/ipodpatcher/main.c
@@ -0,0 +1,622 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2006-2007 Dave Chapman
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include <stdio.h>
23#include <unistd.h>
24#include <fcntl.h>
25#include <string.h>
26#include <stdlib.h>
27#include <inttypes.h>
28#include <sys/types.h>
29#include <sys/stat.h>
30
31#include "ipodpatcher.h"
32#include "ipodio.h"
33
34#ifdef RELEASE
35#undef VERSION
36#define VERSION "5.0 with v4.0 bootloaders (v1.0 for 2nd Gen Nano)"
37#endif
38
39
40enum {
41 NONE,
42#ifdef WITH_BOOTOBJS
43 INSTALL,
44#endif
45 INTERACTIVE,
46 SHOW_INFO,
47 LIST_IMAGES,
48 DELETE_BOOTLOADER,
49 ADD_BOOTLOADER,
50 READ_FIRMWARE,
51 WRITE_FIRMWARE,
52 READ_AUPD,
53 WRITE_AUPD,
54 READ_PARTITION,
55 WRITE_PARTITION,
56 FORMAT_PARTITION,
57 DUMP_XML,
58 CONVERT_TO_FAT32
59};
60
61void print_macpod_warning(void)
62{
63 printf("[INFO] ************************************************************************\n");
64 printf("[INFO] *** WARNING FOR ROCKBOX USERS\n");
65 printf("[INFO] *** You must convert this ipod to FAT32 format (aka a \"winpod\")\n");
66 printf("[INFO] *** if you want to run Rockbox. Rockbox WILL NOT work on this ipod.\n");
67 printf("[INFO] *** See http://www.rockbox.org/wiki/IpodConversionToFAT32\n");
68 printf("[INFO] ************************************************************************\n");
69}
70
71void print_usage(void)
72{
73 fprintf(stderr,"Usage: ipodpatcher --scan\n");
74#ifdef __WIN32__
75 fprintf(stderr," or ipodpatcher [DISKNO] [action]\n");
76#else
77 fprintf(stderr," or ipodpatcher [device] [action]\n");
78#endif
79 fprintf(stderr,"\n");
80 fprintf(stderr,"Where [action] is one of the following options:\n");
81#ifdef WITH_BOOTOBJS
82 fprintf(stderr," --install\n");
83#endif
84 fprintf(stderr," -l, --list\n");
85 fprintf(stderr," -r, --read-partition bootpartition.bin\n");
86 fprintf(stderr," -w, --write-partition bootpartition.bin\n");
87 fprintf(stderr," -rf, --read-firmware filename.ipod[x]\n");
88 fprintf(stderr," -rfb, --read-firmware-bin filename.bin\n");
89 fprintf(stderr," -wf, --write-firmware filename.ipod[x]\n");
90 fprintf(stderr," -wfb, --write-firmware-bin filename.bin\n");
91#ifdef WITH_BOOTOBJS
92 fprintf(stderr," -we, --write-embedded\n");
93#endif
94 fprintf(stderr," -a, --add-bootloader filename.ipod[x]\n");
95 fprintf(stderr," -ab, --add-bootloader-bin filename.bin\n");
96 fprintf(stderr," -d, --delete-bootloader\n");
97 fprintf(stderr," -f, --format\n");
98 fprintf(stderr," -c, --convert\n");
99 fprintf(stderr," --read-aupd filename.bin\n");
100 fprintf(stderr," --write-aupd filename.bin\n");
101 fprintf(stderr," -x --dump-xml filename.xml\n");
102 fprintf(stderr,"\n");
103
104 fprintf(stderr,"The .ipodx extension is used for encrypted images for the 2nd Gen Nano.\n\n");
105
106#ifdef __WIN32__
107 fprintf(stderr,"DISKNO is the number (e.g. 2) Windows has assigned to your ipod's hard disk.\n");
108 fprintf(stderr,"The first hard disk in your computer (i.e. C:\\) will be disk 0, the next disk\n");
109 fprintf(stderr,"will be disk 1 etc. ipodpatcher will refuse to access a disk unless it\n");
110 fprintf(stderr,"can identify it as being an ipod.\n");
111 fprintf(stderr,"\n");
112#else
113#if defined(linux) || defined (__linux)
114 fprintf(stderr,"\"device\" is the device node (e.g. /dev/sda) assigned to your ipod.\n");
115#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
116 fprintf(stderr,"\"device\" is the device node (e.g. /dev/da1) assigned to your ipod.\n");
117#elif defined(__APPLE__) && defined(__MACH__)
118 fprintf(stderr,"\"device\" is the device node (e.g. /dev/disk1) assigned to your ipod.\n");
119#endif
120 fprintf(stderr,"ipodpatcher will refuse to access a disk unless it can identify it as being\n");
121 fprintf(stderr,"an ipod.\n");
122#endif
123}
124
125void display_partinfo(struct ipod_t* ipod)
126{
127 int i;
128 double sectors_per_MB = (1024.0*1024.0)/ipod->sector_size;
129
130 printf("[INFO] Part Start Sector End Sector Size (MB) Type\n");
131 for ( i = 0; i < 4; i++ ) {
132 if (ipod->pinfo[i].start != 0) {
133 printf("[INFO] %d %10ld %10ld %10.1f %s (0x%02x)\n",
134 i,
135 (long int)ipod->pinfo[i].start,
136 (long int)ipod->pinfo[i].start+ipod->pinfo[i].size-1,
137 ipod->pinfo[i].size/sectors_per_MB,
138 get_parttype(ipod->pinfo[i].type),
139 (int)ipod->pinfo[i].type);
140 }
141 }
142}
143
144
145int main(int argc, char* argv[])
146{
147 char yesno[4];
148 int i;
149 int n;
150 int infile, outfile;
151 unsigned int inputsize;
152 char* filename;
153 int action = SHOW_INFO;
154 int type;
155 struct ipod_t ipod;
156
157 fprintf(stderr,"ipodpatcher " VERSION "\n");
158 fprintf(stderr,"(C) Dave Chapman 2006-2009\n");
159 fprintf(stderr,"This is free software; see the source for copying conditions. There is NO\n");
160 fprintf(stderr,"warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n");
161
162 if ((argc > 1) && ((strcmp(argv[1],"-h")==0) || (strcmp(argv[1],"--help")==0))) {
163 print_usage();
164 return IPOD_OK;
165 }
166
167 if (ipod_alloc_buffer(&ipod,BUFFER_SIZE) < 0) {
168 fprintf(stderr,"Failed to allocate memory buffer\n");
169 }
170
171 if ((argc > 1) && (strcmp(argv[1],"--scan")==0)) {
172 if (ipod_scan(&ipod) == 0)
173 fprintf(stderr,"[ERR] No ipods found.\n");
174 return IPOD_NOT_FOUND;
175 }
176
177 /* If the first parameter doesn't start with -, then we interpret it as a device */
178 if ((argc > 1) && (argv[1][0] != '-')) {
179 ipod.diskname[0]=0;
180#ifdef __WIN32__
181 snprintf(ipod.diskname,sizeof(ipod.diskname),"\\\\.\\PhysicalDrive%s",argv[1]);
182#else
183 strncpy(ipod.diskname,argv[1],sizeof(ipod.diskname));
184#endif
185 i = 2;
186 } else {
187 /* Autoscan for ipods */
188 n = ipod_scan(&ipod);
189 if (n==0) {
190 fprintf(stderr,"[ERR] No ipods found, aborting\n");
191 fprintf(stderr,"[ERR] Please connect your ipod and ensure it is in disk mode\n");
192#if defined(__APPLE__) && defined(__MACH__)
193 fprintf(stderr,"[ERR] Also ensure that itunes is closed, and that your ipod is not mounted.\n");
194#elif !defined(__WIN32__)
195 if (geteuid()!=0) {
196 fprintf(stderr,"[ERR] You may also need to run ipodpatcher as root.\n");
197 }
198#endif
199 fprintf(stderr,"[ERR] Please refer to the Rockbox manual if you continue to have problems.\n");
200 } else if (n > 1) {
201 fprintf(stderr,"[ERR] %d ipods found, aborting\n",n);
202 fprintf(stderr,"[ERR] Please connect only one ipod and re-run ipodpatcher.\n");
203 return IPOD_MULTIPLE_DEVICES;
204 } else if (n == 1 && ipod.macpod) {
205 return IPOD_WRONG_TYPE;
206 }
207
208 if (n != 1) {
209#ifdef WITH_BOOTOBJS
210 if (argc==1) {
211 printf("\nPress ENTER to exit ipodpatcher :");
212 fgets(yesno,4,stdin);
213 }
214#endif
215 return IPOD_NOT_FOUND;
216 }
217
218 i = 1;
219 }
220
221#ifdef WITH_BOOTOBJS
222 action = INTERACTIVE;
223#else
224 action = NONE;
225#endif
226
227 while (i < argc) {
228 if ((strcmp(argv[i],"-l")==0) || (strcmp(argv[i],"--list")==0)) {
229 action = LIST_IMAGES;
230 i++;
231#ifdef WITH_BOOTOBJS
232 } else if (strcmp(argv[i],"--install")==0) {
233 action = INSTALL;
234 i++;
235#endif
236 } else if ((strcmp(argv[i],"-d")==0) ||
237 (strcmp(argv[i],"--delete-bootloader")==0)) {
238 action = DELETE_BOOTLOADER;
239 i++;
240 } else if ((strcmp(argv[i],"-a")==0) ||
241 (strcmp(argv[i],"--add-bootloader")==0)) {
242 action = ADD_BOOTLOADER;
243 type = FILETYPE_DOT_IPOD;
244 i++;
245 if (i == argc) { print_usage(); return IPOD_WRONG_ARGUMENTS; }
246 filename=argv[i];
247 i++;
248 } else if ((strcmp(argv[i],"-ab")==0) ||
249 (strcmp(argv[i],"--add-bootloader-bin")==0)) {
250 action = ADD_BOOTLOADER;
251 type = FILETYPE_DOT_BIN;
252 i++;
253 if (i == argc) { print_usage(); return IPOD_WRONG_ARGUMENTS; }
254 filename=argv[i];
255 i++;
256 } else if ((strcmp(argv[i],"-rf")==0) ||
257 (strcmp(argv[i],"--read-firmware")==0)) {
258 action = READ_FIRMWARE;
259 type = FILETYPE_DOT_IPOD;
260 i++;
261 if (i == argc) { print_usage(); return IPOD_WRONG_ARGUMENTS; }
262 filename=argv[i];
263 i++;
264 } else if ((strcmp(argv[i],"-rfb")==0) ||
265 (strcmp(argv[i],"--read-firmware-bin")==0)) {
266 action = READ_FIRMWARE;
267 type = FILETYPE_DOT_BIN;
268 i++;
269 if (i == argc) { print_usage(); return IPOD_WRONG_ARGUMENTS; }
270 filename=argv[i];
271 i++;
272#ifdef WITH_BOOTOBJS
273 } else if ((strcmp(argv[i],"-we")==0) ||
274 (strcmp(argv[i],"--write-embedded")==0)) {
275 action = WRITE_FIRMWARE;
276 type = FILETYPE_INTERNAL;
277 filename="[embedded bootloader]"; /* Only displayed for user */
278 i++;
279#endif
280 } else if ((strcmp(argv[i],"-wf")==0) ||
281 (strcmp(argv[i],"--write-firmware")==0)) {
282 action = WRITE_FIRMWARE;
283 type = FILETYPE_DOT_IPOD;
284 i++;
285 if (i == argc) { print_usage(); return IPOD_WRONG_ARGUMENTS; }
286 filename=argv[i];
287 i++;
288 } else if ((strcmp(argv[i],"-wfb")==0) ||
289 (strcmp(argv[i],"--write-firmware-bin")==0)) {
290 action = WRITE_FIRMWARE;
291 type = FILETYPE_DOT_BIN;
292 i++;
293 if (i == argc) { print_usage(); return IPOD_WRONG_ARGUMENTS; }
294 filename=argv[i];
295 i++;
296 } else if ((strcmp(argv[i],"-r")==0) ||
297 (strcmp(argv[i],"--read-partition")==0)) {
298 action = READ_PARTITION;
299 i++;
300 if (i == argc) { print_usage(); return IPOD_WRONG_ARGUMENTS; }
301 filename=argv[i];
302 i++;
303 } else if ((strcmp(argv[i],"-w")==0) ||
304 (strcmp(argv[i],"--write-partition")==0)) {
305 action = WRITE_PARTITION;
306 i++;
307 if (i == argc) { print_usage(); return IPOD_WRONG_ARGUMENTS; }
308 filename=argv[i];
309 i++;
310 } else if ((strcmp(argv[i],"-v")==0) ||
311 (strcmp(argv[i],"--verbose")==0)) {
312 ipod_verbose++;
313 i++;
314 } else if ((strcmp(argv[i],"-f")==0) ||
315 (strcmp(argv[i],"--format")==0)) {
316 action = FORMAT_PARTITION;
317 i++;
318 } else if (strcmp(argv[i],"--read-aupd")==0) {
319 action = READ_AUPD;
320 i++;
321 if (i == argc) { print_usage(); return IPOD_WRONG_ARGUMENTS; }
322 filename=argv[i];
323 i++;
324 } else if (strcmp(argv[i],"--write-aupd")==0) {
325 action = WRITE_AUPD;
326 i++;
327 if (i == argc) { print_usage(); return IPOD_WRONG_ARGUMENTS; }
328 filename=argv[i];
329 i++;
330 } else if ((strcmp(argv[i],"-x")==0) ||
331 (strcmp(argv[i],"--dump-xml")==0)) {
332 action = DUMP_XML;
333 i++;
334 if (i == argc) { print_usage(); return IPOD_WRONG_ARGUMENTS; }
335 filename=argv[i];
336 i++;
337 } else if ((strcmp(argv[i],"-c")==0) ||
338 (strcmp(argv[i],"--convert")==0)) {
339 action = CONVERT_TO_FAT32;
340 i++;
341 } else {
342 print_usage(); return IPOD_WRONG_ARGUMENTS;
343 }
344 }
345
346 if (ipod.diskname[0]==0) {
347 print_usage();
348 return 1;
349 }
350
351 if (ipod_open(&ipod, 0) < 0) {
352 return IPOD_ACCESS_DENIED;
353 }
354
355 fprintf(stderr,"[INFO] Reading partition table from %s\n",ipod.diskname);
356 fprintf(stderr,"[INFO] Sector size is %d bytes\n",ipod.sector_size);
357
358 if (read_partinfo(&ipod,0) < 0) {
359 return IPOD_PARTITION_ERROR;
360 }
361
362 display_partinfo(&ipod);
363
364 if (ipod.pinfo[0].start==0) {
365 fprintf(stderr,"[ERR] No partition 0 on disk:\n");
366 display_partinfo(&ipod);
367 return IPOD_PARTITION_ERROR;
368 }
369
370 read_directory(&ipod);
371
372 if (ipod.nimages <= 0) {
373 fprintf(stderr,"[ERR] Failed to read firmware directory - nimages=%d\n",ipod.nimages);
374 return IPOD_IMAGE_ERROR;
375 }
376
377 if (getmodel(&ipod,(ipod.ipod_directory[ipod.ososimage].vers>>8)) < 0) {
378 fprintf(stderr,"[ERR] Unknown version number in firmware (%08x)\n",
379 ipod.ipod_directory[ipod.ososimage].vers);
380 return IPOD_UNKNOWN_FW_VERSION;
381 }
382
383#ifdef __WIN32__
384 /* Windows requires the ipod in R/W mode for SCSI Inquiry */
385 if (ipod_reopen_rw(&ipod) < 0) {
386 return IPOD_CANNOT_REOPEN;
387 }
388#endif
389
390
391 /* Read the XML info, and if successful, look for the ramsize
392 (only available for some models - set to 0 if not known) */
393
394 ipod.ramsize = 0;
395
396 if (ipod_get_xmlinfo(&ipod) == 0) {
397 ipod_get_ramsize(&ipod);
398 }
399
400 printf("[INFO] Ipod model: %s ",ipod.modelstr);
401 if (ipod.ramsize > 0) { printf("(%dMB RAM) ",ipod.ramsize); }
402 printf("(\"%s\")\n",ipod.macpod ? "macpod" : "winpod");
403
404 if (ipod.macpod) {
405 print_macpod_warning();
406 }
407
408 if (action==LIST_IMAGES) {
409 list_images(&ipod);
410#ifdef WITH_BOOTOBJS
411 } else if (action==INTERACTIVE) {
412
413 printf("Enter i to install the Rockbox bootloader, u to uninstall\n or c to cancel and do nothing (i/u/c) :");
414
415 if (fgets(yesno,4,stdin)) {
416 if (yesno[0]=='i') {
417 if (ipod_reopen_rw(&ipod) < 0) {
418 return IPOD_CANNOT_REOPEN;
419 }
420
421 if (add_bootloader(&ipod, NULL, FILETYPE_INTERNAL)==0) {
422 fprintf(stderr,"[INFO] Bootloader installed successfully.\n");
423 } else {
424 fprintf(stderr,"[ERR] --install failed.\n");
425 }
426 } else if (yesno[0]=='u') {
427 if (ipod_reopen_rw(&ipod) < 0) {
428 return IPOD_CANNOT_REOPEN;
429 }
430
431 if (delete_bootloader(&ipod)==0) {
432 fprintf(stderr,"[INFO] Bootloader removed.\n");
433 } else {
434 fprintf(stderr,"[ERR] Bootloader removal failed.\n");
435 }
436 }
437 }
438#endif
439 } else if (action==DELETE_BOOTLOADER) {
440 if (ipod_reopen_rw(&ipod) < 0) {
441 return IPOD_CANNOT_REOPEN;
442 }
443
444 if (ipod.ipod_directory[0].entryOffset==0) {
445 fprintf(stderr,"[ERR] No bootloader detected.\n");
446 } else {
447 if (delete_bootloader(&ipod)==0) {
448 fprintf(stderr,"[INFO] Bootloader removed.\n");
449 } else {
450 fprintf(stderr,"[ERR] --delete-bootloader failed.\n");
451 }
452 }
453 } else if (action==ADD_BOOTLOADER) {
454 if (ipod_reopen_rw(&ipod) < 0) {
455 return IPOD_CANNOT_REOPEN;
456 }
457
458 if (add_bootloader(&ipod, filename, type)==0) {
459 fprintf(stderr,"[INFO] Bootloader %s written to device.\n",filename);
460 } else {
461 fprintf(stderr,"[ERR] --add-bootloader failed.\n");
462 }
463#ifdef WITH_BOOTOBJS
464 } else if (action==INSTALL) {
465 if (ipod_reopen_rw(&ipod) < 0) {
466 return IPOD_CANNOT_REOPEN;
467 }
468
469 if (add_bootloader(&ipod, NULL, FILETYPE_INTERNAL)==0) {
470 fprintf(stderr,"[INFO] Bootloader installed successfully.\n");
471 } else {
472 fprintf(stderr,"[ERR] --install failed.\n");
473 }
474#endif
475 } else if (action==WRITE_FIRMWARE) {
476 if (ipod_reopen_rw(&ipod) < 0) {
477 return IPOD_CANNOT_REOPEN;
478 }
479
480 if (write_firmware(&ipod, filename,type)==0) {
481 fprintf(stderr,"[INFO] Firmware %s written to device.\n",filename);
482 } else {
483 fprintf(stderr,"[ERR] --write-firmware failed.\n");
484 }
485 } else if (action==READ_FIRMWARE) {
486 if (read_firmware(&ipod, filename, type)==0) {
487 fprintf(stderr,"[INFO] Firmware read to file %s.\n",filename);
488 } else {
489 fprintf(stderr,"[ERR] --read-firmware failed.\n");
490 }
491 } else if (action==READ_AUPD) {
492 if (read_aupd(&ipod, filename)==0) {
493 fprintf(stderr,"[INFO] AUPD image read to file %s.\n",filename);
494 } else {
495 fprintf(stderr,"[ERR] --read-aupd failed.\n");
496 }
497 } else if (action==WRITE_AUPD) {
498 if (ipod_reopen_rw(&ipod) < 0) {
499 return IPOD_CANNOT_REOPEN;
500 }
501
502 if (write_aupd(&ipod, filename)==0) {
503 fprintf(stderr,"[INFO] AUPD image %s written to device.\n",filename);
504 } else {
505 fprintf(stderr,"[ERR] --write-aupd failed.\n");
506 }
507 } else if (action==DUMP_XML) {
508 if (ipod.xmlinfo == NULL) {
509 fprintf(stderr,"[ERR] No XML to write\n");
510 return IPOD_DUMP_FAILED;
511 }
512
513 outfile = open(filename,O_CREAT|O_TRUNC|O_WRONLY|O_BINARY,S_IREAD|S_IWRITE);
514 if (outfile < 0) {
515 perror(filename);
516 return IPOD_OPEN_OUTFILE_FAILED;
517 }
518
519 if (write(outfile, ipod.xmlinfo, ipod.xmlinfo_len) < 0) {
520 fprintf(stderr,"[ERR] --dump-xml failed.\n");
521 } else {
522 fprintf(stderr,"[INFO] XML info written to %s.\n",filename);
523 }
524 close(outfile);
525 } else if (action==READ_PARTITION) {
526 outfile = open(filename,O_CREAT|O_TRUNC|O_WRONLY|O_BINARY,S_IREAD|S_IWRITE);
527 if (outfile < 0) {
528 perror(filename);
529 return IPOD_OPEN_OUTFILE_FAILED;
530 }
531
532 if (read_partition(&ipod, outfile) < 0) {
533 fprintf(stderr,"[ERR] --read-partition failed.\n");
534 } else {
535 fprintf(stderr,"[INFO] Partition extracted to %s.\n",filename);
536 }
537 close(outfile);
538 } else if (action==WRITE_PARTITION) {
539 if (ipod_reopen_rw(&ipod) < 0) {
540 return IPOD_CANNOT_REOPEN;
541 }
542
543 infile = open(filename,O_RDONLY|O_BINARY);
544 if (infile < 0) {
545 perror(filename);
546 return IPOD_OPEN_INFILE_FAILED;
547 }
548
549 /* Check filesize is <= partition size */
550 inputsize=filesize(infile);
551 if (inputsize > 0) {
552 if (inputsize <= (ipod.pinfo[0].size*ipod.sector_size)) {
553 fprintf(stderr,"[INFO] Input file is %u bytes\n",inputsize);
554 if (write_partition(&ipod,infile) < 0) {
555 fprintf(stderr,"[ERR] --write-partition failed.\n");
556 } else {
557 fprintf(stderr,"[INFO] %s restored to partition\n",filename);
558 }
559 } else {
560 fprintf(stderr,"[ERR] File is too large for firmware partition, aborting.\n");
561 }
562 }
563
564 close(infile);
565 } else if (action==FORMAT_PARTITION) {
566 printf("WARNING!!! YOU ARE ABOUT TO USE AN EXPERIMENTAL FEATURE.\n");
567 printf("ALL DATA ON YOUR IPOD WILL BE ERASED.\n");
568 printf("Are you sure you want to format your ipod? (y/n):");
569
570 if (fgets(yesno,4,stdin)) {
571 if (yesno[0]=='y') {
572 if (ipod_reopen_rw(&ipod) < 0) {
573 return IPOD_CANNOT_REOPEN;
574 }
575
576 if (format_partition(&ipod,1) < 0) {
577 fprintf(stderr,"[ERR] Format failed.\n");
578 }
579 } else {
580 fprintf(stderr,"[INFO] Format cancelled.\n");
581 }
582 }
583 } else if (action==CONVERT_TO_FAT32) {
584 if (!ipod.macpod) {
585 printf("[ERR] Ipod is already FAT32, aborting\n");
586 } else {
587 printf("WARNING!!! YOU ARE ABOUT TO USE AN EXPERIMENTAL FEATURE.\n");
588 printf("ALL DATA ON YOUR IPOD WILL BE ERASED.\n");
589 printf("Are you sure you want to convert your ipod to FAT32? (y/n):");
590
591 if (fgets(yesno,4,stdin)) {
592 if (yesno[0]=='y') {
593 if (ipod_reopen_rw(&ipod) < 0) {
594 return IPOD_CANNOT_REOPEN;
595 }
596
597 if (write_dos_partition_table(&ipod) < 0) {
598 fprintf(stderr,"[ERR] Partition conversion failed.\n");
599 }
600
601 if (format_partition(&ipod,1) < 0) {
602 fprintf(stderr,"[ERR] Format failed.\n");
603 }
604 } else {
605 fprintf(stderr,"[INFO] Format cancelled.\n");
606 }
607 }
608 }
609 }
610
611 ipod_close(&ipod);
612
613#ifdef WITH_BOOTOBJS
614 if (action==INTERACTIVE) {
615 printf("Press ENTER to exit ipodpatcher :");
616 fgets(yesno,4,stdin);
617 }
618#endif
619
620 ipod_dealloc_buffer(&ipod);
621 return IPOD_OK;
622}
diff --git a/utils/ipodpatcher/parttypes.h b/utils/ipodpatcher/parttypes.h
new file mode 100644
index 0000000000..f8de303553
--- /dev/null
+++ b/utils/ipodpatcher/parttypes.h
@@ -0,0 +1,109 @@
1/* DOS partition types - taken from fdisk */
2
3struct parttype {
4 unsigned char type;
5 char *name;
6};
7
8struct 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};