From 59352ea089659392c7076184f03cc0665e52c7b6 Mon Sep 17 00:00:00 2001 From: Paulo Alcantara Date: Mon, 25 Jul 2011 00:24:24 +0000 Subject: [PATCH] ntfs: heh :-) Signed-off-by: Paulo Alcantara --- core/fs/ntfs/ntfs.c | 187 +++++++++++++++++++++++++++------------------------- core/fs/ntfs/ntfs.h | 5 +- 2 files changed, 98 insertions(+), 94 deletions(-) diff --git a/core/fs/ntfs/ntfs.c b/core/fs/ntfs/ntfs.c index 2702f01..f37f3d4 100644 --- a/core/fs/ntfs/ntfs.c +++ b/core/fs/ntfs/ntfs.c @@ -28,14 +28,6 @@ #include "codepage.h" #include "ntfs.h" -#define for_each_mft_record(fs, data, block) \ - for ((data) = get_right_block((fs), (block)); \ - (block) < NTFS_SB((fs))->mft_size && \ - ((const MFT_RECORD *)(data))->magic == NTFS_MAGIC_FILE; \ - (block) += ((const MFT_RECORD *)(data))->bytes_allocated >> \ - BLOCK_SHIFT((fs)), \ - (data) = get_right_block((fs), (block))) - /* Check if there are specific zero fields in an NTFS boot sector */ static inline int ntfs_check_zero_fields(const struct ntfs_bpb *sb) { @@ -66,23 +58,36 @@ static inline struct inode *new_ntfs_inode(struct fs_info *fs) static inline const void *get_right_block(struct fs_info *fs, block_t block) { - return get_cache(fs->fs_dev, NTFS_SB(fs)->mft + block); + return get_cache(fs->fs_dev, NTFS_SB(fs)->mft_block + block); } -static MFT_RECORD *mft_record_lookup(uint32_t file, struct fs_info *fs, - sector_t *block) -{ - const uint8_t *data; - MFT_RECORD *mrec; - - for_each_mft_record(fs, data, *block) { - mrec = (MFT_RECORD *)data; +static MFT_RECORD * mft_record_lookup( + uint32_t file, + struct fs_info * fs, + block_t * block + ) { + int offset = 0; + const uint8_t * data; + MFT_RECORD * mrec; + + goto jump_in; + while (1) { + mrec = (MFT_RECORD *) (data + offset); + if (mrec->magic != NTFS_MAGIC_FILE) + break; if (mrec->mft_record_no == file) - return mrec; - } + return mrec; + offset += mrec->bytes_allocated; + if (offset >= BLOCK_SIZE(fs)) { + ++*block; + offset -= BLOCK_SIZE(fs); + jump_in: + data = get_right_block(fs, *block); + } + } return NULL; -} + } static ATTR_RECORD *attr_lookup(uint32_t type, const MFT_RECORD *mrec) { @@ -109,7 +114,7 @@ static bool ntfs_match_longname(const char *str, unsigned long mft_no, struct fs_info *fs) { MFT_RECORD *mrec; - sector_t block = 0; + block_t block = 0; ATTR_RECORD *attr; FILE_NAME_ATTR *fn; uint8_t len; @@ -133,7 +138,7 @@ static bool ntfs_match_longname(const char *str, unsigned long mft_no, len = fn->file_name_len; match = fn->file_name; - dprintf("Matching: %s\n", str); + printf("Matching: %s\n", str); while (len) { cp = *match++; @@ -268,13 +273,13 @@ static enum dirent_type get_inode_mode(MFT_RECORD *mrec) attr = attr_lookup(NTFS_AT_FILENAME, mrec); if (!attr) { - dprintf("No attribute found!\n"); + printf("No attribute found!\n"); return DT_UNKNOWN; } fn = (FILE_NAME_ATTR *)((uint8_t *)attr + attr->data.resident.value_offset); - dprintf("File attributes: 0x%X\n", fn->file_attrs); + printf("File attributes: 0x%X\n", fn->file_attrs); dir_mask = NTFS_FILE_ATTR_ARCHIVE | NTFS_FILE_ATTR_DUP_FILE_NAME_INDEX_PRESENT; @@ -287,9 +292,9 @@ static enum dirent_type get_inode_mode(MFT_RECORD *mrec) root = fn->file_attrs & ~root_mask; file = fn->file_attrs & ~file_mask; - dprintf("dir = 0x%X\n", dir); - dprintf("root= 0x%X\n", root); - dprintf("file = 0x%X\n", file); + printf("dir = 0x%X\n", dir); + printf("root= 0x%X\n", root); + printf("file = 0x%X\n", file); if (((!dir && root) || (!dir && !root)) && !file) infile = true; @@ -300,7 +305,7 @@ static int index_inode_setup(struct fs_info *fs, unsigned long mft_no, struct inode *inode) { MFT_RECORD *mrec; - sector_t block = 0; + block_t block = 0; ATTR_RECORD *attr; enum dirent_type d_type; uint32_t len; @@ -314,7 +319,7 @@ static int index_inode_setup(struct fs_info *fs, unsigned long mft_no, mrec = mft_record_lookup(mft_no, fs, &block); if (!mrec) { - dprintf("No MFT record found!\n"); + printf("No MFT record found!\n"); goto out; } @@ -326,15 +331,15 @@ static int index_inode_setup(struct fs_info *fs, unsigned long mft_no, d_type = get_inode_mode(mrec); if (d_type == DT_UNKNOWN) { - dprintf("Failed on determining inode's mode\n"); + printf("Failed on determining inode's mode\n"); goto out; } if (d_type == DT_DIR) { /* directory stuff */ - dprintf("Got a directory.\n"); + printf("Got a directory.\n"); attr = attr_lookup(NTFS_AT_INDEX_ROOT, mrec); if (!attr) { - dprintf("No attribute found!\n"); + printf("No attribute found!\n"); goto out; } @@ -344,7 +349,7 @@ static int index_inode_setup(struct fs_info *fs, unsigned long mft_no, len = attr->data.resident.value_len; if ((uint8_t *)ir + len > (uint8_t *)mrec + NTFS_SB(fs)->mft_record_size) { - dprintf("Corrupt index\n"); + printf("Corrupt index\n"); goto out; } @@ -364,10 +369,10 @@ static int index_inode_setup(struct fs_info *fs, unsigned long mft_no, NTFS_PVT(inode)->itype.index.vcn_size_shift = BLOCK_SHIFT(fs); } } else if (d_type == DT_REG) { /* file stuff */ - dprintf("Got a file.\n"); + printf("Got a file.\n"); attr = attr_lookup(NTFS_AT_DATA, mrec); if (!attr) { - dprintf("No attribute found!\n"); + printf("No attribute found!\n"); goto out; } @@ -427,7 +432,7 @@ static struct inode *index_lookup(const char *dname, struct inode *dir) { struct fs_info *fs = dir->fs; MFT_RECORD *mrec; - sector_t block; + block_t block; ATTR_RECORD *attr; INDEX_ROOT *ir; uint32_t len; @@ -435,7 +440,6 @@ static struct inode *index_lookup(const char *dname, struct inode *dir) uint8_t vcn_count; INDEX_BLOCK *iblock; int64_t vcn; - unsigned block_count; uint8_t *stream; uint32_t offset; uint8_t *attr_len; @@ -444,16 +448,16 @@ static struct inode *index_lookup(const char *dname, struct inode *dir) struct inode *inode; block = NTFS_PVT(dir)->start; - dprintf("index_lookup() - mft record number: %d\n", NTFS_PVT(dir)->mft_no); + printf("index_lookup() - mft record number: %d\n", NTFS_PVT(dir)->mft_no); mrec = mft_record_lookup(NTFS_PVT(dir)->mft_no, fs, &block); if (!mrec) { - dprintf("No MFT record found!\n"); + printf("No MFT record found!\n"); goto out; } attr = attr_lookup(NTFS_AT_INDEX_ROOT, mrec); if (!attr) { - dprintf("No attribute found!\n"); + printf("No attribute found!\n"); goto out; } @@ -478,20 +482,20 @@ static struct inode *index_lookup(const char *dname, struct inode *dir) /* last entry cannot contain a key. it can however contain * a pointer to a child node in the B+ tree so we just break out */ - dprintf("(0) ie->flags: 0x%X\n", ie->flags); + printf("(0) ie->flags: 0x%X\n", ie->flags); if (ie->flags & INDEX_ENTRY_END) break; if (ntfs_match_longname(dname, ie->data.dir.indexed_file, fs)) { - dprintf("Filename matches up!\n"); - dprintf("MFT record number = %d\n", ie->data.dir.indexed_file); + printf("Filename matches up!\n"); + printf("MFT record number = %d\n", ie->data.dir.indexed_file); goto found; } } /* check for the presence of a child node */ if (!(ie->flags & INDEX_ENTRY_NODE)) { - dprintf("No child node, aborting...\n"); + printf("No child node, aborting...\n"); goto out; } @@ -499,12 +503,12 @@ static struct inode *index_lookup(const char *dname, struct inode *dir) attr = attr_lookup(NTFS_AT_INDEX_ALLOCATION, mrec); if (!attr) { - dprintf("No attribute found!\n"); + printf("No attribute found!\n"); goto out; } if (!attr->non_resident) { - dprintf("WTF ?! $INDEX_ALLOCATION isn't really resident.\n"); + printf("WTF ?! $INDEX_ALLOCATION isn't really resident.\n"); goto out; } @@ -528,24 +532,21 @@ static struct inode *index_lookup(const char *dname, struct inode *dir) break; if (chunk.flags & MAP_ALLOCATED) { - dprintf("%d cluster(s) starting at 0x%X\n", chunk.vcn_len, + printf("%d cluster(s) starting at 0x%X\n", chunk.vcn_len, chunk.cur_lcn); vcn_count = 0; - vcn = chunk.cur_vcn; + vcn = chunk.cur_vcn; /* HUMMMMMMM!!!!! */ while (vcn_count++ < chunk.vcn_len) { - block = (chunk.cur_lcn + vcn) << NTFS_SB(fs)->clust_shift; + block = ((chunk.cur_lcn + vcn) << NTFS_SB(fs)->clust_shift) << + SECTOR_SHIFT(fs) >> BLOCK_SHIFT(fs); + iblock = (INDEX_BLOCK *)get_cache(fs->fs_dev, block); if (iblock->magic != NTFS_MAGIC_INDX) { - dprintf("Not a valid INDX record\n"); + printf("Not a valid INDX record\n"); goto out; } - /* get the index entries region cached */ - block_count = iblock->index.allocated_size >> BLOCK_SHIFT(fs); - while (block_count--) - (void)get_cache(fs->fs_dev, ++block); - ie = (INDEX_ENTRY *)((uint8_t *)&iblock->index + iblock->index.entries_offset); for (;; ie = (INDEX_ENTRY *)((uint8_t *)ie + ie->len)) { @@ -557,17 +558,17 @@ static struct inode *index_lookup(const char *dname, struct inode *dir) (uint8_t *)&iblock->index + iblock->index.index_len) goto index_err; - dprintf("Entry length 0x%x (%d)\n", ie->len, ie->len); + printf("Entry length 0x%x (%d)\n", ie->len, ie->len); /* last entry cannot contain a key */ - dprintf("(1) ie->flags: 0x%X\n", ie->flags); + printf("(1) ie->flags: 0x%X\n", ie->flags); if (ie->flags & INDEX_ENTRY_END) break; if (ntfs_match_longname(dname, ie->data.dir.indexed_file, fs)) { - dprintf("Filename matches up!\n"); - dprintf("MFT record number = %d\n", + printf("Filename matches up!\n"); + printf("MFT record number = %d\n", ie->data.dir.indexed_file); goto found; } @@ -579,13 +580,13 @@ static struct inode *index_lookup(const char *dname, struct inode *dir) } not_found: - dprintf("Index not found\n"); + printf("Index not found\n"); out: return NULL; found: - dprintf("--------------- Found index -------------------\n"); + printf("--------------- Found index -------------------\n"); inode = new_ntfs_inode(fs); err = index_inode_setup(fs, ie->data.dir.indexed_file, inode); if (err) { @@ -596,7 +597,7 @@ found: return inode; index_err: - dprintf("Corrupt index. Aborting lookup...\n"); + printf("Corrupt index. Aborting lookup...\n"); goto out; } @@ -648,19 +649,21 @@ static int ntfs_next_extent(struct inode *inode, uint32_t lstart) uint32_t tcluster; const uint32_t cluster_bytes = UINT32_C(1) << sbi->clust_byte_shift; sector_t pstart; - const uint32_t blk_size = BLOCK_SIZE(fs); - const uint32_t blk_shift = BLOCK_SHIFT(fs); + const uint32_t sec_size = SECTOR_SIZE(fs); + const uint32_t sec_shift = SECTOR_SHIFT(fs); tcluster = (inode->size + cluster_bytes - 1) >> sbi->clust_byte_shift; if (mcluster >= tcluster) goto out; /* Requested cluster beyond end of file */ - if (!NTFS_PVT(inode)->non_resident) - pstart = sbi->mft + NTFS_PVT(inode)->here; - else + if (!NTFS_PVT(inode)->non_resident) { + pstart = sbi->mft_block + NTFS_PVT(inode)->here; + pstart <<= BLOCK_SHIFT(fs) >> sec_shift; + } else { pstart = NTFS_PVT(inode)->data.non_resident.lcn << sbi->clust_shift; + } - inode->next_extent.len = (inode->size + blk_size - 1) >> blk_shift; + inode->next_extent.len = (inode->size + sec_size - 1) >> sec_shift; inode->next_extent.pstart = pstart; return 0; @@ -707,7 +710,7 @@ static uint32_t ntfs_getfssec(struct file *file, char *buf, int sectors, struct inode *inode = file->inode; uint8_t non_resident; struct fs_info *fs = file->fs; - sector_t block; + block_t block = 0; MFT_RECORD *mrec; ATTR_RECORD *attr; char *data; @@ -719,10 +722,9 @@ static uint32_t ntfs_getfssec(struct file *file, char *buf, int sectors, return ret; if (!non_resident) { - block = NTFS_SB(file->fs)->mft + NTFS_PVT(inode)->here; - - mrec = (MFT_RECORD *)get_cache(fs->fs_dev, block); - if (mrec->magic != NTFS_MAGIC_FILE) { + printf("mft_no: %d\n", NTFS_PVT(inode)->mft_no); + mrec = mft_record_lookup(NTFS_PVT(inode)->mft_no, fs, &block); + if (!mrec) { printf("No MFT record found!\n"); goto out; } @@ -754,23 +756,21 @@ static int ntfs_readdir(struct file *file, struct dirent *dirent) struct fs_info *fs = file->fs; struct inode *inode = file->inode; MFT_RECORD *mrec; - sector_t block = 0; + block_t block = 0; ATTR_RECORD *attr; FILE_NAME_ATTR *fn; char filename[NTFS_MAX_FILE_NAME_LEN + 1]; int len; - printf("here!\n"); - mrec = mft_record_lookup(NTFS_PVT(inode)->mft_no, fs, &block); if (!mrec) { - dprintf("No MFT record found!\n"); + printf("No MFT record found!\n"); goto out; } attr = attr_lookup(NTFS_AT_FILENAME, mrec); if (!attr) { - dprintf("No attribute found!\n"); + printf("No attribute found!\n"); goto out; } @@ -779,7 +779,7 @@ static int ntfs_readdir(struct file *file, struct dirent *dirent) len = ntfs_cvt_longname(filename, fn->file_name); if (len < 0 || len != fn->file_name_len) { - dprintf("Failed on converting UTF-16LE LFN to OEM LFN\n"); + printf("Failed on converting UTF-16LE LFN to OEM LFN\n"); goto out; } @@ -827,6 +827,7 @@ static int ntfs_fs_init(struct fs_info *fs) struct ntfs_bpb ntfs; struct ntfs_sb_info *sbi; struct disk *disk = fs->fs_dev->disk; + uint8_t clust_per_mft_record; disk->rdwr_sectors(disk, &ntfs, 0, 1, 0); @@ -834,8 +835,19 @@ static int ntfs_fs_init(struct fs_info *fs) if (!ntfs_check_sb_fields(&ntfs)) return -1; + /* Note: clust_per_mft_record can be a negative number */ + clust_per_mft_record = ntfs.clust_per_mft_record < 0 ? + -ntfs.clust_per_mft_record : ntfs.clust_per_mft_record; + SECTOR_SHIFT(fs) = disk->sector_shift; + + /* We need _at least_ 1 KiB to read the whole MFT record */ + BLOCK_SHIFT(fs) = ilog2(ntfs.sec_per_clust) + SECTOR_SHIFT(fs); + if (BLOCK_SHIFT(fs) < clust_per_mft_record) + BLOCK_SHIFT(fs) = clust_per_mft_record; + SECTOR_SIZE(fs) = 1 << SECTOR_SHIFT(fs); + BLOCK_SIZE(fs) = 1 << BLOCK_SHIFT(fs); sbi = malloc(sizeof(*sbi)); if (!sbi) @@ -847,21 +859,14 @@ static int ntfs_fs_init(struct fs_info *fs) sbi->clust_byte_shift = sbi->clust_shift + SECTOR_SHIFT(fs); sbi->clust_mask = ntfs.sec_per_clust - 1; sbi->clust_size = ntfs.sec_per_clust << SECTOR_SHIFT(fs); - sbi->mft_record_size = ntfs.clust_per_mft_record << - sbi->clust_byte_shift; - sbi->root = sbi->mft + sbi->mft_size; - - /* Note: we need at least 1 KiB to read the whole MFT record, so the block - * shift will be at least 10 for now. - */ - BLOCK_SHIFT(fs) = sbi->clust_shift > 10 ? sbi->clust_shift : 10; - BLOCK_SIZE(fs) = 1 << BLOCK_SHIFT(fs); + sbi->mft_record_size = 1 << clust_per_mft_record; - sbi->mft = ntfs.mft_lclust << sbi->clust_shift; + sbi->mft_block = ntfs.mft_lclust << sbi->clust_shift << + SECTOR_SHIFT(fs) >> BLOCK_SHIFT(fs); /* 16 MFT entries reserved for metadata files (approximately 16 KiB) */ - sbi->mft_size = (ntfs.clust_per_mft_record << sbi->clust_shift) << 4; + sbi->mft_size = (clust_per_mft_record << sbi->clust_shift) << 4; - sbi->clusters = (ntfs.total_sectors - sbi->root) >> sbi->clust_shift; + sbi->clusters = ntfs.total_sectors << SECTOR_SHIFT(fs) >> sbi->clust_shift; if (sbi->clusters > 0xFFFFFFFFFFF4ULL) sbi->clusters = 0xFFFFFFFFFFF4ULL; diff --git a/core/fs/ntfs/ntfs.h b/core/fs/ntfs/ntfs.h index ac48c84..78a0004 100644 --- a/core/fs/ntfs/ntfs.h +++ b/core/fs/ntfs/ntfs.h @@ -35,7 +35,7 @@ struct ntfs_bpb { uint64_t total_sectors; uint64_t mft_lclust; uint64_t mft_mirr_lclust; - uint8_t clust_per_mft_record; + int8_t clust_per_mft_record; uint8_t unused_4[3]; uint8_t clust_per_idx_buf; uint8_t unused_5[3]; @@ -46,8 +46,7 @@ struct ntfs_bpb { } __attribute__((packed)); struct ntfs_sb_info { - sector_t mft; /* The MFT region */ - sector_t root; /* The root dir region */ + block_t mft_block; /* The first MFT record block */ unsigned mft_size; /* The MFT size in sectors */ unsigned mft_record_size; /* MFT record size in bytes */ -- 2.7.4