freemyipod r141 - Code Review

Jump to: navigation, search
Repository:freemyipod
Revision:r140‎ | r141 | r142 >
Date:04:34, 15 August 2010
Author:cmwslw
Status:new
Tags:
Comment:
Added extract2g and the hacked version by user890104.
Modified paths:
  • /tools/extract2g (added) (history)
  • /tools/extract2g/Makefile (added) (history)
  • /tools/extract2g/extract2g.c (added) (history)
  • /tools/extract2g/extract2g.h (added) (history)
  • /tools/extract2g_HACKED (added) (history)
  • /tools/extract2g_HACKED/Makefile (added) (history)
  • /tools/extract2g_HACKED/README (added) (history)
  • /tools/extract2g_HACKED/extract2g.c (added) (history)
  • /tools/extract2g_HACKED/extract2g.h (added) (history)

Diff [purge]

Index: tools/extract2g_HACKED/extract2g.c
@@ -0,0 +1,514 @@
 2+/*
 3+ This program is free software; you can redistribute it and/or modify
 4+ it under the terms of the GNU General Public License version 2.1 as
 5+ published by the Free Software Foundation.
 6+
 7+ This program is distributed in the hope that it will be useful,
 8+ but WITHOUT ANY WARRANTY; without even the implied warranty of
 9+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 10+ GNU General Public License for more details.
 11+
 12+ You should have received a copy of the GNU General Public License
 13+ along with this program; if not, write to the Free Software
 14+ Foundation Inc., 59 Temple Place, Suite 330, Boston MA 02111-1307 USA
 15+*/
 16+
 17+/*
 18+ $Id$
 19+
 20+ Revision history:
 21+ 1.0 - 2007-01-25 - Brossillon J.Damien <brossill@enseirb.fr>
 22+ -- Initial version
 23+
 24+ 1.1 - 2007-09-15
 25+ -- Stuff added to guess the header versions.
 26+
 27+ Todo list:
 28+ -- Debug
 29+*/
 30+
 31+#include <stdlib.h>
 32+#include <stdio.h>
 33+#include <string.h>
 34+#include <getopt.h>
 35+#include <limits.h>
 36+
 37+#include "extract2g.h"
 38+
 39+#define VERSION_H 1
 40+#define VERSION_L 1
 41+
 42+#define B (0x0FFFFFFF)
 43+
 44+/* Change endian of a 4 bytes memory zone */
 45+void change_endian( char* buf )
 46+{
 47+
 48+ char tmp[4];
 49+
 50+ tmp[3] = buf[0];
 51+ tmp[2] = buf[1];
 52+ tmp[1] = buf[2];
 53+ tmp[0] = buf[3];
 54+
 55+ memcpy(buf,tmp,4*sizeof(char));
 56+
 57+ return;
 58+}
 59+
 60+unsigned int hash_part(FILE* hIn, int start, int len, int header_len)
 61+{
 62+ unsigned int hash = 0;
 63+
 64+ fseek(hIn, start, SEEK_SET);
 65+
 66+ unsigned int tmp;
 67+
 68+ int pos;
 69+ for(pos=0;pos<(len+header_len);pos++)
 70+ {
 71+ tmp = fgetc(hIn);
 72+
 73+ hash = (hash*B + tmp*pos);
 74+ }
 75+
 76+ return hash;
 77+}
 78+
 79+void extract_part(FILE* hIn, FILE* hOut,
 80+ char* name,
 81+ int start, int len,
 82+ int header_len)
 83+{
 84+ int pos;
 85+ char tmp;
 86+
 87+ char* filename = NULL;
 88+
 89+ // No extract name specified
 90+ if( !hOut )
 91+ {
 92+ filename = (char*)malloc( strlen(name) + 4 );
 93+
 94+ if( !filename )
 95+ {
 96+ fprintf(stderr, "Memory allocation failure.");
 97+ exit(EXIT_FAILURE);
 98+ }
 99+
 100+ strcpy(filename, name);
 101+ strcat(filename, ".fw");
 102+
 103+ hOut = fopen(filename, "wb");
 104+ }
 105+
 106+ fprintf(stdout,"Extracting from 0x%8.X to 0x%8.X in %s.\n",
 107+ start, start+len+header_len, filename);
 108+
 109+ // Go to the beginning of the part
 110+ fseek(hIn, start, SEEK_SET);
 111+
 112+ // Extracting
 113+ for(pos=0;pos<(len+header_len);pos++)
 114+ {
 115+ tmp = fgetc(hIn);
 116+ fputc(tmp,hOut);
 117+ }
 118+
 119+ fclose(hOut);
 120+
 121+ free(filename);
 122+
 123+ return;
 124+}
 125+
 126+char is_valid( DIRECTORY* p_dir )
 127+{
 128+ // Test if the directory contain a valid header for the part.
 129+ return ( !strncmp( p_dir->dev, "NAND", 4)
 130+ || !strncmp( p_dir->dev, "ATA!", 4) );
 131+}
 132+
 133+char check_header(FILE* fh, unsigned int l)
 134+{
 135+ DIRECTORY dir;
 136+
 137+ fseek(fh, l, SEEK_SET);
 138+ fread( (void*)&dir, LEN_DIR, sizeof(char), fh);
 139+
 140+ change_endian(dir.dev);
 141+
 142+ return is_valid(&dir);
 143+}
 144+
 145+int guess_directory_address(FILE* fh)
 146+{
 147+ // Check for 1G header
 148+ if(check_header(fh,ADDR_DIR_1G))
 149+ {
 150+ printf("> iPod nano 1g header detected.\n");
 151+ return ADDR_DIR_1G;
 152+ }
 153+
 154+ // Check for 2G header
 155+ if(check_header(fh,ADDR_DIR_2G))
 156+ {
 157+ printf("> iPod nano 2g header detected.\n");
 158+ return ADDR_DIR_2G;
 159+ }
 160+
 161+ // Check for 3G header
 162+ if(check_header(fh,ADDR_DIR_3G))
 163+ {
 164+ printf("> iPod nano 3g header detected.\n");
 165+ return ADDR_DIR_3G;
 166+ }
 167+
 168+ // At least try to find an header
 169+ fseek(fh, 0, SEEK_SET);
 170+
 171+ DIRECTORY dir;
 172+
 173+ while(!feof(fh))
 174+ {
 175+ fread( (void*)&dir, LEN_DIR, sizeof(char), fh);
 176+ change_endian(dir.dev);
 177+
 178+ if(is_valid(&dir))
 179+ {
 180+ int addr = ftell(fh) - LEN_DIR;
 181+ printf("> Unknown header found at 0x%X\n",addr);
 182+ return addr;
 183+ }
 184+
 185+ fseek(fh, -LEN_DIR + 1, SEEK_CUR);
 186+ }
 187+
 188+ return ADDR_DIR_DEFAULT;
 189+}
 190+
 191+void print_directory_infos(DIRECTORY* p_dir, char extended)
 192+{
 193+ if( extended )
 194+ printf("dev: %.4s type: %.4s\n\
 195+id: %X\n\
 196+devOffset: %X\n\
 197+len: %X\n\
 198+addr: %X\n\
 199+entryOffset: %X\n\
 200+checksum: %X\n\
 201+version: %X\n\
 202+loadAddr: %X\n\n",
 203+ p_dir->dev,
 204+ p_dir->type,
 205+ p_dir->id,
 206+ p_dir->devOffset,
 207+ p_dir->len,
 208+ p_dir->addr,
 209+ p_dir->entryOffset,
 210+ p_dir->checksum,
 211+ p_dir->version,
 212+ p_dir->loadAddr );
 213+
 214+ else
 215+ printf("dev: %.4s type: %.4s devOffset: %X len: %X\n",
 216+ p_dir->dev,
 217+ p_dir->type,
 218+ p_dir->devOffset,
 219+ p_dir->len);
 220+
 221+}
 222+
 223+
 224+/* Display help */
 225+void usage(int status)
 226+{
 227+ if (status != EXIT_SUCCESS)
 228+ fputs("Try `extract_2g --help' for more information.\n", stderr);
 229+ else
 230+ {
 231+ fputs("Usage: extract_2g [OPTION] [FILE]\n", stdout);
 232+ fprintf(stdout,"Read & extract iPod Nano 2G data parts from a FILE dump.\n\
 233+\n\
 234+ -l, --list only list avaible parts according to the dump directory\n\n\
 235+ -H, --hash do a hash on every part of the dump\n\n\
 236+ -A, --all extract ALL founded parts from dump (default names used)\n\n\
 237+ -e, --extract=NAME select which part you want to extract (default none)\n\
 238+ -o, --output=FILE put the extracted part into FILE (default NAME.fw)\n\n\
 239+ -d, --directory-address specify the directory address (default 0x%X )\n\
 240+ -a, --header-length specify the header length of each part (default 0x800)\n\n\
 241+ -h, --help display this help and exit\n", ADDR_DIR_DEFAULT);
 242+ }
 243+
 244+ exit(status);
 245+}
 246+
 247+int main(int argc, char **argv)
 248+{
 249+ FILE *file = NULL;
 250+ FILE *hExtract = NULL;
 251+
 252+ char str_target[32];
 253+
 254+ char extract_is_set = 0;
 255+ char extract_all = 0;
 256+ char list_directories = 0;
 257+ char is_found = 0;
 258+ char hash_parts = 0;
 259+
 260+ /* REMOVE */
 261+ char c;
 262+
 263+ int tmp;
 264+
 265+ int i;
 266+
 267+ int directories_size = 0;
 268+ DIRECTORY* directories = NULL;
 269+
 270+ int addr_directory = -1;
 271+
 272+ int length_header = LEN_HEADER;
 273+
 274+ /* Getopt short options */
 275+ static char const short_options[] = "e:o:d:a:AHlhv";
 276+
 277+ /* Getopt long options */
 278+ static struct option const long_options[] = {
 279+ {"extract", required_argument, NULL, 'e'},
 280+ {"output", required_argument, NULL, 'o'},
 281+ {"hash", no_argument, NULL, 'H'},
 282+ {"list", no_argument, NULL, 'l'},
 283+ {"all", no_argument, NULL, 'A'},
 284+ {"directory-address", required_argument, NULL, 'd'},
 285+ {"header-length", required_argument, NULL, 'a'},
 286+ {"help", no_argument, NULL, 'h'},
 287+ {"version", no_argument, NULL, 'v'},
 288+ {NULL, 0, NULL, 0}
 289+ };
 290+
 291+ /* Some informations */
 292+ printf("%s compiled at %s %s.\n\n",argv[0],__TIME__,__DATE__);
 293+
 294+ /* Parse command line options. */
 295+ while ((c = getopt_long(argc, argv,
 296+ short_options, long_options, NULL)) != -1) {
 297+ switch (c) {
 298+ case 'o':
 299+ hExtract = fopen(optarg,"wb");
 300+
 301+ if(!hExtract)
 302+ {
 303+ fprintf(stderr,"Cannot write/create %s.\n", optarg);
 304+ usage(EXIT_FAILURE);
 305+ }
 306+
 307+ break;
 308+
 309+ case 'a':
 310+ if ( (tmp = strtol(optarg, NULL, 0)) > -1 )
 311+ length_header = tmp;
 312+ else {
 313+ fprintf(stderr, "Invalid `header-length' value `%s'.\n", optarg);
 314+ usage(EXIT_FAILURE);
 315+ }
 316+ break;
 317+
 318+ case 'd':
 319+ if ( (tmp = strtol(optarg, NULL, 0)) > 0 )
 320+ addr_directory = tmp;
 321+ else {
 322+ fprintf(stderr, "Invalid `directory-address' value `%s'.\n", optarg);
 323+ usage(EXIT_FAILURE);
 324+ }
 325+ break;
 326+
 327+ case 'e':
 328+ strncpy(str_target,optarg,32);
 329+ extract_is_set = 1;
 330+ break;
 331+
 332+ case 'H':
 333+ hash_parts = 1;
 334+ break;
 335+
 336+ case 'l':
 337+ list_directories = 1;
 338+ break;
 339+
 340+ case 'A':
 341+ extract_all = 1;
 342+ break;
 343+
 344+ case 'h':
 345+ usage(EXIT_SUCCESS);
 346+ break;
 347+
 348+ case 'v':
 349+ fprintf(stdout,"extract_2g version %d.%d\n",VERSION_H,VERSION_L);
 350+ fputs("Copyright (C) 2007 Brossillon J.Damien\n\
 351+This is free software. You may redistribute copies of it under the terms\n\
 352+of the GNU General Public License <http://www.gnu.org/licenses/gpl.html>.\n\
 353+There is NO WARRANTY, to the extent permitted by law.\n", stdout);
 354+ exit(EXIT_SUCCESS);
 355+ break;
 356+
 357+ default:
 358+ usage(EXIT_FAILURE);
 359+ }
 360+ }
 361+
 362+ if (!argv[optind]) {
 363+ fprintf(stderr,"Missing dump filename.\n");
 364+ usage(EXIT_FAILURE);
 365+ } else {
 366+ if (!(file = fopen(argv[optind], "rb")))
 367+ {
 368+ fprintf(stderr,"Cannot open file `%s'.\n", argv[optind]);
 369+ usage(EXIT_FAILURE);
 370+ }
 371+ }
 372+
 373+
 374+ if( addr_directory < 0 )
 375+ addr_directory = guess_directory_address(file);
 376+ else
 377+ addr_directory = ADDR_DIR_DEFAULT;
 378+
 379+
 380+ fseek(file, addr_directory, SEEK_SET);
 381+
 382+ DIRECTORY dir;
 383+
 384+ // List directories
 385+ while(1)
 386+ {
 387+ /* FIXME
 388+ for(i=0;i<(int)LEN_DIR;i++)
 389+ {
 390+ ((char*)&dir)[i] = fgetc(file);
 391+ }*/
 392+ fread( (void*)&dir, LEN_DIR, sizeof(char), file);
 393+
 394+ change_endian(dir.dev);
 395+ change_endian(dir.type);
 396+
 397+ if( is_valid(&dir) )
 398+ {
 399+ directories_size++;
 400+ directories = (DIRECTORY*)realloc(directories,
 401+ directories_size*sizeof(DIRECTORY));
 402+
 403+ if(!directories)
 404+ {
 405+ fprintf(stderr,"Memory allocation failure.\n");
 406+ exit(EXIT_FAILURE);
 407+ }
 408+ dir.devOffset += 4096;
 409+ memcpy(directories + directories_size - 1, &dir, sizeof(DIRECTORY));
 410+ }
 411+ else
 412+ break;
 413+ }
 414+
 415+ // Check if we have, at least, one valid part
 416+ if( directories_size <= 0 )
 417+ {
 418+ fclose(file);
 419+
 420+ if(directories)
 421+ free(directories);
 422+
 423+ fprintf(stderr, "Cannot find at least one valid part in the dump.\n");
 424+ exit(EXIT_FAILURE);
 425+ }
 426+
 427+ // User want to hash every parts of the dump
 428+ if( hash_parts )
 429+ {
 430+
 431+ for(i=0;i<directories_size;i++)
 432+ {
 433+ fprintf(stdout,"%.4s: 0x%X\n",directories[i].type,
 434+ hash_part(file,
 435+ directories[i].devOffset, directories[i].len,
 436+ length_header) );
 437+ }
 438+ }
 439+ else
 440+ if( extract_all )
 441+ {
 442+ // User want to extract every part of the dump
 443+ for(i=0;i<directories_size;i++)
 444+ {
 445+ char name[5];
 446+
 447+ memcpy(name,directories[i].type,4*sizeof(char));
 448+ name[4] = '\0';
 449+
 450+ extract_part(file, NULL,
 451+ name,
 452+ directories[i].devOffset, directories[i].len,
 453+ length_header);
 454+ }
 455+
 456+ fprintf(stdout,"Done.\n");
 457+
 458+
 459+ }
 460+ else
 461+ {
 462+ if( list_directories )
 463+ {
 464+ // User ask a big directory listing
 465+
 466+ for(i=0;i<directories_size; i++)
 467+ print_directory_infos( &(directories[i]), 1 );
 468+ }
 469+ else
 470+ {
 471+
 472+ if( extract_is_set )
 473+ {
 474+ is_found = 0;
 475+
 476+ for(i=0;i<directories_size;i++)
 477+ if( !strcmp( directories[i].type, str_target ) )
 478+ { // Extract & correct part name
 479+
 480+ is_found = 1;
 481+
 482+ // Lock & load, got name, file, position and length !
 483+ extract_part(file, hExtract,
 484+ directories[i].type,
 485+ directories[i].devOffset, directories[i].len,
 486+ length_header);
 487+
 488+ }
 489+
 490+ // Wrong part name, error message & small parts list
 491+ if(!is_found)
 492+ {
 493+ fprintf(stderr,"No part named '%s' found.\n\n",str_target);
 494+
 495+ for(i=0;i<directories_size;i++)
 496+ print_directory_infos( &(directories[i]), 0);
 497+ }
 498+
 499+ }
 500+ else
 501+ { // No actions, small parts list
 502+
 503+ for(i=0;i<directories_size;i++)
 504+ print_directory_infos( &(directories[i]), 0);
 505+ }
 506+
 507+ }
 508+ }
 509+
 510+ fclose(file);
 511+
 512+ free(directories);
 513+
 514+ return EXIT_SUCCESS;
 515+}
