summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/ipodpatcher/Makefile8
-rw-r--r--tools/ipodpatcher/ipodpatcher.c443
-rw-r--r--tools/ipodpatcher/parttypes.h109
3 files changed, 560 insertions, 0 deletions
diff --git a/tools/ipodpatcher/Makefile b/tools/ipodpatcher/Makefile
new file mode 100644
index 0000000..6eb3dce
--- /dev/null
+++ b/tools/ipodpatcher/Makefile
@@ -0,0 +1,8 @@
+all: ipodpatcher.exe
+
+ipodpatcher.exe: ipodpatcher.c
+ i586-mingw32msvc-gcc -Wall -o ipodpatcher.exe ipodpatcher.c
+ i586-mingw32msvc-strip ipodpatcher.exe
+
+clean:
+ rm -f ipodpatcher.exe *~
diff --git a/tools/ipodpatcher/ipodpatcher.c b/tools/ipodpatcher/ipodpatcher.c
new file mode 100644
index 0000000..7d311c8
--- /dev/null
+++ b/tools/ipodpatcher/ipodpatcher.c
@@ -0,0 +1,443 @@
+/***************************************************************************
+ * __________ __ ___.
+ * 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 <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <windows.h>
+#include <winioctl.h>
+
+#include "parttypes.h"
+
+/* 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()
+*/
+unsigned char* sectorbuf;
+
+char* get_parttype(int pt)
+{
+ int i;
+ static char unknown[]="Unknown";
+
+ i=0;
+ while (parttypes[i].name != NULL) {
+ if (parttypes[i].type == pt) {
+ return (parttypes[i].name);
+ }
+ i++;
+ }
+
+ 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;
+
+ if (fstat(fd,&buf) < 0) {
+ perror("[ERR] Checking filesize of input file");
+ return -1;
+ } else {
+ return(buf.st_size);
+ }
+}
+
+
+/* Size of buffer for disk I/O */
+#define BUFFER_SIZE 32*1024
+
+/* Partition table parsing code taken from Rockbox */
+
+#define SECTOR_SIZE 512
+
+struct partinfo {
+ 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 ) | \
+ ((long)array[pos+2] << 16 ) | ((long)array[pos+3] << 24 ))
+
+void display_partinfo(struct partinfo* pinfo)
+{
+ int i;
+
+ printf("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/2048.0,get_parttype(pinfo[i].type),pinfo[i].type);
+ }
+ }
+}
+
+
+int read_partinfo(HANDLE dh, struct partinfo* pinfo)
+{
+ int i;
+ unsigned char sector[SECTOR_SIZE];
+ unsigned long count;
+
+ if (!ReadFile(dh, sector, SECTOR_SIZE, &count, NULL)) {
+ error(" Error reading from disk: ");
+ return -1;
+ }
+
+ /* check that the boot sector is initialized */
+ if ( (sector[510] != 0x55) ||
+ (sector[511] != 0xaa)) {
+ fprintf(stderr,"Bad boot sector signature\n");
+ return 0;
+ }
+
+ if (memcmp(&sector[71],"iPod",4) != 0) {
+ fprintf(stderr,"Drive is not an iPod, aborting\n");
+ return -1;
+ }
+
+ /* parse partitions */
+ for ( i = 0; i < 4; i++ ) {
+ unsigned char* ptr = sector + 0x1be + 16*i;
+ pinfo[i].type = ptr[4];
+ pinfo[i].start = BYTES2INT32(ptr, 8);
+ pinfo[i].size = BYTES2INT32(ptr, 12);
+
+ /* extended? */
+ if ( pinfo[i].type == 5 ) {
+ /* not handled yet */
+ }
+ }
+
+ return 0;
+}
+
+int disk_read(HANDLE dh, int outfile,unsigned long start, unsigned long count)
+{
+ int res;
+ unsigned long n;
+ int bytesleft;
+ int chunksize;
+
+ fprintf(stderr,"[INFO] Seeking to sector %ld\n",start);
+
+ if (SetFilePointer(dh, start*SECTOR_SIZE, NULL, FILE_BEGIN)==0xffffffff) {
+ error(" Seek error ");
+ return -1;
+ }
+
+ fprintf(stderr,"[INFO] Writing %ld sectors to output file\n",count);
+
+ bytesleft = count * SECTOR_SIZE;
+ while (bytesleft > 0) {
+ if (bytesleft > BUFFER_SIZE) {
+ chunksize = BUFFER_SIZE;
+ } else {
+ chunksize = bytesleft;
+ }
+
+ if (!ReadFile(dh, sectorbuf, chunksize, &n, NULL)) {
+ error("[ERR] read in disk_read");
+ 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 %d, received %d - aborting.\n",SECTOR_SIZE,res);
+ return -1;
+ }
+ }
+
+ fprintf(stderr,"[INFO] Done.\n");
+ return 0;
+}
+
+int disk_write(HANDLE dh, int infile,unsigned long start)
+{
+ unsigned long res;
+ int n;
+ int bytesread;
+ int byteswritten = 0;
+ int eof;
+ int padding = 0;
+
+ if (SetFilePointer(dh, start*SECTOR_SIZE, NULL, FILE_BEGIN)==0xffffffff) {
+ error(" Seek error ");
+ 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 % SECTOR_SIZE) != 0) {
+ padding = (SECTOR_SIZE-(n % SECTOR_SIZE));
+ n += padding;
+ }
+ }
+
+ bytesread += n;
+
+ if (!WriteFile(dh, sectorbuf, n, &res, NULL)) {
+ error(" Error writing to disk: ");
+ fprintf(stderr,"Bytes written: %d\n",byteswritten);
+ return -1;
+ }
+
+ if (res != n) {
+ fprintf(stderr,"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;
+}
+
+
+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");
+ fprintf(stderr,"\n");
+ 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");
+}
+
+enum {
+ NONE,
+ SHOW_INFO,
+ READ,
+ WRITE
+};
+
+int main(int argc, char* argv[])
+{
+ int i;
+ struct partinfo pinfo[4]; /* space for 4 partitions on 1 drive */
+ int res;
+ int outfile;
+ int infile;
+ int mode = SHOW_INFO;
+ int p = 0;
+ int diskno = -1;
+ char diskname[32];
+ HANDLE dh;
+ char* filename = NULL;
+ off_t inputsize;
+
+ fprintf(stderr,"ipodpatcher v0.2 - (C) Dave Chapman 2005\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) {
+ print_usage();
+ return 1;
+ }
+
+ i = 1;
+ 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;
+ } 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;
+ }
+ }
+ }
+ i++;
+ }
+
+ if ((mode==NONE) || (diskno==-1) || ((mode!=SHOW_INFO) && (filename==NULL))) {
+ print_usage();
+ return 1;
+ }
+
+ snprintf(diskname,sizeof(diskname),"\\\\.\\PhysicalDrive%d",diskno);
+
+ fprintf(stderr,"[INFO] Reading partition table from %s\n",diskname);
+
+ /* 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;
+ }
+
+ 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 (read_partinfo(dh,pinfo) < 0) {
+ return 2;
+ }
+
+ display_partinfo(pinfo);
+
+ if (pinfo[p].start==0) {
+ fprintf(stderr,"[ERR] Specified partition (%d) does not exist:\n",p);
+ display_partinfo(pinfo);
+ return 3;
+ }
+
+ if (mode==READ) {
+ outfile = open(filename,O_CREAT|O_WRONLY|O_BINARY,S_IREAD|S_IWRITE);
+ if (outfile < 0) {
+ perror(filename);
+ return 4;
+ }
+
+ res = disk_read(dh,outfile,pinfo[p].start,pinfo[p].size);
+
+ 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;
+ }
+
+ 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 <= (pinfo[p].size*SECTOR_SIZE)) {
+ fprintf(stderr,"[INFO] Input file is %lu bytes\n",inputsize);
+ res = disk_write(dh,infile,pinfo[p].start);
+ } else {
+ fprintf(stderr,"[ERR] File is too large for firmware partition, aborting.\n");
+ }
+ }
+
+ close(infile);
+ }
+
+ unlock_volume(dh);
+ CloseHandle(dh);
+ return 0;
+}
diff --git a/tools/ipodpatcher/parttypes.h b/tools/ipodpatcher/parttypes.h
new file mode 100644
index 0000000..f8de303
--- /dev/null
+++ b/tools/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 }
+};