forked from len0rd/rockbox
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
This commit is contained in:
parent
8a55822ae3
commit
4b7e1e0945
5 changed files with 618 additions and 172 deletions
|
|
@ -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 *~
|
||||
|
|
|
|||
96
tools/ipodpatcher/ipodio-posix.c
Normal file
96
tools/ipodpatcher/ipodio-posix.c
Normal file
|
|
@ -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 <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#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);
|
||||
}
|
||||
190
tools/ipodpatcher/ipodio-win32.c
Normal file
190
tools/ipodpatcher/ipodio-win32.c
Normal file
|
|
@ -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 <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(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;
|
||||
}
|
||||
39
tools/ipodpatcher/ipodio.h
Normal file
39
tools/ipodpatcher/ipodio.h
Normal file
|
|
@ -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 <windows.h>
|
||||
#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
|
||||
|
|
@ -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 <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <inttypes.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <windows.h>
|
||||
#include <winioctl.h>
|
||||
|
||||
#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;
|
||||
} 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((strcmp(argv[i],"-l")==0) || (strcmp(argv[i],"--list")==0)) {
|
||||
action = LIST_IMAGES;
|
||||
i++;
|
||||
} else {
|
||||
print_usage(); return 1;
|
||||
}
|
||||
}
|
||||
|
||||
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 (ipod_open(&dh, devicename, §or_size) < 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue