#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)
{
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)
{
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;
len = fn->file_name_len;
match = fn->file_name;
- dprintf("Matching: %s\n", str);
+ printf("Matching: %s\n", str);
while (len) {
cp = *match++;
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;
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;
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;
mrec = mft_record_lookup(mft_no, fs, &block);
if (!mrec) {
- dprintf("No MFT record found!\n");
+ printf("No MFT record found!\n");
goto out;
}
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;
}
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;
}
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;
}
{
struct fs_info *fs = dir->fs;
MFT_RECORD *mrec;
- sector_t block;
+ block_t block;
ATTR_RECORD *attr;
INDEX_ROOT *ir;
uint32_t len;
uint8_t vcn_count;
INDEX_BLOCK *iblock;
int64_t vcn;
- unsigned block_count;
uint8_t *stream;
uint32_t offset;
uint8_t *attr_len;
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;
}
/* 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;
}
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;
}
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)) {
(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;
}
}
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) {
return inode;
index_err:
- dprintf("Corrupt index. Aborting lookup...\n");
+ printf("Corrupt index. Aborting lookup...\n");
goto out;
}
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;
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;
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;
}
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;
}
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;
}
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);
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)
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;