// // Utility program to take a data read from a PureDigital picture flash memory // and "undo" the wear leveling algorithm, resulting in a mountable FAT12 file // system. Any anomolies are noted. Some old versions of data will be lost; to // do extensive file-recovery and forensics, don't use this program. // // Usage: // // flashdump2iso [basename] // // Reads two files: [basename]-data.bin and [basename]-ecc.bin // (both are necessary) // Outputs one file: [basename].iso // // This file system can be mounted under a unix-like OS using the command: // mkdir tempmount // mount [-t xxx] -o loop=/dev/loop0 [basename.iso] tempmount // ^ Not tested, this is from memory. google for it. People mount iso to // check out CD before burning. // // With a Mac, just double-click on the output file. It'll open up with the // "disk copy" application (from the utilites directory), mount it, and run // iPhoto. You can import & view under iPhoto, or you can close it and open // up the newly mounted drive ("Unlabeled") with the Finder. // // Cavets: The output file system will be short and/or sparse. Only the used // sectors are written, so it will not be the full 16MB size that the FAT claims. // There is also a minor chance that sectors in the middle of the file are not // written and are wither filled with 00's or simply don't exist (sparse file), // depending on your c compiler & libraries. The mount may not handle this, and // will especially not like the missing clusters at the end if for any reason // it tries to add a file. I *STRONGLY* suggest mounting read-only. // // Note that the OUTPUT FILE IS MADE READ-ONLY BY DEFAULT. If the file is // writable, a mac will hang when unmounting. // //----------------------------------------------------------------------------- // Copyright 2003 John Maushammer // http://www.maushammer.com // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // #include #include #include #include typedef unsigned char byte; #define MAX_CLUSTERS 0x1000 /* assume FAT12 */ #define SECTORS_PER_CLUSTER 32 /************************************************** * We have seen 0 sectors of each cluster so far: **************************************************/ void init_cluster_count(int * cluster_count) { unsigned int i; for(i=0; i> 1; if(cluster > MAX_CLUSTERS) { printf("Found a too-high cluster number %x at address 0x%x (id1=%x, id2=%x)\n", cluster, addr, id1, id2); return; } sector_in_cluster = cluster_count[cluster]; cluster_count[cluster] += 1; if(sector_in_cluster < SECTORS_PER_CLUSTER) { /* if not, check_final_cluster_count will warn user */ out_sector_number = cluster * SECTORS_PER_CLUSTER + sector_in_cluster; retval = fseek(fout, out_sector_number * 512, SEEK_SET); if (retval == 0) { retval = fwrite(sector, 1, 512, fout); if (retval != 512) { printf("warning: write didn't work"); } } else { // err(1, "seek to byte 0x%x in output file error", out_sector_number * 512); printf("Seek to byte 0x%x in output file error\n", out_sector_number * 512); } } } /************************************************** * Read through the input files sector-by-sector and convert. **************************************************/ void convert( FILE *fdata, FILE *fecc, FILE *fout) { byte sector[512]; byte ecc[16]; int cluster_count[MAX_CLUSTERS]; int count; unsigned addr = 0; init_cluster_count(cluster_count); while(1) { count = fread(sector, 1, 512, fdata); if (count != 512) break; count = fread(ecc, 1, 16, fecc); if (count != 16) break; output_sector(addr, cluster_count, sector, ecc, fout); addr += 512; } check_final_cluster_count(cluster_count); } /************************************************** * Main function. Open files and call convert. **************************************************/ int main(int argc, char * argv[]) { char datafilename[200], eccfilename[200], outputfilename[200]; char basefilename[200]; int error = 0; FILE *fdata, *fecc, *fout; printf("flashdump2iso, copyright 2003 john maushammer. http://www.maushammer.com\n\n"); if(argc==1) { strcpy(basefilename, "flash-dump"); } else if(argc==2) { strncpy(basefilename, argv[1], 180); } else { error++; } if(!error) { strcpy(datafilename, basefilename); strcat(datafilename, "-data.bin"); if((fdata = fopen(datafilename, "rb")) == NULL) { error++; printf("unable to open data file %s\n\nUsage: flashdump2iso [basename]\n", basefilename); } } if(!error) { strcpy(eccfilename, basefilename); strcat(eccfilename, "-ecc.bin"); if((fecc = fopen(eccfilename, "rb")) == NULL) { error++; printf("unable to open ecc file %s\n\nUsage: flashdump2iso [basename]\n", eccfilename); } } if(!error) { strcpy(outputfilename, basefilename); strcat(outputfilename, ".iso"); if((fout = fopen(outputfilename, "wb")) == NULL) { error++; printf("unable to open output file %s\nThe most likely cause is that is is write-protected\n" "because that is the default of this program (for safety). Go ahead and delete it.\n\n" "Usage: flashdump2iso [basename]\n", outputfilename); } } if(!error) { convert(fdata, fecc, fout); fclose(fdata); fclose(fecc); fclose(fout); if(chmod(outputfilename, 0444)) { printf("Warning: unable to set permissions on output file to read-only.\n" "You'll probably want to do this manually with \"chmod a=r %s\"\n", outputfilename); } } return error; }