Property changes on: tools/extract2g_HACKED/extract2g.c
___________________________________________________________________
Added: svn:executable
## -0,0 +1 ##
 516+*
\ No newline at end of property
Index: tools/extract2g_HACKED/extract2g.h
@@ -0,0 +1,27 @@
 2+
 3+#define ADDR_DIR_DEFAULT 0x4800
 4+#define ADDR_DIR_1G 0x4200
 5+#define ADDR_DIR_2G 0x4800
 6+#define ADDR_DIR_3G 0x5000
 7+
 8+
 9+#define LEN_HEADER 0x800
 10+
 11+#define LEN_DIR sizeof(DIRECTORY)
 12+
 13+typedef struct _DIRECTORY
 14+{
 15+ char dev[4];
 16+ char type[4];
 17+
 18+ unsigned int id;
 19+ unsigned int devOffset;
 20+ unsigned int len;
 21+ unsigned int addr;
 22+
 23+ unsigned int entryOffset;
 24+ unsigned int checksum;
 25+ unsigned int version;
 26+ unsigned int loadAddr;
 27+
 28+}DIRECTORY;
Property changes on: tools/extract2g_HACKED/extract2g.h
___________________________________________________________________
Added: svn:executable
## -0,0 +1 ##
 29+*
\ No newline at end of property
Index: tools/extract2g_HACKED/Makefile
@@ -0,0 +1,11 @@
 2+CC= gcc
 3+OPTS= -Wall -g
 4+
 5+all: extract2g
 6+
 7+extract2g: extract2g.c extract2g.h
 8+ $(CC) $(OPTS) $< -o $@
 9+
 10+.PHONY: clean
 11+clean:
 12+ rm -f extract2g
