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

📄 ntfs.c

📁 linux下开发的针对所有磁盘的数据恢复的源码
💻 C
📖 第 1 页 / 共 5 页
字号:
/*** ntfs** The Sleuth Kit **** Content and meta data layer support for the NTFS 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)***/#include "tsk_fs_i.h"#include "tsk_ntfs.h"#include <ctype.h>/** * \file ntfs.c * Contains the TSK internal general NTFS processing code *//* * NOTES TO SELF: * * - multiple ".." entries may exist *//*  * How are we to handle the META flag? Is the MFT $Data Attribute META? *//* needs to be predefined for proc_attrseq */static uint8_t ntfs_proc_attrlist(NTFS_INFO *, TSK_FS_FILE *,    const TSK_FS_ATTR *);/* mini-design note: * The MFT has entries for every file and dir in the fs. * The first entry ($MFT) is for the MFT itself and it is used to find * the location of the entire table because it can become fragmented. * Therefore, the $Data attribute of $MFT is saved in the NTFS_INFO * structure for easy access.  We also use the size of the MFT as * a way to calculate the maximum MFT entry number (last_inum). * * Ok, that is simple, but getting the full $Data attribute can be tough * because $MFT may not fit into one MFT entry (i.e. an attribute list).  * We need to process the attribute list attribute to find out which * other entries to process.  But, the attribute list attribute comes * before any $Data attribute (so it could refer to an MFT that has not * yet been 'defined').  Although, the $Data attribute seems to always  * exist and define at least the run for the entry in the attribute list. * * So, the way this is solved is that generic mft_lookup is used to get * any MFT entry, even $MFT.  If $MFT is not cached then we calculate  * the address of where to read based on mutliplication and guessing.   * When we are loading the $MFT, we set 'loading_the_MFT' to 1 so * that we can update things as we go along.  When we read $MFT we * read all the attributes and save info about the $Data one.  If * there is an attribute list, we will have the location of the * additional MFT in the cached $Data location, which will be  * updated as we process the attribute list.  After each MFT * entry that we process while loading the MFT, the 'final_inum' * value is updated to reflect what we can currently load so  * that the sanity checks still work. *//********************************************************************** * *  MISC FUNCS * **********************************************************************//* convert the NT Time (UTC hundred nanoseconds from 1/1/1601) * to UNIX (UTC seconds from 1/1/1970) * * The basic calculation is to remove the nanoseconds and then * subtract the number of seconds between 1601 and 1970 * i.e. TIME - DELTA * */uint32_tnt2unixtime(uint64_t ntdate){// (369*365 + 89) * 24 * 3600 * 10000000#define	NSEC_BTWN_1601_1970	(uint64_t)(116444736000000000ULL)    ntdate -= (uint64_t) NSEC_BTWN_1601_1970;    ntdate /= (uint64_t) 10000000;    return (uint32_t) ntdate;}/********************************************************************** * * Lookup Functions * **********************************************************************//** * Read an MFT entry and save it in raw form in the given buffer. * NOTE: This will remove the update sequence integrity checks in the * structure. * * @param a_ntfs File system to read from * @param a_mft Buffer to save raw data to * @param a_mftnum Address of MFT entry to read * * @returns Error value */static TSK_RETVAL_ENUMntfs_dinode_lookup(NTFS_INFO * a_ntfs, ntfs_mft * a_mft,    TSK_INUM_T a_mftnum){    TSK_OFF_T mftaddr_b, mftaddr2_b, offset;    size_t mftaddr_len = 0;    int i;    TSK_FS_INFO *fs = (TSK_FS_INFO *) & a_ntfs->fs_info;    TSK_FS_ATTR_RUN *data_run;    ntfs_upd *upd;    uint16_t sig_seq;    /* sanity checks */    if (!a_mft) {        tsk_error_reset();        tsk_errno = TSK_ERR_FS_ARG;        snprintf(tsk_errstr, TSK_ERRSTR_L, "mft_lookup: null mft buffer");        return TSK_ERR;    }    if (a_mftnum < fs->first_inum) {        tsk_error_reset();        tsk_errno = TSK_ERR_FS_ARG;        snprintf(tsk_errstr, TSK_ERRSTR_L,            "mft_lookup: inode number is too small (%" PRIuINUM ")",            a_mftnum);        return TSK_ERR;    }    /* Because this code reads teh actual MFT, we need to make sure we      * decrement the last_inum because the last value is a special value     * for the ORPHANS directory */    if (a_mftnum > fs->last_inum - 1) {        tsk_error_reset();        tsk_errno = TSK_ERR_FS_ARG;        snprintf(tsk_errstr, TSK_ERRSTR_L,            "mft_lookup: inode number is too large (%" PRIuINUM ")",            a_mftnum);        return TSK_ERR;    }    if (tsk_verbose)        tsk_fprintf(stderr,            "ntfs_dinode_lookup: Processing MFT %" PRIuINUM "\n",            a_mftnum);    /* If mft_data (the cached $Data attribute of $MFT) is not there yet,      * then we have not started to load $MFT yet.  In that case, we will     * 'cheat' and calculate where it goes.  This should only be for     * $MFT itself, in which case the calculation is easy     */    if (!a_ntfs->mft_data) {        /* This is just a random check with the assumption being that         * we don't want to just do a guess calculation for a very large         * MFT entry         */        if (a_mftnum > NTFS_LAST_DEFAULT_INO) {            tsk_error_reset();            tsk_errno = TSK_ERR_FS_ARG;            snprintf(tsk_errstr, TSK_ERRSTR_L,                "Error trying to load a high MFT entry when the MFT itself has not been loaded (%"                PRIuINUM ")", a_mftnum);            return TSK_ERR;        }        mftaddr_b = a_ntfs->root_mft_addr + a_mftnum * a_ntfs->mft_rsize_b;        mftaddr2_b = 0;    }    else {        /* The MFT may not be in consecutive clusters, so we need to use its         * data attribute run list to find out what address to read         *         * This is why we cached it         */        // will be set to the address of the MFT entry        mftaddr_b = mftaddr2_b = 0;        /* The byte offset within the $Data stream */        offset = a_mftnum * a_ntfs->mft_rsize_b;        /* NOTE: data_run values are in clusters          *         * cycle through the runs in $Data and identify which         * has the MFT entry that we want         */        for (data_run = a_ntfs->mft_data->nrd.run;            data_run != NULL; data_run = data_run->next) {            /* The length of this specific run */            TSK_OFF_T run_len = data_run->len * a_ntfs->csize_b;            /* Is our MFT entry is in this run somewhere ? */            if (offset < run_len) {                if (tsk_verbose)                    tsk_fprintf(stderr,                        "ntfs_dinode_lookup: Found in offset: %"                        PRIuDADDR "  size: %" PRIuDADDR " at offset: %"                        PRIuOFF "\n", data_run->addr, data_run->len,                        offset);                /* special case where the MFT entry crosses                 * a run (only happens when cluster size is 512-bytes                 * and there are an odd number of clusters in the run)                 */                if (run_len < offset + a_ntfs->mft_rsize_b) {                    if (tsk_verbose)                        tsk_fprintf(stderr,                            "ntfs_dinode_lookup: Entry crosses run border\n");                    if (data_run->next == NULL) {                        tsk_error_reset();                        tsk_errno = TSK_ERR_FS_INODE_COR;                        snprintf(tsk_errstr, TSK_ERRSTR_L,                            "mft_lookup: MFT entry crosses a cluster and there are no more clusters!");                        return TSK_COR;                    }                    /* Assign address where the remainder of the entry is */                    mftaddr2_b = data_run->next->addr * a_ntfs->csize_b;                    /* this should always be 512, but just in case */                    mftaddr_len = (size_t) (run_len - offset);                }                /* Assign address of where the MFT entry starts */                mftaddr_b = data_run->addr * a_ntfs->csize_b + offset;                if (tsk_verbose)                    tsk_fprintf(stderr,                        "ntfs_dinode_lookup: Entry address at: %"                        PRIuOFF "\n", mftaddr_b);                break;            }            /* decrement the offset we are looking for */            offset -= run_len;        }        /* Did we find it? */        if (!mftaddr_b) {            tsk_error_reset();            tsk_errno = TSK_ERR_FS_INODE_NUM;            snprintf(tsk_errstr, TSK_ERRSTR_L,                "mft_lookup: Error finding MFT entry %"                PRIuINUM " in $MFT", a_mftnum);            return TSK_ERR;        }    }    /* can we do just one read or do we need multiple? */    if (mftaddr2_b) {        ssize_t cnt;        /* read the first part into mft */        cnt =            tsk_fs_read(&a_ntfs->fs_info, mftaddr_b, (char *) a_mft,            mftaddr_len);        if (cnt != mftaddr_len) {            if (cnt >= 0) {                tsk_error_reset();                tsk_errno = TSK_ERR_FS_READ;            }            snprintf(tsk_errstr2, TSK_ERRSTR_L,                "ntfs_dinode_lookup: Error reading MFT Entry (part 1) at %"                PRIuOFF, mftaddr_b);            return TSK_ERR;        }        /* read the second part into mft */        cnt = tsk_fs_read            (&a_ntfs->fs_info, mftaddr2_b,            (char *) ((uintptr_t) a_mft + (uintptr_t) mftaddr_len),            a_ntfs->mft_rsize_b - mftaddr_len);        if (cnt != a_ntfs->mft_rsize_b - mftaddr_len) {            if (cnt >= 0) {                tsk_error_reset();                tsk_errno = TSK_ERR_FS_READ;            }            snprintf(tsk_errstr2, TSK_ERRSTR_L,                "ntfs_dinode_lookup: Error reading MFT Entry (part 2) at %"                PRIuOFF, mftaddr2_b);            return TSK_ERR;        }    }    else {        ssize_t cnt;        /* read the raw entry into mft */        cnt =            tsk_fs_read(&a_ntfs->fs_info, mftaddr_b, (char *) a_mft,            a_ntfs->mft_rsize_b);        if (cnt != a_ntfs->mft_rsize_b) {            if (cnt >= 0) {                tsk_error_reset();                tsk_errno = TSK_ERR_FS_READ;            }            snprintf(tsk_errstr2, TSK_ERRSTR_L,                "ntfs_dinode_lookup: Error reading MFT Entry at %"                PRIuOFF, mftaddr_b);            return TSK_ERR;        }    }    /* if we are saving into the NTFS_INFO structure, assign mnum too */    if ((uintptr_t) a_mft == (uintptr_t) a_ntfs->mft)        a_ntfs->mnum = a_mftnum;    /* Sanity Check */#if 0    /* This is no longer applied because it caused too many problems     * with images that had 0 and 1 etc. as values.  Testing shows that     * even Windows XP doesn't care if entries have an invalid entry, so     * this is no longer checked.  The update sequence check should find     * corrupt entries     * */    if ((tsk_getu32(fs->endian, mft->magic) != NTFS_MFT_MAGIC)        && (tsk_getu32(fs->endian, mft->magic) != NTFS_MFT_MAGIC_BAAD)        && (tsk_getu32(fs->endian, mft->magic) != NTFS_MFT_MAGIC_ZERO)) {        tsk_errno = TSK_ERR_FS_INODE_COR;        snprintf(tsk_errstr, TSK_ERRSTR_L,            "entry %d has an invalid MFT magic: %x",            mftnum, tsk_getu32(fs->endian, mft->magic));        return 1;    }#endif    /* The MFT entries have error and integrity checks in them     * called update sequences.  They must be checked and removed     * so that later functions can process the data as normal.      * They are located in the last 2 bytes of each 512-byte sector     *     * We first verify that the the 2-byte value is a give value and     * then replace it with what should be there     */    /* sanity check so we don't run over in the next loop */    if ((tsk_getu16(fs->endian, a_mft->upd_cnt) > 0) &&        (((uint32_t) (tsk_getu16(fs->endian,

⌨️ 快捷键说明

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