From 4b7e1e09450b9132b2e30395d2cd73be618e1255 Mon Sep 17 00:00:00 2001 From: Dave Chapman Date: Wed, 13 Dec 2006 09:02:18 +0000 Subject: Work-in-progress towards a cross-platform ipodpatcher which will edit the firmware partition directly, incorporating the ipod_fw.c functionality. Tested successfully on win32 and Linux but it only lists the contents of the firmware partition at the moment - no actual reading or writing git-svn-id: svn://svn.rockbox.org/rockbox/trunk@11748 a1c6a512-1295-4272-9138-f99709370657 --- tools/ipodpatcher/Makefile | 11 +- tools/ipodpatcher/ipodio-posix.c | 96 +++++++++ tools/ipodpatcher/ipodio-win32.c | 190 ++++++++++++++++ tools/ipodpatcher/ipodio.h | 39 ++++ tools/ipodpatcher/ipodpatcher.c | 454 ++++++++++++++++++++++++--------------- 5 files changed, 618 insertions(+), 172 deletions(-) create mode 100644 tools/ipodpatcher/ipodio-posix.c create mode 100644 tools/ipodpatcher/ipodio-win32.c create mode 100644 tools/ipodpatcher/ipodio.h (limited to 'tools/ipodpatcher') diff --git a/tools/ipodpatcher/Makefile b/tools/ipodpatcher/Makefile index 6eb3dce75e..21994de754 100644 --- a/tools/ipodpatcher/Makefile +++ b/tools/ipodpatcher/Makefile @@ -1,8 +1,11 @@ -all: ipodpatcher.exe +all: ipodpatcher -ipodpatcher.exe: ipodpatcher.c - i586-mingw32msvc-gcc -Wall -o ipodpatcher.exe ipodpatcher.c +ipodpatcher: ipodpatcher.c ipodio-posix.c parttypes.h + gcc -Wall -o ipodpatcher ipodpatcher.c ipodio-posix.c + +ipodpatcher.exe: ipodpatcher.c ipodio-win32.c parttypes.h + i586-mingw32msvc-gcc -Wall -o ipodpatcher.exe ipodpatcher.c ipodio-win32.c i586-mingw32msvc-strip ipodpatcher.exe clean: - rm -f ipodpatcher.exe *~ + rm -f ipodpatcher.exe ipodpatcher *~ diff --git a/tools/ipodpatcher/ipodio-posix.c b/tools/ipodpatcher/ipodio-posix.c new file mode 100644 index 0000000000..cfded35390 --- /dev/null +++ b/tools/ipodpatcher/ipodio-posix.c @@ -0,0 +1,96 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2006 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 +#include +#include +#include +#include +#include +#include + +#include "ipodio.h" + +void print_error(char* msg) +{ + perror(msg); +} + +int ipod_open(HANDLE* dh, char* diskname, int* sector_size) +{ + *dh=open(diskname,O_RDONLY); + if (*dh < 0) { + perror(diskname); + return -1; + } + + /* TODO: Detect sector size */ + *sector_size = 512; + + return 0; +} + + +int ipod_reopen_rw(HANDLE* dh, char* diskname) +{ + close(*dh); + *dh=open(diskname,O_RDWR); + if (*dh < 0) { + perror(diskname); + return -1; + } + return 0; +} + +int ipod_close(HANDLE dh) +{ + close(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(HANDLE dh, unsigned long pos) +{ + off_t res; + + res = lseek(dh, pos, SEEK_SET); + + if (res == -1) { + return -1; + } + return 0; +} + +int ipod_read(HANDLE dh, unsigned char* buf, int nbytes) +{ + return read(dh, buf, nbytes); +} + +int ipod_write(HANDLE dh, unsigned char* buf, int nbytes) +{ + return write(dh, buf, nbytes); +} diff --git a/tools/ipodpatcher/ipodio-win32.c b/tools/ipodpatcher/ipodio-win32.c new file mode 100644 index 0000000000..4914e4b6cd --- /dev/null +++ b/tools/ipodpatcher/ipodio-win32.c @@ -0,0 +1,190 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2006 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 +#include +#include +#include +#include +#include +#include +#ifdef __WIN32__ +#include +#include +#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(HANDLE* dh, char* diskname, int* sector_size) +{ + DISK_GEOMETRY_EX diskgeometry_ex; + DISK_GEOMETRY diskgeometry; + unsigned long n; + + *dh = CreateFile(diskname, GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, + FILE_FLAG_WRITE_THROUGH | FILE_FLAG_NO_BUFFERING, NULL); + + if (*dh == INVALID_HANDLE_VALUE) { + print_error(" Error opening disk: "); + return -1; + } + + if (!lock_volume(*dh)) { + print_error(" Error locking disk: "); + return -1; + } + + if (!DeviceIoControl(*dh, + IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, + NULL, + 0, + &diskgeometry_ex, + sizeof(diskgeometry_ex), + &n, + NULL)) { + if (!DeviceIoControl(*dh, + IOCTL_DISK_GET_DRIVE_GEOMETRY, + NULL, + 0, + &diskgeometry, + sizeof(diskgeometry), + &n, + NULL)) { + print_error(" Error reading disk geometry: "); + return -1; + } else { + *sector_size=diskgeometry.BytesPerSector; + } + } else { + *sector_size=diskgeometry_ex.Geometry.BytesPerSector; + } + + return 0; +} + +int ipod_reopen_rw(HANDLE* dh, char* diskname) +{ + /* Close existing file and re-open for writing */ + unlock_volume(*dh); + CloseHandle(*dh); + + *dh = CreateFile(diskname, GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, + FILE_FLAG_WRITE_THROUGH | FILE_FLAG_NO_BUFFERING, NULL); + + if (*dh == INVALID_HANDLE_VALUE) { + print_error(" Error opening disk: "); + return -1; + } + + if (!lock_volume(*dh)) { + print_error(" Error locking disk: "); + return -1; + } + + return 0; +} + +int ipod_close(HANDLE dh) +{ + unlock_volume(dh); + CloseHandle(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 = VirtualAlloc(NULL, bufsize, MEM_COMMIT, PAGE_READWRITE); + if (*sectorbuf == NULL) { + print_error(" Error allocating a buffer: "); + return -1; + } + return 0; +} + +int ipod_seek(HANDLE dh, unsigned long pos) +{ + if (SetFilePointer(dh, pos, NULL, FILE_BEGIN)==0xffffffff) { + print_error(" Seek error "); + return -1; + } + return 0; +} + +int ipod_read(HANDLE dh, unsigned char* buf, int nbytes) +{ + unsigned long count; + + if (!ReadFile(dh, buf, nbytes, &count, NULL)) { + print_error(" Error reading from disk: "); + return -1; + } + + return count; +} + +int ipod_write(HANDLE dh, unsigned char* buf, int nbytes) +{ + unsigned long count; + + if (!WriteFile(dh, buf, nbytes, &count, NULL)) { + print_error(" Error writing to disk: "); + return -1; + } + + return count; +} diff --git a/tools/ipodpatcher/ipodio.h b/tools/ipodpatcher/ipodio.h new file mode 100644 index 0000000000..8496766b76 --- /dev/null +++ b/tools/ipodpatcher/ipodio.h @@ -0,0 +1,39 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2006 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 + +#ifdef __WIN32__ +#include +#else +#define HANDLE int +#define O_BINARY 0 +#endif + +void print_error(char* msg); +int ipod_open(HANDLE* dh, char* diskname, int* sector_size); +int ipod_reopen_rw(HANDLE* dh, char* diskname); +int ipod_close(HANDLE dh); +int ipod_seek(HANDLE dh, unsigned long pos); +int ipod_read(HANDLE dh, unsigned char* buf, int nbytes); +int ipod_write(HANDLE dh, unsigned char* buf, int nbytes); +int ipod_alloc_buffer(unsigned char** sectorbuf, int bufsize); + +#endif diff --git a/tools/ipodpatcher/ipodpatcher.c b/tools/ipodpatcher/ipodpatcher.c index 32c1291ab4..f965746282 100644 --- a/tools/ipodpatcher/ipodpatcher.c +++ b/tools/ipodpatcher/ipodpatcher.c @@ -9,12 +9,6 @@ * * Copyright (C) 2006 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. * @@ -28,17 +22,45 @@ #include #include #include +#include #include #include -#include -#include #include "parttypes.h" +#include "ipodio.h" + +#define VERSION "0.5" + +//#define DEBUG + +/* 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.----------"\ + "----------------"\ + "----------------"\ + "----------------"\ + "----------------"\ + "----------------"\ + "---------------"; + +/* The maximum number of images in a firmware partition - a guess... */ +#define MAX_IMAGES 10 /* 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 in main() + and initialise it with ipod_alloc_buf() */ + +/* Size of buffer for disk I/O */ +#define BUFFER_SIZE 6*1024*1024 unsigned char* sectorbuf; char* get_parttype(int pt) @@ -57,35 +79,6 @@ char* get_parttype(int pt) return unknown; } -void 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 lock_volume(HANDLE hDisk) -{ - DWORD dummy; - - return DeviceIoControl(hDisk, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, - &dummy, NULL); -} - -int unlock_volume(HANDLE hDisk) -{ - DWORD dummy; - - return DeviceIoControl(hDisk, FSCTL_UNLOCK_VOLUME, NULL, 0, NULL, 0, - &dummy, NULL); -} - off_t filesize(int fd) { struct stat buf; @@ -97,47 +90,67 @@ off_t filesize(int fd) { } } - -/* Size of buffer for disk I/O */ -#define BUFFER_SIZE 32*1024 - /* Partition table parsing code taken from Rockbox */ #define MAX_SECTOR_SIZE 2048 #define SECTOR_SIZE 512 -struct partinfo { +struct partinfo_t { unsigned long start; /* first sector (LBA) */ unsigned long size; /* number of sectors */ unsigned char type; }; -#define BYTES2INT32(array,pos) \ - ((long)array[pos] | ((long)array[pos+1] << 8 ) | \ +int static inline getint32le(unsigned char* buf) +{ + int32_t res = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; + + return res; +} + +int static inline getint16le(char* buf) +{ + int16_t res = (buf[1] << 8) | buf[0]; + + return res; +} + + + +#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 partinfo* pinfo, int sector_size) +void display_partinfo(struct partinfo_t* pinfo, int sector_size) { int i; double sectors_per_MB = (1024.0*1024.0)/sector_size; - printf("Part Start Sector End Sector Size (MB) Type\n"); + printf("[INFO] Part Start Sector End Sector Size (MB) Type\n"); for ( i = 0; i < 4; i++ ) { if (pinfo[i].start != 0) { - printf(" %d %10ld %10ld %10.1f %s (0x%02x)\n",i,pinfo[i].start,pinfo[i].start+pinfo[i].size-1,pinfo[i].size/sectors_per_MB,get_parttype(pinfo[i].type),pinfo[i].type); + printf("[INFO] %d %10ld %10ld %10.1f %s (0x%02x)\n", + i, + pinfo[i].start, + pinfo[i].start+pinfo[i].size-1, + pinfo[i].size/sectors_per_MB, + get_parttype(pinfo[i].type), + pinfo[i].type); } } } -int read_partinfo(HANDLE dh, int sector_size, struct partinfo* pinfo) +int read_partinfo(HANDLE dh, int sector_size, struct partinfo_t* pinfo) { int i; unsigned char sector[MAX_SECTOR_SIZE]; unsigned long count; - if (!ReadFile(dh, sector, sector_size, &count, NULL)) { - error(" Error reading from disk: "); + count = ipod_read(dh,sector,sector_size); + + if (count <= 0) { + print_error(" Error reading from disk: "); return -1; } @@ -180,8 +193,7 @@ int disk_read(HANDLE dh, int outfile,unsigned long start, unsigned long count, fprintf(stderr,"[INFO] Seeking to sector %ld\n",start); - if (SetFilePointer(dh, start*sector_size, NULL, FILE_BEGIN)==0xffffffff) { - error(" Seek error "); + if (ipod_seek(dh,start) < 0) { return -1; } @@ -195,8 +207,9 @@ int disk_read(HANDLE dh, int outfile,unsigned long start, unsigned long count, chunksize = bytesleft; } - if (!ReadFile(dh, sectorbuf, chunksize, &n, NULL)) { - error("[ERR] read in disk_read"); + n = ipod_read(dh, sectorbuf, chunksize); + + if (n < 0) { return -1; } @@ -233,8 +246,7 @@ int disk_write(HANDLE dh, int infile,unsigned long start, int sector_size) int eof; int padding = 0; - if (SetFilePointer(dh, start*sector_size, NULL, FILE_BEGIN)==0xffffffff) { - error(" Seek error "); + if (ipod_seek(dh, start*sector_size) < 0) { return -1; } @@ -260,8 +272,10 @@ int disk_write(HANDLE dh, int infile,unsigned long start, int sector_size) bytesread += n; - if (!WriteFile(dh, sectorbuf, n, &res, NULL)) { - error(" Error writing to disk: "); + res = ipod_write(dh, sectorbuf,n); + + if (res < 0) { + print_error(" Error writing to disk: "); fprintf(stderr,"Bytes written: %d\n",byteswritten); return -1; } @@ -280,134 +294,229 @@ int disk_write(HANDLE dh, int infile,unsigned long start, int sector_size) void print_usage(void) { - fprintf(stderr,"Usage: ipodpatcher [-i|r|w] DISKNO [file]\n"); - fprintf(stderr," -i Display iPod's partition information (default)\n"); - fprintf(stderr," -r Read firmware partition to file\n"); - fprintf(stderr," -w Write file to firmware partition\n"); +#ifdef __WIN32__ + fprintf(stderr,"Usage: ipodpatcher DISKNO [action]\n"); +#else + fprintf(stderr,"Usage: ipodpatcher device [action]\n"); +#endif + fprintf(stderr,"\n"); + fprintf(stderr,"Where [action] is one of:\n"); +#if 0 + fprintf(stderr," -e --extract-firmware filename.bin - extract firmware to a file\n"); + fprintf(stderr," -i --insert-firmware filename.bin - replace the firmware with the file\n"); + fprintf(stderr," -a --add-bootloader filename.bin - add a bootloader\n"); + fprintf(stderr," -r --remove-bootloader - remove a bootloader\n"); +#endif + fprintf(stderr," -l --list - list images in firmware partition\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 disk0, 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 + fprintf(stderr,"\"device\" is the device node (e.g. /dev/sda) assigned to your ipod.\n"); + fprintf(stderr,"ipodpatcher will refuse to access a disk unless it can identify it as being\n"); + fprintf(stderr,"an ipod.\n"); +#endif } enum { NONE, SHOW_INFO, - READ, - WRITE + LIST_IMAGES +}; + +char* ftypename[] = { "OSOS", "RSRC", "AUPD", "HIBE" }; + +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; + uint32_t len; + uint32_t addr; + uint32_t entryOffset; + uint32_t chksum; + uint32_t vers; + uint32_t loadAddr; }; +int read_directory(HANDLE dh, int start, int sector_size, struct ipod_directory_t* ipod_directory) +{ + int n; + int nimages; + off_t diroffset; + unsigned char* p; + + /* Read firmware partition header (first 512 bytes of disk - but let's read a whole sector) */ + + if (ipod_seek(dh, start) < 0) { return -1; } + + n=ipod_read(dh, sectorbuf, sector_size); + if (n < 0) { return -1; } + + if (memcmp(sectorbuf,apple_stop_sign,sizeof(apple_stop_sign))!=0) { + fprintf(stderr,"[ERR] Firmware partition doesn't contain Apple copyright, aborting."); + return -1; + } + + if (memcmp(sectorbuf+0x100,"]ih[",4)!=0) { + fprintf(stderr,"[ERR] Bad firmware directory\n"); + return -1; + } + + diroffset=getint32le(sectorbuf+0x104) + 0x200; + + /* Read directory */ + if (ipod_seek(dh,start + diroffset) < 0) { return -1; } + + n=ipod_read(dh, sectorbuf, sector_size); + if (n < 0) { return -1; } + + nimages=0; + p = sectorbuf; + + while ((nimages < MAX_IMAGES) && (p < (sectorbuf + 400)) && (memcmp(p,"!ATA",4)==0)) { + p+=4; + if (memcmp(p,"soso",4)==0) { + ipod_directory[nimages].ftype=FTYPE_OSOS; + } else if (memcmp(p,"crsr",4)==0) { + ipod_directory[nimages].ftype=FTYPE_RSRC; + } else if (memcmp(p,"dpua",4)==0) { + ipod_directory[nimages].ftype=FTYPE_AUPD; + } else if (memcmp(p,"ebih",4)==0) { + ipod_directory[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_directory[nimages].id=getint32le(p); + p+=4; + ipod_directory[nimages].devOffset=getint32le(p); + p+=4; + ipod_directory[nimages].len=getint32le(p); + p+=4; + ipod_directory[nimages].addr=getint32le(p); + p+=4; + ipod_directory[nimages].entryOffset=getint32le(p); + p+=4; + ipod_directory[nimages].chksum=getint32le(p); + p+=4; + ipod_directory[nimages].vers=getint32le(p); + p+=4; + ipod_directory[nimages].loadAddr=getint32le(p); + p+=4; + nimages++; + } + return nimages; +} + +int list_images(int nimages, struct ipod_directory_t* ipod_directory) +{ + int i; + +#ifdef DEBUG + printf(" Type id devOffset len addr entryOffset chksum vers loadAddr\n"); + for (i = 0 ; i < nimages; i++) { + printf("%d - %s 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n",i, + ftypename[ipod_directory[i].ftype], + ipod_directory[i].id, + ipod_directory[i].devOffset, + ipod_directory[i].len, + ipod_directory[i].addr, + ipod_directory[i].entryOffset, + ipod_directory[i].chksum, + ipod_directory[i].vers, + ipod_directory[i].loadAddr); + } +#endif + + printf("\n"); + printf("Listing firmware partition contents:\n"); + printf("\n"); + + for (i = 0 ; i < nimages; i++) { + printf("Image %d:\n",i+1); + switch(ipod_directory[i].ftype) { + case FTYPE_OSOS: + if (ipod_directory[i].entryOffset==0) { + printf(" Main firmware - %d bytes\n",ipod_directory[i].len); + } else { + printf(" Main firmware - %d bytes\n",ipod_directory[i].entryOffset); + printf(" Third-party bootloader - %d bytes\n",ipod_directory[i].len-ipod_directory[i].entryOffset); + } + break; + default: + printf(" %s - %d bytes\n",ftypename[ipod_directory[i].ftype],ipod_directory[i].len); + } + } + printf("\n"); + + return 0; +} + int main(int argc, char* argv[]) { int i; - struct partinfo pinfo[4]; /* space for 4 partitions on 1 drive */ - int res; - unsigned long n; - int outfile; - int infile; - int mode = SHOW_INFO; - int p = 0; - int diskno = -1; + int ipod_version; + struct partinfo_t pinfo[4]; /* space for 4 partitions on 1 drive */ + int nimages; + struct ipod_directory_t ipod_directory[MAX_IMAGES]; + int action = SHOW_INFO; int sector_size; - DISK_GEOMETRY_EX diskgeometry_ex; - DISK_GEOMETRY diskgeometry; - char diskname[32]; + char devicename[4096]; HANDLE dh; - char* filename = NULL; - off_t inputsize; - fprintf(stderr,"ipodpatcher v0.4b - (C) Dave Chapman 2006\n"); + fprintf(stderr,"ipodpatcher v" VERSION " - (C) Dave Chapman 2006\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) { + if (argc < 2) { print_usage(); return 1; } i = 1; + devicename[0]=0; + +#ifdef __WIN32__ + snprintf(devicename,sizeof(devicename),"\\\\.\\PhysicalDrive%s",argv[1]); +#else + strncpy(devicename,argv[1],sizeof(devicename)); +#endif + + i = 2; while (i < argc) { - if (strncmp(argv[i],"-i",2)==0) { - mode=SHOW_INFO; - } else if (strncmp(argv[i],"-r",2)==0) { - mode = READ; - } else if (strncmp(argv[i],"-w",2)==0) { - mode = WRITE; + if ((strcmp(argv[i],"-l")==0) || (strcmp(argv[i],"--list")==0)) { + action = LIST_IMAGES; + i++; } else { - if (argv[i][0] == '-') { - fprintf(stderr,"Unknown option %s\n",argv[i]); - return 1; - } else { - if (diskno == -1) { - diskno = atoi(argv[i]); - } else if (filename==NULL) { - filename = argv[i]; - } else { - fprintf(stderr,"Too many arguments: %s\n",argv[i]); - return 1; - } - } + print_usage(); return 1; } - i++; } - if ((mode==NONE) || (diskno==-1) || ((mode!=SHOW_INFO) && (filename==NULL))) { + if (devicename[0]==0) { print_usage(); return 1; } - snprintf(diskname,sizeof(diskname),"\\\\.\\PhysicalDrive%d",diskno); - - /* The ReadFile function requires a memory buffer aligned to a multiple of - the disk sector size. */ - sectorbuf = VirtualAlloc(NULL, BUFFER_SIZE, MEM_COMMIT, PAGE_READWRITE); - if (sectorbuf == NULL) { - error(" Error allocating a buffer: "); - return 2; + if (ipod_alloc_buffer(§orbuf,BUFFER_SIZE) < 0) { + fprintf(stderr,"Failed to allocate memory buffer\n"); } - dh = CreateFile(diskname, GENERIC_READ, - FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, - FILE_FLAG_WRITE_THROUGH | FILE_FLAG_NO_BUFFERING, NULL); - - if (dh == INVALID_HANDLE_VALUE) { - error(" Error opening disk: "); - return 2; - } - - if (!lock_volume(dh)) { - error(" Error locking disk: "); - return 2; - } - - if (!DeviceIoControl(dh, - IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, - NULL, - 0, - &diskgeometry_ex, - sizeof(diskgeometry_ex), - &n, - NULL)) { - if (!DeviceIoControl(dh, - IOCTL_DISK_GET_DRIVE_GEOMETRY, - NULL, - 0, - &diskgeometry, - sizeof(diskgeometry), - &n, - NULL)) { - error(" Error reading disk geometry: "); - return 2; - } else { - sector_size=diskgeometry.BytesPerSector; - } - } else { - sector_size=diskgeometry_ex.Geometry.BytesPerSector; + if (ipod_open(&dh, devicename, §or_size) < 0) { + return 1; } - fprintf(stderr,"[INFO] Reading partition table from %s\n",diskname); + fprintf(stderr,"[INFO] Reading partition table from %s\n",devicename); fprintf(stderr,"[INFO] Sector size is %d bytes\n",sector_size); if (read_partinfo(dh,sector_size,pinfo) < 0) { @@ -416,13 +525,35 @@ int main(int argc, char* argv[]) display_partinfo(pinfo, sector_size); - if (pinfo[p].start==0) { - fprintf(stderr,"[ERR] Specified partition (%d) does not exist:\n",p); + if (pinfo[0].start==0) { + fprintf(stderr,"[ERR] No partition 0 on disk:\n"); display_partinfo(pinfo, sector_size); return 3; } - if (mode==READ) { + nimages=read_directory(dh, pinfo[0].start*sector_size, sector_size, ipod_directory); + if (nimages <= 0) { + fprintf(stderr,"[ERR] Failed to read firmware directory\n"); + return 1; + } + + ipod_version=(ipod_directory[0].vers>>12) & 0x0f; + printf("[INFO] Ipod model: "); + switch (ipod_version) { + case 0x3: printf("3rd Generation\n"); break; + case 0x4: printf("1st Generation Mini\n"); break; + case 0x5: printf("4th Generation\n"); break; + case 0x6: printf("Photo/Color\n"); break; + case 0x7: printf("2nd Generation Mini\n"); break; + case 0xc: printf("1st Generation Nano\n"); break; + case 0xb: printf("Video (aka 5th Generation)\n"); break; + default: printf("UNKNOWN (Firmware version is %08x)\n",ipod_directory[0].vers); + } + + if (action==LIST_IMAGES) { + list_images(nimages,ipod_directory); +#if 0 + } else if (mode==READ) { outfile = open(filename,O_CREAT|O_WRONLY|O_BINARY,S_IREAD|S_IWRITE); if (outfile < 0) { perror(filename); @@ -433,22 +564,8 @@ int main(int argc, char* argv[]) close(outfile); } else if (mode==WRITE) { - /* Close existing file and re-open for writing */ - unlock_volume(dh); - CloseHandle(dh); - - dh = CreateFile(diskname, GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, - FILE_FLAG_WRITE_THROUGH | FILE_FLAG_NO_BUFFERING, NULL); - - if (dh == INVALID_HANDLE_VALUE) { - error(" Error opening disk: "); - return 2; - } - - if (!lock_volume(dh)) { - error(" Error locking disk: "); - return 2; + if (ipod_reopen_rw(&dh, devicename) < 0) { + return 5; } infile = open(filename,O_RDONLY|O_BINARY); @@ -469,9 +586,10 @@ int main(int argc, char* argv[]) } close(infile); +#endif } - unlock_volume(dh); - CloseHandle(dh); + ipod_close(dh); + return 0; } -- cgit v1.2.3