Property changes on: tools/extract2g_HACKED/Makefile
___________________________________________________________________
Added: svn:executable
## -0,0 +1 ##
 13+*
\ No newline at end of property
Index: tools/extract2g_HACKED/README
@@ -0,0 +1,13 @@
 2+This is a hacked version of the original extract2g utility to work with the
 3+Nano 4G's new firmware changes. It breaks compatibility with all other firmware.
 4+
 5+Here are the only changes made:
 6+
 7+309c309
 8+< if ( (tmp = strtol(optarg, NULL, 0)) > 0 )
 9+---
 10+> if ( (tmp = strtol(optarg, NULL, 0)) > -1 )
 11+407c407
 12+<
 13+---
 14+> dir.devOffset += 4096;
Index: tools/extract2g/extract2g.c
@@ -0,0 +1,514 @@
 2+/*
 3+ This program is free software; you can redistribute it and/or modify
 4+ it under the terms of the GNU General Public License version 2.1 as
 5+ published by the Free Software Foundation.
 6+
 7+ This program is distributed in the hope that it will be useful,
 8+ but WITHOUT ANY WARRANTY; without even the implied warranty of
 9+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 10+ GNU General Public License for more details.
 11+
 12+ You should have received a copy of the GNU General Public License
 13+ along with this program; if not, write to the Free Software
 14+ Foundation Inc., 59 Temple Place, Suite 330, Boston MA 02111-1307 USA
 15+*/
 16+
 17+/*
 18+ $Id$
 19+
 20+ Revision history:
 21+ 1.0 - 2007-01-25 - Brossillon J.Damien <brossill@enseirb.fr>
 22+ -- Initial version
 23+
 24+ 1.1 - 2007-09-15
 25+ -- Stuff added to guess the header versions.
 26+
 27+ Todo list:
 28+ -- Debug
 29+*/
 30+
 31+#include <stdlib.h>
 32+#include <stdio.h>
 33+#include <string.h>
 34+#include <getopt.h>
 35+#include <limits.h>
 36+
 37+#include "extract2g.h"
 38+
 39+#define VERSION_H 1
 40+#define VERSION_L 1
 41+
 42+#define B (0x0FFFFFFF)
 43+
 44+/* Change endian of a 4 bytes memory zone */
 45+void change_endian( char* buf )
 46+{
 47+
 48+ char tmp[4];
 49+
 50+ tmp[3] = buf[0];
 51+ tmp[2] = buf[1];
 52+ tmp[1] = buf[2];
 53+ tmp[0] = buf[3];
 54+
 55+ memcpy(buf,tmp,4*sizeof(char));
 56+
 57+ return;
 58+}
 59+
 60+unsigned int hash_part(FILE* hIn, int start, int len, int header_len)
 61+{
 62+ unsigned int hash = 0;
 63+
 64+ fseek(hIn, start, SEEK_SET);
 65+
 66+ unsigned int tmp;
 67+
 68+ int pos;
 69+ for(pos=0;pos<(len+header_len);pos++)
 70+ {
 71+ tmp = fgetc(hIn);
 72+
 73+ hash = (hash*B + tmp*pos);
 74+ }
 75+
 76+ return hash;
 77+}
 78+
 79+void extract_part(FILE* hIn, FILE* hOut,
 80+ char* name,
 81+ int start, int len,
 82+ int header_len)
 83+{
 84+ int pos;
 85+ char tmp;
 86+
 87+ char* filename = NULL;
 88+
 89+ // No extract name specified
 90+ if( !hOut )
 91+ {
 92+ filename = (char*)malloc( strlen(name) + 4 );
 93+
 94+ if( !filename )
 95+ {
 96+ fprintf(stderr, "Memory allocation failure.");
 97+ exit(EXIT_FAILURE);
 98+ }
 99+
 100+ strcpy(filename, name);
 101+ strcat(filename, ".fw");
 102+
 103+ hOut = fopen(filename, "wb");
 104+ }
 105+
 106+ fprintf(stdout,"Extracting from 0x%8.X to 0x%8.X in %s.\n",
 107+ start, start+len+header_len, filename);
 108+
 109+ // Go to the beginning of the part
 110+ fseek(hIn, start, SEEK_SET);
 111+
 112+ // Extracting
 113+ for(pos=0;pos<(len+header_len);pos++)
 114+ {
 115+ tmp = fgetc(hIn);
 116+ fputc(tmp,hOut);
 117+ }
 118+
 119+ fclose(hOut);
 120+
 121+ free(filename);
 122+
 123+ return;
 124+}
 125+
 126+char is_valid( DIRECTORY* p_dir )
 127+{
 128+ // Test if the directory contain a valid header for the part.
 129+ return ( !strncmp( p_dir->dev, "NAND", 4)
 130+ || !strncmp( p_dir->dev, "ATA!", 4) );
 131+}
 132+
 133+char check_header(FILE* fh, unsigned int l)
 134+{
 135+ DIRECTORY dir;
 136+
 137+ fseek(fh, l, SEEK_SET);
 138+ fread( (void*)&dir, LEN_DIR, sizeof(char), fh);
 139+
 140+ change_endian(dir.dev);
 141+
 142+ return is_valid(&dir);
 143+}
 144+
 145+int guess_directory_address(FILE* fh)
 146+{
 147+ // Check for 1G header
 148+ if(check_header(fh,ADDR_DIR_1G))
 149+ {
 150+ printf("> iPod nano 1g header detected.\n");
 151+ return ADDR_DIR_1G;
 152+ }
 153+
 154+ // Check for 2G header
 155+ if(check_header(fh,ADDR_DIR_2G))
 156+ {
 157+ printf("> iPod nano 2g header detected.\n");
 158+ return ADDR_DIR_2G;
 159+ }
 160+
 161+ // Check for 3G header
 162+ if(check_header(fh,ADDR_DIR_3G))
 163+ {
 164+ printf("> iPod nano 3g header detected.\n");
 165+ return ADDR_DIR_3G;
 166+ }
 167+
 168+ // At least try to find an header
 169+ fseek(fh, 0, SEEK_SET);
 170+
 171+ DIRECTORY dir;
 172+
 173+ while(!feof(fh))
 174+ {
 175+ fread( (void*)&dir, LEN_DIR, sizeof(char), fh);
 176+ change_endian(dir.dev);
 177+
 178+ if(is_valid(&dir))
 179+ {
 180+ int addr = ftell(fh) - LEN_DIR;
 181+ printf("> Unknown header found at 0x%X\n",addr);
 182+ return addr;
 183+ }
 184+
 185+ fseek(fh, -LEN_DIR + 1, SEEK_CUR);
 186+ }
 187+
 188+ return ADDR_DIR_DEFAULT;
 189+}
 190+
 191+void print_directory_infos(DIRECTORY* p_dir, char extended)
 192+{
 193+ if( extended )
 194+ printf("dev: %.4s type: %.4s\n\
 195+id: %X\n\
 196+devOffset: %X\n\
 197+len: %X\n\
 198+addr: %X\n\
 199+entryOffset: %X\n\
 200+checksum: %X\n\
 201+version: %X\n\
 202+loadAddr: %X\n\n",
 203+ p_dir->dev,
 204+ p_dir->type,
 205+ p_dir->id,
 206+ p_dir->devOffset,
 207+ p_dir->len,
 208+ p_dir->addr,
 209+ p_dir->entryOffset,
 210+ p_dir->checksum,
 211+ p_dir->version,
 212+ p_dir->loadAddr );
 213+
 214+ else
 215+ printf("dev: %.4s type: %.4s devOffset: %X len: %X\n",
 216+ p_dir->dev,
 217+ p_dir->type,
 218+ p_dir->devOffset,
 219+ p_dir->len);
 220+
 221+}
 222+
 223+
 224+/* Display help */
 225+void usage(int status)
 226+{
 227+ if (status != EXIT_SUCCESS)
 228+ fputs("Try `extract_2g --help' for more information.\n", stderr);
 229+ else
 230+ {
 231+ fputs("Usage: extract_2g [OPTION] [FILE]\n", stdout);
 232+ fprintf(stdout,"Read & extract iPod Nano 2G data parts from a FILE dump.\n\
 233+\n\
 234+ -l, --list only list avaible parts according to the dump directory\n\n\
 235+ -H, --hash do a hash on every part of the dump\n\n\
 236+ -A, --all extract ALL founded parts from dump (default names used)\n\n\
 237+ -e, --extract=NAME select which part you want to extract (default none)\n\
 238+ -o, --output=FILE put the extracted part into FILE (default NAME.fw)\n\n\
 239+ -d, --directory-address specify the directory address (default 0x%X )\n\
 240+ -a, --header-length specify the header length of each part (default 0x800)\n\n\
 241+ -h, --help display this help and exit\n", ADDR_DIR_DEFAULT);
 242+ }
 243+
 244+ exit(status);
 245+}
 246+
 247+int main(int argc, char **argv)
 248+{
 249+ FILE *file = NULL;
 250+ FILE *hExtract = NULL;
 251+
 252+ char str_target[32];
 253+
 254+ char extract_is_set = 0;
 255+ char extract_all = 0;
 256+ char list_directories = 0;
 257+ char is_found = 0;
 258+ char hash_parts = 0;
 259+
 260+ /* REMOVE */
 261+ char c;
 262+
 263+ int tmp;
 264+
 265+ int i;
 266+
 267+ int directories_size = 0;
 268+ DIRECTORY* directories = NULL;
 269+
 270+ int addr_directory = -1;
 271+
 272+ int length_header = LEN_HEADER;
 273+
 274+ /* Getopt short options */
 275+ static char const short_options[] = "e:o:d:a:AHlhv";
 276+
 277+ /* Getopt long options */
 278+ static struct option const long_options[] = {
 279+ {"extract", required_argument, NULL, 'e'},
 280+ {"output", required_argument, NULL, 'o'},
 281+ {"hash", no_argument, NULL, 'H'},
 282+ {"list", no_argument, NULL, 'l'},
 283+ {"all", no_argument, NULL, 'A'},
 284+ {"directory-address", required_argument, NULL, 'd'},
 285+ {"header-length", required_argument, NULL, 'a'},
 286+ {"help", no_argument, NULL, 'h'},
 287+ {"version", no_argument, NULL, 'v'},
 288+ {NULL, 0, NULL, 0}
 289+ };
 290+
 291+ /* Some informations */
 292+ printf("%s compiled at %s %s.\n\n",argv[0],__TIME__,__DATE__);
 293+
 294+ /* Parse command line options. */
 295+ while ((c = getopt_long(argc, argv,
 296+ short_options, long_options, NULL)) != -1) {
 297+ switch (c) {
 298+ case 'o':
 299+ hExtract = fopen(optarg,"wb");
 300+
 301+ if(!hExtract)
 302+ {
 303+ fprintf(stderr,"Cannot write/create %s.\n", optarg);
 304+ usage(EXIT_FAILURE);
 305+ }
 306+
 307+ break;
 308+
 309+ case 'a':
 310+ if ( (tmp = strtol(optarg, NULL, 0)) > 0 )
 311+ length_header = tmp;
 312+ else {
 313+ fprintf(stderr, "Invalid `header-length' value `%s'.\n", optarg);
 314+ usage(EXIT_FAILURE);
 315+ }
 316+ break;
 317+
 318+ case 'd':
 319+ if ( (tmp = strtol(optarg, NULL, 0)) > 0 )
 320+ addr_directory = tmp;
 321+ else {
 322+ fprintf(stderr, "Invalid `directory-address' value `%s'.\n", optarg);
 323+ usage(EXIT_FAILURE);
 324+ }
 325+ break;
 326+
 327+ case 'e':
 328+ strncpy(str_target,optarg,32);
 329+ extract_is_set = 1;
 330+ break;
 331+
 332+ case 'H':
 333+ hash_parts = 1;
 334+ break;
 335+
 336+ case 'l':
 337+ list_directories = 1;
 338+ break;
 339+
 340+ case 'A':
 341+ extract_all = 1;
 342+ break;
 343+
 344+ case 'h':
 345+ usage(EXIT_SUCCESS);
 346+ break;
 347+
 348+ case 'v':
 349+ fprintf(stdout,"extract_2g version %d.%d\n",VERSION_H,VERSION_L);
 350+ fputs("Copyright (C) 2007 Brossillon J.Damien\n\
 351+This is free software. You may redistribute copies of it under the terms\n\
 352+of the GNU General Public License <http://www.gnu.org/licenses/gpl.html>.\n\
 353+There is NO WARRANTY, to the extent permitted by law.\n", stdout);
 354+ exit(EXIT_SUCCESS);
 355+ break;
 356+
 357+ default:
 358+ usage(EXIT_FAILURE);
 359+ }
 360+ }
 361+
 362+ if (!argv[optind]) {
 363+ fprintf(stderr,"Missing dump filename.\n");
 364+ usage(EXIT_FAILURE);
 365+ } else {
 366+ if (!(file = fopen(argv[optind], "rb")))
 367+ {
 368+ fprintf(stderr,"Cannot open file `%s'.\n", argv[optind]);
 369+ usage(EXIT_FAILURE);
 370+ }
 371+ }
 372+
 373+
 374+ if( addr_directory < 0 )
 375+ addr_directory = guess_directory_address(file);
 376+ else
 377+ addr_directory = ADDR_DIR_DEFAULT;
 378+
 379+
 380+ fseek(file, addr_directory, SEEK_SET);
 381+
 382+ DIRECTORY dir;
 383+
 384+ // List directories
 385+ while(1)
 386+ {
 387+ /* FIXME
 388+ for(i=0;i<(int)LEN_DIR;i++)
 389+ {
 390+ ((char*)&dir)[i] = fgetc(file);
 391+ }*/
 392+ fread( (void*)&dir, LEN_DIR, sizeof(char), file);
 393+
 394+ change_endian(dir.dev);
 395+ change_endian(dir.type);
 396+
 397+ if( is_valid(&dir) )
 398+ {
 399+ directories_size++;
 400+ directories = (DIRECTORY*)realloc(directories,
 401+ directories_size*sizeof(DIRECTORY));
 402+
 403+ if(!directories)
 404+ {
 405+ fprintf(stderr,"Memory allocation failure.\n");
 406+ exit(EXIT_FAILURE);
 407+ }
 408+
 409+ memcpy(directories + directories_size - 1, &dir, sizeof(DIRECTORY));
 410+ }
 411+ else
 412+ break;
 413+ }
 414+
 415+ // Check if we have, at least, one valid part
 416+ if( directories_size <= 0 )
 417+ {
 418+ fclose(file);
 419+
 420+ if(directories)
 421+ free(directories);
 422+
 423+ fprintf(stderr, "Cannot find at least one valid part in the dump.\n");
 424+ exit(EXIT_FAILURE);
 425+ }
 426+
 427+ // User want to hash every parts of the dump
 428+ if( hash_parts )
 429+ {
 430+
 431+ for(i=0;i<directories_size;i++)
 432+ {
 433+ fprintf(stdout,"%.4s: 0x%X\n",directories[i].type,
 434+ hash_part(file,
 435+ directories[i].devOffset, directories[i].len,
 436+ length_header) );
 437+ }
 438+ }
 439+ else
 440+ if( extract_all )
 441+ {
 442+ // User want to extract every part of the dump
 443+ for(i=0;i<directories_size;i++)
 444+ {
 445+ char name[5];
 446+
 447+ memcpy(name,directories[i].type,4*sizeof(char));
 448+ name[4] = '\0';
 449+
 450+ extract_part(file, NULL,
 451+ name,
 452+ directories[i].devOffset, directories[i].len,
 453+ length_header);
 454+ }
 455+
 456+ fprintf(stdout,"Done.\n");
 457+
 458+
 459+ }
 460+ else
 461+ {
 462+ if( list_directories )
 463+ {
 464+ // User ask a big directory listing
 465+
 466+ for(i=0;i<directories_size; i++)
 467+ print_directory_infos( &(directories[i]), 1 );
 468+ }
 469+ else
 470+ {
 471+
 472+ if( extract_is_set )
 473+ {
 474+ is_found = 0;
 475+
 476+ for(i=0;i<directories_size;i++)
 477+ if( !strcmp( directories[i].type, str_target ) )
 478+ { // Extract & correct part name
 479+
 480+ is_found = 1;
 481+
 482+ // Lock & load, got name, file, position and length !
 483+ extract_part(file, hExtract,
 484+ directories[i].type,
 485+ directories[i].devOffset, directories[i].len,
 486+ length_header);
 487+
 488+ }
 489+
 490+ // Wrong part name, error message & small parts list
 491+ if(!is_found)
 492+ {
 493+ fprintf(stderr,"No part named '%s' found.\n\n",str_target);
 494+
 495+ for(i=0;i<directories_size;i++)
 496+ print_directory_infos( &(directories[i]), 0);
 497+ }
 498+
 499+ }
 500+ else
 501+ { // No actions, small parts list
 502+
 503+ for(i=0;i<directories_size;i++)
 504+ print_directory_infos( &(directories[i]), 0);
 505+ }
 506+
 507+ }
 508+ }
 509+
 510+ fclose(file);
 511+
 512+ free(directories);
 513+
 514+ return EXIT_SUCCESS;
 515+}
