⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fatfs.c

📁 linux下开发的针对所有磁盘的数据恢复的源码
💻 C
📖 第 1 页 / 共 4 页
字号:
/*** fatfs** The Sleuth Kit **** Content and meta data layer support for the FAT file system **** Brian Carrier [carrier <at> sleuthkit [dot] org]** Copyright (c) 2006-2008 Brian Carrier, Basis Technology.  All Rights reserved** Copyright (c) 2003-2005 Brian Carrier.  All rights reserved **** TASK** Copyright (c) 2002 Brian Carrier, @stake Inc.  All rights reserved****** This software is distributed under the Common Public License 1.0**** Unicode added with support from I.D.E.A.L. Technology Corp (Aug '05)***//** * \file fatfs.c * Contains the internal TSK FAT file system code to handle basic file system  * processing for opening file system, processing sectors, and directory entries.  */#include "tsk_fs_i.h"#include "tsk_fatfs.h"/* * Implementation NOTES  * * TSK_FS_META contains the first cluster.  file_walk will return sector * values though because the cluster numbers do not start until after * the FAT.  That makes it very hard to address the first few blocks! * * Inodes numbers do not exist in FAT.  To make up for this we will count * directory entries as the inodes.   As the root directory does not have * any records in FAT, we will give it times of 0 and call it inode 2 to * keep consistent with UNIX.  After that, each 32-byte slot is numbered * as though it were a directory entry (even if it is not).  Therefore, * when an inode walk is performed, not all inode values will be displayed * even when '-e' is given for ils.  * * Progs like 'ils -e' are very slow because we have to look at each * block to see if it is a file system structure. *//* TTL is 0 if the entry has not been used.  TTL of 1 means it was the * most recently used, and TTL of FAT_CACHE_N means it was the least  * recently used.  This function has a LRU replacement algo */// return -1 on error, or cache index on success (0 to FAT_CACHE_N)static intgetFATCacheIdx(FATFS_INFO * fatfs, TSK_DADDR_T sect){    int i, cidx;    ssize_t cnt;    TSK_FS_INFO *fs = (TSK_FS_INFO *) & fatfs->fs_info;    // see if we already have it in the cache    for (i = 0; i < FAT_CACHE_N; i++) {        if ((fatfs->fatc_ttl[i] > 0) &&            (sect >= fatfs->fatc_addr[i]) &&            (sect < (fatfs->fatc_addr[i] + FAT_CACHE_S))) {            int a;            // update the TTLs to push i to the front            for (a = 0; a < FAT_CACHE_N; a++) {                if (fatfs->fatc_ttl[a] == 0)                    continue;                if (fatfs->fatc_ttl[a] < fatfs->fatc_ttl[i])                    fatfs->fatc_ttl[a]++;            }            fatfs->fatc_ttl[i] = 1;//          fprintf(stdout, "FAT Hit: %d\n", sect);//          fflush(stdout);            return i;        }    }//    fprintf(stdout, "FAT Miss: %d\n", (int)sect);//    fflush(stdout);    // Look for an unused entry or an entry with a TTL of FAT_CACHE_N    cidx = 0;    for (i = 0; i < FAT_CACHE_N; i++) {        if ((fatfs->fatc_ttl[i] == 0) ||            (fatfs->fatc_ttl[i] >= FAT_CACHE_N)) {            cidx = i;        }    }//    fprintf(stdout, "FAT Removing: %d\n", (int)fatfs->fatc_addr[cidx]);    //   fflush(stdout);    // read the data    cnt =        tsk_fs_read(fs, sect * fs->block_size, fatfs->fatc_buf[cidx],        FAT_CACHE_B);    if (cnt != FAT_CACHE_B) {        if (cnt >= 0) {            tsk_error_reset();            tsk_errno = TSK_ERR_FS_READ;        }        snprintf(tsk_errstr2, TSK_ERRSTR_L,            "getFATCacheIdx: FAT: %" PRIuDADDR, sect);        return -1;    }    // update the TTLs    if (fatfs->fatc_ttl[cidx] == 0)     // special case for unused entry        fatfs->fatc_ttl[cidx] = FAT_CACHE_N + 1;    for (i = 0; i < FAT_CACHE_N; i++) {        if (fatfs->fatc_ttl[i] == 0)            continue;        if (fatfs->fatc_ttl[i] < fatfs->fatc_ttl[cidx])            fatfs->fatc_ttl[i]++;    }    fatfs->fatc_ttl[cidx] = 1;    fatfs->fatc_addr[cidx] = sect;    return cidx;}/* * Set *value to the entry in the File Allocation Table (FAT)  * for the given cluster * * *value is in clusters and may need to be coverted to * sectors by the calling function * * Invalid values in the FAT (i.e. greater than the largest * cluster have a value of 0 returned and a 0 return value. * * Return 1 on error and 0 on success */uint8_tfatfs_getFAT(FATFS_INFO * fatfs, TSK_DADDR_T clust, TSK_DADDR_T * value){    uint8_t *a_ptr;    uint16_t tmp16;    TSK_FS_INFO *fs = (TSK_FS_INFO *) & fatfs->fs_info;    TSK_DADDR_T sect, offs;    ssize_t cnt;    int cidx;    /* Sanity Check */    if (clust > fatfs->lastclust) {        /* silently ignore requests for the unclustered sectors... */        if ((clust == fatfs->lastclust + 1) &&            ((fatfs->firstclustsect + fatfs->csize * fatfs->clustcnt -                    1) != fs->last_block)) {            if (tsk_verbose)                tsk_fprintf(stderr,                    "fatfs_getFAT: Ignoring request for non-clustered sector\n");            return 0;        }        tsk_error_reset();        tsk_errno = TSK_ERR_FS_ARG;        snprintf(tsk_errstr, TSK_ERRSTR_L,            "fatfs_getFAT: invalid cluster address: %" PRIuDADDR, clust);        return 1;    }    switch (fatfs->fs_info.ftype) {    case TSK_FS_TYPE_FAT12:        if (clust & 0xf000) {            tsk_error_reset();            tsk_errno = TSK_ERR_FS_ARG;            snprintf(tsk_errstr, TSK_ERRSTR_L,                "fatfs_getFAT: TSK_FS_TYPE_FAT12 Cluster %" PRIuDADDR                " too large", clust);            return 1;        }        /* id the sector in the FAT */        sect = fatfs->firstfatsect +            ((clust + (clust >> 1)) >> fatfs->ssize_sh);        /* Load the FAT if we don't have it */        // see if it is in the cache        if (-1 == (cidx = getFATCacheIdx(fatfs, sect)))            return 1;        /* get the offset into the cache */        offs = ((sect - fatfs->fatc_addr[cidx]) << fatfs->ssize_sh) +            (clust + (clust >> 1)) % fatfs->ssize;        /* special case when the 12-bit value goes across the cache         * we load the cache to start at this sect.  The cache         * size must therefore be at least 2 sectors large          */        if (offs == (FAT_CACHE_B - 1)) {            // read the data -- TTLs will already have been updated            cnt =                tsk_fs_read(fs, sect * fs->block_size,                fatfs->fatc_buf[cidx], FAT_CACHE_B);            if (cnt != FAT_CACHE_B) {                if (cnt >= 0) {                    tsk_error_reset();                    tsk_errno = TSK_ERR_FS_READ;                }                snprintf(tsk_errstr2, TSK_ERRSTR_L,                    "fatfs_getFAT: TSK_FS_TYPE_FAT12 FAT overlap: %"                    PRIuDADDR, sect);                return 1;            }            fatfs->fatc_addr[cidx] = sect;            offs = (clust + (clust >> 1)) % fatfs->ssize;        }        /* get pointer to entry in current buffer */        a_ptr = (uint8_t *) fatfs->fatc_buf[cidx] + offs;        tmp16 = tsk_getu16(fs->endian, a_ptr);        /* slide it over if it is one of the odd clusters */        if (clust & 1)            tmp16 >>= 4;        *value = tmp16 & FATFS_12_MASK;        /* sanity check */        if ((*value > (fatfs->lastclust)) &&            (*value < (0x0ffffff7 & FATFS_12_MASK))) {            if (tsk_verbose)                tsk_fprintf(stderr,                    "fatfs_getFAT: TSK_FS_TYPE_FAT12 cluster (%" PRIuDADDR                    ") too large (%" PRIuDADDR ") - resetting\n", clust,                    *value);            *value = 0;        }        return 0;    case TSK_FS_TYPE_FAT16:        /* Get sector in FAT for cluster and load it if needed */        sect = fatfs->firstfatsect + ((clust << 1) >> fatfs->ssize_sh);        if (-1 == (cidx = getFATCacheIdx(fatfs, sect)))            return 1;        /* get pointer to entry in the cache buffer */        a_ptr = (uint8_t *) fatfs->fatc_buf[cidx] +            ((sect - fatfs->fatc_addr[cidx]) << fatfs->ssize_sh) +            ((clust << 1) % fatfs->ssize);        *value = tsk_getu16(fs->endian, a_ptr) & FATFS_16_MASK;        /* sanity check */        if ((*value > (fatfs->lastclust)) &&            (*value < (0x0ffffff7 & FATFS_16_MASK))) {            if (tsk_verbose)                tsk_fprintf(stderr,                    "fatfs_getFAT: contents of TSK_FS_TYPE_FAT16 entry %"                    PRIuDADDR " too large - resetting\n", clust);            *value = 0;        }        return 0;    case TSK_FS_TYPE_FAT32:        /* Get sector in FAT for cluster and load if needed */        sect = fatfs->firstfatsect + ((clust << 2) >> fatfs->ssize_sh);        if (-1 == (cidx = getFATCacheIdx(fatfs, sect)))            return 1;        /* get pointer to entry in current buffer */        a_ptr = (uint8_t *) fatfs->fatc_buf[cidx] +            ((sect - fatfs->fatc_addr[cidx]) << fatfs->ssize_sh) +            (clust << 2) % fatfs->ssize;        *value = tsk_getu32(fs->endian, a_ptr) & FATFS_32_MASK;        /* sanity check */        if ((*value > fatfs->lastclust) &&            (*value < (0x0ffffff7 & FATFS_32_MASK))) {            if (tsk_verbose)                tsk_fprintf(stderr,                    "fatfs_getFAT: contents of entry %" PRIuDADDR                    " too large - resetting\n", clust);            *value = 0;        }        return 0;    default:        tsk_error_reset();        tsk_errno = TSK_ERR_FS_ARG;        snprintf(tsk_errstr, TSK_ERRSTR_L,            "fatfs_getFAT: Unknown FAT type: %d", fatfs->fs_info.ftype);        return 1;    }}/* Return 1 if allocated, 0 if unallocated, and -1 if error */int8_tfatfs_is_clustalloc(FATFS_INFO * fatfs, TSK_DADDR_T clust){    TSK_DADDR_T content;    if (fatfs_getFAT(fatfs, clust, &content))        return -1;    else if (content == FATFS_UNALLOC)        return 0;    else        return 1;}/*  * Identifies if a sector is allocated * * If it is less than the data area, then it is allocated * else the FAT table is consulted * * Return 1 if allocated, 0 if unallocated, and -1 if error  */int8_tfatfs_is_sectalloc(FATFS_INFO * fatfs, TSK_DADDR_T sect){    TSK_FS_INFO *fs = (TSK_FS_INFO *) fatfs;    /* If less than the first cluster sector, then it is allocated      * otherwise check the FAT     */    if (sect < fatfs->firstclustsect)        return 1;    /* If we are in the unused area, then we are "unalloc" */    if ((sect <= fs->last_block) &&        (sect >= (fatfs->firstclustsect + fatfs->csize * fatfs->clustcnt)))        return 0;    return fatfs_is_clustalloc(fatfs, FATFS_SECT_2_CLUST(fatfs, sect));}TSK_FS_BLOCK_FLAG_ENUMfatfs_block_getflags(TSK_FS_INFO * a_fs, TSK_DADDR_T a_addr){    FATFS_INFO *fatfs = (FATFS_INFO *) a_fs;    int flags = 0;    // FATs and boot sector    if (a_addr < fatfs->firstdatasect) {        flags = TSK_FS_BLOCK_FLAG_META | TSK_FS_BLOCK_FLAG_ALLOC;    }    // root directory for FAT12/16    else if (a_addr < fatfs->firstclustsect) {        flags = TSK_FS_BLOCK_FLAG_CONT | TSK_FS_BLOCK_FLAG_ALLOC;    }    else {        int retval;        flags = TSK_FS_BLOCK_FLAG_CONT;        /* Identify its allocation status */        retval = fatfs_is_sectalloc(fatfs, a_addr);        if (retval != -1) {            if (retval == 1)                flags |= TSK_FS_BLOCK_FLAG_ALLOC;            else                flags |= TSK_FS_BLOCK_FLAG_UNALLOC;        }    }    return flags;}/************************************************************************** * * BLOCK WALKING *  *************************************************************************//* ** Walk the sectors of the partition. **** NOTE: This is by SECTORS and not CLUSTERS** _flags: TSK_FS_BLOCK_FLAG_ALLOC, TSK_FS_BLOCK_FLAG_UNALLOC, TSK_FS_BLOCK_FLAG_META**  TSK_FS_BLOCK_FLAG_CONT***/uint8_tfatfs_block_walk(TSK_FS_INFO * fs, TSK_DADDR_T a_start_blk,    TSK_DADDR_T a_end_blk, TSK_FS_BLOCK_WALK_FLAG_ENUM a_flags,    TSK_FS_BLOCK_WALK_CB a_action, void *a_ptr){    char *myname = "fatfs_block_walk";    FATFS_INFO *fatfs = (FATFS_INFO *) fs;    char *data_buf = NULL;    ssize_t cnt;    TSK_FS_BLOCK *fs_block;    TSK_DADDR_T addr;    int myflags;    unsigned int i;    // clean up any error messages that are lying around    tsk_error_reset();    /*     * Sanity checks.     */    if (a_start_blk < fs->first_block || a_start_blk > fs->last_block) {        tsk_error_reset();        tsk_errno = TSK_ERR_FS_WALK_RNG;        snprintf(tsk_errstr, TSK_ERRSTR_L,            "%s: Start block: %" PRIuDADDR "", myname, a_start_blk);        return 1;    }    if (a_end_blk < fs->first_block || a_end_blk > fs->last_block) {        tsk_error_reset();        tsk_errno = TSK_ERR_FS_WALK_RNG;        snprintf(tsk_errstr, TSK_ERRSTR_L,            "%s: End block: %" PRIuDADDR "", myname, a_end_blk);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -