summaryrefslogtreecommitdiffstats
path: root/tools/ipodpatcher/ipodpatcher.c
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 /tools/ipodpatcher/ipodpatcher.c
parentf0efde23039064d393e8cc35c2d88a487c47b1c7 (diff)
downloadrockbox-955afed1b74793a3f06f98f3c259ec98f26a0b82.tar.gz
rockbox-955afed1b74793a3f06f98f3c259ec98f26a0b82.tar.bz2
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 'tools/ipodpatcher/ipodpatcher.c')
-rw-r--r--tools/ipodpatcher/ipodpatcher.c1261
1 files changed, 0 insertions, 1261 deletions
diff --git a/tools/ipodpatcher/ipodpatcher.c b/tools/ipodpatcher/ipodpatcher.c
deleted file mode 100644
index 6c60bae38d..0000000000
--- a/tools/ipodpatcher/ipodpatcher.c
+++ /dev/null
@@ -1,1261 +0,0 @@
-/***************************************************************************
- * __________ __ ___.
- * 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;
-}