Property changes on: tools/extract2g/extract2g.c
___________________________________________________________________
Added: svn:executable
## -0,0 +1 ##
 516+*
\ No newline at end of property
Index: tools/extract2g/extract2g.h
@@ -0,0 +1,27 @@
 2+
 3+#define ADDR_DIR_DEFAULT 0x4800
 4+#define ADDR_DIR_1G 0x4200
 5+#define ADDR_DIR_2G 0x4800
 6+#define ADDR_DIR_3G 0x5000
 7+
 8+
 9+#define LEN_HEADER 0x800
 10+
 11+#define LEN_DIR sizeof(DIRECTORY)
 12+
 13+typedef struct _DIRECTORY
 14+{
 15+ char dev[4];
 16+ char type[4];
 17+
 18+ unsigned int id;
 19+ unsigned int devOffset;
 20+ unsigned int len;
 21+ unsigned int addr;
 22+
 23+ unsigned int entryOffset;
 24+ unsigned int checksum;
 25+ unsigned int version;
 26+ unsigned int loadAddr;
 27+
 28+}DIRECTORY;
Property changes on: tools/extract2g/extract2g.h
___________________________________________________________________
Added: svn:executable
## -0,0 +1 ##
 29+*
\ No newline at end of property
Index: tools/extract2g/Makefile
@@ -0,0 +1,11 @@
 2+CC= gcc
 3+OPTS= -Wall -g
 4+
 5+all: extract2g
 6+
 7+extract2g: extract2g.c extract2g.h
 8+ $(CC) $(OPTS) $< -o $@
 9+
 10+.PHONY: clean
 11+clean:
 12+ rm -f extract2g
Property changes on: tools/extract2g/Makefile
___________________________________________________________________
Added: svn:executable
## -0,0 +1 ##
 13+*
\ No newline at end of property