列出 Fat 的 Bitmap

列出 Fat 的 Bitmap

根據 M\$ 官方的文件與 Wiki 上的描述,大致了解 FAT 的作法。其主要結構如下圖:

| | | | Bootsector | | More reservedsectors(optional) | | FileAllocationTable #1 | | FileAllocationTable #2 | | RootDirectory(FAT12/16 only) | | Data Region (for files and directories) ...(To end of partition or disk) | | | |

Boot sector Area 大約 512 Bytes

Reserved Area 依據 FAT16, FAT32 小有差異,Boot sector 會提供 reserved 數量 在乘以 sector size。

FAT Table 提供哪些 Cluster 是被使用到的,一個 Cluster 有幾個 sector。

因此 FAT 的最小單位 Block 也就是 sector 大約是 512 bytes,bitmap size 會比較大。

#include

#include

#include

#include

#include

#include

#include

#include

#define FAT_12 1

#define FAT_16 2

#define FAT_32 3

// describers the FAT Boot sector, stolen from libparted

struct attribute ((packed)) FatBootSector {

uint8_t boot_jump[3]; /* 00: Boot strap short or near jump */

uint8_t system_id[8]; /* 03: system name */

uint16_t sector_size; /* 0b: bytes per logical sector */

uint8_t cluster_size; /* 0d: sectors/cluster */

uint16_t reserved; /* 0e: reserved sectors */

uint8_t fats; /* 10: number of FATs */

uint16_t dir_entries; /* 11: number of root directory entries */

uint16_t sectors; /* 13: if 0, total_sect supersedes */

uint8_t media; /* 15: media code */

uint16_t fat_length; /* 16: sectors/FAT for FAT12/16 */

uint16_t secs_track; /* 18: sectors per track */

uint16_t heads; /* 1a: number of heads */

uint32_t hidden; /* 1c: hidden sectors (partition start) */

uint32_t sector_count; /* 20: no. of sectors (if sectors == 0) */

union attribute ((packed)) {

/* FAT16 fields */

struct attribute ((packed)) {

uint8_t drive_num; /* 24: */

uint8_t empty_1; /* 25: */

uint8_t ext_signature; /* 26: always 0x29 */

uint32_t serial_number; /* 27: */

uint8_t volume_name [11]; /* 2b: */

uint8_t fat_name [8]; /* 36: */

uint8_t boot_code[448]; /* 3f: Boot code (or message) */

} fat16;

/* FAT32 fields */

struct attribute ((packed)) {

uint32_t fat_length; /* 24: size of FAT in sectors */

uint16_t flags; /* 28: bit8: fat mirroring, low4: active fat */

uint16_t version; /* 2a: minor * 256 + major */

uint32_t root_dir_cluster; /* 2c: */

uint16_t info_sector; /* 30: */

uint16_t backup_sector; /* 32: */

uint8_t empty_1 [12]; /* 34: */

uint16_t drive_num; /* 40: */

uint8_t ext_signature; /* 42: always 0x29 */

uint32_t serial_number; /* 43: */

uint8_t volume_name [11]; /* 47: */

uint8_t fat_name [8]; /* 52: */

uint8_t boot_code[420]; /* 5a: Boot code (or message) */

} fat32;

} u;

uint16_t boot_sign; /* 1fe: always 0xAA55 */

}fat_bs;

struct FatFsInfo{

uint32_t magic;

uint8_t rev[480];

uint32_t signature;

uint32_t free_count;

uint32_t next_free;

uint32_t reserved2[3];

uint32_t trail;

}fatfs_info;

int main (int argc, char** argv){

int fd, rd;

char sig = '0', boot[512];

int total_sector = 0;

int sec_per_fat = 0;

int root_sec = 0;

int data_sec = 0;

int Cluster_Count = 0;

int Free_blocks = 0;

char *bitmap;

int bitmap_size;

int block = 0;

int FatReservedBytes = 0;

int DamagedClusters = 0;

int FS;

uint16_t Fat16_Entry = 0;

uint32_t Fat32_Entry = 0;

int i = 0, j = 0, bused = 0, bfree = 0;

memset(&boot, 0, 512);

printf("open device %sn", argv[1]);

fd = open (argv[1], O_RDONLY);

if (fd == -1)

{

printf("open errorn");

exit(1);

}

rd = read(fd, &boot, sizeof(fat_bs));

if (rd == -1)

return -1;

memcpy(&fat_bs, &boot, 512);

/// display some information of boot sector

printf("FAT Boot Sector size %in", sizeof(fat_bs));

printf("sector_size %itn", fat_bs.sector_size);

printf("cluster_size %itn", fat_bs.cluster_size);

printf("reserved %itn", fat_bs.reserved);

printf("fats %itn", fat_bs.fats);

printf("dir_entries %itn", fat_bs.dir_entries);

printf("fat_length %itn", fat_bs.fat_length);

printf("secs_track %itn", fat_bs.secs_track);

printf("sector_count %itn", fat_bs.sector_count);

printf("sectors %itn", fat_bs.sectors);

printf("boot_sign %xtn", fat_bs.boot_sign);

/// Get LABEL name

memcpy(&sig, boot+38, 1);

if (sig == 0x29){

printf("serinal %x, FAT16tn", fat_bs.u.fat16.ext_signature);

printf("volume_name %stn", fat_bs.u.fat16.volume_name);

FS = FAT_16;

} else {

printf("serinal %x, FAT32tn", fat_bs.u.fat32.ext_signature);

printf("volume_name %stn", fat_bs.u.fat32.volume_name);

FS = FAT_32;

}

/// Get total sector

if (fat_bs.sectors != 0)

total_sector = fat_bs.sectors;

else

total_sector = fat_bs.sector_count;

/// avoid bug: cannot read last sector, just follow partimage

total_sector--;

/// Count of sectors occupied by one FAT -> fat_length

if(fat_bs.fat_length != 0)

sec_per_fat = fat_bs.fat_length;

else

sec_per_fat = fat_bs.u.fat32.fat_length;

/// calculate the FAT Type with the cluster count (FAT12 or FAT16 or FAT32)

root_sec = ((fat_bs.dir_entries * 32) + fat_bs.sector_size - 1) / fat_bs.sector_size;

data_sec = total_sector - ( fat_bs.reserved + (fat_bs.fats * sec_per_fat) + root_sec);

Cluster_Count = data_sec / fat_bs.cluster_size;

/// get free blocks, FAT32 only

rd = read(fd, &fatfs_info, 512);

if (rd == -1)

return -1;

//if (fatfs_info.magic == 0x41615252)

printf("magic %xn", fatfs_info.magic);

Free_blocks = fatfs_info.free_count;

printf("Total sector: %in", total_sector);

printf("Sector per fat: %in", sec_per_fat);

printf("Cluster Count: %in", Cluster_Count);

printf("Free Blocks Count: %in", Free_blocks);

/// bitmap

bitmap_size = total_sector;

printf("bitmap size %in", bitmap_size);

bitmap = (char *)malloc(bitmap_size);

if (bitmap == NULL)

return -1;

memset(bitmap, 0, bitmap_size);

/// A) the reserved sectors are used

for (i=0; i < fat_bs.reserved; i++,block++)

bitmap[block] = 1;

/// B) the FAT tables are on used sectors

for (j=0; j < fat_bs.fats; j++)

for (i=0; i < sec_per_fat ; i++,block++)

bitmap[block] = 1;

/// C) The rootdirectory is on used sectors

if (root_sec > 0) /// no rootdir sectors on FAT32

for (i=0; i < root_sec; i++,block++)

bitmap[block] = 1;

/// D) The clusters

FatReservedBytes = fat_bs.sector_size * fat_bs.reserved;

/// skip reserved data and two first FAT entries

if (FS == FAT_16)

lseek(fd, FatReservedBytes+(2*2), SEEK_SET);

else if (FS == FAT_32)

lseek(fd, FatReservedBytes+(2*4), SEEK_SET);

else

printf("ERR_WRONG_FSn");

for (i=0; i < Cluster_Count; i++){

printf("Cluster %i, tt", i);

/// If FAT16

if(FS == FAT_16){

rd = read(fd, &Fat16_Entry, sizeof(Fat16_Entry));

if (rd == -1)

return -1;

if (Fat16_Entry == 0xFFF7) { /// bad FAT16 cluster

DamagedClusters++;

printf("bad sec %in", block);

for (j=0; j < fat_bs.cluster_size; j++,block++)

bitmap[block] = 0;

} else if (Fat16_Entry == 0x0000){ /// free

bfree++;

for (j=0; j < fat_bs.cluster_size; j++,block++)

bitmap[block] = 0;

} else {

bused++;

for (j=0; j < fat_bs.cluster_size; j++,block++)

bitmap[block] = 1;

}

printf("free: %it, used: %it, block: %itn", bfree, bused, block);

} else if (FS == FAT_32){ /// FAT32

rd = read(fd, &Fat32_Entry, sizeof(Fat32_Entry));

if (rd == -1)

return -1;

if (Fat32_Entry == 0x0FFFFFF7) { /// bad FAT32 cluster

DamagedClusters++;

printf("bad sec %in", block);

for (j=0; j < fat_bs.cluster_size; j++,block++)

bitmap[block] = 0;

} else if (Fat32_Entry == 0x0000){ /// free

bfree++;

for (j=0; j < fat_bs.cluster_size; j++,block++)

bitmap[block] = 0;

} else {

bused++;

for (j=0; j < fat_bs.cluster_size; j++,block++)

bitmap[block] = 1;

}

printf("free: %it, used: %it, block: %itn", bfree, bused, block);

} else

printf("error fsn");

}

while(block < total_sector){

bitmap[block] = 1;

block++;

}

free(bitmap);

close(fd);

printf("Free Blocks %in", bfree);

printf("Used Blocks %in", bused);

printf("Bad Blocks %in", DamagedClusters);

printf("donen");

return 1;

}

程式會大量輸出所有 sector 是否被使用到的情形 ,以及整體使用的統計。

目前只是簡單的 Sample Code ,未來會加入到 Partclone

ref.1 http://www.microsoft.com/whdc/system/platform/firmware/fatgendown.mspx?

ref.2 http://en.wikipedia.org/wiki/File_Allocation_Table

ref.3 http://www.partimage.org/

convert from Thomas blog post id 219 old convert log: ./094823/tag%3E2008%2002%20linux)

@2008 @02 @linux

Comments