pagx 发表于 2009-08-22 16:42

读取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]
查看完整版本: 读取FAT12磁盘镜像的文件。