Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <stdio.h>
- #include <stdlib.h>
- #include <stdint.h>
- #include <string.h>
- #include <stdbool.h>
- #include <unistd.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- #include <sys/mman.h>
- const unsigned int bytesPerSector = 512;
- const unsigned int rootDirectoryEntryCount = 256;
- typedef struct {
- int8_t magic[4];
- uint32_t volumeId;
- uint32_t sectorsPerCluster;
- uint16_t fatCopies;
- uint32_t unknown;
- uint8_t unused[4078];
- } __attribute__((packed)) superblock_t;
- typedef void* fatEntry_t; // Dummy
- typedef uint16_t fat16Entry_t;
- typedef uint32_t fat32Entry_t;
- typedef struct {
- superblock_t superblock;
- union {
- fatEntry_t fatEntries[1];
- fat16Entry_t fat16Entries[1];
- fat32Entry_t fat32Entries[1];
- };
- } __attribute__((packed)) fatx_t;
- typedef struct {
- uint8_t filenameSize;
- uint8_t attributes;
- char filename[42]; //TODO: Meh char seems sort of unportable - should be changed
- uint32_t firstCluster;
- uint32_t fileSize;
- /*52 2 Modification time
- 54 2 Modification date
- 56 2 Creation time
- 58 2 Creation date
- 60 2 Last access time
- 62 2 Last access date
- */
- uint16_t timesAndDates[6];
- } __attribute__((packed)) directoryEntry_t;
- /*
- 0x0000 0x00000000 Free Cluster — also used as parent directory starting cluster in ".." entries for subdirectories of the root directory (FAT12/16)
- 0x0001 0x00000001 Reserved, do not use
- 0x0002‑0xFFEF 0x00000002‑0x0FFFFFEF Used cluster; value points to next cluster
- 0xFFF0‑0xFFF5 0x0FFFFFF0‑0x0FFFFFF5 Reserved in some contexts[11] or also used[3][9][10]
- 0xFFF6 0x0FFFFFF6 Reserved; do not use[3][9][10][29]
- 0xFFF7 0x0FFFFFF7 Bad sector in cluster or reserved cluster
- 0xFFF8‑0xFFFF 0x0FFFFFF8‑0x0FFFFFFF Last cluster in file (EOC)
- */
- void extractFile(bool fat16, fatEntry_t* fatEntries, void* clusterBase, size_t clusterSize, unsigned int cluster, char* path, unsigned int fileSize) {
- uint8_t* clusterData = (uint8_t*)clusterBase;
- printf("Extracting '%s' from cluster %i\n",path,cluster);
- FILE* file = fopen(path,"wb");
- while((cluster < fat16?0xFFF0:0x0FFFFFF0) && fileSize) {
- void* clusterContent = &clusterData[clusterSize * cluster];
- size_t chunkSize;
- if (fileSize < clusterSize) {
- chunkSize = fileSize;
- } else {
- chunkSize = clusterSize;
- if (fat16) {
- fat16Entry_t* fat16Entries = (fat16Entry_t*)fatEntries;
- cluster = fat16Entries[cluster];
- } else {
- fat32Entry_t* fat32Entries = (fat32Entry_t*)fatEntries;
- cluster = fat32Entries[cluster];
- }
- }
- fwrite(clusterContent,1,chunkSize,file);
- fileSize -= chunkSize;
- printf("Wrote one chunk, now going to cluster %i, %i bytes left\n",cluster,fileSize);
- }
- fclose(file);
- }
- void extractDirectory(bool fat16, fatEntry_t* fatEntries, void* clusterBase, size_t clusterSize, unsigned int cluster, char* path, unsigned int entryCount) {
- // Create the directory
- mkdir(path, S_IRWXU | S_IRWXG | S_IRWXO);
- // Start to fill it
- uint8_t* clusterData = (uint8_t*)clusterBase;
- directoryEntry_t* entries = (directoryEntry_t*)&clusterData[cluster * clusterSize];
- unsigned int i;
- for(i = 0; i < entryCount; i++) {
- char newPath[4096]; //TODO: allocate on stack on demand
- directoryEntry_t* entry = &entries[i];
- if (entry->filenameSize == 0xE5) {
- printf("[deleted file]\n");
- } else if (entry->filenameSize == 0xFF) {
- printf("[end of directory]\n");
- break;
- // continue;
- } else {
- // Get filename
- char filename[42+1];
- strncpy(filename,entry->filename,entry->filenameSize);
- filename[entry->filenameSize] = '\0';
- // Create a path for the entry
- strcpy(newPath,path);
- strcat(newPath,filename);
- // Debug message
- printf("Cluster %i is called %i '%s' (extracting to '%s'), firstcluster is %i\n",i,entry->filenameSize,entry->filename,newPath,entry->firstCluster);
- // Check if new attributes are used
- if (entry->attributes & (~0x30)) { //TODO: Use dir condition instead
- printf("Unknown attributes included: 0x%02X!\n",entry->attributes);
- while(1);
- }
- //TODO: Print all attributes
- // Extract file or directory
- if (entry->attributes & 0x10) { //TODO: Use dir condition instead
- printf("Trying to open dir\n");
- strcat(newPath,"/");
- extractDirectory(fat16, fatEntries, clusterBase, clusterSize, entry->firstCluster, newPath, -1);
- //TODO: what if this cluster has a following one?
- } else {
- extractFile(fat16, fatEntries, clusterBase, clusterSize, entry->firstCluster, newPath, entry->fileSize);
- }
- }
- }
- }
- int main(int argc, char* argv[]) {
- uint8_t* buffer;
- size_t length;
- // Parse arguments
- if ((argc != 3) && (argc != 4)) {
- printf("%s <source> <destination> [<partition size in MB>]\n",argv[0]);
- }
- char* source = argv[1];
- char* path = argv[2];
- char* size = "";
- if (argc == 4) {
- size = argv[3];
- }
- // Load the source file
- /*
- {
- FILE* bin = fopen(source,"rb");
- fseek(bin,0,SEEK_END);
- length = ftell(bin);
- fseek(bin,0,SEEK_SET);
- buffer = malloc(length);
- fread(buffer,1,length,bin);
- fclose(bin);
- printf("Read %i bytes from file!\n",(int)length);
- }
- */
- int file = open(source, O_RDONLY);
- length = lseek(file, 0, SEEK_END);
- buffer = mmap(NULL, length, PROT_READ, MAP_PRIVATE, file, 0);
- fatx_t* fatx = (fatx_t*)buffer;
- unsigned int partitionSize = length - sizeof(superblock_t);
- if (sscanf(size, "0x%X", &partitionSize) != 1) {
- sscanf(size, "%u", &partitionSize);
- }
- size_t fatEntrySize;
- size_t clusterSize = fatx->superblock.sectorsPerCluster * bytesPerSector;
- unsigned int clusterCount = partitionSize / clusterSize;
- bool fat16 = clusterCount < 65525;
- if (fat16) {
- fatEntrySize = sizeof(fat16Entry_t);
- } else {
- fatEntrySize = sizeof(fat32Entry_t);
- }
- printf("Partition-Size: %u\n",partitionSize);
- printf("Cluster sector count is %u\n",fatx->superblock.sectorsPerCluster);
- printf("FAT Copies: %u (Should be 1)\n",fatx->superblock.fatCopies);
- printf("Unknown: %u\n",fatx->superblock.unknown);
- //((69632-4096)/2)*16384 = ps
- size_t fatSize = clusterCount * fatEntrySize;
- printf("Fat size is %lu / 0x%lX\n",fatSize,fatSize);
- size_t fatxSize = sizeof(superblock_t) + ((fatSize + 0xFFF) & (~0xFFF)); // Xbox-Linux describes this with 0x1000 alignment, I chose a cluster..
- printf("Fatx size is %lu / 0x%lX\n",fatxSize,fatxSize);
- printf("Cluster size is %lu / 0x%lX\n",clusterSize,clusterSize);
- //(directoryEntry_t*)((uintptr_t)buffer + 0x11000); //
- 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
- char newPath[4096];
- strcpy(newPath,path);
- if (newPath[strlen(newPath) - 1] != '/') {
- strcat(newPath,"/");
- }
- 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)?
- printf("Done!\n");
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement