| Index: tools/extract2g_HACKED/extract2g.c | 
| — | — | @@ -1,514 +0,0 @@ | 
| 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 | 
| ___________________________________________________________________ | 
| Deleted: svn:executable | 
| ## -1 +0,0 ## | 
| 516 |  | -* | 
| \ No newline at end of property | 
| Index: tools/extract2g_HACKED/README | 
| — | — | @@ -1,13 +0,0 @@ | 
| 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 |  | ->       if ( (tmp = strtol(optarg, NULL, 0)) > -1 ) | 
| 10 |  | -407c407 | 
| 11 |  | -<  | 
| 12 |  | -> 		dir.devOffset += 4096; | 
| Index: tools/extract2g_HACKED/extract2g.h | 
| — | — | @@ -1,27 +0,0 @@ | 
| 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 | 
| ___________________________________________________________________ | 
| Deleted: svn:executable | 
| ## -1 +0,0 ## | 
| 29 |  | -* | 
| \ No newline at end of property | 
| Index: tools/extract2g_HACKED/Makefile | 
| — | — | @@ -1,11 +0,0 @@ | 
| 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 | 
| ___________________________________________________________________ | 
| Deleted: svn:executable | 
| ## -1 +0,0 ## | 
| 13 |  | -* | 
| \ No newline at end of property | 
| Index: tools/extract2g/extract2g.c | 
| — | — | @@ -23,6 +23,9 @@ | 
| 24 | 24 | 1.1 - 2007-09-15 | 
| 25 | 25 | -- Stuff added to guess the header versions. | 
| 26 | 26 |  | 
|  | 27 | +  1.2 - 2010-08-15 | 
|  | 28 | +  -- Added Nano 4G firmware support. | 
|  | 29 | + | 
| 27 | 30 | Todo list: | 
| 28 | 31 | -- Debug | 
| 29 | 32 | */ | 
| — | — | @@ -36,7 +39,7 @@ | 
| 37 | 40 | #include "extract2g.h" | 
| 38 | 41 |  | 
| 39 | 42 | #define VERSION_H 1 | 
| 40 |  | -#define VERSION_L 1 | 
|  | 43 | +#define VERSION_L 2 | 
| 41 | 44 |  | 
| 42 | 45 | #define B (0x0FFFFFFF) | 
| 43 | 46 |  | 
| — | — | @@ -230,14 +233,15 @@ | 
| 231 | 234 | fputs("Usage: extract_2g [OPTION] [FILE]\n", stdout); | 
| 232 | 235 | fprintf(stdout,"Read & extract iPod Nano 2G data parts from a FILE dump.\n\ | 
| 233 | 236 | \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); | 
|  | 237 | +-l, --list               only list avaible parts according to the dump directory\n\n\ | 
|  | 238 | +-H, --hash               do a hash on every part of the dump\n\n\ | 
|  | 239 | +-A, --all                extract ALL founded parts from dump (default names used)\n\n\ | 
|  | 240 | +-4, --nano4g-compat      forces iPod Nano 3G firmwares to be recognised as iPod Nano 4G's\n\n\ | 
|  | 241 | +-e, --extract=NAME       select which part you want to extract (default none)\n\ | 
|  | 242 | +-o, --output=FILE        put the extracted part into FILE (default NAME.fw)\n\n\ | 
|  | 243 | +-d, --directory-address  specify the directory address (default 0x%X )\n\ | 
|  | 244 | +-a, --header-length      specify the header length of each part (default 0x800)\n\n\ | 
|  | 245 | +-h, --help               display this help and exit\n", ADDR_DIR_DEFAULT); | 
| 242 | 246 | } | 
| 243 | 247 |  | 
| 244 | 248 | exit(status); | 
| — | — | @@ -252,6 +256,7 @@ | 
| 253 | 257 |  | 
| 254 | 258 | char extract_is_set = 0; | 
| 255 | 259 | char extract_all = 0; | 
|  | 260 | +  char nano4g_compat = 0; | 
| 256 | 261 | char list_directories = 0; | 
| 257 | 262 | char is_found = 0; | 
| 258 | 263 | char hash_parts = 0; | 
| — | — | @@ -271,7 +276,7 @@ | 
| 272 | 277 | int length_header = LEN_HEADER; | 
| 273 | 278 |  | 
| 274 | 279 | /* Getopt short options */ | 
| 275 |  | -  static char const short_options[] = "e:o:d:a:AHlhv"; | 
|  | 280 | +  static char const short_options[] = "e:o:d:a:AHl4hv"; | 
| 276 | 281 |  | 
| 277 | 282 | /* Getopt long options */ | 
| 278 | 283 | static struct option const long_options[] = { | 
| — | — | @@ -282,6 +287,7 @@ | 
| 283 | 288 | {"all", no_argument, NULL, 'A'}, | 
| 284 | 289 | {"directory-address", required_argument, NULL, 'd'}, | 
| 285 | 290 | {"header-length", required_argument, NULL, 'a'}, | 
|  | 291 | +    {"nano4g-compat", no_argument, NULL, '4'}, | 
| 286 | 292 | {"help", no_argument, NULL, 'h'}, | 
| 287 | 293 | {"version", no_argument, NULL, 'v'}, | 
| 288 | 294 | {NULL, 0, NULL, 0} | 
| — | — | @@ -340,6 +346,10 @@ | 
| 341 | 347 | extract_all = 1; | 
| 342 | 348 | break; | 
| 343 | 349 |  | 
|  | 350 | +    case '4': | 
|  | 351 | +        nano4g_compat = 1; | 
|  | 352 | +      break; | 
|  | 353 | + | 
| 344 | 354 | case 'h': | 
| 345 | 355 | usage(EXIT_SUCCESS); | 
| 346 | 356 | break; | 
| — | — | @@ -375,7 +385,10 @@ | 
| 376 | 386 | else | 
| 377 | 387 | addr_directory = ADDR_DIR_DEFAULT; | 
| 378 | 388 |  | 
|  | 389 | +  if (addr_directory == ADDR_DIR_3G && nano4g_compat) | 
|  | 390 | +    printf("> iPod nano 4g compat. mode enabled\n"); | 
| 379 | 391 |  | 
|  | 392 | + | 
| 380 | 393 | fseek(file, addr_directory, SEEK_SET); | 
| 381 | 394 |  | 
| 382 | 395 | DIRECTORY dir; | 
| — | — | @@ -404,7 +417,10 @@ | 
| 405 | 418 | fprintf(stderr,"Memory allocation failure.\n"); | 
| 406 | 419 | exit(EXIT_FAILURE); | 
| 407 | 420 | } | 
| 408 |  | - | 
|  | 421 | + | 
|  | 422 | +	  if (addr_directory == ADDR_DIR_3G && nano4g_compat) | 
|  | 423 | +        dir.devOffset += 4096; | 
|  | 424 | + | 
| 409 | 425 | memcpy(directories + directories_size - 1, &dir, sizeof(DIRECTORY)); | 
| 410 | 426 | } | 
| 411 | 427 | else |