From 7f79f1395be123f4a32624ed6d4e2633b33cbe68 Mon Sep 17 00:00:00 2001 From: Paulo Alcantara Date: Tue, 9 Aug 2011 03:37:25 +0000 Subject: [PATCH] ntfs: more bugfixes Need more tests, hence I don't recommend to rely on it right now. Signed-off-by: Paulo Alcantara --- core/fs/ntfs/ntfs.c | 348 +++++++++++++++++++++++++++++++++------------------- core/fs/ntfs/ntfs.h | 20 +-- 2 files changed, 231 insertions(+), 137 deletions(-) diff --git a/core/fs/ntfs/ntfs.c b/core/fs/ntfs/ntfs.c index 8fe6087..9424452 100644 --- a/core/fs/ntfs/ntfs.c +++ b/core/fs/ntfs/ntfs.c @@ -14,7 +14,7 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the * Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111EXIT_FAILURE307, USA. + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* Note: No support for compressed files */ @@ -61,23 +61,15 @@ static inline struct inode *new_ntfs_inode(struct fs_info *fs) return inode; } -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 + block); -} - -static int fixups_writeback(struct fs_info *fs, NTFS_RECORD *nrec) +static void ntfs_fixups_writeback(struct fs_info *fs, NTFS_RECORD *nrec) { uint16_t *usa; uint16_t usa_no; uint16_t usa_count; - uint16_t *block; + uint16_t *blk; - if (nrec->magic != NTFS_MAGIC_FILE && nrec->magic != NTFS_MAGIC_INDX) { - printf("Not a valid NTFS record\n"); - goto out; - } + if (nrec->magic != NTFS_MAGIC_FILE && nrec->magic != NTFS_MAGIC_INDX) + return; /* get the Update Sequence Array offset */ usa = (uint16_t *)((uint8_t *)nrec + nrec->usa_ofs); @@ -86,56 +78,135 @@ static int fixups_writeback(struct fs_info *fs, NTFS_RECORD *nrec) /* get the Update Sequene Array count */ usa_count = nrec->usa_count - 1; /* exclude the USA number */ /* make it to point to the last two bytes of the RECORD's first sector */ - block = (uint16_t *)((uint8_t *)nrec + SECTOR_SIZE(fs) - 2); + blk = (uint16_t *)((uint8_t *)nrec + SECTOR_SIZE(fs) - 2); while (usa_count--) { - if (*block != usa_no) + if (*blk != usa_no) break; - *block = *usa++; - block = (uint16_t *)((uint8_t *)block + SECTOR_SIZE(fs)); + *blk = *usa++; + blk = (uint16_t *)((uint8_t *)blk + SECTOR_SIZE(fs)); + } +} + +/* read content from cache */ +static int ntfs_read(struct fs_info *fs, void *buf, size_t len, uint64_t count, + block_t *blk, uint64_t *blk_offset, + uint64_t *blk_next_offset, uint64_t *lcn) +{ + uint8_t *data; + uint64_t offset = *blk_offset; + const uint32_t clust_byte_shift = NTFS_SB(fs)->clust_byte_shift; + const uint64_t blk_size = UINT64_C(1) << BLOCK_SHIFT(fs); + uint64_t bytes; + uint64_t lbytes; + uint64_t loffset; + uint64_t k; + + if (count > len) + goto out; + + data = (uint8_t *)get_cache(fs->fs_dev, *blk); + if (!data) + goto out; + + if (!offset) + offset = (*lcn << clust_byte_shift) % blk_size; + + bytes = count; /* bytes to copy */ + lbytes = blk_size - offset; /* bytes left to copy */ + if (lbytes >= bytes) { + /* so there's room enough, then copy the whole content */ + memcpy(buf, data + offset, bytes); + loffset = offset; + offset += count; + } else { + /* otherwise, let's copy it partially... */ + k = 0; + while (bytes) { + memcpy(buf + k, data + offset, lbytes); + bytes -= lbytes; + loffset = offset; + offset += lbytes; + k += lbytes; + if (offset >= blk_size) { + /* then fetch a new FS block */ + data = (uint8_t *)get_cache(fs->fs_dev, ++*blk); + if (!data) + goto out; + + loffset = offset; + offset = 0; + } + } } + if (loffset >= blk_size) + loffset = 0; /* it must be aligned on a block boundary */ + + *blk_offset = loffset; + + if (blk_next_offset) + *blk_next_offset = offset; + + *lcn += blk_size / count; /* update LCN */ + return 0; out: return -1; } -static MFT_RECORD *mft_record_lookup(uint32_t file, struct fs_info *fs, - block_t *block) +static MFT_RECORD *ntfs_mft_record_lookup(uint32_t file, struct fs_info *fs, + block_t *blk, uint64_t *blk_offset) { - uint8_t *data; - int64_t offset = 0; + const uint64_t mft_record_size = NTFS_SB(fs)->mft_record_size; + uint8_t *buf; + block_t right_blk; + uint64_t offset = *blk_offset; + uint64_t next_offset; + uint64_t lcn = NTFS_SB(fs)->mft_lcn; int err; MFT_RECORD *mrec; - goto jump_in; + buf = (uint8_t *)malloc(mft_record_size); + if (!buf) + malloc_error("uint8_t *"); for (;;) { - err = fixups_writeback(fs, (NTFS_RECORD *)(data + offset)); - if (err) + right_blk = *blk + NTFS_SB(fs)->mft_blk; + err = ntfs_read(fs, buf, mft_record_size, mft_record_size, &right_blk, + &offset, &next_offset, &lcn); + if (err) { + printf("Error on reading from cache.\n"); break; + } + + ntfs_fixups_writeback(fs, (NTFS_RECORD *)buf); + + mrec = (MFT_RECORD *)buf; + if (mrec->mft_record_no == file) { + *blk_offset = offset; /* update FS block offset */ + return mrec; /* found MFT record */ + } - mrec = (MFT_RECORD *)(data + offset); - if (mrec->mft_record_no == file) - return mrec; /* MFT record found! */ - - offset += mrec->bytes_allocated; - if (offset >= BLOCK_SIZE(fs)) { - ++*block; - offset -= BLOCK_SIZE(fs); -jump_in: - data = (uint8_t *)get_right_block(fs, *block); - if (!data) - break; + if (next_offset >= BLOCK_SIZE(fs)) { + /* try the next FS block */ + offset = 0; + *blk = right_blk - NTFS_SB(fs)->mft_blk + 1; + } else { + /* there's still content to fetch in the current block */ + *blk = right_blk - NTFS_SB(fs)->mft_blk; + offset = next_offset; /* update FS block offset */ } } + free(buf); + return NULL; } -static ATTR_RECORD *attr_lookup(uint32_t type, const MFT_RECORD *mrec) +static ATTR_RECORD *ntfs_attr_lookup(uint32_t type, const MFT_RECORD *mrec) { ATTR_RECORD *attr; @@ -168,7 +239,7 @@ static bool ntfs_filename_cmp(const char *dname, INDEX_ENTRY *ie) if (strlen(dname) != entry_fn_len) return false; - /* Do case-sensitive compares for Posix file names */ + /* Do case-sensitive compares for Posix file names */ if (ie->key.file_name.file_name_type == FILE_NAME_POSIX) { for (i = 0; i < entry_fn_len; i++) if (entry_fn[i] != dname[i]) @@ -273,8 +344,9 @@ static inline enum dirent_type get_inode_mode(MFT_RECORD *mrec) return mrec->flags & MFT_RECORD_IS_DIRECTORY ? DT_DIR : DT_REG; } -static int index_inode_setup(struct fs_info *fs, block_t start_block, - unsigned long mft_no, struct inode *inode) +static int index_inode_setup(struct fs_info *fs, block_t start_blk, + uint64_t blk_offset, unsigned long mft_no, + struct inode *inode) { MFT_RECORD *mrec; ATTR_RECORD *attr; @@ -288,22 +360,23 @@ static int index_inode_setup(struct fs_info *fs, block_t start_block, uint8_t *stream; uint32_t offset; - mrec = mft_record_lookup(mft_no, fs, &start_block); + mrec = ntfs_mft_record_lookup(mft_no, fs, &start_blk, &blk_offset); if (!mrec) { printf("No MFT record found.\n"); goto out; } NTFS_PVT(inode)->mft_no = mft_no; + NTFS_PVT(inode)->mft_blk_offset = blk_offset; NTFS_PVT(inode)->seq_no = mrec->seq_no; - NTFS_PVT(inode)->start_cluster = start_block >> NTFS_SB(fs)->clust_shift; - NTFS_PVT(inode)->here = start_block; + NTFS_PVT(inode)->start_cluster = start_blk >> NTFS_SB(fs)->clust_shift; + NTFS_PVT(inode)->here = start_blk; d_type = get_inode_mode(mrec); if (d_type == DT_DIR) { /* directory stuff */ dprintf("Got a directory.\n"); - attr = attr_lookup(NTFS_AT_INDEX_ROOT, mrec); + attr = ntfs_attr_lookup(NTFS_AT_INDEX_ROOT, mrec); if (!attr) { printf("No attribute found.\n"); goto out; @@ -320,12 +393,12 @@ static int index_inode_setup(struct fs_info *fs, block_t start_block, } NTFS_PVT(inode)->itype.index.collation_rule = ir->collation_rule; - NTFS_PVT(inode)->itype.index.block_size = ir->index_block_size; - NTFS_PVT(inode)->itype.index.block_size_shift = - ilog2(NTFS_PVT(inode)->itype.index.block_size); + NTFS_PVT(inode)->itype.index.blk_size = ir->index_block_size; + NTFS_PVT(inode)->itype.index.blk_size_shift = + ilog2(NTFS_PVT(inode)->itype.index.blk_size); /* determine the size of a vcn in the index */ - clust_size = NTFS_PVT(inode)->itype.index.block_size; + clust_size = NTFS_PVT(inode)->itype.index.blk_size; if (NTFS_SB(fs)->clust_size <= clust_size) { NTFS_PVT(inode)->itype.index.vcn_size = NTFS_SB(fs)->clust_size; NTFS_PVT(inode)->itype.index.vcn_size_shift = @@ -338,7 +411,7 @@ static int index_inode_setup(struct fs_info *fs, block_t start_block, NTFS_PVT(inode)->in_idx_root = true; } else if (d_type == DT_REG) { /* file stuff */ dprintf("Got a file.\n"); - attr = attr_lookup(NTFS_AT_DATA, mrec); + attr = ntfs_attr_lookup(NTFS_AT_DATA, mrec); if (!attr) { printf("No attribute found.\n"); goto out; @@ -387,17 +460,20 @@ out: return -1; } -static struct inode *index_lookup(const char *dname, struct inode *dir) +static struct inode *ntfs_index_lookup(const char *dname, struct inode *dir) { struct fs_info *fs = dir->fs; MFT_RECORD *mrec; - block_t block; + block_t blk; + uint64_t blk_offset; ATTR_RECORD *attr; INDEX_ROOT *ir; uint32_t len; INDEX_ENTRY *ie; - uint8_t *data; - INDEX_BLOCK *iblock; + const uint32_t clust_byte_shift = NTFS_SB(fs)->clust_byte_shift; + const uint64_t blk_size = UINT64_C(1) << BLOCK_SHIFT(fs); + uint8_t buf[blk_size]; + INDEX_BLOCK *iblk; int err; uint8_t *stream; uint8_t *attr_len; @@ -407,15 +483,18 @@ static struct inode *index_lookup(const char *dname, struct inode *dir) int64_t lcn; struct inode *inode; - block = NTFS_PVT(dir)->start; - dprintf("index_lookup() - mft record number: %d\n", NTFS_PVT(dir)->mft_no); - mrec = mft_record_lookup(NTFS_PVT(dir)->mft_no, fs, &block); + blk = NTFS_PVT(dir)->start; + blk_offset = NTFS_PVT(dir)->mft_blk_offset; + dprintf("ntfs_index_lookup() - mft record number: %d\n", + NTFS_PVT(dir)->mft_no); + mrec = ntfs_mft_record_lookup(NTFS_PVT(dir)->mft_no, fs, &blk, + &blk_offset); if (!mrec) { printf("No MFT record found.\n"); goto out; } - attr = attr_lookup(NTFS_AT_INDEX_ROOT, mrec); + attr = ntfs_attr_lookup(NTFS_AT_INDEX_ROOT, mrec); if (!attr) { printf("No attribute found.\n"); goto out; @@ -458,7 +537,7 @@ static struct inode *index_lookup(const char *dname, struct inode *dir) /* then descend into child node */ - attr = attr_lookup(NTFS_AT_INDEX_ALLOCATION, mrec); + attr = ntfs_attr_lookup(NTFS_AT_INDEX_ALLOCATION, mrec); if (!attr) { printf("No attribute found.\n"); goto out; @@ -480,39 +559,40 @@ static struct inode *index_lookup(const char *dname, struct inode *dir) continue; if (chunk.flags & MAP_ALLOCATED) { - dprintf("%d cluster(s) starting at 0x%X\n", chunk.len, chunk.lcn); + printf("%d cluster(s) starting at %llu\n", chunk.len, chunk.lcn); vcn = 0; lcn = chunk.lcn; while (vcn < chunk.len) { - block = ((lcn + vcn) << NTFS_SB(fs)->clust_shift) << - SECTOR_SHIFT(fs) >> BLOCK_SHIFT(fs); + lcn += vcn; + blk = lcn << NTFS_SB(fs)->clust_shift << SECTOR_SHIFT(fs) >> + BLOCK_SHIFT(fs); - data = (uint8_t *)get_cache(fs->fs_dev, block); - if (!data) { - printf("get_cache() returned NULL.\n"); + blk_offset = 0; + err = ntfs_read(fs, &buf, blk_size, blk_size, &blk, + &blk_offset, NULL, (uint64_t *)&lcn); + if (err) { + printf("Error on reading from cache.\n"); goto not_found; } - err = fixups_writeback(fs, (NTFS_RECORD *)data); - if (err) - goto not_found; + ntfs_fixups_writeback(fs, (NTFS_RECORD *)&buf); - iblock = (INDEX_BLOCK *)&data[0]; - if (iblock->magic != NTFS_MAGIC_INDX) { + iblk = (INDEX_BLOCK *)&buf; + if (iblk->magic != NTFS_MAGIC_INDX) { printf("Not a valid INDX record.\n"); goto not_found; } - ie = (INDEX_ENTRY *)((uint8_t *)&iblock->index + - iblock->index.entries_offset); + ie = (INDEX_ENTRY *)((uint8_t *)&iblk->index + + iblk->index.entries_offset); for (;; ie = (INDEX_ENTRY *)((uint8_t *)ie + ie->len)) { /* bounds checks */ - if ((uint8_t *)ie < (uint8_t *)iblock || (uint8_t *)ie + + if ((uint8_t *)ie < (uint8_t *)iblk || (uint8_t *)ie + sizeof(INDEX_ENTRY_HEADER) > - (uint8_t *)&iblock->index + iblock->index.index_len || + (uint8_t *)&iblk->index + iblk->index.index_len || (uint8_t *)ie + ie->len > - (uint8_t *)&iblock->index + iblock->index.index_len) + (uint8_t *)&iblk->index + iblk->index.index_len) goto index_err; /* last entry cannot contain a key */ @@ -523,7 +603,8 @@ static struct inode *index_lookup(const char *dname, struct inode *dir) goto found; } - vcn++; /* go to the next VCN */ + /* go to the next VCN */ + vcn += (blk_size / (1 << clust_byte_shift)); } } } while (!(chunk.flags & MAP_END)); @@ -539,14 +620,16 @@ out: found: dprintf("Index found\n"); inode = new_ntfs_inode(fs); - err = index_inode_setup(fs, NTFS_PVT(dir)->here, ie->data.dir.indexed_file, - inode); + err = index_inode_setup(fs, NTFS_PVT(dir)->here, + NTFS_PVT(dir)->mft_blk_offset, + ie->data.dir.indexed_file, inode); if (err) { + printf("leaving index_inode_setup()\n"); free(inode); goto out; } - dprintf("%s found!\n", dname); + printf("%s found!\n", dname); return inode; @@ -589,7 +672,7 @@ static int ntfs_next_extent(struct inode *inode, uint32_t lstart) goto out; /* Requested cluster beyond end of file */ if (!NTFS_PVT(inode)->non_resident) { - pstart = sbi->mft_block + NTFS_PVT(inode)->here; + pstart = sbi->mft_blk + NTFS_PVT(inode)->here; pstart <<= BLOCK_SHIFT(fs) >> sec_shift; } else { pstart = NTFS_PVT(inode)->data.non_resident.lcn << sbi->clust_shift; @@ -611,7 +694,8 @@ static uint32_t ntfs_getfssec(struct file *file, char *buf, int sectors, uint32_t ret; struct fs_info *fs = file->fs; struct inode *inode = file->inode; - block_t block; + block_t blk; + uint64_t blk_offset; MFT_RECORD *mrec; ATTR_RECORD *attr; char *p; @@ -623,14 +707,16 @@ static uint32_t ntfs_getfssec(struct file *file, char *buf, int sectors, return ret; if (!non_resident) { - block = NTFS_PVT(inode)->here; - mrec = mft_record_lookup(NTFS_PVT(inode)->mft_no, fs, &block); + blk = NTFS_PVT(inode)->here; + blk_offset = NTFS_PVT(inode)->mft_blk_offset; + mrec = ntfs_mft_record_lookup(NTFS_PVT(inode)->mft_no, fs, &blk, + &blk_offset); if (!mrec) { printf("No MFT record found.\n"); goto out; } - attr = attr_lookup(NTFS_AT_DATA, mrec); + attr = ntfs_attr_lookup(NTFS_AT_DATA, mrec); if (!attr) { printf("No attribute found.\n"); goto out; @@ -655,31 +741,36 @@ static int ntfs_readdir(struct file *file, struct dirent *dirent) struct fs_info *fs = file->fs; struct inode *inode = file->inode; MFT_RECORD *mrec; - block_t block; + block_t blk; + uint64_t blk_offset; + const uint64_t blk_size = UINT64_C(1) << BLOCK_SHIFT(fs); ATTR_RECORD *attr; INDEX_ROOT *ir; uint32_t count; int len; INDEX_ENTRY *ie = NULL; - uint8_t *data; - INDEX_BLOCK *iblock; + uint8_t buf[BLOCK_SIZE(fs)]; + INDEX_BLOCK *iblk; int err; uint8_t *stream; uint8_t *attr_len; struct mapping_chunk chunk; uint32_t offset; + const uint32_t clust_byte_shift = NTFS_SB(fs)->clust_byte_shift; int64_t vcn; int64_t lcn; char filename[NTFS_MAX_FILE_NAME_LEN + 1]; - block = NTFS_PVT(inode)->here; - mrec = mft_record_lookup(NTFS_PVT(inode)->mft_no, fs, &block); + blk = NTFS_PVT(inode)->here; + blk_offset = NTFS_PVT(inode)->mft_blk_offset; + mrec = ntfs_mft_record_lookup(NTFS_PVT(inode)->mft_no, fs, &blk, + &blk_offset); if (!mrec) { printf("No MFT record found.\n"); goto out; } - attr = attr_lookup(NTFS_AT_INDEX_ROOT, mrec); + attr = ntfs_attr_lookup(NTFS_AT_INDEX_ROOT, mrec); if (!attr) { printf("No attribute found.\n"); goto out; @@ -702,7 +793,7 @@ static int ntfs_readdir(struct file *file, struct dirent *dirent) if (ie->flags & INDEX_ENTRY_END) { file->offset = 0; NTFS_PVT(inode)->in_idx_root = false; - NTFS_PVT(inode)->idx_blocks_count = 1; + NTFS_PVT(inode)->idx_blks_count = 1; NTFS_PVT(inode)->entries_count = 0; NTFS_PVT(inode)->last_vcn = 0; goto descend_into_child_node; @@ -716,7 +807,7 @@ descend_into_child_node: if (!(ie->flags & INDEX_ENTRY_NODE)) goto out; - attr = attr_lookup(NTFS_AT_INDEX_ALLOCATION, mrec); + attr = ntfs_attr_lookup(NTFS_AT_INDEX_ALLOCATION, mrec); if (!attr) goto out; @@ -729,7 +820,7 @@ descend_into_child_node: next_run: stream = mapping_chunk_init(attr, &chunk, &offset); - count = NTFS_PVT(inode)->idx_blocks_count; + count = NTFS_PVT(inode)->idx_blks_count; while (count--) { err = parse_data_run(stream, &offset, attr_len, &chunk); if (err) { @@ -744,7 +835,7 @@ next_run: } if (chunk.flags & MAP_UNALLOCATED) { - NTFS_PVT(inode)->idx_blocks_count++; + NTFS_PVT(inode)->idx_blks_count++; goto next_run; } @@ -752,45 +843,45 @@ next_vcn: vcn = NTFS_PVT(inode)->last_vcn; if (vcn >= chunk.len) { NTFS_PVT(inode)->last_vcn = 0; - NTFS_PVT(inode)->idx_blocks_count++; + NTFS_PVT(inode)->idx_blks_count++; goto next_run; } - lcn = chunk.lcn; - block = ((lcn + vcn) << NTFS_SB(fs)->clust_shift) << SECTOR_SHIFT(fs) >> + lcn = chunk.lcn + vcn; + blk = lcn << NTFS_SB(fs)->clust_shift << SECTOR_SHIFT(fs) >> BLOCK_SHIFT(fs); - data = (uint8_t *)get_cache(fs->fs_dev, block); - if (!data) { - printf("get_cache() returned NULL.\n"); + blk_offset = 0; + err = ntfs_read(fs, &buf, blk_size, blk_size, &blk, &blk_offset, NULL, + (uint64_t *)&lcn); + if (err) { + printf("Error on reading from cache.\n"); goto not_found; } - err = fixups_writeback(fs, (NTFS_RECORD *)data); - if (err) - goto not_found; + ntfs_fixups_writeback(fs, (NTFS_RECORD *)&buf); - iblock = (INDEX_BLOCK *)data; - if (iblock->magic != NTFS_MAGIC_INDX) { + iblk = (INDEX_BLOCK *)&buf; + if (iblk->magic != NTFS_MAGIC_INDX) { printf("Not a valid INDX record.\n"); goto not_found; } - ie = (INDEX_ENTRY *)((uint8_t *)&iblock->index + - iblock->index.entries_offset); + ie = (INDEX_ENTRY *)((uint8_t *)&iblk->index + + iblk->index.entries_offset); count = NTFS_PVT(inode)->entries_count; for ( ; count--; ie = (INDEX_ENTRY *)((uint8_t *)ie + ie->len)) { /* bounds checks */ - if ((uint8_t *)ie < (uint8_t *)iblock || (uint8_t *)ie + + if ((uint8_t *)ie < (uint8_t *)iblk || (uint8_t *)ie + sizeof(INDEX_ENTRY_HEADER) > - (uint8_t *)&iblock->index + iblock->index.index_len || + (uint8_t *)&iblk->index + iblk->index.index_len || (uint8_t *)ie + ie->len > - (uint8_t *)&iblock->index + iblock->index.index_len) + (uint8_t *)&iblk->index + iblk->index.index_len) goto index_err; /* last entry cannot contain a key */ if (ie->flags & INDEX_ENTRY_END) { - NTFS_PVT(inode)->last_vcn++; + NTFS_PVT(inode)->last_vcn += (blk_size / (1 << clust_byte_shift)); NTFS_PVT(inode)->entries_count = 0; goto next_vcn; } @@ -811,12 +902,16 @@ done: len = ntfs_cvt_filename(filename, ie); dirent->d_reclen = offsetof(struct dirent, d_name) + len + 1; - if (NTFS_PVT(inode)->mft_no == FILE_root) - block = 0; - else - block = NTFS_SB(fs)->mft_block; + if (NTFS_PVT(inode)->mft_no == FILE_root) { + blk = 0; + blk_offset = 0; + } else { + blk = NTFS_SB(fs)->mft_blk; + blk_offset = NTFS_PVT(inode)->mft_blk_offset; + } - mrec = mft_record_lookup(ie->data.dir.indexed_file, fs, &block); + mrec = ntfs_mft_record_lookup(ie->data.dir.indexed_file, fs, &blk, + &blk_offset); if (!mrec) { printf("No MFT record found.\n"); goto out; @@ -838,7 +933,7 @@ index_err: static struct inode *ntfs_iget(const char *dname, struct inode *parent) { - return index_lookup(dname, parent); + return ntfs_index_lookup(dname, parent); } static struct inode *ntfs_iget_root(struct fs_info *fs) @@ -848,7 +943,7 @@ static struct inode *ntfs_iget_root(struct fs_info *fs) inode->fs = fs; - err = index_inode_setup(fs, 0, FILE_root, inode); + err = index_inode_setup(fs, 0, 0, FILE_root, inode); if (err) goto free_out; @@ -862,7 +957,7 @@ free_out: return NULL; } -/* Initialize the filesystem metadata and return block size in bits */ +/* Initialize the filesystem metadata and return blk size in bits */ static int ntfs_fs_init(struct fs_info *fs) { struct ntfs_bpb ntfs; @@ -878,23 +973,16 @@ static int ntfs_fs_init(struct fs_info *fs) SECTOR_SHIFT(fs) = disk->sector_shift; - BLOCK_SHIFT(fs) = ilog2(ntfs.sec_per_clust) + SECTOR_SHIFT(fs); - /* Note: ntfs.clust_per_mft_record can be a negative number. * If negative, it represents a shift count, else it represents * a multiplier for the cluster size. - * - * We need _at least_ 1 KiB to read the whole MFT record. */ mft_record_shift = ntfs.clust_per_mft_record < 0 ? -ntfs.clust_per_mft_record : - BLOCK_SHIFT(fs) + ilog2(ntfs.clust_per_mft_record); - - if (BLOCK_SHIFT(fs) < mft_record_shift) - BLOCK_SHIFT(fs) = mft_record_shift; + ilog2(ntfs.sec_per_clust) + SECTOR_SHIFT(fs) + + ilog2(ntfs.clust_per_mft_record); SECTOR_SIZE(fs) = 1 << SECTOR_SHIFT(fs); - BLOCK_SIZE(fs) = 1 << BLOCK_SHIFT(fs); sbi = malloc(sizeof *sbi); if (!sbi) @@ -908,7 +996,11 @@ static int ntfs_fs_init(struct fs_info *fs) sbi->clust_size = ntfs.sec_per_clust << SECTOR_SHIFT(fs); sbi->mft_record_size = 1 << mft_record_shift; - sbi->mft_block = ntfs.mft_lclust << sbi->clust_shift << + BLOCK_SHIFT(fs) = ilog2(ntfs.clust_per_idx_buf) + sbi->clust_byte_shift; + BLOCK_SIZE(fs) = 1 << BLOCK_SHIFT(fs); + + sbi->mft_lcn = ntfs.mft_lclust; + sbi->mft_blk = 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 = mft_record_shift << sbi->clust_shift << 4; diff --git a/core/fs/ntfs/ntfs.h b/core/fs/ntfs/ntfs.h index 7356936..9e6da4d 100644 --- a/core/fs/ntfs/ntfs.h +++ b/core/fs/ntfs/ntfs.h @@ -14,7 +14,7 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the * Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111EXIT_FAILURE307, USA. + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _NTFS_H_ @@ -49,7 +49,8 @@ struct ntfs_bpb { } __attribute__((__packed__)); struct ntfs_sb_info { - block_t mft_block; /* The first MFT record block */ + block_t mft_blk; /* The first MFT record block */ + uint64_t mft_lcn; /* LCN of the first MFT record */ unsigned mft_size; /* The MFT size in sectors */ uint64_t mft_record_size; /* MFT record size in bytes */ @@ -67,12 +68,13 @@ struct ntfs_sb_info { struct ntfs_inode { int64_t initialized_size; int64_t allocated_size; - unsigned long mft_no; /* Number of the mft record / inode */ - uint16_t seq_no; /* Sequence number of the mft record */ - uint32_t type; /* Attribute type of this inode */ + unsigned long mft_no; /* Number of the mft record / inode */ + uint64_t mft_blk_offset; /* MFT record's offset of the FS block */ + uint16_t seq_no; /* Sequence number of the mft record */ + uint32_t type; /* Attribute type of this inode */ uint8_t non_resident; bool in_idx_root; - uint32_t idx_blocks_count; + uint32_t idx_blks_count; uint32_t entries_count; int64_t last_vcn; union { /* Non-resident $DATA attribute */ @@ -86,11 +88,11 @@ struct ntfs_inode { } data; union { struct { /* It is a directory, $MFT, or an index inode */ - uint32_t block_size; + uint32_t blk_size; uint32_t vcn_size; uint32_t collation_rule; - uint8_t block_size_shift; /* log2 of the above */ - uint8_t vcn_size_shift; /* log2 of the above */ + uint8_t blk_size_shift; /* log2 of the above */ + uint8_t vcn_size_shift; /* log2 of the above */ } index; } itype; uint32_t start_cluster; /* Starting cluster address */ -- 2.7.4