Advertisement
Guest User

extract-fatx

a guest
Sep 17th, 2011
298
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 7.37 KB | None | 0 0
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <stdint.h>
  4. #include <string.h>
  5. #include <stdbool.h>
  6.  
  7. #include <unistd.h>
  8. #include <sys/types.h>
  9. #include <sys/stat.h>
  10. #include <fcntl.h>
  11. #include <sys/mman.h>
  12.  
  13. const unsigned int bytesPerSector = 512;
  14. const unsigned int rootDirectoryEntryCount = 256;
  15.  
  16. typedef struct {
  17.   int8_t magic[4];
  18.   uint32_t volumeId;
  19.   uint32_t sectorsPerCluster;
  20.   uint16_t fatCopies;
  21.   uint32_t unknown;
  22.   uint8_t unused[4078];
  23. } __attribute__((packed)) superblock_t;
  24.  
  25. typedef void* fatEntry_t; // Dummy
  26. typedef uint16_t fat16Entry_t;
  27. typedef uint32_t fat32Entry_t;
  28.  
  29. typedef struct {
  30.   superblock_t superblock;
  31.   union {
  32.     fatEntry_t fatEntries[1];
  33.     fat16Entry_t fat16Entries[1];
  34.     fat32Entry_t fat32Entries[1];
  35.   };
  36. } __attribute__((packed)) fatx_t;
  37.  
  38. typedef struct {
  39.   uint8_t filenameSize;
  40.   uint8_t attributes;
  41.   char filename[42]; //TODO: Meh char seems sort of unportable - should be changed
  42.   uint32_t firstCluster;
  43.   uint32_t fileSize;
  44.   /*52  2   Modification time
  45.   54    2   Modification date
  46.   56    2   Creation time
  47.   58    2   Creation date
  48.   60    2   Last access time
  49.   62    2   Last access date
  50.   */
  51.   uint16_t timesAndDates[6];
  52. } __attribute__((packed)) directoryEntry_t;
  53.  
  54. /*
  55.   0x0000          0x00000000                Free Cluster — also used as parent directory starting cluster in ".." entries for subdirectories of the root directory (FAT12/16)
  56.   0x0001            0x00000001              Reserved, do not use
  57.   0x0002‑0xFFEF   0x00000002‑0x0FFFFFEF     Used cluster; value points to next cluster
  58.   0xFFF0‑0xFFF5   0x0FFFFFF0‑0x0FFFFFF5     Reserved in some contexts[11] or also used[3][9][10]
  59.   0xFFF6            0x0FFFFFF6              Reserved; do not use[3][9][10][29]
  60.   0xFFF7            0x0FFFFFF7              Bad sector in cluster or reserved cluster
  61.   0xFFF8‑0xFFFF   0x0FFFFFF8‑0x0FFFFFFF     Last cluster in file (EOC)
  62. */
  63.  
  64. void extractFile(bool fat16, fatEntry_t* fatEntries, void* clusterBase, size_t clusterSize, unsigned int cluster, char* path, unsigned int fileSize) {
  65.   uint8_t* clusterData = (uint8_t*)clusterBase;
  66.   printf("Extracting '%s' from cluster %i\n",path,cluster);
  67.   FILE* file = fopen(path,"wb");
  68.   while((cluster < fat16?0xFFF0:0x0FFFFFF0) && fileSize) {
  69.     void* clusterContent = &clusterData[clusterSize * cluster];
  70.     size_t chunkSize;
  71.     if (fileSize < clusterSize) {
  72.       chunkSize = fileSize;
  73.     } else {
  74.       chunkSize = clusterSize;
  75.       if (fat16) {
  76.         fat16Entry_t* fat16Entries = (fat16Entry_t*)fatEntries;
  77.         cluster = fat16Entries[cluster];
  78.       } else {
  79.         fat32Entry_t* fat32Entries = (fat32Entry_t*)fatEntries;
  80.         cluster = fat32Entries[cluster];
  81.       }
  82.     }
  83.     fwrite(clusterContent,1,chunkSize,file);
  84.     fileSize -= chunkSize;
  85.     printf("Wrote one chunk, now going to cluster %i, %i bytes left\n",cluster,fileSize);
  86.   }
  87.   fclose(file);
  88. }
  89.  
  90. void extractDirectory(bool fat16, fatEntry_t* fatEntries, void* clusterBase, size_t clusterSize, unsigned int cluster, char* path, unsigned int entryCount) {
  91.  
  92.   // Create the directory  
  93.  
  94.   mkdir(path, S_IRWXU | S_IRWXG | S_IRWXO);
  95.  
  96.   // Start to fill it
  97.  
  98.   uint8_t* clusterData = (uint8_t*)clusterBase;
  99.   directoryEntry_t* entries = (directoryEntry_t*)&clusterData[cluster * clusterSize];
  100.   unsigned int i;
  101.   for(i = 0; i < entryCount; i++) {
  102.     char newPath[4096]; //TODO: allocate on stack on demand
  103.     directoryEntry_t* entry = &entries[i];
  104.  
  105.     if (entry->filenameSize == 0xE5) {
  106.       printf("[deleted file]\n");
  107.     } else if (entry->filenameSize == 0xFF) {
  108.       printf("[end of directory]\n");
  109.       break;
  110. //      continue;
  111.     } else {
  112.  
  113.       // Get filename
  114.  
  115.       char filename[42+1];
  116.       strncpy(filename,entry->filename,entry->filenameSize);
  117.       filename[entry->filenameSize] = '\0';
  118.  
  119.       // Create a path for the entry
  120.  
  121.       strcpy(newPath,path);
  122.       strcat(newPath,filename);
  123.  
  124.       // Debug message
  125.  
  126.       printf("Cluster %i is called %i '%s' (extracting to '%s'), firstcluster is %i\n",i,entry->filenameSize,entry->filename,newPath,entry->firstCluster);
  127.  
  128.       // Check if new attributes are used
  129.  
  130.       if (entry->attributes & (~0x30)) { //TODO: Use dir condition instead
  131.         printf("Unknown attributes included: 0x%02X!\n",entry->attributes);
  132.         while(1);
  133.       }
  134.    
  135.       //TODO: Print all attributes
  136.  
  137.       // Extract file or directory
  138.  
  139.       if (entry->attributes & 0x10) { //TODO: Use dir condition instead
  140.         printf("Trying to open dir\n");
  141.         strcat(newPath,"/");
  142.         extractDirectory(fat16, fatEntries, clusterBase, clusterSize, entry->firstCluster, newPath, -1);          
  143.         //TODO: what if this cluster has a following one?
  144.       } else {
  145.         extractFile(fat16, fatEntries, clusterBase, clusterSize, entry->firstCluster, newPath, entry->fileSize);
  146.       }
  147.     }
  148.   }
  149. }
  150.  
  151. int main(int argc, char* argv[]) {
  152.  
  153.   uint8_t* buffer;
  154.   size_t length;
  155.  
  156.   // Parse arguments
  157.  
  158.   if ((argc != 3) && (argc != 4)) {
  159.     printf("%s <source> <destination> [<partition size in MB>]\n",argv[0]);
  160.   }
  161.  
  162.   char* source = argv[1];
  163.   char* path = argv[2];
  164.   char* size = "";
  165.   if (argc == 4) {
  166.     size = argv[3];
  167.   }
  168.  
  169.   // Load the source file
  170.  
  171. /*
  172.   {
  173.     FILE* bin = fopen(source,"rb");
  174.     fseek(bin,0,SEEK_END);  
  175.     length = ftell(bin);
  176.     fseek(bin,0,SEEK_SET);  
  177.     buffer = malloc(length);
  178.     fread(buffer,1,length,bin);
  179.     fclose(bin);  
  180.     printf("Read %i bytes from file!\n",(int)length);
  181.   }
  182. */
  183.   int file = open(source, O_RDONLY);
  184.   length = lseek(file, 0, SEEK_END);
  185.   buffer = mmap(NULL, length, PROT_READ, MAP_PRIVATE, file, 0);
  186.  
  187.   fatx_t* fatx = (fatx_t*)buffer;  
  188.  
  189.   unsigned int partitionSize = length - sizeof(superblock_t);
  190.   if (sscanf(size, "0x%X", &partitionSize) != 1) {
  191.     sscanf(size, "%u", &partitionSize);
  192.   }
  193.  
  194.   size_t fatEntrySize;
  195.   size_t clusterSize = fatx->superblock.sectorsPerCluster * bytesPerSector;
  196.   unsigned int clusterCount = partitionSize / clusterSize;
  197.   bool fat16 = clusterCount < 65525;
  198.   if (fat16) {
  199.     fatEntrySize = sizeof(fat16Entry_t);
  200.   } else {
  201.     fatEntrySize = sizeof(fat32Entry_t);
  202.   }
  203.  
  204.   printf("Partition-Size: %u\n",partitionSize);
  205.   printf("Cluster sector count is %u\n",fatx->superblock.sectorsPerCluster);
  206.   printf("FAT Copies: %u (Should be 1)\n",fatx->superblock.fatCopies);
  207.   printf("Unknown: %u\n",fatx->superblock.unknown);
  208.  
  209. //((69632-4096)/2)*16384 = ps
  210.  
  211.   size_t fatSize = clusterCount * fatEntrySize;
  212.   printf("Fat size is %lu / 0x%lX\n",fatSize,fatSize);
  213.   size_t fatxSize = sizeof(superblock_t) + ((fatSize + 0xFFF) & (~0xFFF)); // Xbox-Linux describes this with 0x1000 alignment, I chose a cluster..
  214.   printf("Fatx size is %lu / 0x%lX\n",fatxSize,fatxSize);
  215.   printf("Cluster size is %lu / 0x%lX\n",clusterSize,clusterSize);
  216.   //(directoryEntry_t*)((uintptr_t)buffer + 0x11000); //
  217.   uint8_t* clusterBase = (uint8_t*)((uintptr_t)fatx + fatxSize - clusterSize); // All clusters are starting at 1, we fix this by starting moving our array one index down
  218.  
  219.   char newPath[4096];
  220.   strcpy(newPath,path);
  221.   if (newPath[strlen(newPath) - 1] != '/') {
  222.     strcat(newPath,"/");
  223.   }
  224.   extractDirectory(fat16, fatx->fatEntries, clusterBase, clusterSize, 1, newPath, rootDirectoryEntryCount); //TODO: Why do I have to advance one cluster? Why isn't this in the first one (which would be 0)?
  225.  
  226.   printf("Done!\n");
  227.  
  228.   return 0;
  229. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement