Created
February 26, 2013 17:02
-
-
Save giannitedesco/5040131 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdlib.h> | |
#include <stdint.h> | |
#include <inttypes.h> | |
#include <stdio.h> | |
#include <assert.h> | |
#include <errno.h> | |
#include <unistd.h> | |
#include <sys/stat.h> | |
#include <fcntl.h> | |
#include <string.h> | |
#include <ctype.h> | |
#include "vdisk.h" | |
#include "partition.h" | |
#include "fat32-format.h" | |
#include "fat32.h" | |
#if 1 | |
#define dprintf printf | |
#else | |
#define dprintf(x...) do {}while(0); | |
#endif | |
struct _fat32 { | |
partition_t fs_part; | |
uint32_t *fs_fat0; | |
uint32_t *fs_fat1; | |
#if DUMP_SLACK | |
uint32_t *visited; | |
#endif | |
uint32_t fat_begin; | |
uint32_t cluster_begin; | |
uint32_t sectors_per_cluster; | |
uint32_t root_dir; | |
uint32_t num_clusters; | |
}; | |
// cluster_begin + (cluster_number - 2) * sectors_per_cluster | |
static int read_cluster(struct _fat32 *fs, void *buf, uint32_t cluster) | |
{ | |
//printf(" - reading cluster %u\n", cluster); | |
if ( cluster < 2 ) | |
return 0; | |
#if DUMP_SLACK | |
if ( cluster < fs->num_clusters ) | |
fs->visited[cluster] = 1; | |
#endif | |
return part_read_sectors(fs->fs_part, buf, | |
fs->cluster_begin + (cluster - 2) * fs->sectors_per_cluster, | |
fs->sectors_per_cluster); | |
} | |
static uint32_t get_next_cluster(struct _fat32 *fs, uint32_t cluster) | |
{ | |
//printf(" - next cluster for %u is 0x%.8x\n", | |
// cluster, fs->fs_fat0[cluster]); | |
if ( cluster >= fs->num_clusters ) { | |
printf("Attempt to access beyond end of MFT\n"); | |
return ~0; | |
} | |
if ( fs->fs_fat0[cluster] != fs->fs_fat1[cluster] ) | |
printf(" -- FAT1 disagrees 0x%.8x\n", fs->fs_fat1[cluster]); | |
return fs->fs_fat0[cluster]; | |
} | |
static int read_file(struct _fat32 *fs, const char *fn, | |
uint32_t size, uint32_t cluster) | |
{ | |
uint8_t buf[SECTOR_SIZE * fs->sectors_per_cluster]; | |
uint32_t last_cluster; | |
char outfn[256]; | |
FILE *out; | |
printf("%s %u bytes @ 0x%x\n", | |
fn, size, cluster); | |
snprintf(outfn, sizeof(outfn), "./dump/%s", fn); | |
out = fopen(outfn, "w"); | |
if ( NULL == out ) | |
return 0; | |
again: | |
do { | |
size_t sz; | |
if ( !size ) | |
break; | |
last_cluster = cluster; | |
if ( !read_cluster(fs, buf, cluster) ) { | |
printf("ugh\n"); | |
return 0; | |
} | |
sz = (size < sizeof(buf)) ? size : sizeof(buf); | |
fwrite(buf, 1, sz, out); | |
size -= sz; | |
#if 0 | |
if ( !sz ) | |
hex_dump(buf, sizeof(buf), 0); | |
else if ( sz < sizeof(buf) ) | |
hex_dump(buf + sz, sizeof(buf) - sz, 0); | |
#endif | |
cluster = get_next_cluster(fs, cluster); | |
}while( cluster >= 2 && cluster < 0x0ffffff8 ); | |
if ( size ) { | |
//printf("ARGH! %u bytes unread\n", size); | |
/* just assume its in the next cluster */ | |
cluster = last_cluster + 1; | |
goto again; | |
} | |
fclose(out); | |
return 1; | |
} | |
static int read_dir(struct _fat32 *fs, uint32_t cluster) | |
{ | |
unsigned int num_dirent = (SECTOR_SIZE * fs->sectors_per_cluster) / | |
sizeof(struct fat32_dirent); | |
struct fat32_dirent dir[num_dirent]; | |
unsigned int i, eof = 0; | |
do { | |
if ( !read_cluster(fs, dir, cluster) ) | |
return 0; | |
for(i = 0; i < num_dirent; i++) { | |
uint32_t fclus; | |
char fn[13]; | |
if ( dir[i].short_name[0] == 0 ) { | |
eof = 1; | |
continue; | |
} | |
if ( eof ) | |
printf("hidden pat EOD: "); | |
if ( (dir[i].attrib & 0xf) == 0xf ) { | |
printf("extended filename:\n"); | |
hex_dump((uint8_t *)(dir + i), | |
sizeof(dir[0]), 0); | |
continue; | |
} | |
if ( dir[i].short_name[0] == 0xe5 ) | |
dir[i].short_name[0] = '+'; | |
snprintf(fn, sizeof(fn), "%.8s.%.3s", | |
dir[i].short_name, | |
dir[i].short_name + 8); | |
if ( dir[i].attrib & FAT32_ATTR_DIR ) { | |
printf("DIR "); | |
} | |
fclus = dir[i].cluster_hi << 16; | |
fclus |= dir[i].cluster_lo; | |
read_file(fs, fn, dir[i].size, fclus); | |
} | |
cluster = get_next_cluster(fs, cluster); | |
}while( cluster >= 2 && cluster < 0x0fffffff ); | |
return 1; | |
} | |
fat32_t fat32_open(partition_t part) | |
{ | |
struct _fat32 *fs = NULL; | |
struct fat32_hdr hdr; | |
#if DUMP_SLACK | |
unsigned int i; | |
#endif | |
fs = calloc(1, sizeof(*fs)); | |
if ( NULL == fs ) | |
goto out; | |
if ( !part_read_sectors(part, &hdr, 0, 1) ) | |
goto out_free; | |
printf(" - oem_name=%.*s, vol_label=%.*s, fs_label=%.*s\n", | |
(int)sizeof(hdr.oem_name), hdr.oem_name, | |
(int)sizeof(hdr.vol_label), hdr.vol_label, | |
(int)sizeof(hdr.fs_label), hdr.fs_label); | |
printf(" - %u sectors per cluster\n", hdr.sec_per_clus); | |
printf(" - root dir on cluster %u\n", hdr.root_dir_cluster); | |
printf(" - tot_sec=%u, fat_sz=%u\n", hdr.tot_sec32, hdr.fat_sz32); | |
printf(" - %u reserved sectors, %u FATs\n", | |
hdr.reserved_sec, hdr.num_fat); | |
printf("boot code:\n"); | |
hex_dump(hdr._pad2, sizeof(hdr._pad2), 0); | |
fs->fs_part = part; | |
fs->fat_begin = hdr.reserved_sec; | |
fs->cluster_begin = fs->fat_begin + (hdr.num_fat * hdr.fat_sz32); | |
fs->sectors_per_cluster = hdr.sec_per_clus; | |
fs->root_dir = hdr.root_dir_cluster; | |
fs->fs_fat0 = malloc(hdr.fat_sz32 * SECTOR_SIZE); | |
if ( NULL == fs->fs_fat0 ) | |
goto out_free; | |
if ( !part_read_sectors(fs->fs_part, fs->fs_fat0, | |
fs->fat_begin, | |
hdr.fat_sz32) ) | |
goto out_free_fat0; | |
fs->fs_fat1 = malloc(hdr.fat_sz32 * SECTOR_SIZE); | |
if ( NULL == fs->fs_fat1 ) | |
goto out_free; | |
if ( !part_read_sectors(fs->fs_part, fs->fs_fat1, | |
fs->fat_begin + hdr.fat_sz32, | |
hdr.fat_sz32) ) | |
goto out_free_fat0; | |
fs->num_clusters = hdr.fat_sz32 * (SECTOR_SIZE / sizeof(uint32_t)); | |
do { | |
uint8_t buf[SECTOR_SIZE * (hdr.reserved_sec - 1)]; | |
part_read_sectors(fs->fs_part, buf, 1, hdr.reserved_sec - 1); | |
printf("Reserved sectors:\n"); | |
hex_dump(buf, sizeof(buf), 0); | |
}while(0); | |
#if DUMP_SLACK | |
fs->visited = calloc(fs->num_clusters, SECTOR_SIZE); | |
if ( NULL == fs->visited) | |
goto out_free_fat1; | |
#endif | |
read_dir(fs, fs->root_dir); | |
#if DUMP_SLACK | |
for(i = 0; i < hdr.fat_sz32; i++) { | |
uint8_t buf[SECTOR_SIZE * fs->sectors_per_cluster]; | |
unsigned int j, interesting, visited; | |
char fn[64]; | |
FILE *out; | |
visited = fs->visited[i]; | |
if ( !read_cluster(fs, buf, i) ) { | |
continue; | |
} | |
for(interesting = j = 0; j < sizeof(buf); j++) { | |
if ( buf[j] != 0 ) { | |
interesting = 1; | |
break; | |
} | |
} | |
if ( !interesting ) | |
continue; | |
snprintf(fn, sizeof(fn), "clusters/cluster%.8x-%s.bin", | |
i, (visited) ? "live" : "dead"); | |
//printf("writing %s\n", fn); | |
out = fopen(fn, "w"); | |
fwrite(buf, 1, sizeof(buf), out); | |
fclose(out); | |
} | |
#endif | |
/* success */ | |
goto out; | |
#if DUMP_SLACK | |
out_free_fat1: | |
free(fs->fs_fat1); | |
#endif | |
out_free_fat0: | |
free(fs->fs_fat0); | |
out_free: | |
free(fs); | |
fs = NULL; | |
out: | |
return fs; | |
} | |
void fat32_close(fat32_t fs) | |
{ | |
if ( fs ) { | |
free(fs->fs_fat1); | |
free(fs->fs_fat0); | |
free(fs); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment