读取FAT12磁盘镜像的文件。
头文件
#ifndef __FAT_H__
#define __FAT_H__
struct fat32_struct{
uint8_t jmp;
uint8_t oem;
uint8_t bpb;
uint8_t bpbx;
uint8_t boot;
uint8_t magic;
}__attribute__((packed));
struct fat32_bpb{
uint16_t bytes_per_sector;
uint8_tsectors_per_cluster;
uint16_t reserved_sector;
uint8_tnumber_of_FAT;
uint16_t root_entries;
uint16_t small_sector;
uint8_tmedia_descriptor;
uint16_t sectors_per_fat;
uint16_t sectors_per_track;
uint16_t number_of_head;
uint32_t hidden_sectors;
uint32_t large_sector;
uint32_t sectors_per_fat32;
uint16_t extended_flags;
uint16_t filesystem_version;
uint32_t root_cluster_number;
uint16_t system_info_sector_number;
uint16_t backup_sectors;
uint16_t reserverd;
}__attribute__((packed));
struct fat32_bpbx{
uint8_t driver_number;
uint8_t reserver;
uint8_t extended_boot_signature;
uint32_t volume_serial_number;
uint8_tvolume_label;
uint8_tfilesystem_type;
}__attribute__((packed));
struct fat_struct{
uint8_t jmp;
uint8_t oem;
uint8_t bpb;
uint8_t bpbx;
uint8_t boot;
uint8_t magic;
}__attribute__((packed));
struct fat_bpb{
uint16_t bytes_per_sector;
uint8_tsectors_per_cluster;
uint16_t reserved_sector;
uint8_tnumber_of_FAT;
uint16_t root_entries;
uint16_t small_sector;
uint8_tmedia_desc;
uint16_t sectors_per_fat;
uint16_t sectors_per_track;
uint16_t number_of_heads;
uint32_t hidden_sectors;
uint32_t large_sectors;
}__attribute__((packed));
struct fat_bpbx{
uint8_tphysical_drive_number;
uint8_treserverd;
uint8_textended_boot_signature;
uint32_t volume_serial_number;
uint8_tvolume_label;
uint8_tfilesystem_type;
}__attribute__((packed));
struct fat_entry{
uint8_t name;
uint8_t fext;
uint8_t attribute;
uint8_t reserverd;
uint16_t mtime;
uint16_t mdate;
uint16_t cluster_entry;
uint32_t length;
}__attribute__((packed));
#endif
源文件:
#include stdio.h>
#include string.h>
#include stdint.h>
#include stdlib.h>
#include assert.h>
#include "fat.h"
#define WRITE_FILE 1
struct fat_fsop{
FILE *fp;
struct fat_bpb bpb;
};
struct fat_file{
size_t offset;
size_t cluster;
struct fat_fsop *fsop;
struct fat_entry entry;
};
int fat_read_sector(struct fat_fsop *fsop, size_t sector, void *buff)
{
struct fat_bpb *bpb = &fsop->bpb;
assert(bpb->bytes_per_sector>=512);
if (0!=fseek(fsop->fp, sector*bpb->bytes_per_sector, SEEK_SET)){
printf("__fat_read_sector: %d\n", sector);
return -1;
}
return fread(buff, bpb->bytes_per_sector, 1, fsop->fp);
}
int fat_read_cluster(struct fat_fsop *fsop, size_t cluster, void *buff)
{
int i = 0;
size_t cpcnt = 0;
char *p = (char*)buff;
struct fat_bpb *bpb = &fsop->bpb;
size_t sector = bpb->reserved_sector;
sector += bpb->sectors_per_fat*bpb->number_of_FAT;
sector += (cluster-2)*bpb->sectors_per_cluster;
sector += (bpb->root_entries*32)/(bpb->sectors_per_cluster*bpb->bytes_per_sector);
assert(bpb->sectors_per_cluster>0);
for (i=0; ibpb->sectors_per_cluster; i++){
if (fat_read_sector(fsop, sector, p+cpcnt)==-1){
printf("fat_read_sector: %d\n", sector);
return -1;
}
cpcnt += bpb->bytes_per_sector;
sector++;
}
return 0;
}
int fat_read_dir(struct fat_fsop *fsop, const char *path)
{
struct fat_bpb *bpb = &fsop->bpb;
return -1;
}
int dirent_trim(const char *buff, size_t count)
{
const char *p = buff;
const char *end = buff+count;
while(pend&&*p&&*p!=' ')p++;
return (p-buff);
}
#define IS_DIR(flag) ((flag)&0x10)
int fat_dirent_lookup(struct fat_entry *dirents, size_t dpcnt, const char *path, struct fat_entry *dirent)
{
char name;
size_t j, cpcnt, cpcntext;
for (j=0; jdpcnt; j++){
cpcnt = dirent_trim(dirents.name, 8);
if (cpcnt > 0){
strncpy(name, dirents.name, cpcnt);
cpcntext = dirent_trim(dirents.fext, 3);
cpcntext&&(name='.');
strncpy(name+cpcnt, dirents.fext, cpcntext);
name = 0;
if (!strcmp(path, name)){
*dirent= dirents;
return 0;
}
}
}
return -1;
}
int fat_lookup(struct fat_fsop *fsop, struct fat_entry *folder,
const char *path, struct fat_entry *entry)
{
struct fat_bpb *bpb = &fsop->bpb;
size_t bytes_per_cluster = (bpb->bytes_per_sector*bpb->sectors_per_cluster);
char *cluster_buffer = (char*)malloc(bytes_per_cluster);
if (!IS_DIR(folder->attribute)){
return -1;
}
size_t valid_cluster = folder->cluster_entry;
size_t dpcnt= bytes_per_cluster/32;
struct fat_entry *dirents;
dirents = (struct fat_entry*)cluster_buffer;
while (valid_cluster0xFF0){
size_t cluster;
if (-1==fat_read_cluster(fsop, valid_cluster, cluster_buffer)){
free(cluster_buffer);
return -1;
}
if (0==fat_dirent_lookup(dirents, dpcnt, path, entry)){
free(cluster_buffer);
return 0;
}
if (-1==fat_next_cluster(fsop, valid_cluster, &cluster)){
free(cluster_buffer);
return -1;
}
valid_cluster = cluster;
}
free(cluster_buffer);
return -1;
}
int fat_namei(struct fat_fsop *fsop, const char *path, struct fat_entry *entry)
{
int idx, count;
struct fat_bpb *bpb = &fsop->bpb;
idx= bpb->reserved_sector;
idx += bpb->sectors_per_fat*bpb->number_of_FAT;
char *sector_buffer = (char*)malloc(bpb->bytes_per_sector);
for (count=0; countbpb->root_entries;idx++){
if (0>=fat_read_sector(fsop, idx, sector_buffer)){
free(sector_buffer);
return -1;
}
size_t dpcnt= bpb->bytes_per_sector/32;
if (dpcnt+count > bpb->root_entries)
dpcnt = bpb->root_entries-count;
struct fat_entry *dirents;
dirents = (struct fat_entry*)sector_buffer;
if (0==fat_dirent_lookup(dirents, dpcnt, path, entry)){
free(sector_buffer);
return 0;
}
count += dpcnt;
}
free(sector_buffer);
return -1;
}
int fat_open_volume(struct fat_fsop *fsop, const char *path)
{
FILE *fp = NULL;
char volume;
struct fat_struct *fs;
fs = (struct fat_struct*)volume;
struct fat_bpb *bpb;
bpb = (struct fat_bpb*)fs->bpb;
struct fat_bpbx *bpbx;
bpbx = (struct fat_bpbx *)fs->bpbx;
if (NULL==(fp=fopen(path, "rb"))){
return -1;
}
if (!fread(volume, 512, 1, fp)){
goto open_volume_fail;
}
if (memcmp(bpbx->filesystem_type, "FAT12 ", 8)){
goto open_volume_fail;
}
if (bpb->root_entries&0xF){
goto open_volume_fail;
}
fsop->bpb = *bpb;
fsop->fp = fp;
return 0;
open_volume_fail:
fclose(fp);
return -1;
}
#define IS_FILE(flag) (((flag)&0x18)==0)
int fat_open_file(struct fat_fsop *fsop, struct fat_entry *entry,
struct fat_file *file)
{
file->fsop = fsop;
file->entry = *entry;
file->offset = 0;
file->cluster = entry->cluster_entry;
return 0;
}
int fat_next_cluster(struct fat_fsop *fsop, size_t cluster, size_t *pcluster)
{
int count;
struct fat_bpb *bpb = &fsop->bpb;
size_t fat_start = bpb->reserved_sector;
size_t bitcnt = cluster*12;
size_t sectorcnt = bitcnt/(bpb->bytes_per_sector*8);
uint8_t *sector_buffer = (uint8_t*)malloc(bpb->bytes_per_sector*2);
assert(sector_buffer != NULL);
if (-1==fat_read_sector(fsop, fat_start+sectorcnt, sector_buffer)){
free(sector_buffer);
return -1;
}
size_t bitcnt_in_sector = bitcnt-(bpb->bytes_per_sector*8*sectorcnt);
size_t bytecnt_in_sector = bitcnt_in_sector/8;
if (bytecnt_in_sector+1 == bpb->bytes_per_sector){
if (-1==fat_read_sector(fsop, fat_start+sectorcnt+1,
sector_buffer+bpb->bytes_per_sector)){
free(sector_buffer);
return -1;
}
}
uint8_t *fat_cluster = (sector_buffer+bytecnt_in_sector);
uint32_t retval = fat_cluster|(fat_cluster8);
free(sector_buffer);
*pcluster = (bitcnt_in_sector&0x7)?(retval>>4):(retval&0xFFF);
return 0;
}
int fat_pread_file(struct fat_file *file, void *buff,
size_t count, size_t offset)
{
struct fat_entry *dirent = &file->entry;
if (!IS_DIR(file->entry.attribute)){
if (offset > dirent->length)
return -1;
if (offset+count > dirent->length)
count = dirent->length - offset;
}
if (count == 0)
return 0;
if (offsetfile->offset){
file->cluster = dirent->cluster_entry;
file->offset = 0;
}
size_t i;
struct fat_bpb *bpb = &file->fsop->bpb;
size_t bytes_per_cluster = (bpb->bytes_per_sector*bpb->sectors_per_cluster);
size_t cluster_count = (offset - file->offset)/bytes_per_cluster;
while(cluster_count>0){
size_t cluster;
if (fat_next_cluster(file->fsop, file->cluster, &cluster)==-1){
return -1;
}
if (cluster >= 0xFFF){
return 0;
}
file->offset += bytes_per_cluster;
file->cluster = cluster;
cluster_count--;
}
char *cluster_buffer = (char*)malloc(bytes_per_cluster);
assert(cluster_buffer);
if (fat_read_cluster(file->fsop, file->cluster, cluster_buffer)){
free(cluster_buffer);
return -1;
}
size_t cluster_offset = offset-file->offset;
size_t cpcnt = bytes_per_cluster>cluster_offset+count?
count:bytes_per_cluster-cluster_offset;
memcpy(buff, cluster_buffer+cluster_offset, cpcnt);
free(cluster_buffer);
offset += cpcnt;
count-= cpcnt;
int hr = 0;
while (offsetdirent->length && count>0){
if ((hr=fat_pread_file(file, (char*)buff+cpcnt, count, offset))==-1){
return -1;
}
if (hr == 0){
break;
}
offset += hr;
count -= hr;
cpcnt += hr;
}
return cpcnt;
}
const char *paths[] = {
"IO.SYS", "AUTOEXEC.BAT", "CONFIG.SYS", "SETRAMD.BAT", "README.TXT",
"FINDRAMD.EXE", "RAMDRIVE.SYS", "ASPI4DOS.SYS", "BTCDROM.SYS", "ASPICD.SYS",
"BTDOSM.SYS", "ASPI2DOS.SYS", "ASPI8DOS.SYS", "ASPI8U2.SYS", "FLASHPT.SYS",
"EXTRACT.EXE", "FDISK.EXE", "DRVSPACE.BIN", "COMMAND.COM", "HIMEM.SYS",
"OAKCDROM.SYS", "EBD.CAB", "MSDOS.SYS", "EBD.SYS", "HELLO", "TEST.TXT", NULL
};
void save2file(struct fat_file *file, const char *path)
{
char buffer;
size_t offset = 0;
int rcnt = fat_pread_file(file, buffer, sizeof(buffer), offset);
#ifdef WRITE_FILE
char file_name;
sprintf(file_name, "data/%s", path);
FILE *fp = fopen(file_name, "wb");
#endif
while (rcnt > 0){
offset += rcnt;
#ifdef WRITE_FILE
if (fp != NULL)
fwrite(buffer, rcnt, 1, fp);
#endif
rcnt = fat_pread_file(file, buffer, sizeof(buffer), offset);
}
printf("last read count: %d %d\n", rcnt, offset);
#ifdef WRITE_FILE
if (fp != NULL)
fclose(fp);
#endif
}
int main(int argc, char *argv[])
{
int i;
struct fat_fsop fsop;
if (fat_open_volume(&fsop, "win98.img"))
return -1;
struct fat_file file;
struct fat_entry entry;
/* save hello/fstab to local disk */
if (-1!=fat_namei(&fsop, "HELLO", &entry)){
if (0==fat_open_file(&fsop, &entry, &file)){
save2file(&file, "fstab");
}
#if 1
struct fat_entry dirent;
if (0==fat_lookup(&fsop, &entry, "__.TXT", &dirent)){
if (0==fat_open_file(&fsop, &dirent, &file)){
save2file(&file, "fstab.txt");
}
}
#endif
}
for (i=0; paths; i++){
if (fat_namei(&fsop, paths, &entry))
continue;
printf("%-13s first cluster: %6d length: %6d\n",
paths, entry.cluster_entry, entry.length);
if (fat_open_file(&fsop, &entry, &file)){
printf("file %s open fail!\n", paths);
continue;
}
save2file(&file, paths);
}
return 0;
}
本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u2/69656/showart_2034540.html
页:
[1]