summaryrefslogtreecommitdiffstats
path: root/rbutil
diff options
context:
space:
mode:
authorDave Chapman <dave@dchapman.com>2007-02-10 19:49:43 +0000
committerDave Chapman <dave@dchapman.com>2007-02-10 19:49:43 +0000
commit955afed1b74793a3f06f98f3c259ec98f26a0b82 (patch)
tree6dcaa6b318ce282b21327530171f4f6a3297cb04 /rbutil
parentf0efde23039064d393e8cc35c2d88a487c47b1c7 (diff)
downloadrockbox-955afed1b74793a3f06f98f3c259ec98f26a0b82.tar.gz
rockbox-955afed1b74793a3f06f98f3c259ec98f26a0b82.zip
Move ipodpatcher into rbutil directory
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@12263 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'rbutil')
-rw-r--r--rbutil/ipodpatcher/Makefile61
-rw-r--r--rbutil/ipodpatcher/ipod2c.c139
-rw-r--r--rbutil/ipodpatcher/ipodio-posix.c115
-rw-r--r--rbutil/ipodpatcher/ipodio-win32.c190
-rw-r--r--rbutil/ipodpatcher/ipodio.h89
-rw-r--r--rbutil/ipodpatcher/ipodpatcher.c1261
-rw-r--r--rbutil/ipodpatcher/ipodpatcher.h51
-rw-r--r--rbutil/ipodpatcher/main.c429
-rw-r--r--rbutil/ipodpatcher/parttypes.h109
9 files changed, 2444 insertions, 0 deletions
diff --git a/rbutil/ipodpatcher/Makefile b/rbutil/ipodpatcher/Makefile
new file mode 100644
index 0000000000..f5a4d7cfb3
--- /dev/null
+++ b/rbutil/ipodpatcher/Makefile
@@ -0,0 +1,61 @@
+CFLAGS=-Wall
+
+BOOT_H = ipod3g.h ipod4g.h ipodcolor.h ipodmini.h ipodmini2g.h ipodnano.h ipodvideo.h
+
+# Uncomment the next two lines to build with embedded bootloaders and the
+# --install option and interactive mode. You need the full set of Rockbox
+# bootloaders in this directory - download them from
+# http://download.rockbox.org/bootloader/ipod/bootloaders.zip
+
+#BOOTSRC = ipod3g.c ipod4g.c ipodcolor.c ipodmini.c ipodmini2g.c ipodnano.c ipodvideo.c
+#CFLAGS += -DWITH_BOOTOBJS
+
+ifeq ($(findstring CYGWIN,$(shell uname)),CYGWIN)
+OUTPUT=ipodpatcher.exe
+CROSS=
+CFLAGS+=-mno-cygwin
+else
+OUTPUT=ipodpatcher
+CROSS=i586-mingw32msvc-
+endif
+
+NATIVECC = gcc
+CC = $(CROSS)gcc
+
+all: $(OUTPUT)
+
+ipodpatcher: main.c ipodpatcher.c ipodio-posix.c parttypes.h $(BOOTSRC)
+ gcc $(CFLAGS) -o ipodpatcher main.c ipodpatcher.c ipodio-posix.c $(BOOTSRC)
+ strip ipodpatcher
+
+ipodpatcher.exe: main.c ipodpatcher.c ipodio-win32.c parttypes.h $(BOOTSRC)
+ $(CC) $(CFLAGS) -o ipodpatcher.exe main.c ipodpatcher.c ipodio-win32.c $(BOOTSRC)
+ $(CROSS)strip ipodpatcher.exe
+
+ipod2c: ipod2c.c
+ $(NATIVECC) $(CFLAGS) -o ipod2c ipod2c.c
+
+ipod3g.c: bootloader-ipod3g.ipod ipod2c
+ ./ipod2c bootloader-ipod3g.ipod ipod3g
+
+ipod4g.c: bootloader-ipod4g.ipod ipod2c
+ ./ipod2c bootloader-ipod4g.ipod ipod4g
+
+ipodcolor.c: bootloader-ipodcolor.ipod ipod2c
+ ./ipod2c bootloader-ipodcolor.ipod ipodcolor
+
+ipodmini.c: bootloader-ipodmini.ipod ipod2c
+ ./ipod2c bootloader-ipodmini.ipod ipodmini
+
+ipodmini2g.c: bootloader-ipodmini2g.ipod ipod2c
+ ./ipod2c bootloader-ipodmini2g.ipod ipodmini2g
+
+ipodnano.c: bootloader-ipodnano.ipod ipod2c
+ ./ipod2c bootloader-ipodnano.ipod ipodnano
+
+ipodvideo.c: bootloader-ipodvideo.ipod ipod2c
+ ./ipod2c bootloader-ipodvideo.ipod ipodvideo
+
+
+clean:
+ rm -f ipodpatcher.exe ipodpatcher ipod2c *~ $(BOOTSRC) $(BOOT_H)
diff --git a/rbutil/ipodpatcher/ipod2c.c b/rbutil/ipodpatcher/ipod2c.c
new file mode 100644
index 0000000000..af2e25dd09
--- /dev/null
+++ b/rbutil/ipodpatcher/ipod2c.c
@@ -0,0 +1,139 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id: ipodio-win32.c 12205 2007-02-05 01:20:20Z dave $
+ *
+ * Copyright (C) 2007 Dave Chapman
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdlib.h>
+
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+static off_t filesize(int fd)
+{
+ struct stat buf;
+
+ fstat(fd,&buf);
+ return buf.st_size;
+}
+
+static int write_cfile(unsigned char* buf, off_t len, char* cname)
+{
+ char filename[256];
+ FILE* fp;
+ int i;
+
+ snprintf(filename,256,"%s.c",cname);
+
+ fp = fopen(filename,"w+");
+ if (fp == NULL) {
+ fprintf(stderr,"Couldn't open %s\n",filename);
+ return -1;
+ }
+
+ fprintf(fp,"/* Generated by ipod2c */\n\n");
+ fprintf(fp,"unsigned char %s[] = {",cname);
+
+ for (i=0;i<len;i++) {
+ if ((i % 16) == 0) {
+ fprintf(fp,"\n ");
+ }
+ if (i == (len-1)) {
+ fprintf(fp,"0x%02x",buf[i]);
+ } else {
+ fprintf(fp,"0x%02x, ",buf[i]);
+ }
+ }
+ fprintf(fp,"\n};\n");
+
+ fclose(fp);
+ return 0;
+}
+
+static int write_hfile(unsigned char* buf, off_t len, char* cname)
+{
+ char filename[256];
+ FILE* fp;
+
+ snprintf(filename,256,"%s.h",cname);
+ fp = fopen(filename,"w+");
+ if (fp == NULL) {
+ fprintf(stderr,"Couldn't open %s\n",filename);
+ return -1;
+ }
+
+ fprintf(fp,"/* Generated by ipod2c */\n\n");
+ fprintf(fp,"#define LEN_%s %d\n",cname,(int)len);
+ fprintf(fp,"extern unsigned char %s[];\n",cname);
+ fclose(fp);
+ return 0;
+}
+
+int main (int argc, char* argv[])
+{
+ char* infile;
+ char* cname;
+ int fd;
+ unsigned char* buf;
+ int len;
+ int n;
+
+ if (argc != 3) {
+ fprintf(stderr,"Usage: ipod2c file.bin cname\n");
+ return 0;
+ }
+
+ infile=argv[1];
+ cname=argv[2];
+
+ fd = open(infile,O_RDONLY);
+ if (fd < 0) {
+ fprintf(stderr,"Can not open %s\n",infile);
+ return 0;
+ }
+
+ len = filesize(fd) - 8;
+
+ n = lseek(fd,8,SEEK_SET);
+ if (n != 8) {
+ fprintf(stderr,"Seek failed\n");
+ return 0;
+ }
+
+ buf = malloc(len);
+ n = read(fd,buf,len);
+ if (n < len) {
+ fprintf(stderr,"Short read, aborting\n");
+ return 0;
+ }
+ close(fd);
+
+ if (write_cfile(buf,len,cname) < 0) {
+ return -1;
+ }
+ if (write_hfile(buf,len,cname) < 0) {
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/rbutil/ipodpatcher/ipodio-posix.c b/rbutil/ipodpatcher/ipodio-posix.c
new file mode 100644
index 0000000000..365bc27291
--- /dev/null
+++ b/rbutil/ipodpatcher/ipodio-posix.c
@@ -0,0 +1,115 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2006-2007 Dave Chapman
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+
+#if defined(linux) || defined (__linux)
+#include <sys/mount.h>
+#define IPOD_SECTORSIZE_IOCTL BLKSSZGET
+#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) \
+ || defined(__bsdi__) || defined(__DragonFly__)
+#include <sys/disk.h>
+#define IPOD_SECTORSIZE_IOCTL DIOCGSECTORSIZE
+#elif defined(__APPLE__) && defined(__MACH__)
+#include <sys/disk.h>
+#define IPOD_SECTORSIZE_IOCTL DKIOCGETBLOCKSIZE
+#else
+ #error No sector-size detection implemented for this platform
+#endif
+
+#include "ipodio.h"
+
+void print_error(char* msg)
+{
+ perror(msg);
+}
+
+int ipod_open(struct ipod_t* ipod, int silent)
+{
+ ipod->dh=open(ipod->diskname,O_RDONLY);
+ if (ipod->dh < 0) {
+ if (!silent) perror(ipod->diskname);
+ return -1;
+ }
+
+ if(ioctl(ipod->dh,IPOD_SECTORSIZE_IOCTL,&ipod->sector_size) < 0) {
+ ipod->sector_size=512;
+ if (!silent) {
+ fprintf(stderr,"[ERR] ioctl() call to get sector size failed, defaulting to %d\n"
+ ,ipod->sector_size);
+ }
+ }
+ return 0;
+}
+
+
+int ipod_reopen_rw(struct ipod_t* ipod)
+{
+ close(ipod->dh);
+ ipod->dh=open(ipod->diskname,O_RDWR);
+ if (ipod->dh < 0) {
+ perror(ipod->diskname);
+ return -1;
+ }
+ return 0;
+}
+
+int ipod_close(struct ipod_t* ipod)
+{
+ close(ipod->dh);
+ return 0;
+}
+
+int ipod_alloc_buffer(unsigned char** sectorbuf, int bufsize)
+{
+ *sectorbuf=malloc(bufsize);
+ if (*sectorbuf == NULL) {
+ return -1;
+ }
+ return 0;
+}
+
+int ipod_seek(struct ipod_t* ipod, unsigned long pos)
+{
+ off_t res;
+
+ res = lseek(ipod->dh, pos, SEEK_SET);
+
+ if (res == -1) {
+ return -1;
+ }
+ return 0;
+}
+
+int ipod_read(struct ipod_t* ipod, unsigned char* buf, int nbytes)
+{
+ return read(ipod->dh, buf, nbytes);
+}
+
+int ipod_write(struct ipod_t* ipod, unsigned char* buf, int nbytes)
+{
+ return write(ipod->dh, buf, nbytes);
+}
diff --git a/rbutil/ipodpatcher/ipodio-win32.c b/rbutil/ipodpatcher/ipodio-win32.c
new file mode 100644
index 0000000000..83f00b8cd9
--- /dev/null
+++ b/rbutil/ipodpatcher/ipodio-win32.c
@@ -0,0 +1,190 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2006-2007 Dave Chapman
+ *
+ * error(), lock_volume() and unlock_volume() functions and inspiration taken
+ * from:
+ * RawDisk - Direct Disk Read/Write Access for NT/2000/XP
+ * Copyright (c) 2003 Jan Kiszka
+ * http://www.stud.uni-hannover.de/user/73174/RawDisk/
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef __WIN32__
+#include <windows.h>
+#include <winioctl.h>
+#endif
+
+#include "ipodio.h"
+
+static int lock_volume(HANDLE hDisk)
+{
+ DWORD dummy;
+
+ return DeviceIoControl(hDisk, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0,
+ &dummy, NULL);
+}
+
+static int unlock_volume(HANDLE hDisk)
+{
+ DWORD dummy;
+
+ return DeviceIoControl(hDisk, FSCTL_UNLOCK_VOLUME, NULL, 0, NULL, 0,
+ &dummy, NULL);
+}
+
+void print_error(char* msg)
+{
+ char* pMsgBuf;
+
+ printf(msg);
+ FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(),
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&pMsgBuf,
+ 0, NULL);
+ printf(pMsgBuf);
+ LocalFree(pMsgBuf);
+}
+
+int ipod_open(struct ipod_t* ipod, int silent)
+{
+ DISK_GEOMETRY_EX diskgeometry_ex;
+ DISK_GEOMETRY diskgeometry;
+ unsigned long n;
+
+ ipod->dh = CreateFile(ipod->diskname, GENERIC_READ,
+ FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
+ FILE_FLAG_WRITE_THROUGH | FILE_FLAG_NO_BUFFERING, NULL);
+
+ if (ipod->dh == INVALID_HANDLE_VALUE) {
+ if (!silent) print_error(" Error opening disk: ");
+ return -1;
+ }
+
+ if (!lock_volume(ipod->dh)) {
+ if (!silent) print_error(" Error locking disk: ");
+ return -1;
+ }
+
+ if (!DeviceIoControl(ipod->dh,
+ IOCTL_DISK_GET_DRIVE_GEOMETRY_EX,
+ NULL,
+ 0,
+ &diskgeometry_ex,
+ sizeof(diskgeometry_ex),
+ &n,
+ NULL)) {
+ if (!DeviceIoControl(ipod->dh,
+ IOCTL_DISK_GET_DRIVE_GEOMETRY,
+ NULL,
+ 0,
+ &diskgeometry,
+ sizeof(diskgeometry),
+ &n,
+ NULL)) {
+ if (!silent) print_error(" Error reading disk geometry: ");
+ return -1;
+ } else {
+ ipod->sector_size=diskgeometry.BytesPerSector;
+ }
+ } else {
+ ipod->sector_size=diskgeometry_ex.Geometry.BytesPerSector;
+ }
+
+ return 0;
+}
+
+int ipod_reopen_rw(struct ipod_t* ipod)
+{
+ /* Close existing file and re-open for writing */
+ unlock_volume(ipod->dh);
+ CloseHandle(ipod->dh);
+
+ ipod->dh = CreateFile(ipod->diskname, GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
+ FILE_FLAG_WRITE_THROUGH | FILE_FLAG_NO_BUFFERING, NULL);
+
+ if (ipod->dh == INVALID_HANDLE_VALUE) {
+ print_error(" Error opening disk: ");
+ return -1;
+ }
+
+ if (!lock_volume(ipod->dh)) {
+ print_error(" Error locking disk: ");
+ return -1;
+ }
+
+ return 0;
+}
+
+int ipod_close(struct ipod_t* ipod)
+{
+ unlock_volume(ipod->dh);
+ CloseHandle(ipod->dh);
+ return 0;
+}
+
+int ipod_alloc_buffer(unsigned char** sectorbuf, int bufsize)
+{
+ /* The ReadFile function requires a memory buffer aligned to a multiple of
+ the disk sector size. */
+ *sectorbuf = (unsigned char*)VirtualAlloc(NULL, bufsize, MEM_COMMIT, PAGE_READWRITE);
+ if (*sectorbuf == NULL) {
+ print_error(" Error allocating a buffer: ");
+ return -1;
+ }
+ return 0;
+}
+
+int ipod_seek(struct ipod_t* ipod, unsigned long pos)
+{
+ if (SetFilePointer(ipod->dh, pos, NULL, FILE_BEGIN)==0xffffffff) {
+ print_error(" Seek error ");
+ return -1;
+ }
+ return 0;
+}
+
+int ipod_read(struct ipod_t* ipod, unsigned char* buf, int nbytes)
+{
+ unsigned long count;
+
+ if (!ReadFile(ipod->dh, buf, nbytes, &count, NULL)) {
+ print_error(" Error reading from disk: ");
+ return -1;
+ }
+
+ return count;
+}
+
+int ipod_write(struct ipod_t* ipod, unsigned char* buf, int nbytes)
+{
+ unsigned long count;
+
+ if (!WriteFile(ipod->dh, buf, nbytes, &count, NULL)) {
+ print_error(" Error writing to disk: ");
+ return -1;
+ }
+
+ return count;
+}
diff --git a/rbutil/ipodpatcher/ipodio.h b/rbutil/ipodpatcher/ipodio.h
new file mode 100644
index 0000000000..d0641faa2b
--- /dev/null
+++ b/rbutil/ipodpatcher/ipodio.h
@@ -0,0 +1,89 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2006-2007 Dave Chapman
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#ifndef __IPODIO_H
+#define __IPODIO_H
+
+#include <stdint.h>
+
+#ifdef __WIN32__
+#include <windows.h>
+#else
+#define HANDLE int
+#define O_BINARY 0
+#endif
+
+/* The maximum number of images in a firmware partition - a guess... */
+#define MAX_IMAGES 10
+
+enum firmwaretype_t {
+ FTYPE_OSOS = 0,
+ FTYPE_RSRC,
+ FTYPE_AUPD,
+ FTYPE_HIBE
+};
+
+struct ipod_directory_t {
+ enum firmwaretype_t ftype;
+ int id;
+ uint32_t devOffset; /* Offset of image relative to one sector into bootpart*/
+ uint32_t len;
+ uint32_t addr;
+ uint32_t entryOffset;
+ uint32_t chksum;
+ uint32_t vers;
+ uint32_t loadAddr;
+};
+
+struct partinfo_t {
+ unsigned long start; /* first sector (LBA) */
+ unsigned long size; /* number of sectors */
+ int type;
+};
+
+struct ipod_t {
+ HANDLE dh;
+ char diskname[4096];
+ int sector_size;
+ struct ipod_directory_t ipod_directory[MAX_IMAGES];
+ int nimages;
+ off_t diroffset;
+ off_t start; /* Offset in bytes of firmware partition from start of disk */
+ off_t fwoffset; /* Offset in bytes of start of firmware images from start of disk */
+ struct partinfo_t pinfo[4];
+ int modelnum;
+ char* modelname;
+ char* modelstr;
+ int macpod;
+#ifdef WITH_BOOTOBJS
+ unsigned char* bootloader;
+ int bootloader_len;
+#endif
+};
+
+void print_error(char* msg);
+int ipod_open(struct ipod_t* ipod, int silent);
+int ipod_reopen_rw(struct ipod_t* ipod);
+int ipod_close(struct ipod_t* ipod);
+int ipod_seek(struct ipod_t* ipod, unsigned long pos);
+int ipod_read(struct ipod_t* ipod, unsigned char* buf, int nbytes);
+int ipod_write(struct ipod_t* ipod, unsigned char* buf, int nbytes);
+int ipod_alloc_buffer(unsigned char** sectorbuf, int bufsize);
+
+#endif
diff --git a/rbutil/ipodpatcher/ipodpatcher.c b/rbutil/ipodpatcher/ipodpatcher.c
new file mode 100644
index 0000000000..6c60bae38d
--- /dev/null
+++ b/rbutil/ipodpatcher/ipodpatcher.c
@@ -0,0 +1,1261 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2006-2007 Dave Chapman
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "parttypes.h"
+#include "ipodio.h"
+#include "ipodpatcher.h"
+
+#ifdef WITH_BOOTOBJS
+#include "ipod3g.h"
+#include "ipod4g.h"
+#include "ipodmini.h"
+#include "ipodmini2g.h"
+#include "ipodcolor.h"
+#include "ipodnano.h"
+#include "ipodvideo.h"
+#endif
+
+extern int verbose;
+
+unsigned char* sectorbuf;
+
+/* The following string appears at the start of the firmware partition */
+static const char *apple_stop_sign = "{{~~ /-----\\ "\
+ "{{~~ / \\ "\
+ "{{~~| | "\
+ "{{~~| S T O P | "\
+ "{{~~| | "\
+ "{{~~ \\ / "\
+ "{{~~ \\-----/ "\
+ "Copyright(C) 200"\
+ "1 Apple Computer"\
+ ", Inc.----------"\
+ "----------------"\
+ "----------------"\
+ "----------------"\
+ "----------------"\
+ "----------------"\
+ "---------------";
+
+/* Windows requires the buffer for disk I/O to be aligned in memory on a
+ multiple of the disk volume size - so we use a single global variable
+ and initialise it with ipod_alloc_buf()
+*/
+
+char* get_parttype(int pt)
+{
+ int i;
+ static char unknown[]="Unknown";
+
+ if (pt == -1) {
+ return "HFS/HFS+";
+ }
+
+ i=0;
+ while (parttypes[i].name != NULL) {
+ if (parttypes[i].type == pt) {
+ return (parttypes[i].name);
+ }
+ i++;
+ }
+
+ return unknown;
+}
+
+off_t filesize(int fd) {
+ struct stat buf;
+
+ if (fstat(fd,&buf) < 0) {
+ perror("[ERR] Checking filesize of input file");
+ return -1;
+ } else {
+ return(buf.st_size);
+ }
+}
+
+/* Partition table parsing code taken from Rockbox */
+
+#define MAX_SECTOR_SIZE 2048
+#define SECTOR_SIZE 512
+
+unsigned short static inline le2ushort(unsigned char* buf)
+{
+ unsigned short res = (buf[1] << 8) | buf[0];
+
+ return res;
+}
+
+int static inline le2int(unsigned char* buf)
+{
+ int32_t res = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
+
+ return res;
+}
+
+int static inline be2int(unsigned char* buf)
+{
+ int32_t res = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
+
+ return res;
+}
+
+int static inline getint16le(char* buf)
+{
+ int16_t res = (buf[1] << 8) | buf[0];
+
+ return res;
+}
+
+void static inline short2le(unsigned short val, unsigned char* addr)
+{
+ addr[0] = val & 0xFF;
+ addr[1] = (val >> 8) & 0xff;
+}
+
+void static inline int2le(unsigned int val, unsigned char* addr)
+{
+ addr[0] = val & 0xFF;
+ addr[1] = (val >> 8) & 0xff;
+ addr[2] = (val >> 16) & 0xff;
+ addr[3] = (val >> 24) & 0xff;
+}
+
+void int2be(unsigned int val, unsigned char* addr)
+{
+ addr[0] = (val >> 24) & 0xff;
+ addr[1] = (val >> 16) & 0xff;
+ addr[2] = (val >> 8) & 0xff;
+ addr[3] = val & 0xFF;
+}
+
+
+#define BYTES2INT32(array,pos)\
+ ((long)array[pos] | ((long)array[pos+1] << 8 ) |\
+ ((long)array[pos+2] << 16 ) | ((long)array[pos+3] << 24 ))
+
+void display_partinfo(struct ipod_t* ipod)
+{
+ int i;
+ double sectors_per_MB = (1024.0*1024.0)/ipod->sector_size;
+
+ printf("[INFO] Part Start Sector End Sector Size (MB) Type\n");
+ for ( i = 0; i < 4; i++ ) {
+ if (ipod->pinfo[i].start != 0) {
+ printf("[INFO] %d %10ld %10ld %10.1f %s (0x%02x)\n",
+ i,
+ ipod->pinfo[i].start,
+ ipod->pinfo[i].start+ipod->pinfo[i].size-1,
+ ipod->pinfo[i].size/sectors_per_MB,
+ get_parttype(ipod->pinfo[i].type),
+ ipod->pinfo[i].type);
+ }
+ }
+}
+
+int read_partinfo(struct ipod_t* ipod, int silent)
+{
+ int i;
+ unsigned long count;
+
+ count = ipod_read(ipod,sectorbuf, ipod->sector_size);
+
+ if (count <= 0) {
+ print_error(" Error reading from disk: ");
+ return -1;
+ }
+
+ if ((sectorbuf[510] == 0x55) && (sectorbuf[511] == 0xaa)) {
+ /* DOS partition table */
+ if ((memcmp(&sectorbuf[71],"iPod",4) != 0) &&
+ (memcmp(&sectorbuf[0x40],"This is your Apple iPod. You probably do not want to boot from it!",66) != 0) ) {
+ if (!silent) fprintf(stderr,"[ERR] Drive is not an iPod, aborting\n");
+ return -1;
+ }
+
+ ipod->macpod = 0;
+ /* parse partitions */
+ for ( i = 0; i < 4; i++ ) {
+ unsigned char* ptr = sectorbuf + 0x1be + 16*i;
+ ipod->pinfo[i].type = ptr[4];
+ ipod->pinfo[i].start = BYTES2INT32(ptr, 8);
+ ipod->pinfo[i].size = BYTES2INT32(ptr, 12);
+
+ /* extended? */
+ if ( ipod->pinfo[i].type == 5 ) {
+ /* not handled yet */
+ }
+ }
+ } else if ((sectorbuf[0] == 'E') && (sectorbuf[1] == 'R')) {
+ /* Apple Partition Map */
+
+ /* APM parsing code based on the check_mac_partitions() function in
+ ipodloader2 - written by Thomas Tempelmann and released
+ under the GPL. */
+
+ int blkNo = 1;
+ int partBlkCount = 1;
+ int partBlkSizMul = sectorbuf[2] / 2;
+
+ int pmMapBlkCnt; /* # of blks in partition map */
+ int pmPyPartStart; /* physical start blk of partition */
+ int pmPartBlkCnt; /* # of blks in this partition */
+ int i = 0;
+
+ ipod->macpod = 1;
+
+ memset(ipod->pinfo,0,sizeof(ipod->pinfo));
+
+ while (blkNo <= partBlkCount) {
+ if (ipod_seek(ipod, blkNo * partBlkSizMul * 512) < 0) {
+ fprintf(stderr,"[ERR] Seek failed whilst reading APM\n");
+ return -1;
+ }
+
+ count = ipod_read(ipod, sectorbuf, ipod->sector_size);
+
+ if (count <= 0) {
+ print_error(" Error reading from disk: ");
+ return -1;
+ }
+
+ /* see if it's a partition entry */
+ if ((sectorbuf[0] != 'P') || (sectorbuf[1] != 'M')) {
+ /* end of partition table -> leave the loop */
+ break;
+ }
+
+ /* Extract the interesting entries */
+ pmMapBlkCnt = be2int(sectorbuf + 4);
+ pmPyPartStart = be2int(sectorbuf + 8);
+ pmPartBlkCnt = be2int(sectorbuf + 12);
+
+ /* update the number of part map blocks */
+ partBlkCount = pmMapBlkCnt;
+
+ if (strncmp((char*)(sectorbuf + 48), "Apple_MDFW", 32)==0) {
+ /* A Firmware partition */
+ ipod->pinfo[i].start = pmPyPartStart;
+ ipod->pinfo[i].size = pmPartBlkCnt;
+ ipod->pinfo[i].type = 0;
+ i++;
+ } else if (strncmp((char*)(sectorbuf + 48), "Apple_HFS", 32)==0) {
+ /* A HFS partition */
+ ipod->pinfo[i].start = pmPyPartStart;
+ ipod->pinfo[i].size = pmPartBlkCnt;
+ ipod->pinfo[i].type = -1;
+ i++;
+ }
+
+ blkNo++; /* read next partition map entry */
+ }
+ } else {
+ if (!silent) fprintf(stderr,"[ERR] Bad boot sector signature\n");
+ return -1;
+ }
+
+ ipod->start = ipod->pinfo[0].start*ipod->sector_size;
+ return 0;
+}
+
+int read_partition(struct ipod_t* ipod, int outfile)
+{
+ int res;
+ unsigned long n;
+ int bytesleft;
+ int chunksize;
+ int count = ipod->pinfo[0].size;
+
+ if (ipod_seek(ipod, ipod->start) < 0) {
+ return -1;
+ }
+
+ fprintf(stderr,"[INFO] Writing %d sectors to output file\n",count);
+
+ bytesleft = count * ipod->sector_size;
+ while (bytesleft > 0) {
+ if (bytesleft > BUFFER_SIZE) {
+ chunksize = BUFFER_SIZE;
+ } else {
+ chunksize = bytesleft;
+ }
+
+ n = ipod_read(ipod, sectorbuf, chunksize);
+
+ if (n < 0) {
+ return -1;
+ }
+
+ if (n < chunksize) {
+ fprintf(stderr,
+ "[ERR] Short read in disk_read() - requested %d, got %lu\n",
+ chunksize,n);
+ return -1;
+ }
+
+ bytesleft -= n;
+
+ res = write(outfile,sectorbuf,n);
+
+ if (res < 0) {
+ perror("[ERR] write in disk_read");
+ return -1;
+ }
+
+ if (res != n) {
+ fprintf(stderr,
+ "Short write - requested %lu, received %d - aborting.\n",n,res);
+ return -1;
+ }
+ }
+
+ fprintf(stderr,"[INFO] Done.\n");
+ return 0;
+}
+
+int write_partition(struct ipod_t* ipod, int infile)
+{
+ unsigned long res;
+ int n;
+ int bytesread;
+ int byteswritten = 0;
+ int eof;
+ int padding = 0;
+
+ if (ipod_seek(ipod, ipod->start) < 0) {
+ return -1;
+ }
+
+ fprintf(stderr,"[INFO] Writing input file to device\n");
+ bytesread = 0;
+ eof = 0;
+ while (!eof) {
+ n = read(infile,sectorbuf,BUFFER_SIZE);
+
+ if (n < 0) {
+ perror("[ERR] read in disk_write");
+ return -1;
+ }
+
+ if (n < BUFFER_SIZE) {
+ eof = 1;
+ /* We need to pad the last write to a multiple of SECTOR_SIZE */
+ if ((n % ipod->sector_size) != 0) {
+ padding = (ipod->sector_size-(n % ipod->sector_size));
+ n += padding;
+ }
+ }
+
+ bytesread += n;
+
+ res = ipod_write(ipod, sectorbuf, n);
+
+ if (res < 0) {
+ print_error(" Error writing to disk: ");
+ fprintf(stderr,"Bytes written: %d\n",byteswritten);
+ return -1;
+ }
+
+ if (res != n) {
+ fprintf(stderr,"[ERR] Short write - requested %d, received %lu - aborting.\n",n,res);
+ return -1;
+ }
+
+ byteswritten += res;
+ }
+
+ fprintf(stderr,"[INFO] Wrote %d bytes plus %d bytes padding.\n",
+ byteswritten-padding,padding);
+ return 0;
+}
+
+char* ftypename[] = { "OSOS", "RSRC", "AUPD", "HIBE" };
+
+int diskmove(struct ipod_t* ipod, int delta)
+{
+ int src_start;
+ int src_end;
+ int bytesleft;
+ int chunksize;
+ int i;
+ int n;
+
+ src_start = ipod->ipod_directory[1].devOffset + ipod->sector_size;
+ src_end = (ipod->ipod_directory[ipod->nimages-1].devOffset + ipod->sector_size +
+ ipod->ipod_directory[ipod->nimages-1].len +
+ (ipod->sector_size-1)) & ~(ipod->sector_size-1);
+ bytesleft = src_end - src_start;
+
+ if (verbose) {
+ fprintf(stderr,"[INFO] Need to move images 2-%d forward %08x bytes\n", ipod->nimages,delta);
+ fprintf(stderr,"[VERB] src_start = %08x\n",src_start);
+ fprintf(stderr,"[VERB] src_end = %08x\n",src_end);
+ fprintf(stderr,"[VERB] dest_start = %08x\n",src_start+delta);
+ fprintf(stderr,"[VERB] dest_end = %08x\n",src_end+delta);
+ fprintf(stderr,"[VERB] bytes to copy = %08x\n",bytesleft);
+ }
+
+ while (bytesleft > 0) {
+ if (bytesleft <= BUFFER_SIZE) {
+ chunksize = bytesleft;
+ } else {
+ chunksize = BUFFER_SIZE;
+ }
+
+ if (verbose) {
+ fprintf(stderr,"[VERB] Copying %08x bytes from %08x to %08x (absolute %08x to %08x)\n",
+ chunksize,
+ src_end-chunksize,
+ src_end-chunksize+delta,
+ (unsigned int)(ipod->start+src_end-chunksize),
+ (unsigned int)(ipod->start+src_end-chunksize+delta));
+ }
+
+
+ if (ipod_seek(ipod, ipod->start+src_end-chunksize) < 0) {
+ fprintf(stderr,"[ERR] Seek failed\n");
+ return -1;
+ }
+
+ if ((n = ipod_read(ipod,sectorbuf,chunksize)) < 0) {
+ perror("[ERR] Write failed\n");
+ return -1;
+ }
+
+ if (n < chunksize) {
+ fprintf(stderr,"[ERR] Short read - requested %d bytes, received %d\n",
+ i,n);
+ return -1;
+ }
+
+ if (ipod_seek(ipod, ipod->start+src_end-chunksize+delta) < 0) {
+ fprintf(stderr,"[ERR] Seek failed\n");
+ return -1;
+ }
+
+ if ((n = ipod_write(ipod,sectorbuf,chunksize)) < 0) {
+ perror("[ERR] Write failed\n");
+ return -1;
+ }
+
+ if (n < chunksize) {
+ fprintf(stderr,"[ERR] Short write - requested %d bytes, received %d\n"
+ ,i,n);
+ return -1;
+ }
+
+ src_end -= chunksize;
+ bytesleft -= chunksize;
+ }
+
+ return 0;
+}
+
+int add_bootloader(struct ipod_t* ipod, char* filename, int type)
+{
+ int length;
+ int i;
+ int x;
+ int n;
+ int infile;
+ int paddedlength;
+ int entryOffset;
+ int delta = 0;
+ unsigned long chksum=0;
+ unsigned long filechksum=0;
+ unsigned char header[8]; /* Header for .ipod file */
+ unsigned char* bootloader_buf;
+
+ /* Calculate the position in the OSOS image where our bootloader will go. */
+ if (ipod->ipod_directory[0].entryOffset>0) {
+ /* Keep the same entryOffset */
+ entryOffset = ipod->ipod_directory[0].entryOffset;
+ } else {
+ entryOffset = (ipod->ipod_directory[0].len+ipod->sector_size-1)&~(ipod->sector_size-1);
+ }
+
+#ifdef WITH_BOOTOBJS
+ if (type == FILETYPE_INTERNAL) {
+ fprintf(stderr,"[INFO] Using internal bootloader - %d bytes\n",ipod->bootloader_len);
+ memcpy(sectorbuf+entryOffset,ipod->bootloader,ipod->bootloader_len);
+ length = ipod->bootloader_len;
+ paddedlength=(ipod->bootloader_len+ipod->sector_size-1)&~(ipod->sector_size-1);
+ }
+ else
+#endif
+ {
+ infile=open(filename,O_RDONLY);
+ if (infile < 0) {
+ fprintf(stderr,"[ERR] Couldn't open input file %s\n",filename);
+ return -1;
+ }
+
+ if (type==FILETYPE_DOT_IPOD) {
+ /* First check that the input file is the correct type for this ipod. */
+ n = read(infile,header,8);
+ if (n < 8) {
+ fprintf(stderr,"[ERR] Failed to read header from %s\n",filename);
+ close(infile);
+ return -1;
+ }
+
+ if (memcmp(header+4, ipod->modelname,4)!=0) {
+ fprintf(stderr,"[ERR] Model name in input file (%c%c%c%c) doesn't match ipod model (%s)\n",
+ header[4],header[5],header[6],header[7], ipod->modelname);
+ close(infile);
+ return -1;
+ }
+
+ filechksum = be2int(header);
+
+ length=filesize(infile)-8;
+ } else {
+ length=filesize(infile);
+ }
+ paddedlength=(length+ipod->sector_size-1)&~(ipod->sector_size-1);
+
+ bootloader_buf = malloc(length);
+ if (bootloader_buf == NULL) {
+ fprintf(stderr,"[ERR] Can not allocate memory for bootlaoder\n");
+ }
+ /* Now read our bootloader - we need to check it before modifying the partition*/
+ n = read(infile,bootloader_buf,length);
+ close(infile);
+
+ if (n < 0) {
+ fprintf(stderr,"[ERR] Couldn't read input file\n");
+ return -1;
+ }
+
+ if (type==FILETYPE_DOT_IPOD) {
+ /* Calculate and confirm bootloader checksum */
+ chksum = ipod->modelnum;
+ for (i = 0; i < length; i++) {
+ /* add 8 unsigned bits but keep a 32 bit sum */
+ chksum += bootloader_buf[i];
+ }
+
+ if (chksum == filechksum) {
+ fprintf(stderr,"[INFO] Checksum OK in %s\n",filename);
+ } else {
+ fprintf(stderr,"[ERR] Checksum in %s failed check\n",filename);
+ return -1;
+ }
+ }
+ }
+
+ if (entryOffset+paddedlength > BUFFER_SIZE) {
+ fprintf(stderr,"[ERR] Input file too big for buffer\n");
+ return -1;
+ }
+
+ if (verbose) {
+ fprintf(stderr,"[VERB] Original firmware begins at 0x%08x\n", ipod->ipod_directory[0].devOffset + ipod->sector_size);
+ fprintf(stderr,"[VERB] New entryOffset will be 0x%08x\n",entryOffset);
+ fprintf(stderr,"[VERB] End of bootloader will be at 0x%08x\n",entryOffset+paddedlength);
+ }
+
+ /* Check if we have enough space */
+ /* TODO: Check the size of the partition. */
+ if (ipod->nimages > 1) {
+ if ((ipod->ipod_directory[0].devOffset+entryOffset+paddedlength) >
+ ipod->ipod_directory[1].devOffset) {
+ fprintf(stderr,"[INFO] Moving images to create room for new firmware...\n");
+ delta = ipod->ipod_directory[0].devOffset + entryOffset+paddedlength
+ - ipod->ipod_directory[1].devOffset;
+
+ if (diskmove(ipod, delta) < 0) {
+ fprintf(stderr,"[ERR] Image movement failed.\n");
+ return -1;
+ }
+ }
+ }
+
+
+ /* We have moved the partitions, now we can write our bootloader */
+
+ /* Firstly read the original firmware into sectorbuf */
+ fprintf(stderr,"[INFO] Reading original firmware...\n");
+ if (ipod_seek(ipod, ipod->fwoffset+ipod->ipod_directory[0].devOffset) < 0) {
+ fprintf(stderr,"[ERR] Seek failed\n");
+ return -1;
+ }
+
+ if ((n = ipod_read(ipod,sectorbuf,entryOffset)) < 0) {
+ perror("[ERR] Read failed\n");
+ return -1;
+ }
+
+ if (n < entryOffset) {
+ fprintf(stderr,"[ERR] Short read - requested %d bytes, received %d\n"
+ ,i,n);
+ return -1;
+ }
+
+#ifdef WITH_BOOTOBJS
+ if (type == FILETYPE_INTERNAL) {
+ memcpy(sectorbuf+entryOffset,ipod->bootloader,ipod->bootloader_len);
+ }
+ else
+#endif
+ {
+ memcpy(sectorbuf+entryOffset,bootloader_buf,length);
+ free(bootloader_buf);
+ }
+
+ /* Calculate new checksum for combined image */
+ chksum = 0;
+ for (i=0;i<entryOffset + length; i++) {
+ chksum += sectorbuf[i];
+ }
+
+ /* Now write the combined firmware image to the disk */
+
+ if (ipod_seek(ipod, ipod->fwoffset+ipod->ipod_directory[0].devOffset) < 0) {
+ fprintf(stderr,"[ERR] Seek failed\n");
+ return -1;
+ }
+
+ if ((n = ipod_write(ipod,sectorbuf,entryOffset+paddedlength)) < 0) {
+ perror("[ERR] Write failed\n");
+ return -1;
+ }
+
+ if (n < (entryOffset+paddedlength)) {
+ fprintf(stderr,"[ERR] Short read - requested %d bytes, received %d\n"
+ ,i,n);
+ return -1;
+ }
+
+ fprintf(stderr,"[INFO] Wrote %d bytes to firmware partition\n",entryOffset+paddedlength);
+
+ x = ipod->diroffset % ipod->sector_size;
+
+ /* Read directory */
+ if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) {
+ fprintf(stderr,"[ERR] Seek failed\n");
+ return -1;
+ }
+
+ n=ipod_read(ipod, sectorbuf, ipod->sector_size);
+ if (n < 0) {
+ fprintf(stderr,"[ERR] Directory read failed\n");
+ return -1;
+ }
+
+ /* Update entries for image 0 */
+ int2le(entryOffset+length,sectorbuf+x+16);
+ int2le(entryOffset,sectorbuf+x+24);
+ int2le(chksum,sectorbuf+x+28);
+ int2le(0xffffffff,sectorbuf+x+36); /* loadAddr */
+
+ /* Update devOffset entries for other images, if we have moved them */
+ if (delta > 0) {
+ for (i=1;i<ipod->nimages;i++) {
+ int2le(le2int(sectorbuf+x+i*40+12)+delta,sectorbuf+x+i*40+12);
+ }
+ }
+
+ /* Write directory */
+ if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) {
+ fprintf(stderr,"[ERR] Seek to %d failed\n", (int)(ipod->start+ipod->diroffset-x));
+ return -1;
+ }
+ n=ipod_write(ipod, sectorbuf, ipod->sector_size);
+ if (n < 0) {
+ fprintf(stderr,"[ERR] Directory write failed\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+int delete_bootloader(struct ipod_t* ipod)
+{
+ int length;
+ int i;
+ int x;
+ int n;
+ unsigned long chksum=0; /* 32 bit checksum - Rockbox .ipod style*/
+
+ /* Removing the bootloader involves adjusting the "length",
+ "chksum" and "entryOffset" values in the osos image's directory
+ entry. */
+
+ /* Firstly check we have a bootloader... */
+
+ if (ipod->ipod_directory[0].entryOffset == 0) {
+ fprintf(stderr,"[ERR] No bootloader found.\n");
+ return -1;
+ }
+
+ length = ipod->ipod_directory[0].entryOffset;
+
+ /* Read the firmware so we can calculate the checksum */
+ fprintf(stderr,"[INFO] Reading firmware (%d bytes)\n",length);
+
+ if (ipod_seek(ipod, ipod->fwoffset+ipod->ipod_directory[0].devOffset) < 0) {
+ return -1;
+ }
+
+ i = (length+ipod->sector_size-1) & ~(ipod->sector_size-1);
+ fprintf(stderr,"[INFO] Padding read from 0x%08x to 0x%08x bytes\n",
+ length,i);
+
+ if ((n = ipod_read(ipod,sectorbuf,i)) < 0) {
+ return -1;
+ }
+
+ if (n < i) {
+ fprintf(stderr,"[ERR] Short read - requested %d bytes, received %d\n",
+ i,n);
+ return -1;
+ }
+
+ chksum = 0;
+ for (i = 0; i < length; i++) {
+ /* add 8 unsigned bits but keep a 32 bit sum */
+ chksum += sectorbuf[i];
+ }
+
+ /* Now write back the updated directory entry */
+
+ fprintf(stderr,"[INFO] Updating firmware checksum\n");
+
+ x = ipod->diroffset % ipod->sector_size;
+
+ /* Read directory */
+ if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; }
+
+ n=ipod_read(ipod, sectorbuf, ipod->sector_size);
+ if (n < 0) { return -1; }
+
+ /* Update entries for image 0 */
+ int2le(length,sectorbuf+x+16);
+ int2le(0,sectorbuf+x+24);
+ int2le(chksum,sectorbuf+x+28);
+
+ /* Write directory */
+ if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; }
+ n=ipod_write(ipod, sectorbuf, ipod->sector_size);
+ if (n < 0) { return -1; }
+
+ return 0;
+}
+
+int write_firmware(struct ipod_t* ipod, char* filename, int type)
+{
+ int length;
+ int i;
+ int x;
+ int n;
+ int infile;
+ int newsize;
+ int bytesavailable;
+ unsigned long chksum=0;
+ unsigned long filechksum=0;
+ unsigned char header[8]; /* Header for .ipod file */
+
+ /* First check that the input file is the correct type for this ipod. */
+ infile=open(filename,O_RDONLY);
+ if (infile < 0) {
+ fprintf(stderr,"[ERR] Couldn't open input file %s\n",filename);
+ return -1;
+ }
+
+ if (type==FILETYPE_DOT_IPOD) {
+ n = read(infile,header,8);
+ if (n < 8) {
+ fprintf(stderr,"[ERR] Failed to read header from %s\n",filename);
+ close(infile);
+ return -1;
+ }
+
+ if (memcmp(header+4, ipod->modelname,4)!=0) {
+ fprintf(stderr,"[ERR] Model name in input file (%c%c%c%c) doesn't match ipod model (%s)\n",
+ header[4],header[5],header[6],header[7], ipod->modelname);
+ close(infile);
+ return -1;
+ }
+
+ filechksum = be2int(header);
+
+ length = filesize(infile)-8;
+ } else {
+ length = filesize(infile);
+ }
+ newsize=(length+ipod->sector_size-1)&~(ipod->sector_size-1);
+
+ fprintf(stderr,"[INFO] Padding input file from 0x%08x to 0x%08x bytes\n",
+ length,newsize);
+
+ if (newsize > BUFFER_SIZE) {
+ fprintf(stderr,"[ERR] Input file too big for buffer\n");
+ close(infile);
+ return -1;
+ }
+
+ /* Check if we have enough space */
+ /* TODO: Check the size of the partition. */
+ if (ipod->nimages > 1) {
+ bytesavailable=ipod->ipod_directory[1].devOffset-ipod->ipod_directory[0].devOffset;
+ if (bytesavailable < newsize) {
+ fprintf(stderr,"[INFO] Moving images to create room for new firmware...\n");
+
+ /* TODO: Implement image movement */
+ fprintf(stderr,"[ERR] Image movement not yet implemented.\n");
+ close(infile);
+ return -1;
+ }
+ }
+
+ fprintf(stderr,"[INFO] Reading input file...\n");
+ /* We now know we have enough space, so write it. */
+ memset(sectorbuf+length,0,newsize-length);
+ n = read(infile,sectorbuf,length);
+ if (n < 0) {
+ fprintf(stderr,"[ERR] Couldn't read input file\n");
+ close(infile);
+ return -1;
+ }
+ close(infile);
+
+ if (type==FILETYPE_DOT_IPOD) {
+ chksum = ipod->modelnum;
+ for (i = 0; i < length; i++) {
+ /* add 8 unsigned bits but keep a 32 bit sum */
+ chksum += sectorbuf[i];
+ }
+
+ if (chksum == filechksum) {
+ fprintf(stderr,"[INFO] Checksum OK in %s\n",filename);
+ } else {
+ fprintf(stderr,"[ERR] Checksum in %s failed check\n",filename);
+ return -1;
+ }
+ }
+
+ if (ipod_seek(ipod, ipod->fwoffset+ipod->ipod_directory[0].devOffset) < 0) {
+ fprintf(stderr,"[ERR] Seek failed\n");
+ return -1;
+ }
+
+ if ((n = ipod_write(ipod,sectorbuf,newsize)) < 0) {
+ perror("[ERR] Write failed\n");
+ return -1;
+ }
+
+ if (n < newsize) {
+ fprintf(stderr,"[ERR] Short write - requested %d bytes, received %d\n"
+ ,i,n);
+ return -1;
+ }
+ fprintf(stderr,"[INFO] Wrote %d bytes to firmware partition\n",n);
+
+ /* Now we need to update the "len", "entryOffset" and "chksum" fields */
+ chksum = 0;
+ for (i = 0; i < length; i++) {
+ /* add 8 unsigned bits but keep a 32 bit sum */
+ chksum += sectorbuf[i];
+ }
+
+ x = ipod->diroffset % ipod->sector_size;
+
+ /* Read directory */
+ if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; }
+
+ n=ipod_read(ipod, sectorbuf, ipod->sector_size);
+ if (n < 0) { return -1; }
+
+ /* Update entries for image 0 */
+ int2le(length,sectorbuf+x+16);
+ int2le(0,sectorbuf+x+24);
+ int2le(chksum,sectorbuf+x+28);
+
+ /* Write directory */
+ if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; }
+ n=ipod_write(ipod, sectorbuf, ipod->sector_size);
+ if (n < 0) { return -1; }
+
+ return 0;
+}
+
+int read_firmware(struct ipod_t* ipod, char* filename)
+{
+ int length;
+ int i;
+ int outfile;
+ int n;
+ unsigned long chksum=0; /* 32 bit checksum - Rockbox .ipod style*/
+ unsigned char header[8]; /* Header for .ipod file */
+
+ if (ipod->ipod_directory[0].entryOffset != 0) {
+ /* We have a bootloader... */
+ length = ipod->ipod_directory[0].entryOffset;
+ } else {
+ length = ipod->ipod_directory[0].len;
+ }
+
+ fprintf(stderr,"[INFO] Reading firmware (%d bytes)\n",length);
+
+ if (ipod_seek(ipod, ipod->fwoffset+ipod->ipod_directory[0].devOffset) < 0) {
+ return -1;
+ }
+
+ i = (length+ipod->sector_size-1) & ~(ipod->sector_size-1);
+ fprintf(stderr,"[INFO] Padding read from 0x%08x to 0x%08x bytes\n",
+ length,i);
+
+ if ((n = ipod_read(ipod,sectorbuf,i)) < 0) {
+ return -1;
+ }
+
+ if (n < i) {
+ fprintf(stderr,"[ERR] Short read - requested %d bytes, received %d\n",
+ i,n);
+ return -1;
+ }
+
+ chksum = ipod->modelnum;
+ for (i = 0; i < length; i++) {
+ /* add 8 unsigned bits but keep a 32 bit sum */
+ chksum += sectorbuf[i];
+ }
+
+ int2be(chksum,header);
+ memcpy(header+4, ipod->modelname,4);
+
+ outfile = open(filename,O_CREAT|O_TRUNC|O_WRONLY|O_BINARY,0666);
+ if (outfile < 0) {
+ fprintf(stderr,"[ERR] Couldn't open file %s\n",filename);
+ return -1;
+ }
+
+ write(outfile,header,8);
+ write(outfile,sectorbuf,length);
+ close(outfile);
+
+ return 0;
+}
+
+int read_directory(struct ipod_t* ipod)
+{
+ int n;
+ int x;
+ unsigned char* p;
+ unsigned short version;
+
+ ipod->nimages=0;
+
+ /* Read firmware partition header (first 512 bytes of disk - but
+ let's read a whole sector) */
+
+ if (ipod_seek(ipod, ipod->start) < 0) {
+ fprintf(stderr,"[ERR] Seek to 0x%08x in read_directory() failed.\n",
+ (unsigned int)(ipod->start));
+ return -1;
+ }
+
+ n=ipod_read(ipod, sectorbuf, ipod->sector_size);
+ if (n < 0) {
+ fprintf(stderr,"[ERR] ipod_read(ipod,buf,0x%08x) failed in read_directory()\n", ipod->sector_size);
+ return -1;
+ }
+
+ if (memcmp(sectorbuf,apple_stop_sign,sizeof(apple_stop_sign))!=0) {
+ fprintf(stderr,"[ERR] Firmware partition doesn't contain Apple copyright, aborting.\n");
+ return -1;
+ }
+
+ if (memcmp(sectorbuf+0x100,"]ih[",4)!=0) {
+ fprintf(stderr,"[ERR] Bad firmware directory\n");
+ return -1;
+ }
+
+ version = le2ushort(sectorbuf+0x10a);
+ if ((version != 2) && (version != 3)) {
+ fprintf(stderr,"[ERR] Unknown firmware format version %04x\n",
+ version);
+ }
+ ipod->diroffset=le2int(sectorbuf+0x104) + 0x200;
+
+ /* diroffset may not be sector-aligned */
+ x = ipod->diroffset % ipod->sector_size;
+
+ /* Read directory */
+ if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) {
+ fprintf(stderr,"[ERR] Seek to diroffset (%08x) failed.\n",(unsigned)ipod->diroffset);
+ return -1;
+ }
+
+ n=ipod_read(ipod, sectorbuf, ipod->sector_size);
+ if (n < 0) {
+ fprintf(stderr,"[ERR] Read of directory failed.\n");
+ return -1;
+ }
+
+ p = sectorbuf + x;
+
+ while ((ipod->nimages < MAX_IMAGES) && (p < (sectorbuf + x + 400)) &&
+ (memcmp(p,"!ATA",4)==0)) {
+ p+=4;
+ if (memcmp(p,"soso",4)==0) {
+ ipod->ipod_directory[ipod->nimages].ftype=FTYPE_OSOS;
+ } else if (memcmp(p,"crsr",4)==0) {
+ ipod->ipod_directory[ipod->nimages].ftype=FTYPE_RSRC;
+ } else if (memcmp(p,"dpua",4)==0) {
+ ipod->ipod_directory[ipod->nimages].ftype=FTYPE_AUPD;
+ } else if (memcmp(p,"ebih",4)==0) {
+ ipod->ipod_directory[ipod->nimages].ftype=FTYPE_HIBE;
+ } else {
+ fprintf(stderr,"[ERR] Unknown image type %c%c%c%c\n",
+ p[0],p[1],p[2],p[3]);
+ }
+ p+=4;
+ ipod->ipod_directory[ipod->nimages].id=le2int(p);
+ p+=4;
+ ipod->ipod_directory[ipod->nimages].devOffset=le2int(p);
+ p+=4;
+ ipod->ipod_directory[ipod->nimages].len=le2int(p);
+ p+=4;
+ ipod->ipod_directory[ipod->nimages].addr=le2int(p);
+ p+=4;
+ ipod->ipod_directory[ipod->nimages].entryOffset=le2int(p);
+ p+=4;
+ ipod->ipod_directory[ipod->nimages].chksum=le2int(p);
+ p+=4;
+ ipod->ipod_directory[ipod->nimages].vers=le2int(p);
+ p+=4;
+ ipod->ipod_directory[ipod->nimages].loadAddr=le2int(p);
+ p+=4;
+ ipod->nimages++;
+ }
+
+ if ((ipod->nimages > 1) && (version==2)) {
+ /* The 3g firmware image doesn't appear to have a version, so
+ let's make one up... Note that this is never written back to the
+ ipod, so it's OK to do. */
+
+ if (ipod->ipod_directory[0].vers == 0) { ipod->ipod_directory[0].vers = 3; }
+
+ ipod->fwoffset = ipod->start;
+ } else {
+ ipod->fwoffset = ipod->start + ipod->sector_size;
+ }
+
+ return 0;
+}
+
+int list_images(struct ipod_t* ipod)
+{
+ int i;
+
+ if (verbose) {
+ printf(" Type id devOffset len addr entryOffset chksum vers loadAddr devOffset+len\n");
+ for (i = 0 ; i < ipod->nimages; i++) {
+ printf("%d - %s 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n",i,
+ ftypename[ipod->ipod_directory[i].ftype],
+ ipod->ipod_directory[i].id,
+ ipod->ipod_directory[i].devOffset,
+ ipod->ipod_directory[i].len,
+ ipod->ipod_directory[i].addr,
+ ipod->ipod_directory[i].entryOffset,
+ ipod->ipod_directory[i].chksum,
+ ipod->ipod_directory[i].vers,
+ ipod->ipod_directory[i].loadAddr,
+ ipod->ipod_directory[i].devOffset+((ipod->ipod_directory[i].len+ipod->sector_size-1)&~(ipod->sector_size-1)));
+ }
+ }
+
+ printf("\n");
+ printf("Listing firmware partition contents:\n");
+ printf("\n");
+
+ for (i = 0 ; i < ipod->nimages; i++) {
+ printf("Image %d:\n",i+1);
+ switch(ipod->ipod_directory[i].ftype) {
+ case FTYPE_OSOS:
+ if (ipod->ipod_directory[i].entryOffset==0) {
+ printf(" Main firmware - %d bytes\n",
+ ipod->ipod_directory[i].len);
+ } else {
+ printf(" Main firmware - %d bytes\n",
+ ipod->ipod_directory[i].entryOffset);
+ printf(" Third-party bootloader - %d bytes\n",
+ ipod->ipod_directory[i].len-ipod->ipod_directory[i].entryOffset);
+ }
+ break;
+ default:
+ printf(" %s - %d bytes\n",
+ ftypename[ipod->ipod_directory[i].ftype],
+ ipod->ipod_directory[i].len);
+ }
+ }
+ printf("\n");
+
+ return 0;
+}
+
+int getmodel(struct ipod_t* ipod, int ipod_version)
+{
+ switch (ipod_version) {
+ case 0x02:
+ ipod->modelstr="3rd Generation";
+ ipod->modelnum = 7;
+ ipod->modelname = "ip3g";
+#ifdef WITH_BOOTOBJS
+ ipod->bootloader = ipod3g;
+ ipod->bootloader_len = LEN_ipod3g;
+#endif
+ break;
+ case 0x40:
+ ipod->modelstr="1st Generation Mini";
+ ipod->modelnum = 9;
+ ipod->modelname = "mini";
+#ifdef WITH_BOOTOBJS
+ ipod->bootloader = ipodmini;
+ ipod->bootloader_len = LEN_ipodmini;
+#endif
+ break;
+ case 0x50:
+ ipod->modelstr="4th Generation";
+ ipod->modelnum = 8;
+ ipod->modelname = "ip4g";
+#ifdef WITH_BOOTOBJS
+ ipod->bootloader = ipod4g;
+ ipod->bootloader_len = LEN_ipod4g;
+#endif
+ break;
+ case 0x60:
+ ipod->modelstr="Photo/Color";
+ ipod->modelnum = 3;
+ ipod->modelname = "ipco";
+#ifdef WITH_BOOTOBJS
+ ipod->bootloader = ipodcolor;
+ ipod->bootloader_len = LEN_ipodcolor;
+#endif
+ break;
+ case 0x70:
+ ipod->modelstr="2nd Generation Mini";
+ ipod->modelnum = 11;
+ ipod->modelname = "mn2g";
+#ifdef WITH_BOOTOBJS
+ ipod->bootloader = ipodmini2g;
+ ipod->bootloader_len = LEN_ipodmini2g;
+#endif
+ break;
+ case 0xc0:
+ ipod->modelstr="1st Generation Nano";
+ ipod->modelnum = 4;
+ ipod->modelname = "nano";
+#ifdef WITH_BOOTOBJS
+ ipod->bootloader = ipodnano;
+ ipod->bootloader_len = LEN_ipodnano;
+#endif
+ break;
+ case 0xb0:
+ ipod->modelstr="Video (aka 5th Generation)";
+ ipod->modelnum = 5;
+ ipod->modelname = "ipvd";
+#ifdef WITH_BOOTOBJS
+ ipod->bootloader = ipodvideo;
+ ipod->bootloader_len = LEN_ipodvideo;
+#endif
+ break;
+ default:
+ ipod->modelname = NULL;
+ ipod->modelnum = 0;
+#ifdef WITH_BOOTOBJS
+ ipod->bootloader = NULL;
+ ipod->bootloader_len = 0;
+#endif
+ return -1;
+ }
+ return 0;
+}
+
+int ipod_scan(struct ipod_t* ipod)
+{
+ int i;
+ int n = 0;
+ int ipod_version;
+ char last_ipod[4096];
+
+ printf("[INFO] Scanning disk devices...\n");
+
+ for (i = 0; i <= 25 ; i++) {
+#ifdef __WIN32__
+ sprintf(ipod->diskname,"\\\\.\\PhysicalDrive%d",i);
+#elif defined(linux) || defined (__linux)
+ sprintf(ipod->diskname,"/dev/sd%c",'a'+i);
+#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) \
+ || defined(__bsdi__) || defined(__DragonFly__)
+ sprintf(ipod->diskname,"/dev/da%d",i);
+#elif defined(__APPLE__) && defined(__MACH__)
+ sprintf(ipod->diskname,"/dev/disk%d",i);
+#else
+ #error No disk paths defined for this platform
+#endif
+ if (ipod_open(ipod, 1) < 0) {
+ continue;
+ }
+
+ if (read_partinfo(ipod,1) < 0) {
+ continue;
+ }
+
+ if ((ipod->pinfo[0].start==0) || (ipod->pinfo[0].type != 0)) {
+ continue;
+ }
+
+ if (read_directory(ipod) < 0) {
+ continue;
+ }
+
+ ipod_version=(ipod->ipod_directory[0].vers>>8);
+ if (getmodel(ipod,ipod_version) < 0) {
+ continue;
+ }
+
+#ifdef __WIN32__
+ printf("[INFO] Ipod found - %s (\"%s\") - disk device %d\n",
+ ipod->modelstr,ipod->macpod ? "macpod" : "winpod",i);
+#else
+ printf("[INFO] Ipod found - %s (\"%s\") - %s\n",
+ ipod->modelstr,ipod->macpod ? "macpod" : "winpod",ipod->diskname);
+#endif
+ n++;
+ strcpy(last_ipod,ipod->diskname);
+ ipod_close(ipod);
+ }
+
+ if (n==1) {
+ /* Remember the disk name */
+ strcpy(ipod->diskname,last_ipod);
+ }
+ return n;
+}
diff --git a/rbutil/ipodpatcher/ipodpatcher.h b/rbutil/ipodpatcher/ipodpatcher.h
new file mode 100644
index 0000000000..c533f4c2dc
--- /dev/null
+++ b/rbutil/ipodpatcher/ipodpatcher.h
@@ -0,0 +1,51 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id: ipodpatcher.c 12237 2007-02-08 21:31:38Z dave $
+ *
+ * Copyright (C) 2006-2007 Dave Chapman
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#ifndef _IPODPATCHER_H
+#define _IPODPATCHER_H
+
+#include "ipodio.h"
+
+/* Size of buffer for disk I/O - 8MB is large enough for any version
+ of the Apple firmware, but not the Nano's RSRC image. */
+#define BUFFER_SIZE 8*1024*1024
+extern unsigned char* sectorbuf;
+
+#define FILETYPE_DOT_IPOD 0
+#define FILETYPE_DOT_BIN 1
+#ifdef WITH_BOOTOBJS
+ #define FILETYPE_INTERNAL 2
+#endif
+
+void display_partinfo(struct ipod_t* ipod);
+int read_partinfo(struct ipod_t* ipod, int silent);
+int read_partition(struct ipod_t* ipod, int outfile);
+int write_partition(struct ipod_t* ipod, int infile);
+int diskmove(struct ipod_t* ipod, int delta);
+int add_bootloader(struct ipod_t* ipod, char* filename, int type);
+int delete_bootloader(struct ipod_t* ipod);
+int write_firmware(struct ipod_t* ipod, char* filename, int type);
+int read_firmware(struct ipod_t* ipod, char* filename);
+int read_directory(struct ipod_t* ipod);
+int list_images(struct ipod_t* ipod);
+int getmodel(struct ipod_t* ipod, int ipod_version);
+int ipod_scan(struct ipod_t* ipod);
+off_t filesize(int fd);
+
+#endif
diff --git a/rbutil/ipodpatcher/main.c b/rbutil/ipodpatcher/main.c
new file mode 100644
index 0000000000..d183b9bc52
--- /dev/null
+++ b/rbutil/ipodpatcher/main.c
@@ -0,0 +1,429 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id: ipodpatcher.c 12237 2007-02-08 21:31:38Z dave $
+ *
+ * Copyright (C) 2006-2007 Dave Chapman
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "ipodpatcher.h"
+#include "ipodio.h"
+
+#define VERSION "0.8 with r12194-070204 bootloaders"
+
+int verbose = 0;
+
+enum {
+ NONE,
+#ifdef WITH_BOOTOBJS
+ INSTALL,
+#endif
+ INTERACTIVE,
+ SHOW_INFO,
+ LIST_IMAGES,
+ DELETE_BOOTLOADER,
+ ADD_BOOTLOADER,
+ READ_FIRMWARE,
+ WRITE_FIRMWARE,
+ READ_PARTITION,
+ WRITE_PARTITION
+};
+
+void print_macpod_warning(void)
+{
+ printf("[INFO] ************************************************************************\n");
+ printf("[INFO] *** WARNING FOR ROCKBOX USERS\n");
+ printf("[INFO] *** You must convert this ipod to FAT32 format (aka a \"winpod\")\n");
+ printf("[INFO] *** if you want to run Rockbox. Rockbox WILL NOT work on this ipod.\n");
+ printf("[INFO] *** See http://www.rockbox.org/twiki/bin/view/Main/IpodConversionToFAT32\n");
+ printf("[INFO] ************************************************************************\n");
+}
+
+void print_usage(void)
+{
+ fprintf(stderr,"Usage: ipodpatcher --scan\n");
+#ifdef __WIN32__
+ fprintf(stderr," or ipodpatcher [DISKNO] [action]\n");
+#else
+ fprintf(stderr," or ipodpatcher [device] [action]\n");
+#endif
+ fprintf(stderr,"\n");
+ fprintf(stderr,"Where [action] is one of the following options:\n");
+#ifdef WITH_BOOTOBJS
+ fprintf(stderr," --install\n");
+#endif
+ fprintf(stderr," -l, --list\n");
+ fprintf(stderr," -r, --read-partition bootpartition.bin\n");
+ fprintf(stderr," -w, --write-partition bootpartition.bin\n");
+ fprintf(stderr," -rf, --read-firmware filename.ipod\n");
+ fprintf(stderr," -wf, --write-firmware filename.ipod\n");
+ fprintf(stderr," -wfb, --write-firmware-bin filename.bin\n");
+ fprintf(stderr," -a, --add-bootloader filename.ipod\n");
+ fprintf(stderr," -ab, --add-bootloader-bin filename.bin\n");
+ fprintf(stderr," -d, --delete-bootloader\n");
+ fprintf(stderr,"\n");
+
+#ifdef __WIN32__
+ fprintf(stderr,"DISKNO is the number (e.g. 2) Windows has assigned to your ipod's hard disk.\n");
+ fprintf(stderr,"The first hard disk in your computer (i.e. C:\\) will be disk 0, the next disk\n");
+ fprintf(stderr,"will be disk 1 etc. ipodpatcher will refuse to access a disk unless it\n");
+ fprintf(stderr,"can identify it as being an ipod.\n");
+ fprintf(stderr,"\n");
+#else
+#if defined(linux) || defined (__linux)
+ fprintf(stderr,"\"device\" is the device node (e.g. /dev/sda) assigned to your ipod.\n");
+#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
+ fprintf(stderr,"\"device\" is the device node (e.g. /dev/da1) assigned to your ipod.\n");
+#elif defined(__APPLE__) && defined(__MACH__)
+ fprintf(stderr,"\"device\" is the device node (e.g. /dev/disk1) assigned to your ipod.\n");
+#endif
+ fprintf(stderr,"ipodpatcher will refuse to access a disk unless it can identify it as being\n");
+ fprintf(stderr,"an ipod.\n");
+#endif
+}
+
+int main(int argc, char* argv[])
+{
+#ifdef WITH_BOOTOBJS
+ char yesno[4];
+#endif
+ int i;
+ int n;
+ int infile, outfile;
+ unsigned int inputsize;
+ char* filename;
+ int action = SHOW_INFO;
+ int type;
+ struct ipod_t ipod;
+
+ fprintf(stderr,"ipodpatcher v" VERSION " - (C) Dave Chapman 2006-2007\n");
+ fprintf(stderr,"This is free software; see the source for copying conditions. There is NO\n");
+ fprintf(stderr,"warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n");
+
+ if ((argc > 1) && ((strcmp(argv[1],"-h")==0) || (strcmp(argv[1],"--help")==0))) {
+ print_usage();
+ return 1;
+ }
+
+ if (ipod_alloc_buffer(&sectorbuf,BUFFER_SIZE) < 0) {
+ fprintf(stderr,"Failed to allocate memory buffer\n");
+ }
+
+ if ((argc > 1) && (strcmp(argv[1],"--scan")==0)) {
+ if (ipod_scan(&ipod) == 0)
+ fprintf(stderr,"[ERR] No ipods found.\n");
+ return 0;
+ }
+
+ /* If the first parameter doesn't start with -, then we interpret it as a device */
+ if ((argc > 1) && (argv[1][0] != '-')) {
+ ipod.diskname[0]=0;
+#ifdef __WIN32__
+ snprintf(ipod.diskname,sizeof(ipod.diskname),"\\\\.\\PhysicalDrive%s",argv[1]);
+#else
+ strncpy(ipod.diskname,argv[1],sizeof(ipod.diskname));
+#endif
+ i = 2;
+ } else {
+ /* Autoscan for ipods */
+ n = ipod_scan(&ipod);
+ if (n==0) {
+ fprintf(stderr,"[ERR] No ipods found, aborting\n");
+ fprintf(stderr,"[ERR] Please connect your ipod and ensure it is in disk mode\n");
+#if defined(__APPLE__) && defined(__MACH__)
+ fprintf(stderr,"[ERR] Also ensure that itunes is closed, and that your ipod is not mounted.\n");
+#elif !defined(__WIN32__)
+ if (geteuid()!=0) {
+ fprintf(stderr,"[ERR] You may also need to run ipodpatcher as root.\n");
+ }
+#endif
+ fprintf(stderr,"[ERR] Please refer to the Rockbox manual if you continue to have problems.\n");
+ } else if (n > 1) {
+ fprintf(stderr,"[ERR] %d ipods found, aborting\n",n);
+ fprintf(stderr,"[ERR] Please connect only one ipod and re-run ipodpatcher.\n");
+ }
+
+ if (n != 1) {
+#ifdef WITH_BOOTOBJS
+ if (argc==1) {
+ printf("\nPress ENTER to exit ipodpatcher :");
+ fgets(yesno,4,stdin);
+ }
+#endif
+ return 0;
+ }
+
+ i = 1;
+ }
+
+#ifdef WITH_BOOTOBJS
+ action = INTERACTIVE;
+#else
+ action = NONE;
+#endif
+
+ while (i < argc) {
+ if ((strcmp(argv[i],"-l")==0) || (strcmp(argv[i],"--list")==0)) {
+ action = LIST_IMAGES;
+ i++;
+#ifdef WITH_BOOTOBJS
+ } else if (strcmp(argv[i],"--install")==0) {
+ action = INSTALL;
+ i++;
+#endif
+ } else if ((strcmp(argv[i],"-d")==0) ||
+ (strcmp(argv[i],"--delete-bootloader")==0)) {
+ action = DELETE_BOOTLOADER;
+ i++;
+ } else if ((strcmp(argv[i],"-a")==0) ||
+ (strcmp(argv[i],"--add-bootloader")==0)) {
+ action = ADD_BOOTLOADER;
+ type = FILETYPE_DOT_IPOD;
+ i++;
+ if (i == argc) { print_usage(); return 1; }
+ filename=argv[i];
+ i++;
+ } else if ((strcmp(argv[i],"-ab")==0) ||
+ (strcmp(argv[i],"--add-bootloader-bin")==0)) {
+ action = ADD_BOOTLOADER;
+ type = FILETYPE_DOT_BIN;
+ i++;
+ if (i == argc) { print_usage(); return 1; }
+ filename=argv[i];
+ i++;
+ } else if ((strcmp(argv[i],"-rf")==0) ||
+ (strcmp(argv[i],"--read-firmware")==0)) {
+ action = READ_FIRMWARE;
+ i++;
+ if (i == argc) { print_usage(); return 1; }
+ filename=argv[i];
+ i++;
+ } else if ((strcmp(argv[i],"-wf")==0) ||
+ (strcmp(argv[i],"--write-firmware")==0)) {
+ action = WRITE_FIRMWARE;
+ type = FILETYPE_DOT_IPOD;
+ i++;
+ if (i == argc) { print_usage(); return 1; }
+ filename=argv[i];
+ i++;
+ } else if ((strcmp(argv[i],"-wfb")==0) ||
+ (strcmp(argv[i],"--write-firmware-bin")==0)) {
+ action = WRITE_FIRMWARE;
+ type = FILETYPE_DOT_BIN;
+ i++;
+ if (i == argc) { print_usage(); return 1; }
+ filename=argv[i];
+ i++;
+ } else if ((strcmp(argv[i],"-r")==0) ||
+ (strcmp(argv[i],"--read-partition")==0)) {
+ action = READ_PARTITION;
+ i++;
+ if (i == argc) { print_usage(); return 1; }
+ filename=argv[i];
+ i++;
+ } else if ((strcmp(argv[i],"-w")==0) ||
+ (strcmp(argv[i],"--write-partition")==0)) {
+ action = WRITE_PARTITION;
+ i++;
+ if (i == argc) { print_usage(); return 1; }
+ filename=argv[i];
+ i++;
+ } else if ((strcmp(argv[i],"-v")==0) ||
+ (strcmp(argv[i],"--verbose")==0)) {
+ verbose++;
+ i++;
+ } else {
+ print_usage(); return 1;
+ }
+ }
+
+ if (ipod.diskname[0]==0) {
+ print_usage();
+ return 1;
+ }
+
+ if (ipod_open(&ipod, 0) < 0) {
+ return 1;
+ }
+
+ fprintf(stderr,"[INFO] Reading partition table from %s\n",ipod.diskname);
+ fprintf(stderr,"[INFO] Sector size is %d bytes\n",ipod.sector_size);
+
+ if (read_partinfo(&ipod,0) < 0) {
+ return 2;
+ }
+
+ display_partinfo(&ipod);
+
+ if (ipod.pinfo[0].start==0) {
+ fprintf(stderr,"[ERR] No partition 0 on disk:\n");
+ display_partinfo(&ipod);
+ return 3;
+ }
+
+ read_directory(&ipod);
+
+ if (ipod.nimages <= 0) {
+ fprintf(stderr,"[ERR] Failed to read firmware directory - nimages=%d\n",ipod.nimages);
+ return 1;
+ }
+
+ if (getmodel(&ipod,(ipod.ipod_directory[0].vers>>8)) < 0) {
+ fprintf(stderr,"[ERR] Unknown version number in firmware (%08x)\n",
+ ipod.ipod_directory[0].vers);
+ return -1;
+ }
+
+ printf("[INFO] Ipod model: %s (\"%s\")\n",ipod.modelstr,
+ ipod.macpod ? "macpod" : "winpod");
+
+ if (ipod.macpod) {
+ print_macpod_warning();
+ }
+
+ if (action==LIST_IMAGES) {
+ list_images(&ipod);
+#ifdef WITH_BOOTOBJS
+ } else if (action==INTERACTIVE) {
+
+ printf("Do you wish to install the rockbox bootloader? (y/n) :");
+ if (fgets(yesno,4,stdin)) {
+ if (yesno[0]=='y') {
+ if (ipod_reopen_rw(&ipod) < 0) {
+ return 5;
+ }
+
+ if (add_bootloader(&ipod, NULL, FILETYPE_INTERNAL)==0) {
+ fprintf(stderr,"[INFO] Bootloader installed successfully.\n");
+ } else {
+ fprintf(stderr,"[ERR] --install failed.\n");
+ }
+ }
+ }
+#endif
+ } else if (action==DELETE_BOOTLOADER) {
+ if (ipod_reopen_rw(&ipod) < 0) {
+ return 5;
+ }
+
+ if (ipod.ipod_directory[0].entryOffset==0) {
+ fprintf(stderr,"[ERR] No bootloader detected.\n");
+ } else {
+ if (delete_bootloader(&ipod)==0) {
+ fprintf(stderr,"[INFO] Bootloader removed.\n");
+ } else {
+ fprintf(stderr,"[ERR] --delete-bootloader failed.\n");
+ }
+ }
+ } else if (action==ADD_BOOTLOADER) {
+ if (ipod_reopen_rw(&ipod) < 0) {
+ return 5;
+ }
+
+ if (add_bootloader(&ipod, filename, type)==0) {
+ fprintf(stderr,"[INFO] Bootloader %s written to device.\n",filename);
+ } else {
+ fprintf(stderr,"[ERR] --add-bootloader failed.\n");
+ }
+#ifdef WITH_BOOTOBJS
+ } else if (action==INSTALL) {
+ if (ipod_reopen_rw(&ipod) < 0) {
+ return 5;
+ }
+
+ if (add_bootloader(&ipod, NULL, FILETYPE_INTERNAL)==0) {
+ fprintf(stderr,"[INFO] Bootloader installed successfully.\n");
+ } else {
+ fprintf(stderr,"[ERR] --install failed.\n");
+ }
+#endif
+ } else if (action==WRITE_FIRMWARE) {
+ if (ipod_reopen_rw(&ipod) < 0) {
+ return 5;
+ }
+
+ if (write_firmware(&ipod, filename,type)==0) {
+ fprintf(stderr,"[INFO] Firmware %s written to device.\n",filename);
+ } else {
+ fprintf(stderr,"[ERR] --write-firmware failed.\n");
+ }
+ } else if (action==READ_FIRMWARE) {
+ if (read_firmware(&ipod, filename)==0) {
+ fprintf(stderr,"[INFO] Firmware read to file %s.\n",filename);
+ } else {
+ fprintf(stderr,"[ERR] --read-firmware failed.\n");
+ }
+ } else if (action==READ_PARTITION) {
+ outfile = open(filename,O_CREAT|O_TRUNC|O_WRONLY|O_BINARY,S_IREAD|S_IWRITE);
+ if (outfile < 0) {
+ perror(filename);
+ return 4;
+ }
+
+ if (read_partition(&ipod, outfile) < 0) {
+ fprintf(stderr,"[ERR] --read-partition failed.\n");
+ } else {
+ fprintf(stderr,"[INFO] Partition extracted to %s.\n",filename);
+ }
+ close(outfile);
+ } else if (action==WRITE_PARTITION) {
+ if (ipod_reopen_rw(&ipod) < 0) {
+ return 5;
+ }
+
+ infile = open(filename,O_RDONLY|O_BINARY);
+ if (infile < 0) {
+ perror(filename);
+ return 2;
+ }
+
+ /* Check filesize is <= partition size */
+ inputsize=filesize(infile);
+ if (inputsize > 0) {
+ if (inputsize <= (ipod.pinfo[0].size*ipod.sector_size)) {
+ fprintf(stderr,"[INFO] Input file is %u bytes\n",inputsize);
+ if (write_partition(&ipod,infile) < 0) {
+ fprintf(stderr,"[ERR] --write-partition failed.\n");
+ } else {
+ fprintf(stderr,"[INFO] %s restored to partition\n",filename);
+ }
+ } else {
+ fprintf(stderr,"[ERR] File is too large for firmware partition, aborting.\n");
+ }
+ }
+
+ close(infile);
+ }
+
+ ipod_close(&ipod);
+
+#ifdef WITH_BOOTOBJS
+ if (action==INTERACTIVE) {
+ printf("Press ENTER to exit ipodpatcher :");
+ fgets(yesno,4,stdin);
+ }
+#endif
+
+
+ return 0;
+}
diff --git a/rbutil/ipodpatcher/parttypes.h b/rbutil/ipodpatcher/parttypes.h
new file mode 100644
index 0000000000..f8de303553
--- /dev/null
+++ b/rbutil/ipodpatcher/parttypes.h
@@ -0,0 +1,109 @@
+/* DOS partition types - taken from fdisk */
+
+struct parttype {
+ unsigned char type;
+ char *name;
+};
+
+struct parttype parttypes[] = {
+ {0x00, "Empty"},
+ {0x01, "FAT12"},
+ {0x02, "XENIX root"},
+ {0x03, "XENIX usr"},
+ {0x04, "FAT16 <32M"},
+ {0x05, "Extended"}, /* DOS 3.3+ extended partition */
+ {0x06, "FAT16"}, /* DOS 16-bit >=32M */
+ {0x07, "HPFS/NTFS"}, /* OS/2 IFS, eg, HPFS or NTFS or QNX */
+ {0x08, "AIX"}, /* AIX boot (AIX -- PS/2 port) or SplitDrive */
+ {0x09, "AIX bootable"}, /* AIX data or Coherent */
+ {0x0a, "OS/2 Boot Manager"},/* OS/2 Boot Manager */
+ {0x0b, "W95 FAT32"},
+ {0x0c, "W95 FAT32 (LBA)"},/* LBA really is `Extended Int 13h' */
+ {0x0e, "W95 FAT16 (LBA)"},
+ {0x0f, "W95 Ext'd (LBA)"},
+ {0x10, "OPUS"},
+ {0x11, "Hidden FAT12"},
+ {0x12, "Compaq diagnostics"},
+ {0x14, "Hidden FAT16 <32M"},
+ {0x16, "Hidden FAT16"},
+ {0x17, "Hidden HPFS/NTFS"},
+ {0x18, "AST SmartSleep"},
+ {0x1b, "Hidden W95 FAT32"},
+ {0x1c, "Hidden W95 FAT32 (LBA)"},
+ {0x1e, "Hidden W95 FAT16 (LBA)"},
+ {0x24, "NEC DOS"},
+ {0x39, "Plan 9"},
+ {0x3c, "PartitionMagic recovery"},
+ {0x40, "Venix 80286"},
+ {0x41, "PPC PReP Boot"},
+ {0x42, "SFS"},
+ {0x4d, "QNX4.x"},
+ {0x4e, "QNX4.x 2nd part"},
+ {0x4f, "QNX4.x 3rd part"},
+ {0x50, "OnTrack DM"},
+ {0x51, "OnTrack DM6 Aux1"}, /* (or Novell) */
+ {0x52, "CP/M"}, /* CP/M or Microport SysV/AT */
+ {0x53, "OnTrack DM6 Aux3"},
+ {0x54, "OnTrackDM6"},
+ {0x55, "EZ-Drive"},
+ {0x56, "Golden Bow"},
+ {0x5c, "Priam Edisk"},
+ {0x61, "SpeedStor"},
+ {0x63, "GNU HURD or SysV"}, /* GNU HURD or Mach or Sys V/386 (such as ISC UNIX) */
+ {0x64, "Novell Netware 286"},
+ {0x65, "Novell Netware 386"},
+ {0x70, "DiskSecure Multi-Boot"},
+ {0x75, "PC/IX"},
+ {0x80, "Old Minix"}, /* Minix 1.4a and earlier */
+ {0x81, "Minix / old Linux"},/* Minix 1.4b and later */
+ {0x82, "Linux swap / Solaris"},
+ {0x83, "Linux"},
+ {0x84, "OS/2 hidden C: drive"},
+ {0x85, "Linux extended"},
+ {0x86, "NTFS volume set"},
+ {0x87, "NTFS volume set"},
+ {0x88, "Linux plaintext"},
+ {0x8e, "Linux LVM"},
+ {0x93, "Amoeba"},
+ {0x94, "Amoeba BBT"}, /* (bad block table) */
+ {0x9f, "BSD/OS"}, /* BSDI */
+ {0xa0, "IBM Thinkpad hibernation"},
+ {0xa5, "FreeBSD"}, /* various BSD flavours */
+ {0xa6, "OpenBSD"},
+ {0xa7, "NeXTSTEP"},
+ {0xa8, "Darwin UFS"},
+ {0xa9, "NetBSD"},
+ {0xab, "Darwin boot"},
+ {0xb7, "BSDI fs"},
+ {0xb8, "BSDI swap"},
+ {0xbb, "Boot Wizard hidden"},
+ {0xbe, "Solaris boot"},
+ {0xbf, "Solaris"},
+ {0xc1, "DRDOS/sec (FAT-12)"},
+ {0xc4, "DRDOS/sec (FAT-16 < 32M)"},
+ {0xc6, "DRDOS/sec (FAT-16)"},
+ {0xc7, "Syrinx"},
+ {0xda, "Non-FS data"},
+ {0xdb, "CP/M / CTOS / ..."},/* CP/M or Concurrent CP/M or
+ Concurrent DOS or CTOS */
+ {0xde, "Dell Utility"}, /* Dell PowerEdge Server utilities */
+ {0xdf, "BootIt"}, /* BootIt EMBRM */
+ {0xe1, "DOS access"}, /* DOS access or SpeedStor 12-bit FAT
+ extended partition */
+ {0xe3, "DOS R/O"}, /* DOS R/O or SpeedStor */
+ {0xe4, "SpeedStor"}, /* SpeedStor 16-bit FAT extended
+ partition < 1024 cyl. */
+ {0xeb, "BeOS fs"},
+ {0xee, "EFI GPT"}, /* Intel EFI GUID Partition Table */
+ {0xef, "EFI (FAT-12/16/32)"},/* Intel EFI System Partition */
+ {0xf0, "Linux/PA-RISC boot"},/* Linux/PA-RISC boot loader */
+ {0xf1, "SpeedStor"},
+ {0xf4, "SpeedStor"}, /* SpeedStor large partition */
+ {0xf2, "DOS secondary"}, /* DOS 3.3+ secondary */
+ {0xfd, "Linux raid autodetect"},/* New (2.2.x) raid partition with
+ autodetect using persistent
+ superblock */
+ {0xfe, "LANstep"}, /* SpeedStor >1024 cyl. or LANstep */
+ {0xff, "BBT"}, /* Xenix Bad Block Table */
+ { 0, 0 }
+};