A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 1995 lines 60 kB view raw
1/*************************************************************************** 2 * __________ __ ___. 3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___ 4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / 5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < 6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ 7 * \/ \/ \/ \/ \/ 8 * $Id$ 9 * 10 * Copyright (C) 2006-2007 Dave Chapman 11 * 12 * This program is free software; you can redistribute it and/or 13 * modify it under the terms of the GNU General Public License 14 * as published by the Free Software Foundation; either version 2 15 * of the License, or (at your option) any later version. 16 * 17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 18 * KIND, either express or implied. 19 * 20 ****************************************************************************/ 21 22#include <stdio.h> 23#include <unistd.h> 24#include <fcntl.h> 25#include <string.h> 26#include <stdlib.h> 27#include <inttypes.h> 28#include <stdbool.h> 29#include <sys/types.h> 30#include <sys/stat.h> 31 32#include "parttypes.h" 33#include "ipodio.h" 34#include "ipodpatcher.h" 35 36#ifdef WITH_BOOTOBJS 37#include "ipod1g2g.h" 38#include "ipod3g.h" 39#include "ipod4g.h" 40#include "ipodmini1g.h" 41#include "ipodmini2g.h" 42#include "ipodcolor.h" 43#include "ipodnano1g.h" 44#include "ipodvideo.h" 45#include "ipodnano2g.h" 46#endif 47 48int ipod_verbose = 0; 49 50 51/* The following string appears at the start of the firmware partition */ 52static const char apple_stop_sign[] = "{{~~ /-----\\ "\ 53 "{{~~ / \\ "\ 54 "{{~~| | "\ 55 "{{~~| S T O P | "\ 56 "{{~~| | "\ 57 "{{~~ \\ / "\ 58 "{{~~ \\-----/ "\ 59 "Copyright(C) 200"\ 60 "1 Apple Computer"\ 61 ", Inc.----------"\ 62 "----------------"\ 63 "----------------"\ 64 "----------------"\ 65 "----------------"\ 66 "----------------"\ 67 "---------------"; 68 69/* Windows requires the buffer for disk I/O to be aligned in memory on a 70 multiple of the disk volume size - so we use a single global variable 71 and initialise it with ipod_alloc_buf() 72*/ 73 74char* get_parttype(unsigned int pt) 75{ 76 int i; 77 static char unknown[]="Unknown"; 78 79 if (pt == PARTTYPE_HFS) { 80 return "HFS/HFS+"; 81 } 82 83 i=0; 84 while (parttypes[i].name != NULL) { 85 if (parttypes[i].type == pt) { 86 return (parttypes[i].name); 87 } 88 i++; 89 } 90 91 return unknown; 92} 93 94off_t filesize(int fd) { 95 struct stat buf; 96 97 if (fstat(fd,&buf) < 0) { 98 perror("[ERR] Checking filesize of input file"); 99 return -1; 100 } else { 101 return(buf.st_size); 102 } 103} 104 105/* Partition table parsing code taken from Rockbox */ 106 107#define MAX_SECTOR_SIZE 2048 108#define SECTOR_SIZE 512 109 110static inline unsigned short le2ushort(unsigned char* buf) 111{ 112 unsigned short res = (buf[1] << 8) | buf[0]; 113 114 return res; 115} 116 117static inline int le2int(unsigned char* buf) 118{ 119 int32_t res = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; 120 121 return res; 122} 123 124static inline int be2int(unsigned char* buf) 125{ 126 int32_t res = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; 127 128 return res; 129} 130 131static inline int getint16le(char* buf) 132{ 133 int16_t res = (buf[1] << 8) | buf[0]; 134 135 return res; 136} 137 138static inline void short2le(unsigned short val, unsigned char* addr) 139{ 140 addr[0] = val & 0xFF; 141 addr[1] = (val >> 8) & 0xff; 142} 143 144static inline void int2le(unsigned int val, unsigned char* addr) 145{ 146 addr[0] = val & 0xFF; 147 addr[1] = (val >> 8) & 0xff; 148 addr[2] = (val >> 16) & 0xff; 149 addr[3] = (val >> 24) & 0xff; 150} 151 152static inline void int2be(unsigned int val, unsigned char* addr) 153{ 154 addr[0] = (val >> 24) & 0xff; 155 addr[1] = (val >> 16) & 0xff; 156 addr[2] = (val >> 8) & 0xff; 157 addr[3] = val & 0xFF; 158} 159 160 161#define BYTES2INT32(array,pos)\ 162 ((long)array[pos] | ((long)array[pos+1] << 8 ) |\ 163 ((long)array[pos+2] << 16 ) | ((long)array[pos+3] << 24 )) 164 165int read_partinfo(struct ipod_t* ipod, int silent) 166{ 167 int i; 168 unsigned long count; 169 170 if(ipod->sectorbuf == NULL) { 171 fprintf(stderr,"[ERR] Buffer not initialized."); 172 return -1; 173 } 174 175 count = ipod_read(ipod,ipod->sector_size); 176 177 if (count <= 0) { 178 ipod_print_error(" Error reading from disk: "); 179 return -1; 180 } 181 182 memset(ipod->pinfo, 0, sizeof(ipod->pinfo)); 183 184 if ((ipod->sectorbuf[510] == 0x55) && (ipod->sectorbuf[511] == 0xaa)) { 185 /* DOS partition table */ 186 ipod->macpod = 0; 187 /* parse partitions */ 188 for ( i = 0; i < 4; i++ ) { 189 unsigned char* ptr = ipod->sectorbuf + 0x1be + 16*i; 190 ipod->pinfo[i].type = ptr[4]; 191 ipod->pinfo[i].start = BYTES2INT32(ptr, 8); 192 ipod->pinfo[i].size = BYTES2INT32(ptr, 12); 193 194 /* extended? */ 195 if ( ipod->pinfo[i].type == 5 ) { 196 /* not handled yet */ 197 } 198 } 199 } else if ((ipod->sectorbuf[0] == 'E') && (ipod->sectorbuf[1] == 'R')) { 200 /* Apple Partition Map */ 201 202 /* APM parsing code based on the check_mac_partitions() function in 203 ipodloader2 - written by Thomas Tempelmann and released 204 under the GPL. */ 205 206 int blkNo = 1; 207 int partBlkCount = 1; 208 int partBlkSizMul = ipod->sectorbuf[2] / 2; 209 210 int pmMapBlkCnt; /* # of blks in partition map */ 211 int pmPyPartStart; /* physical start blk of partition */ 212 int pmPartBlkCnt; /* # of blks in this partition */ 213 int i = 0; 214 215 ipod->macpod = 1; 216 217 memset(ipod->pinfo,0,sizeof(ipod->pinfo)); 218 219 while (blkNo <= partBlkCount) { 220 if (ipod_seek(ipod, blkNo * partBlkSizMul * 512) < 0) { 221 fprintf(stderr,"[ERR] Seek failed whilst reading APM\n"); 222 return -1; 223 } 224 225 count = ipod_read(ipod, ipod->sector_size); 226 227 if (count <= 0) { 228 ipod_print_error(" Error reading from disk: "); 229 return -1; 230 } 231 232 /* see if it's a partition entry */ 233 if ((ipod->sectorbuf[0] != 'P') || (ipod->sectorbuf[1] != 'M')) { 234 /* end of partition table -> leave the loop */ 235 break; 236 } 237 238 /* Extract the interesting entries */ 239 pmMapBlkCnt = be2int(ipod->sectorbuf + 4); 240 pmPyPartStart = be2int(ipod->sectorbuf + 8); 241 pmPartBlkCnt = be2int(ipod->sectorbuf + 12); 242 243 /* update the number of part map blocks */ 244 partBlkCount = pmMapBlkCnt; 245 246 if (strncmp((char*)(ipod->sectorbuf + 48), "Apple_MDFW", 32)==0) { 247 /* A Firmware partition */ 248 ipod->pinfo[i].start = pmPyPartStart; 249 ipod->pinfo[i].size = pmPartBlkCnt; 250 ipod->pinfo[i].type = 0; 251 i++; 252 } else if (strncmp((char*)(ipod->sectorbuf + 48), "Apple_HFS", 32)==0) { 253 /* A HFS partition */ 254 ipod->pinfo[i].start = pmPyPartStart; 255 ipod->pinfo[i].size = pmPartBlkCnt; 256 ipod->pinfo[i].type = PARTTYPE_HFS; 257 i++; 258 } 259 260 blkNo++; /* read next partition map entry */ 261 } 262 } else { 263 if (!silent) fprintf(stderr,"[ERR] Bad boot sector signature\n"); 264 return -1; 265 } 266 267 /* Check that the partition table looks like an ipod: 268 1) Partition 1 is of type 0 (Empty) but isn't empty. 269 2) Partition 2 is of type 0xb or 0xc (winpod) or -1 (macpod) 270 */ 271 if ((ipod->pinfo[0].type != 0) || (ipod->pinfo[0].size == 0) || 272 ((ipod->pinfo[1].type != 0xb) && (ipod->pinfo[1].type != 0xc) && 273 (ipod->pinfo[1].type != PARTTYPE_HFS))) { 274 if (!silent) fprintf(stderr,"[ERR] Partition layout is not an ipod\n"); 275 return -1; 276 } 277 278 ipod->start = ipod->pinfo[0].start*ipod->sector_size; 279 return 0; 280} 281 282int read_partition(struct ipod_t* ipod, int outfile) 283{ 284 int res; 285 ssize_t n; 286 int bytesleft; 287 int chunksize; 288 int count = ipod->pinfo[0].size; 289 290 if (ipod_seek(ipod, ipod->start) < 0) { 291 return -1; 292 } 293 if(ipod->sectorbuf == NULL) { 294 fprintf(stderr,"[ERR] Buffer not initialized."); 295 return -1; 296 } 297 298 fprintf(stderr,"[INFO] Writing %d sectors to output file\n",count); 299 300 bytesleft = count * ipod->sector_size; 301 while (bytesleft > 0) { 302 if (bytesleft > BUFFER_SIZE) { 303 chunksize = BUFFER_SIZE; 304 } else { 305 chunksize = bytesleft; 306 } 307 308 n = ipod_read(ipod, chunksize); 309 310 if (n < 0) { 311 return -1; 312 } 313 314 if (n < chunksize) { 315 fprintf(stderr, 316 "[ERR] Short read in disk_read() - requested %d, got %d\n", 317 chunksize,(int)n); 318 return -1; 319 } 320 321 bytesleft -= n; 322 323 res = write(outfile,ipod->sectorbuf,n); 324 325 if (res < 0) { 326 perror("[ERR] write in disk_read"); 327 return -1; 328 } 329 330 if (res != n) { 331 fprintf(stderr, 332 "Short write - requested %d, received %d - aborting.\n",(int)n,res); 333 return -1; 334 } 335 } 336 337 fprintf(stderr,"[INFO] Done.\n"); 338 return 0; 339} 340 341int write_partition(struct ipod_t* ipod, int infile) 342{ 343 ssize_t res; 344 int n; 345 int bytesread; 346 int byteswritten = 0; 347 int eof; 348 int padding = 0; 349 350 if (ipod_seek(ipod, ipod->start) < 0) { 351 return -1; 352 } 353 if(ipod->sectorbuf == NULL) { 354 fprintf(stderr,"[ERR] Buffer not initialized."); 355 return -1; 356 } 357 358 fprintf(stderr,"[INFO] Writing input file to device\n"); 359 bytesread = 0; 360 eof = 0; 361 while (!eof) { 362 n = read(infile,ipod->sectorbuf,BUFFER_SIZE); 363 364 if (n < 0) { 365 perror("[ERR] read in disk_write"); 366 return -1; 367 } 368 369 if (n < BUFFER_SIZE) { 370 eof = 1; 371 /* We need to pad the last write to a multiple of SECTOR_SIZE */ 372 if ((n % ipod->sector_size) != 0) { 373 padding = (ipod->sector_size-(n % ipod->sector_size)); 374 n += padding; 375 } 376 } 377 378 bytesread += n; 379 380 res = ipod_write(ipod, n); 381 382 if (res < 0) { 383 ipod_print_error(" Error writing to disk: "); 384 fprintf(stderr,"Bytes written: %d\n",byteswritten); 385 return -1; 386 } 387 388 if (res != n) { 389 fprintf(stderr,"[ERR] Short write - requested %d, received %d - aborting.\n",n,(int)res); 390 return -1; 391 } 392 393 byteswritten += res; 394 } 395 396 fprintf(stderr,"[INFO] Wrote %d bytes plus %d bytes padding.\n", 397 byteswritten-padding,padding); 398 return 0; 399} 400 401char* ftypename[] = { "OSOS", "RSRC", "AUPD", "HIBE", "OSBK" }; 402 403int diskmove(struct ipod_t* ipod, int delta) 404{ 405 int src_start; 406 int src_end; 407 int bytesleft; 408 int chunksize; 409 int n; 410 411 src_start = ipod->ipod_directory[1].devOffset; 412 src_end = (ipod->ipod_directory[ipod->nimages-1].devOffset + ipod->sector_size + 413 ipod->ipod_directory[ipod->nimages-1].len + 414 (ipod->sector_size-1)) & ~(ipod->sector_size-1); 415 bytesleft = src_end - src_start; 416 417 if (ipod_verbose) { 418 fprintf(stderr,"[INFO] Need to move images 2-%d forward %08x bytes\n", ipod->nimages,delta); 419 fprintf(stderr,"[VERB] src_start = %08x\n",src_start); 420 fprintf(stderr,"[VERB] src_end = %08x\n",src_end); 421 fprintf(stderr,"[VERB] dest_start = %08x\n",src_start+delta); 422 fprintf(stderr,"[VERB] dest_end = %08x\n",src_end+delta); 423 fprintf(stderr,"[VERB] bytes to copy = %08x\n",bytesleft); 424 } 425 426 while (bytesleft > 0) { 427 if (bytesleft <= BUFFER_SIZE) { 428 chunksize = bytesleft; 429 } else { 430 chunksize = BUFFER_SIZE; 431 } 432 433 if (ipod_verbose) { 434 fprintf(stderr,"[VERB] Copying %08x bytes from %08x to %08x (absolute %08x to %08x)\n", 435 chunksize, 436 src_end-chunksize, 437 src_end-chunksize+delta, 438 (unsigned int)(ipod->start+src_end-chunksize), 439 (unsigned int)(ipod->start+src_end-chunksize+delta)); 440 } 441 442 443 if (ipod_seek(ipod, ipod->start+src_end-chunksize) < 0) { 444 fprintf(stderr,"[ERR] Seek failed\n"); 445 return -1; 446 } 447 448 if ((n = ipod_read(ipod,chunksize)) < 0) { 449 perror("[ERR] Write failed\n"); 450 return -1; 451 } 452 453 if (n < chunksize) { 454 fprintf(stderr,"[ERR] Short read - requested %d bytes, received %d\n", 455 chunksize,n); 456 return -1; 457 } 458 459 if (ipod_seek(ipod, ipod->start+src_end-chunksize+delta) < 0) { 460 fprintf(stderr,"[ERR] Seek failed\n"); 461 return -1; 462 } 463 464 if ((n = ipod_write(ipod,chunksize)) < 0) { 465 perror("[ERR] Write failed\n"); 466 return -1; 467 } 468 469 if (n < chunksize) { 470 fprintf(stderr,"[ERR] Short write - requested %d bytes, received %d\n" 471 ,chunksize,n); 472 return -1; 473 } 474 475 src_end -= chunksize; 476 bytesleft -= chunksize; 477 } 478 479 return 0; 480} 481 482static int rename_image(struct ipod_t* ipod, char* from, char* to) 483{ 484 int n; 485 int x; 486 int found; 487 int i; 488 unsigned char* p; 489 490 /* diroffset may not be sector-aligned */ 491 x = ipod->diroffset % ipod->sector_size; 492 493 if(ipod->sectorbuf == NULL) { 494 fprintf(stderr,"[ERR] Buffer not initialized."); 495 return -1; 496 } 497 /* Read directory */ 498 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { 499 fprintf(stderr,"[ERR] Seek to diroffset (%08x) failed.\n",(unsigned)ipod->diroffset); 500 return -1; 501 } 502 503 n=ipod_read(ipod, ipod->sector_size); 504 if (n < 0) { 505 fprintf(stderr,"[ERR] Read of directory failed.\n"); 506 return -1; 507 } 508 509 p = ipod->sectorbuf + x; 510 511 /* A hack to detect 2nd gen Nanos - maybe there is a better way? */ 512 if (p[0] == 0) 513 { 514 /* Adjust diroffset */ 515 ipod->diroffset += ipod->sector_size - x; 516 517 n=ipod_read(ipod, ipod->sector_size); 518 if (n < 0) { 519 fprintf(stderr,"[ERR] Read of directory failed.\n"); 520 return -1; 521 } 522 p = ipod->sectorbuf; 523 } 524 525 found = 0; 526 for (i=0 ; !found && i < MAX_IMAGES; i++) { 527 if (memcmp(p + 4, from, 4) == 0) { 528 memcpy(p + 4, to, 4); 529 530 found = 1; 531 } 532 p += 40; 533 } 534 535 if (!found) { 536 fprintf(stderr,"[ERR] Unexpected error - no \"%s\" image!\n", from); 537 return -1; 538 } 539 540 /* Write directory back to disk */ 541 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { 542 fprintf(stderr,"[ERR] Seek to diroffset (%08x) failed.\n",(unsigned)ipod->diroffset); 543 return -1; 544 } 545 546 n=ipod_write(ipod, ipod->sector_size); 547 if (n < 0) { 548 fprintf(stderr,"[ERR] Write of directory failed in rename_image.\n"); 549 return -1; 550 } 551 552 return 0; 553} 554 555static int delete_image(struct ipod_t* ipod, char* name) 556{ 557 int n; 558 int x; 559 int found; 560 int i; 561 unsigned char* p; 562 563 /* diroffset may not be sector-aligned */ 564 x = ipod->diroffset % ipod->sector_size; 565 566 /* Read directory */ 567 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { 568 fprintf(stderr,"[ERR] Seek to diroffset (%08x) failed.\n",(unsigned)ipod->diroffset); 569 return -1; 570 } 571 572 n=ipod_read(ipod, ipod->sector_size); 573 if (n < 0) { 574 fprintf(stderr,"[ERR] Read of directory failed.\n"); 575 return -1; 576 } 577 578 p = ipod->sectorbuf + x; 579 580 /* A hack to detect 2nd gen Nanos - maybe there is a better way? */ 581 if (p[0] == 0) 582 { 583 /* Adjust diroffset */ 584 ipod->diroffset += ipod->sector_size - x; 585 586 n=ipod_read(ipod, ipod->sector_size); 587 if (n < 0) { 588 fprintf(stderr,"[ERR] Read of directory failed.\n"); 589 return -1; 590 } 591 p = ipod->sectorbuf; 592 } 593 594 found = 0; 595 for (i=0 ; !found && i < MAX_IMAGES; i++) { 596 if (memcmp(p + 4, name, 4) == 0) { 597 memset(p, 0, 40); /* Delete directory entry */ 598 found = 1; 599 } 600 p += 40; 601 } 602 603 if (!found) { 604 fprintf(stderr,"[ERR] Unexpected error - no \"%s\" image!\n", name); 605 return -1; 606 } 607 608 /* Write directory back to disk */ 609 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { 610 fprintf(stderr,"[ERR] Seek to diroffset (%08x) failed.\n",(unsigned)ipod->diroffset); 611 return -1; 612 } 613 614 n=ipod_write(ipod, ipod->sector_size); 615 if (n < 0) { 616 fprintf(stderr,"[ERR] Write of directory failed in delete_image.\n"); 617 return -1; 618 } 619 620 return 0; 621} 622 623int add_new_image(struct ipod_t* ipod, char* imagename, char* filename, int type) 624{ 625 int length; 626 int found; 627 int i; 628 int x; 629 int n; 630 int infile; 631 int newsize; 632 unsigned long chksum=0; 633 unsigned long filechksum=0; 634 unsigned long offset; 635 unsigned char header[8]; /* Header for .ipod file */ 636 unsigned char* p; 637 638 if(ipod->sectorbuf == NULL) { 639 fprintf(stderr,"[ERR] Buffer not initialized."); 640 return -1; 641 } 642#ifdef WITH_BOOTOBJS 643 if (type == FILETYPE_INTERNAL) { 644 fprintf(stderr,"[INFO] Using internal bootloader - %d bytes\n",ipod->bootloader_len); 645 length = ipod->bootloader_len; 646 infile = -1; 647 } 648 else 649#endif 650 { 651 /* First check that the input file is the correct type for this ipod. */ 652 infile=open(filename,O_RDONLY); 653 if (infile < 0) { 654 fprintf(stderr,"[ERR] Couldn't open input file %s\n",filename); 655 return -1; 656 } 657 658 if (type==FILETYPE_DOT_IPOD) { 659 n = read(infile,header,8); 660 if (n < 8) { 661 fprintf(stderr,"[ERR] Failed to read header from %s\n",filename); 662 close(infile); 663 return -1; 664 } 665 666 if (memcmp(header+4, ipod->modelname,4)!=0) { 667 fprintf(stderr,"[ERR] Model name in input file (%c%c%c%c) doesn't match ipod model (%s)\n", 668 header[4],header[5],header[6],header[7], ipod->modelname); 669 close(infile); 670 return -1; 671 } 672 673 filechksum = be2int(header); 674 675 length = filesize(infile)-8; 676 } else { 677 length = filesize(infile); 678 } 679 } 680 681 newsize=(length+ipod->sector_size-1)&~(ipod->sector_size-1); 682 683 fprintf(stderr,"[INFO] Padding input file from 0x%08x to 0x%08x bytes\n", 684 length,newsize); 685 686 if (newsize > BUFFER_SIZE) { 687 fprintf(stderr,"[ERR] Input file too big for buffer\n"); 688 if (infile >= 0) close(infile); 689 return -1; 690 } 691 692 /* TODO: Check if we have enough space in the partition for the new image */ 693 694#ifdef WITH_BOOTOBJS 695 if (type == FILETYPE_INTERNAL) { 696 memcpy(ipod->sectorbuf,ipod->bootloader,ipod->bootloader_len); 697 } 698 else 699#endif 700 { 701 fprintf(stderr,"[INFO] Reading input file...\n"); 702 703 n = read(infile,ipod->sectorbuf,length); 704 if (n < 0) { 705 fprintf(stderr,"[ERR] Couldn't read input file\n"); 706 close(infile); 707 return -1; 708 } 709 close(infile); 710 } 711 712 /* Pad the data with zeros */ 713 memset(ipod->sectorbuf+length,0,newsize-length); 714 715 if (type==FILETYPE_DOT_IPOD) { 716 chksum = ipod->modelnum; 717 for (i = 0; i < length; i++) { 718 /* add 8 unsigned bits but keep a 32 bit sum */ 719 chksum += ipod->sectorbuf[i]; 720 } 721 722 if (chksum == filechksum) { 723 fprintf(stderr,"[INFO] Checksum OK in %s\n",filename); 724 } else { 725 fprintf(stderr,"[ERR] Checksum in %s failed check\n",filename); 726 return -1; 727 } 728 } 729 730 731 offset = ipod->fwoffset + ipod->ipod_directory[ipod->nimages - 1].devOffset + 732 ipod->ipod_directory[ipod->nimages - 1].len + ipod->sector_size; 733 734 /* 2nd Gen Nano has encrypted firmware, and the sector 735 preceeding the firmware contains hashes that need to be 736 preserved. Nano 2G images include these extra 2048 (0x800) 737 bytes 738 */ 739 if (ipod_seek(ipod, offset - (ipod->modelnum == 62 ? 0x800 : 0)) < 0) { 740 fprintf(stderr,"[ERR] Seek failed\n"); 741 return -1; 742 } 743 744 if ((n = ipod_write(ipod,newsize)) < 0) { 745 perror("[ERR] Write failed\n"); 746 return -1; 747 } 748 749 if (n < newsize) { 750 fprintf(stderr,"[ERR] Short write - requested %d bytes, received %d\n" 751 ,newsize,n); 752 return -1; 753 } 754 fprintf(stderr,"[INFO] Wrote %d bytes to firmware partition\n",n); 755 756 /* Now we need to create a new directory entry 757 758 NOTE: On the Nano 2G, the checksum is the checksum of the 759 unencrypted firmware. But this isn't checked by the NOR 760 bootloader (there are cryptographic hashes in the 761 firmware itself), so it doesn't matter that this is 762 wrong. 763 */ 764 chksum = 0; 765 for (i = 0; i < length; i++) { 766 /* add 8 unsigned bits but keep a 32 bit sum */ 767 chksum += ipod->sectorbuf[i]; 768 } 769 770 x = ipod->diroffset % ipod->sector_size; 771 772 /* Read directory */ 773 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; } 774 775 n=ipod_read(ipod, ipod->sector_size); 776 if (n < 0) { return -1; } 777 778 /* Create a new directory entry */ 779 780 /* Copy OSOS or OSBK details - we assume one of them exists */ 781 p = ipod->sectorbuf + x; 782 found = 0; 783 for (i = 0; !found && i < ipod->nimages; i++) { 784 if ((memcmp(p + 4, "soso", 4)==0) || (memcmp(p + 4, "kbso", 4)==0)) { 785 found = 1; 786 } else { 787 p += 40; 788 } 789 } 790 791 if (!found) { 792 fprintf(stderr,"[ERR] No OSOS or OSBK image to copy directory from\n"); 793 return -1; 794 } 795 796 /* Copy directory image */ 797 memcpy(ipod->sectorbuf + x + (ipod->nimages * 40), p, 40); 798 p = ipod->sectorbuf + x + (ipod->nimages * 40); 799 800 /* Modify directory. */ 801 memcpy(p + 4, imagename, 4); 802 int2le(offset - ipod->fwoffset, p + 12); /* devOffset */ 803 int2le(length - (ipod->modelnum==62 ? 0x800: 0), p + 16); /* len */ 804 int2le(chksum, p + 28); /* checksum */ 805 806 /* Write directory */ 807 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; } 808 n=ipod_write(ipod, ipod->sector_size); 809 if (n < 0) { return -1; } 810 811 return 0; 812} 813 814 815int ipod_has_bootloader(struct ipod_t* ipod) 816{ 817 /* The 2nd gen Nano is installed differently */ 818 if (ipod->modelnum == 62) { 819 int i; 820 int has_osbk = 0; 821 /* Check if we have an OSBK image */ 822 for (i = 0; i < ipod->nimages; i++) { 823 if (ipod->ipod_directory[i].ftype==FTYPE_OSBK) { 824 has_osbk = 1; 825 } 826 } 827 return has_osbk; 828 } 829 else { 830 return (ipod->ipod_directory[0].entryOffset != 0); 831 } 832} 833 834 835/* 836 Bootloader installation on the Nano2G consists of renaming the 837 OSOS image to OSBK and then writing the Rockbox bootloader as a 838 new OSOS image. 839 840 Maybe this approach can/should be adapted for other ipods, as it 841 prevents the Apple bootloader loading the original firmware into 842 RAM along with the Rockbox bootloader (and hence will give a 843 faster boot when the user just wants to start Rockbox). 844 845*/ 846 847static int add_bootloader_nano2g(struct ipod_t* ipod, char* filename, int type) 848{ 849 /* Check if we already have an OSBK image */ 850 if (ipod_has_bootloader(ipod) == 0) { 851 /* First-time install - rename OSOS to OSBK and create new OSOS for bootloader */ 852 fprintf(stderr,"[INFO] Creating OSBK backup image of original firmware\n"); 853 854 if (rename_image(ipod, "soso", "kbso") < 0) { 855 fprintf(stderr,"[ERR] Could not rename OSOS image\n"); 856 return -1; 857 } 858 859 /* Add our bootloader as a brand new image */ 860 return add_new_image(ipod, "soso", filename, type); 861 } else { 862 /* This is an update, just replace OSOS with our bootloader */ 863 864 return write_firmware(ipod, filename, type); 865 } 866} 867 868 869static int delete_bootloader_nano2g(struct ipod_t* ipod) 870{ 871 /* Check if we have an OSBK image */ 872 if (ipod_has_bootloader(ipod) == 0) { 873 fprintf(stderr,"[ERR] No OSBK image found - nothing to uninstall\n"); 874 return -1; 875 } else { 876 /* Delete our bootloader image */ 877 if (delete_image(ipod, "soso") < 0) { 878 fprintf(stderr,"[WARN] Could not delete OSOS image\n"); 879 } else { 880 fprintf(stderr,"[INFO] OSOS image deleted\n"); 881 } 882 883 if (rename_image(ipod, "kbso", "soso") < 0) { 884 fprintf(stderr,"[ERR] Could not rename OSBK image\n"); 885 return -1; 886 } 887 888 889 fprintf(stderr,"[INFO] OSBK image renamed to OSOS - bootloader uninstalled.\n"); 890 return 0; 891 } 892} 893 894 895int add_bootloader(struct ipod_t* ipod, char* filename, int type) 896{ 897 int length; 898 int i; 899 int x; 900 int n; 901 int infile; 902 int paddedlength; 903 int entryOffset; 904 int delta = 0; 905 unsigned long chksum=0; 906 unsigned long filechksum=0; 907 unsigned char header[8]; /* Header for .ipod file */ 908 unsigned char* bootloader_buf; 909 910 /* The 2nd gen Nano is installed differently */ 911 if (ipod->modelnum == 62) { 912 return add_bootloader_nano2g(ipod, filename, type); 913 } 914 if(ipod->sectorbuf == NULL) { 915 fprintf(stderr,"[ERR] Buffer not initialized."); 916 return -1; 917 } 918 919 /* Calculate the position in the OSOS image where our bootloader will go. */ 920 if (ipod->ipod_directory[0].entryOffset>0) { 921 /* Keep the same entryOffset */ 922 entryOffset = ipod->ipod_directory[0].entryOffset; 923 } else { 924 entryOffset = (ipod->ipod_directory[0].len+ipod->sector_size-1)&~(ipod->sector_size-1); 925 } 926 927#ifdef WITH_BOOTOBJS 928 if (type == FILETYPE_INTERNAL) { 929 fprintf(stderr,"[INFO] Using internal bootloader - %d bytes\n",ipod->bootloader_len); 930 memcpy(ipod->sectorbuf+entryOffset,ipod->bootloader,ipod->bootloader_len); 931 length = ipod->bootloader_len; 932 paddedlength=(ipod->bootloader_len+ipod->sector_size-1)&~(ipod->sector_size-1); 933 } 934 else 935#endif 936 { 937 infile=open(filename,O_RDONLY); 938 if (infile < 0) { 939 fprintf(stderr,"[ERR] Couldn't open input file %s\n",filename); 940 return -1; 941 } 942 943 if (type==FILETYPE_DOT_IPOD) { 944 /* First check that the input file is the correct type for this ipod. */ 945 n = read(infile,header,8); 946 if (n < 8) { 947 fprintf(stderr,"[ERR] Failed to read header from %s\n",filename); 948 close(infile); 949 return -1; 950 } 951 952 if (memcmp(header+4, ipod->modelname,4)!=0) { 953 fprintf(stderr,"[ERR] Model name in input file (%c%c%c%c) doesn't match ipod model (%s)\n", 954 header[4],header[5],header[6],header[7], ipod->modelname); 955 close(infile); 956 return -1; 957 } 958 959 filechksum = be2int(header); 960 961 length=filesize(infile)-8; 962 } else { 963 length=filesize(infile); 964 } 965 paddedlength=(length+ipod->sector_size-1)&~(ipod->sector_size-1); 966 967 bootloader_buf = malloc(length); 968 if (bootloader_buf == NULL) { 969 fprintf(stderr,"[ERR] Can not allocate memory for bootloader\n"); 970 return -1; 971 } 972 /* Now read our bootloader - we need to check it before modifying the partition*/ 973 n = read(infile,bootloader_buf,length); 974 close(infile); 975 976 if (n < 0) { 977 fprintf(stderr,"[ERR] Couldn't read input file\n"); 978 return -1; 979 } 980 981 if (type==FILETYPE_DOT_IPOD) { 982 /* Calculate and confirm bootloader checksum */ 983 chksum = ipod->modelnum; 984 for (i = 0; i < length; i++) { 985 /* add 8 unsigned bits but keep a 32 bit sum */ 986 chksum += bootloader_buf[i]; 987 } 988 989 if (chksum == filechksum) { 990 fprintf(stderr,"[INFO] Checksum OK in %s\n",filename); 991 } else { 992 fprintf(stderr,"[ERR] Checksum in %s failed check\n",filename); 993 return -1; 994 } 995 } 996 } 997 998 if (entryOffset+paddedlength > BUFFER_SIZE) { 999 fprintf(stderr,"[ERR] Input file too big for buffer\n"); 1000 return -1; 1001 } 1002 1003 if (ipod_verbose) { 1004 fprintf(stderr,"[VERB] Original firmware begins at 0x%08x\n", ipod->ipod_directory[0].devOffset + ipod->sector_size); 1005 fprintf(stderr,"[VERB] New entryOffset will be 0x%08x\n",entryOffset); 1006 fprintf(stderr,"[VERB] End of bootloader will be at 0x%08x\n",entryOffset+paddedlength); 1007 } 1008 1009 /* Check if we have enough space */ 1010 /* TODO: Check the size of the partition. */ 1011 if (ipod->nimages > 1) { 1012 if ((ipod->ipod_directory[0].devOffset+entryOffset+paddedlength) > 1013 ipod->ipod_directory[1].devOffset) { 1014 fprintf(stderr,"[INFO] Moving images to create room for new firmware...\n"); 1015 delta = ipod->ipod_directory[0].devOffset + entryOffset+paddedlength 1016 - ipod->ipod_directory[1].devOffset + ipod->sector_size; 1017 1018 if (diskmove(ipod, delta) < 0) { 1019 fprintf(stderr,"[ERR] Image movement failed.\n"); 1020 return -1; 1021 } 1022 } 1023 } 1024 1025 1026 /* We have moved the partitions, now we can write our bootloader */ 1027 1028 /* Firstly read the original firmware into ipod->sectorbuf */ 1029 fprintf(stderr,"[INFO] Reading original firmware...\n"); 1030 if (ipod_seek(ipod, ipod->fwoffset+ipod->ipod_directory[0].devOffset) < 0) { 1031 fprintf(stderr,"[ERR] Seek failed\n"); 1032 return -1; 1033 } 1034 1035 if ((n = ipod_read(ipod,entryOffset)) < 0) { 1036 perror("[ERR] Read failed\n"); 1037 return -1; 1038 } 1039 1040 if (n < entryOffset) { 1041 fprintf(stderr,"[ERR] Short read - requested %d bytes, received %d\n" 1042 ,entryOffset,n); 1043 return -1; 1044 } 1045 1046#ifdef WITH_BOOTOBJS 1047 if (type == FILETYPE_INTERNAL) { 1048 memcpy(ipod->sectorbuf+entryOffset,ipod->bootloader,ipod->bootloader_len); 1049 } 1050 else 1051#endif 1052 { 1053 memcpy(ipod->sectorbuf+entryOffset,bootloader_buf,length); 1054 free(bootloader_buf); 1055 } 1056 1057 /* Calculate new checksum for combined image */ 1058 chksum = 0; 1059 for (i=0;i<entryOffset + length; i++) { 1060 chksum += ipod->sectorbuf[i]; 1061 } 1062 1063 /* Now write the combined firmware image to the disk */ 1064 1065 if (ipod_seek(ipod, ipod->fwoffset+ipod->ipod_directory[0].devOffset) < 0) { 1066 fprintf(stderr,"[ERR] Seek failed\n"); 1067 return -1; 1068 } 1069 1070 if ((n = ipod_write(ipod,entryOffset+paddedlength)) < 0) { 1071 perror("[ERR] Write failed\n"); 1072 return -1; 1073 } 1074 1075 if (n < (entryOffset+paddedlength)) { 1076 fprintf(stderr,"[ERR] Short read - requested %d bytes, received %d\n" 1077 ,entryOffset+paddedlength,n); 1078 return -1; 1079 } 1080 1081 fprintf(stderr,"[INFO] Wrote %d bytes to firmware partition\n",entryOffset+paddedlength); 1082 1083 x = ipod->diroffset % ipod->sector_size; 1084 1085 /* Read directory */ 1086 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { 1087 fprintf(stderr,"[ERR] Seek failed\n"); 1088 return -1; 1089 } 1090 1091 n=ipod_read(ipod, ipod->sector_size); 1092 if (n < 0) { 1093 fprintf(stderr,"[ERR] Directory read failed\n"); 1094 return -1; 1095 } 1096 1097 /* Update entries for image 0 */ 1098 int2le(entryOffset+length,ipod->sectorbuf+x+16); 1099 int2le(entryOffset,ipod->sectorbuf+x+24); 1100 int2le(chksum,ipod->sectorbuf+x+28); 1101 int2le(0xffffffff,ipod->sectorbuf+x+36); /* loadAddr */ 1102 1103 /* Update devOffset entries for other images, if we have moved them */ 1104 if (delta > 0) { 1105 for (i=1;i<ipod->nimages;i++) { 1106 int2le(le2int(ipod->sectorbuf+x+i*40+12)+delta,ipod->sectorbuf+x+i*40+12); 1107 } 1108 } 1109 1110 /* Write directory */ 1111 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { 1112 fprintf(stderr,"[ERR] Seek to %d failed\n", (int)(ipod->start+ipod->diroffset-x)); 1113 return -1; 1114 } 1115 n=ipod_write(ipod, ipod->sector_size); 1116 if (n < 0) { 1117 fprintf(stderr,"[ERR] Directory write failed\n"); 1118 return -1; 1119 } 1120 1121 return 0; 1122} 1123 1124int delete_bootloader(struct ipod_t* ipod) 1125{ 1126 int length; 1127 int i; 1128 int x; 1129 int n; 1130 unsigned long chksum=0; /* 32 bit checksum - Rockbox .ipod style*/ 1131 1132 /* The 2nd gen Nano is installed differently */ 1133 if (ipod->modelnum == 62) { 1134 return delete_bootloader_nano2g(ipod); 1135 } 1136 if(ipod->sectorbuf == NULL) { 1137 fprintf(stderr,"[ERR] Buffer not initialized."); 1138 return -1; 1139 } 1140 1141 /* Removing the bootloader involves adjusting the "length", 1142 "chksum" and "entryOffset" values in the osos image's directory 1143 entry. */ 1144 1145 /* Firstly check we have a bootloader... */ 1146 1147 if (ipod_has_bootloader(ipod) == 0) { 1148 fprintf(stderr,"[ERR] No bootloader found.\n"); 1149 return -1; 1150 } 1151 1152 length = ipod->ipod_directory[0].entryOffset; 1153 1154 /* Read the firmware so we can calculate the checksum */ 1155 fprintf(stderr,"[INFO] Reading firmware (%d bytes)\n",length); 1156 1157 if (ipod_seek(ipod, ipod->fwoffset+ipod->ipod_directory[0].devOffset) < 0) { 1158 return -1; 1159 } 1160 1161 i = (length+ipod->sector_size-1) & ~(ipod->sector_size-1); 1162 fprintf(stderr,"[INFO] Padding read from 0x%08x to 0x%08x bytes\n", 1163 length,i); 1164 1165 if ((n = ipod_read(ipod,i)) < 0) { 1166 return -1; 1167 } 1168 1169 if (n < i) { 1170 fprintf(stderr,"[ERR] Short read - requested %d bytes, received %d\n", 1171 i,n); 1172 return -1; 1173 } 1174 1175 chksum = 0; 1176 for (i = 0; i < length; i++) { 1177 /* add 8 unsigned bits but keep a 32 bit sum */ 1178 chksum += ipod->sectorbuf[i]; 1179 } 1180 1181 /* Now write back the updated directory entry */ 1182 1183 fprintf(stderr,"[INFO] Updating firmware checksum\n"); 1184 1185 x = ipod->diroffset % ipod->sector_size; 1186 1187 /* Read directory */ 1188 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; } 1189 1190 n=ipod_read(ipod, ipod->sector_size); 1191 if (n < 0) { return -1; } 1192 1193 /* Update entries for image 0 */ 1194 int2le(length,ipod->sectorbuf+x+16); 1195 int2le(0,ipod->sectorbuf+x+24); 1196 int2le(chksum,ipod->sectorbuf+x+28); 1197 1198 /* Write directory */ 1199 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; } 1200 n=ipod_write(ipod, ipod->sector_size); 1201 if (n < 0) { return -1; } 1202 1203 return 0; 1204} 1205 1206int write_firmware(struct ipod_t* ipod, char* filename, int type) 1207{ 1208 int length; 1209 int i; 1210 int x; 1211 int n; 1212 int infile; 1213 int newsize; 1214 int bytesavailable; 1215 unsigned long chksum=0; 1216 unsigned long filechksum=0; 1217 unsigned long offset; 1218 unsigned char header[8]; /* Header for .ipod file */ 1219 unsigned char* p; 1220 1221 if(ipod->sectorbuf == NULL) { 1222 fprintf(stderr,"[ERR] Buffer not initialized."); 1223 return -1; 1224 } 1225#ifdef WITH_BOOTOBJS 1226 if (type == FILETYPE_INTERNAL) { 1227 fprintf(stderr,"[INFO] Using internal bootloader - %d bytes\n",ipod->bootloader_len); 1228 length = ipod->bootloader_len; 1229 infile = -1; 1230 } 1231 else 1232#endif 1233 { 1234 /* First check that the input file is the correct type for this ipod. */ 1235 infile=open(filename,O_RDONLY); 1236 if (infile < 0) { 1237 fprintf(stderr,"[ERR] Couldn't open input file %s\n",filename); 1238 return -1; 1239 } 1240 1241 if (type==FILETYPE_DOT_IPOD) { 1242 n = read(infile,header,8); 1243 if (n < 8) { 1244 fprintf(stderr,"[ERR] Failed to read header from %s\n",filename); 1245 close(infile); 1246 return -1; 1247 } 1248 1249 if (memcmp(header+4, ipod->modelname,4)!=0) { 1250 fprintf(stderr,"[ERR] Model name in input file (%c%c%c%c) doesn't match ipod model (%s)\n", 1251 header[4],header[5],header[6],header[7], ipod->modelname); 1252 close(infile); 1253 return -1; 1254 } 1255 1256 filechksum = be2int(header); 1257 1258 length = filesize(infile)-8; 1259 } else { 1260 length = filesize(infile); 1261 } 1262 } 1263 1264 newsize=(length+ipod->sector_size-1)&~(ipod->sector_size-1); 1265 1266 fprintf(stderr,"[INFO] Padding input file from 0x%08x to 0x%08x bytes\n", 1267 length,newsize); 1268 1269 if (newsize > BUFFER_SIZE) { 1270 fprintf(stderr,"[ERR] Input file too big for buffer\n"); 1271 if (infile >= 0) close(infile); 1272 return -1; 1273 } 1274 1275 /* Check if we have enough space */ 1276 /* TODO: Check the size of the partition. */ 1277 if (ipod->nimages > 1) { 1278 bytesavailable=ipod->ipod_directory[1].devOffset-ipod->ipod_directory[0].devOffset; 1279 if (bytesavailable < newsize) { 1280 fprintf(stderr,"[INFO] Moving images to create room for new firmware...\n"); 1281 1282 /* TODO: Implement image movement */ 1283 fprintf(stderr,"[ERR] Image movement not yet implemented.\n"); 1284 close(infile); 1285 return -1; 1286 } 1287 } 1288 1289#ifdef WITH_BOOTOBJS 1290 if (type == FILETYPE_INTERNAL) { 1291 memcpy(ipod->sectorbuf,ipod->bootloader,ipod->bootloader_len); 1292 } 1293 else 1294#endif 1295 { 1296 fprintf(stderr,"[INFO] Reading input file...\n"); 1297 /* We now know we have enough space, so write it. */ 1298 n = read(infile,ipod->sectorbuf,length); 1299 if (n < 0) { 1300 fprintf(stderr,"[ERR] Couldn't read input file\n"); 1301 close(infile); 1302 return -1; 1303 } 1304 close(infile); 1305 } 1306 1307 /* Pad the data with zeros */ 1308 memset(ipod->sectorbuf+length,0,newsize-length); 1309 1310 if (type==FILETYPE_DOT_IPOD) { 1311 chksum = ipod->modelnum; 1312 for (i = 0; i < length; i++) { 1313 /* add 8 unsigned bits but keep a 32 bit sum */ 1314 chksum += ipod->sectorbuf[i]; 1315 } 1316 1317 if (chksum == filechksum) { 1318 fprintf(stderr,"[INFO] Checksum OK in %s\n",filename); 1319 } else { 1320 fprintf(stderr,"[ERR] Checksum in %s failed check\n",filename); 1321 return -1; 1322 } 1323 } 1324 1325 1326 offset = ipod->fwoffset+ipod->ipod_directory[ipod->ososimage].devOffset; 1327 1328 if (ipod->modelnum==62) { 1329 1330 /* 2nd Gen Nano has encrypted firmware, and the sector 1331 preceeding the firmware contains hashes that need to be 1332 preserved. Nano 2G images include these extra 2048 (0x800) 1333 bytes 1334 */ 1335 1336 offset -= 0x800; 1337 1338 /* TODO: The above checks need to take into account this 0x800 bytes */ 1339 } 1340 1341 if (ipod_seek(ipod, offset) < 0) { 1342 fprintf(stderr,"[ERR] Seek failed\n"); 1343 return -1; 1344 } 1345 1346 if ((n = ipod_write(ipod,newsize)) < 0) { 1347 perror("[ERR] Write failed\n"); 1348 return -1; 1349 } 1350 1351 if (n < newsize) { 1352 fprintf(stderr,"[ERR] Short write - requested %d bytes, received %d\n" 1353 ,newsize,n); 1354 return -1; 1355 } 1356 fprintf(stderr,"[INFO] Wrote %d bytes to firmware partition\n",n); 1357 1358 /* Now we need to update the "len", "entryOffset" and "chksum" fields 1359 1360 NOTE: On the Nano 2G, the checksum is the checksum of the 1361 unencrypted firmware. But this isn't checked by the NOR 1362 bootloader (there are cryptographic hashes in the 1363 firmware itself), so it doesn't matter that this is 1364 wrong. 1365 */ 1366 chksum = 0; 1367 for (i = 0; i < length; i++) { 1368 /* add 8 unsigned bits but keep a 32 bit sum */ 1369 chksum += ipod->sectorbuf[i]; 1370 } 1371 1372 x = ipod->diroffset % ipod->sector_size; 1373 1374 /* Read directory */ 1375 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; } 1376 1377 n=ipod_read(ipod, ipod->sector_size); 1378 if (n < 0) { return -1; } 1379 1380 /* Update entries for image */ 1381 p = ipod->sectorbuf + x + (ipod->ososimage * 40); 1382 int2le(length - (ipod->modelnum==62 ? 0x800: 0), p + 16); 1383 int2le(0, p + 24); 1384 int2le(chksum, p + 28); 1385 1386 /* Write directory */ 1387 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; } 1388 n=ipod_write(ipod, ipod->sector_size); 1389 if (n < 0) { return -1; } 1390 1391 return 0; 1392} 1393 1394int read_firmware(struct ipod_t* ipod, char* filename, int type) 1395{ 1396 int length; 1397 int i; 1398 int outfile; 1399 int n; 1400 unsigned long offset; 1401 unsigned long chksum=0; /* 32 bit checksum - Rockbox .ipod style*/ 1402 unsigned char header[8]; /* Header for .ipod file */ 1403 1404 if(ipod->sectorbuf == NULL) { 1405 fprintf(stderr,"[ERR] Buffer not initialized."); 1406 return -1; 1407 } 1408 if (ipod->ipod_directory[ipod->ososimage].entryOffset != 0) { 1409 /* We have a bootloader... */ 1410 length = ipod->ipod_directory[ipod->ososimage].entryOffset; 1411 } else { 1412 length = ipod->ipod_directory[ipod->ososimage].len; 1413 } 1414 1415 fprintf(stderr,"[INFO] Reading firmware (%d bytes)\n",length); 1416 1417 offset = ipod->fwoffset + ipod->ipod_directory[ipod->ososimage].devOffset; 1418 i = (length+ipod->sector_size-1) & ~(ipod->sector_size-1); 1419 fprintf(stderr,"[INFO] Padding read from 0x%08x to 0x%08x bytes\n", 1420 length,i); 1421 1422 if (ipod->modelnum==62) { 1423 /* 2nd Gen Nano has encrypted firmware, and we need to dump the 1424 sector preceeding the image - it contains hashes */ 1425 offset -= 0x800; 1426 length += 0x800; 1427 i += 0x800; 1428 } 1429 1430 if (ipod_seek(ipod, offset)) { 1431 return -1; 1432 } 1433 1434 if ((n = ipod_read(ipod,i)) < 0) { 1435 return -1; 1436 } 1437 1438 if (n < i) { 1439 fprintf(stderr,"[ERR] Short read - requested %d bytes, received %d\n", 1440 i,n); 1441 return -1; 1442 } 1443 1444 outfile = open(filename,O_CREAT|O_TRUNC|O_WRONLY|O_BINARY,0666); 1445 if (outfile < 0) { 1446 fprintf(stderr,"[ERR] Couldn't open file %s\n",filename); 1447 return -1; 1448 } 1449 1450 if (type == FILETYPE_DOT_IPOD) { 1451 chksum = ipod->modelnum; 1452 for (i = 0; i < length; i++) { 1453 /* add 8 unsigned bits but keep a 32 bit sum */ 1454 chksum += ipod->sectorbuf[i]; 1455 } 1456 1457 int2be(chksum,header); 1458 memcpy(header+4, ipod->modelname,4); 1459 1460 n = write(outfile,header,8); 1461 if (n != 8) { 1462 fprintf(stderr,"[ERR] Write error - %d\n",n); 1463 } 1464 } 1465 1466 n = write(outfile,ipod->sectorbuf,length); 1467 if (n != length) { 1468 fprintf(stderr,"[ERR] Write error - %d\n",n); 1469 } 1470 close(outfile); 1471 1472 return 0; 1473} 1474 1475int read_directory(struct ipod_t* ipod) 1476{ 1477 ssize_t n; 1478 int x; 1479 unsigned char* p; 1480 unsigned short version; 1481 1482 ipod->nimages=0; 1483 1484 /* Read firmware partition header (first 512 bytes of disk - but 1485 let's read a whole sector) */ 1486 1487 if (ipod_seek(ipod, ipod->start) < 0) { 1488 fprintf(stderr,"[ERR] Seek to 0x%08x in read_directory() failed.\n", 1489 (unsigned int)(ipod->start)); 1490 return -1; 1491 } 1492 1493 n=ipod_read(ipod, ipod->sector_size); 1494 if (n < 0) { 1495 fprintf(stderr,"[ERR] ipod_read(ipod,0x%08x) failed in read_directory()\n", ipod->sector_size); 1496 return -1; 1497 } 1498 1499 if (memcmp(ipod->sectorbuf,apple_stop_sign,sizeof(apple_stop_sign))!=0) { 1500 fprintf(stderr,"[ERR] Firmware partition doesn't contain Apple copyright, aborting.\n"); 1501 return -1; 1502 } 1503 1504 if (memcmp(ipod->sectorbuf+0x100,"]ih[",4)!=0) { 1505 fprintf(stderr,"[ERR] Bad firmware directory\n"); 1506 return -1; 1507 } 1508 1509 version = le2ushort(ipod->sectorbuf+0x10a); 1510 if ((version != 2) && (version != 3)) { 1511 fprintf(stderr,"[ERR] Unknown firmware format version %04x\n", 1512 version); 1513 } 1514 ipod->diroffset=le2int(ipod->sectorbuf+0x104) + 0x200; 1515 1516 /* diroffset may not be sector-aligned */ 1517 x = ipod->diroffset % ipod->sector_size; 1518 1519 /* Read directory */ 1520 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { 1521 fprintf(stderr,"[ERR] Seek to diroffset (%08x) failed.\n",(unsigned)ipod->diroffset); 1522 return -1; 1523 } 1524 1525 n=ipod_read(ipod, ipod->sector_size); 1526 if (n < 0) { 1527 fprintf(stderr,"[ERR] Read of directory failed.\n"); 1528 return -1; 1529 } 1530 1531 p = ipod->sectorbuf + x; 1532 1533 /* A hack to detect 2nd gen Nanos - maybe there is a better way? */ 1534 if (p[0] == 0) 1535 { 1536 /* Adjust diroffset */ 1537 ipod->diroffset += ipod->sector_size - x; 1538 1539 n=ipod_read(ipod, ipod->sector_size); 1540 if (n < 0) { 1541 fprintf(stderr,"[ERR] Read of directory failed.\n"); 1542 return -1; 1543 } 1544 p = ipod->sectorbuf; 1545 } 1546 1547 ipod->ososimage = -1; 1548 while ((ipod->nimages < MAX_IMAGES) && (p < (ipod->sectorbuf + x + 400)) && 1549 ((memcmp(p,"!ATA",4)==0) || (memcmp(p,"DNAN",4)==0))) { 1550 p+=4; 1551 if (memcmp(p,"soso",4)==0) { 1552 ipod->ipod_directory[ipod->nimages].ftype=FTYPE_OSOS; 1553 ipod->ososimage = ipod->nimages; 1554 } else if (memcmp(p,"crsr",4)==0) { 1555 ipod->ipod_directory[ipod->nimages].ftype=FTYPE_RSRC; 1556 } else if (memcmp(p,"dpua",4)==0) { 1557 ipod->ipod_directory[ipod->nimages].ftype=FTYPE_AUPD; 1558 } else if (memcmp(p,"kbso",4)==0) { 1559 ipod->ipod_directory[ipod->nimages].ftype=FTYPE_OSBK; 1560 } else if (memcmp(p,"ebih",4)==0) { 1561 ipod->ipod_directory[ipod->nimages].ftype=FTYPE_HIBE; 1562 } else { 1563 fprintf(stderr,"[ERR] Unknown image type %c%c%c%c\n", 1564 p[0],p[1],p[2],p[3]); 1565 } 1566 p+=4; 1567 ipod->ipod_directory[ipod->nimages].id=le2int(p); 1568 p+=4; 1569 ipod->ipod_directory[ipod->nimages].devOffset=le2int(p); 1570 p+=4; 1571 ipod->ipod_directory[ipod->nimages].len=le2int(p); 1572 p+=4; 1573 ipod->ipod_directory[ipod->nimages].addr=le2int(p); 1574 p+=4; 1575 ipod->ipod_directory[ipod->nimages].entryOffset=le2int(p); 1576 p+=4; 1577 ipod->ipod_directory[ipod->nimages].chksum=le2int(p); 1578 p+=4; 1579 ipod->ipod_directory[ipod->nimages].vers=le2int(p); 1580 p+=4; 1581 ipod->ipod_directory[ipod->nimages].loadAddr=le2int(p); 1582 p+=4; 1583 ipod->nimages++; 1584 } 1585 1586 if (ipod->ososimage < 0) { 1587 fprintf(stderr,"[ERR] No OSOS image found.\n"); 1588 return -1; 1589 } 1590 1591 if ((ipod->nimages > 1) && (version==2)) { 1592 /* The 3g firmware image doesn't appear to have a version, so 1593 let's make one up... Note that this is never written back to the 1594 ipod, so it's OK to do. */ 1595 1596 if (ipod->ipod_directory[ipod->ososimage].vers == 0) { ipod->ipod_directory[ipod->ososimage].vers = 3; } 1597 1598 ipod->fwoffset = ipod->start; 1599 } else { 1600 ipod->fwoffset = ipod->start + ipod->sector_size; 1601 } 1602 1603 return 0; 1604} 1605 1606int list_images(struct ipod_t* ipod) 1607{ 1608 int i; 1609 1610 if (ipod_verbose) { 1611 printf(" Type id devOffset len addr entryOffset chksum vers loadAddr devOffset+len\n"); 1612 for (i = 0 ; i < ipod->nimages; i++) { 1613 printf("%d - %s 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n",i, 1614 ftypename[ipod->ipod_directory[i].ftype], 1615 ipod->ipod_directory[i].id, 1616 ipod->ipod_directory[i].devOffset, 1617 ipod->ipod_directory[i].len, 1618 ipod->ipod_directory[i].addr, 1619 ipod->ipod_directory[i].entryOffset, 1620 ipod->ipod_directory[i].chksum, 1621 ipod->ipod_directory[i].vers, 1622 ipod->ipod_directory[i].loadAddr, 1623 ipod->ipod_directory[i].devOffset+((ipod->ipod_directory[i].len+ipod->sector_size-1)&~(ipod->sector_size-1))); 1624 } 1625 } 1626 1627 printf("\n"); 1628 printf("Listing firmware partition contents:\n"); 1629 printf("\n"); 1630 1631 for (i = 0 ; i < ipod->nimages; i++) { 1632 printf("Image %d:\n",i+1); 1633 switch(ipod->ipod_directory[i].ftype) { 1634 case FTYPE_OSOS: 1635 if (ipod->ipod_directory[i].entryOffset==0) { 1636 printf(" Main firmware - %d bytes\n", 1637 ipod->ipod_directory[i].len); 1638 } else { 1639 printf(" Main firmware - %d bytes\n", 1640 ipod->ipod_directory[i].entryOffset); 1641 printf(" Third-party bootloader - %d bytes\n", 1642 ipod->ipod_directory[i].len-ipod->ipod_directory[i].entryOffset); 1643 } 1644 break; 1645 default: 1646 printf(" %s - %d bytes\n", 1647 ftypename[ipod->ipod_directory[i].ftype], 1648 ipod->ipod_directory[i].len); 1649 } 1650 } 1651 printf("\n"); 1652 1653 return 0; 1654} 1655 1656int getmodel(struct ipod_t* ipod, int ipod_version) 1657{ 1658 switch (ipod_version) { 1659 case 0x01: 1660 ipod->modelstr="1st or 2nd Generation"; 1661 ipod->modelnum = 19; 1662 ipod->modelname = "1g2g"; 1663 ipod->targetname = "ipod1g2g"; 1664#ifdef WITH_BOOTOBJS 1665 ipod->bootloader = ipod1g2g; 1666 ipod->bootloader_len = LEN_ipod1g2g; 1667#endif 1668 break; 1669 case 0x02: 1670 ipod->modelstr="3rd Generation"; 1671 ipod->modelnum = 7; 1672 ipod->modelname = "ip3g"; 1673 ipod->targetname = "ipod3g"; 1674#ifdef WITH_BOOTOBJS 1675 ipod->bootloader = ipod3g; 1676 ipod->bootloader_len = LEN_ipod3g; 1677#endif 1678 break; 1679 case 0x40: 1680 ipod->modelstr="1st Generation Mini"; 1681 ipod->modelnum = 9; 1682 ipod->modelname = "mini"; 1683 ipod->targetname = "ipodmini1g"; 1684#ifdef WITH_BOOTOBJS 1685 ipod->bootloader = ipodmini1g; 1686 ipod->bootloader_len = LEN_ipodmini1g; 1687#endif 1688 break; 1689 case 0x50: 1690 ipod->modelstr="4th Generation"; 1691 ipod->modelnum = 8; 1692 ipod->modelname = "ip4g"; 1693 ipod->targetname = "ipod4gray"; 1694#ifdef WITH_BOOTOBJS 1695 ipod->bootloader = ipod4g; 1696 ipod->bootloader_len = LEN_ipod4g; 1697#endif 1698 break; 1699 case 0x60: 1700 ipod->modelstr="Photo/Color"; 1701 ipod->modelnum = 3; 1702 ipod->modelname = "ipco"; 1703 ipod->targetname = "ipodcolor"; 1704#ifdef WITH_BOOTOBJS 1705 ipod->bootloader = ipodcolor; 1706 ipod->bootloader_len = LEN_ipodcolor; 1707#endif 1708 break; 1709 case 0x70: 1710 ipod->modelstr="2nd Generation Mini"; 1711 ipod->modelnum = 11; 1712 ipod->modelname = "mn2g"; 1713 ipod->targetname = "ipodmini2g"; 1714#ifdef WITH_BOOTOBJS 1715 ipod->bootloader = ipodmini2g; 1716 ipod->bootloader_len = LEN_ipodmini2g; 1717#endif 1718 break; 1719 case 0xc0: 1720 ipod->modelstr="1st Generation Nano"; 1721 ipod->modelnum = 4; 1722 ipod->modelname = "nano"; 1723 ipod->targetname = "ipodnano1g"; 1724#ifdef WITH_BOOTOBJS 1725 ipod->bootloader = ipodnano1g; 1726 ipod->bootloader_len = LEN_ipodnano1g; 1727#endif 1728 break; 1729 case 0xb0: 1730 ipod->modelstr="Video (aka 5th Generation)"; 1731 ipod->modelnum = 5; 1732 ipod->modelname = "ipvd"; 1733 ipod->targetname = "ipodvideo"; 1734#ifdef WITH_BOOTOBJS 1735 ipod->bootloader = ipodvideo; 1736 ipod->bootloader_len = LEN_ipodvideo; 1737#endif 1738 break; 1739 case 0x100: 1740 ipod->modelstr="2nd Generation Nano"; 1741 ipod->modelnum = 62; 1742 ipod->modelname = "nn2x"; 1743 ipod->targetname = "ipodnano2g"; 1744#ifdef WITH_BOOTOBJS 1745 ipod->bootloader = ipodnano2g; 1746 ipod->bootloader_len = LEN_ipodnano2g; 1747#endif 1748 break; 1749 default: 1750 ipod->modelname = NULL; 1751 ipod->modelnum = 0; 1752 ipod->targetname = NULL; 1753#ifdef WITH_BOOTOBJS 1754 ipod->bootloader = NULL; 1755 ipod->bootloader_len = 0; 1756#endif 1757 return -1; 1758 } 1759 return 0; 1760} 1761 1762/* returns number of found ipods or -1 if no ipods found and permission 1763 * for raw disc access was denied. */ 1764int ipod_scan(struct ipod_t* ipod) 1765{ 1766 int i; 1767 int n = 0; 1768 int ipod_version; 1769 struct ipod_t ipod_found; 1770 int denied = 0; 1771 int result; 1772 1773 printf("[INFO] Scanning disk devices...\n"); 1774 1775 for (i = 0; i <= 25 ; i++) { 1776#ifdef __WIN32__ 1777 sprintf(ipod->diskname,"\\\\.\\PhysicalDrive%d",i); 1778#elif defined(linux) || defined (__linux) 1779 sprintf(ipod->diskname,"/dev/sd%c",'a'+i); 1780#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) \ 1781 || defined(__bsdi__) || defined(__DragonFly__) 1782 sprintf(ipod->diskname,"/dev/da%d",i); 1783#elif defined(__APPLE__) && defined(__MACH__) 1784 sprintf(ipod->diskname,"/dev/disk%d",i); 1785#else 1786 #error No disk paths defined for this platform 1787#endif 1788 if ((result = ipod_open(ipod, 1)) < 0) { 1789 if(result == -2) { 1790 denied++; 1791 } 1792 ipod_close(ipod); 1793 continue; 1794 } 1795 1796 if (read_partinfo(ipod,1) < 0) { 1797 ipod_close(ipod); 1798 continue; 1799 } 1800 1801 if ((ipod->pinfo[0].start==0) || (ipod->pinfo[0].type != 0)) { 1802 ipod_close(ipod); 1803 continue; 1804 } 1805 1806 if (read_directory(ipod) < 0) { 1807 ipod_close(ipod); 1808 continue; 1809 } 1810 1811 ipod_version=(ipod->ipod_directory[ipod->ososimage].vers>>8); 1812 ipod->ramsize = 0; 1813#ifdef __WIN32__ 1814 /* Windows requires the ipod in R/W mode for SCSI Inquiry. 1815 * ipod_reopen_rw does unmount the player on OS X so do this on 1816 * W32 only during scanning. */ 1817 ipod_reopen_rw(ipod); 1818#endif 1819 ipod_get_xmlinfo(ipod); 1820 ipod_get_ramsize(ipod); 1821 if (getmodel(ipod,ipod_version) < 0) { 1822 ipod_close(ipod); 1823 continue; 1824 } 1825 1826#ifdef __WIN32__ 1827 printf("[INFO] Ipod found - %s (\"%s\") - disk device %d\n", 1828 ipod->modelstr,ipod->macpod ? "macpod" : "winpod",i); 1829#else 1830 printf("[INFO] Ipod found - %s (\"%s\") - %s\n", 1831 ipod->modelstr,ipod->macpod ? "macpod" : "winpod",ipod->diskname); 1832#endif 1833 n++; 1834 /* save the complete ipod_t structure for match. The for loop might 1835 * overwrite it, so we need to restore it later if only one found. */ 1836 memcpy(&ipod_found, ipod, sizeof(struct ipod_t)); 1837 ipod_close(ipod); 1838 } 1839 1840 if (n==1) { 1841 /* restore the ipod_t structure, it might have been overwritten */ 1842 memcpy(ipod, &ipod_found, sizeof(struct ipod_t)); 1843 } 1844 else if(n == 0 && denied) { 1845 printf("[ERR] FATAL: Permission denied on %d device(s) and no ipod detected.\n", denied); 1846#ifdef __WIN32__ 1847 printf("[ERR] You need to run this program with administrator priviledges!\n"); 1848#else 1849 printf("[ERR] You need permissions for raw disc access for this program to work!\n"); 1850#endif 1851 } 1852 return (n == 0 && denied) ? -1 : n; 1853} 1854 1855static void put_int32le(uint32_t x, unsigned char* p) 1856{ 1857 p[0] = x & 0xff; 1858 p[1] = (x >> 8) & 0xff; 1859 p[2] = (x >> 16) & 0xff; 1860 p[3] = (x >> 24) & 0xff; 1861} 1862 1863int write_dos_partition_table(struct ipod_t* ipod) 1864{ 1865 unsigned char* p; 1866 int i, n; 1867 uint32_t type; 1868 1869 /* Only support 512-byte sectors at the moment */ 1870 if ( ipod->sector_size != 512 ) 1871 { 1872 fprintf(stderr,"[ERR] Only ipods with 512 bytes per sector are supported.\n"); 1873 return -1; 1874 } 1875 if(ipod->sectorbuf == NULL) { 1876 fprintf(stderr,"[ERR] Buffer not initialized."); 1877 return -1; 1878 } 1879 1880 /* Firstly zero the entire MBR */ 1881 memset(ipod->sectorbuf, 0, ipod->sector_size); 1882 1883 /* Now add the partition info */ 1884 for (i=0; i < 4 ; i++) 1885 { 1886 p = ipod->sectorbuf + 0x1be + i*16; 1887 1888 /* Ensure first partition is type 0, and second is 0xb */ 1889 if (i==0) { type = 0; } 1890 else if (i==1) { type = 0xb; } 1891 else { type = ipod->pinfo[i].type; } 1892 1893 put_int32le(type, p + 4); 1894 put_int32le(ipod->pinfo[i].start, p + 8); 1895 put_int32le(ipod->pinfo[i].size, p + 12); 1896 } 1897 1898 /* Finally add the magic */ 1899 ipod->sectorbuf[0x1fe] = 0x55; 1900 ipod->sectorbuf[0x1ff] = 0xaa; 1901 1902 if (ipod_seek(ipod, 0) < 0) { 1903 fprintf(stderr,"[ERR] Seek failed writing MBR\n"); 1904 return -1; 1905 } 1906 1907 /* Write MBR */ 1908 if ((n = ipod_write(ipod, ipod->sector_size)) < 0) { 1909 perror("[ERR] Write failed\n"); 1910 return -1; 1911 } 1912 1913 return 0; 1914} 1915 1916/* Get the XML Device Information, as documented here: 1917 1918 http://www.ipodlinux.org/wiki/Device_Information 1919*/ 1920 1921int ipod_get_xmlinfo(struct ipod_t* ipod) 1922{ 1923 unsigned char hdr[255]; 1924 unsigned char buf[255]; 1925 char* p; 1926 int psize; 1927 int npages; 1928 int i; 1929 1930 if (ipod_scsi_inquiry(ipod, 0xc0, buf, sizeof(buf)) < 0) 1931 { 1932 fprintf(stderr,"[ERR] Sending SCSI Command failed.\n"); 1933 return -1; 1934 } 1935 1936 /* Reading directly into hdr[] causes problems (for an unknown reason) on 1937 win32 */ 1938 memcpy(hdr, buf, sizeof(hdr)); 1939 1940 npages = hdr[3]; 1941 1942 psize = npages * 0xf8; /* Hopefully this is enough. */ 1943 1944 ipod->xmlinfo = malloc(psize); 1945 ipod->xmlinfo_len = 0; 1946 1947 if (ipod->xmlinfo == NULL) { 1948 fprintf(stderr,"[ERR] Could not allocate RAM for xmlinfo\n"); 1949 return -1; 1950 } 1951 1952 p = ipod->xmlinfo; 1953 1954 for (i=0; i < npages; i++) { 1955 if (ipod_scsi_inquiry(ipod, hdr[i+4], buf, sizeof(buf)) < 0) { 1956 fprintf(stderr,"[ERR] Sending SCSI Command failed.\n"); 1957 return -1; 1958 } 1959 1960 if ((buf[3] + ipod->xmlinfo_len) > psize) { 1961 fprintf(stderr,"[ERR] Ran out of memory reading xmlinfo\n"); 1962 free(ipod->xmlinfo); 1963 ipod->xmlinfo = NULL; 1964 ipod->xmlinfo_len = 0; 1965 return -1; 1966 } 1967 1968 memcpy(p, buf + 4, buf[3]); 1969 p += buf[3]; 1970 ipod->xmlinfo_len += buf[3]; 1971 } 1972 1973 /* NULL-terminate the XML info */ 1974 *p = 0; 1975 1976 fprintf(stderr,"[INFO] Read XML info (%d bytes)\n",ipod->xmlinfo_len); 1977 1978 return 0; 1979} 1980 1981void ipod_get_ramsize(struct ipod_t* ipod) 1982{ 1983 const char needle[] = "<key>RAM</key>\n<integer>"; 1984 char* p; 1985 1986 if (ipod->xmlinfo == NULL) 1987 return; 1988 1989 p = strstr(ipod->xmlinfo, needle); 1990 1991 if (p) { 1992 ipod->ramsize = atoi(p + sizeof(needle) - 1); 1993 } 1994} 1995