176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Copyright (C) 2011-2012 Paulo Alcantara <pcacjr@gmail.com> 376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * This program is free software; you can redistribute it and/or modify 576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * it under the terms of the GNU General Public License as published by 676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * the Free Software Foundation; either version 2 of the License, or 776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * (at your option) any later version. 876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * This program is distributed in the hope that it will be useful, 1076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * but WITHOUT ANY WARRANTY; without even the implied warranty of 1176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * GNU General Public License for more details. 1376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 1476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * You should have received a copy of the GNU General Public License 1576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * along with this program; if not, write to the 1676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Free Software Foundation, Inc., 1776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 1876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman*/ 1976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 2076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Note: No support for compressed files */ 2176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 2276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <dprintf.h> 2376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <stdio.h> 2476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <string.h> 2576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <sys/dirent.h> 2676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <cache.h> 2776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <core.h> 2876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <disk.h> 2976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <fs.h> 3076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <ilog2.h> 3176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <klibc/compiler.h> 3276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <ctype.h> 3376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 3476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "codepage.h" 3576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "ntfs.h" 3676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "runlist.h" 3776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 3876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic struct ntfs_readdir_state *readdir_state; 3976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 4076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/*** Function declarations */ 4176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic f_mft_record_lookup ntfs_mft_record_lookup_3_0; 4276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic f_mft_record_lookup ntfs_mft_record_lookup_3_1; 4376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic inline enum dirent_type get_inode_mode(struct ntfs_mft_record *mrec); 4476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic inline struct ntfs_attr_record * ntfs_attr_lookup(struct fs_info *fs, uint32_t type, struct ntfs_mft_record **mmrec, struct ntfs_mft_record *mrec); 4576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic inline uint8_t *mapping_chunk_init(struct ntfs_attr_record *attr,struct mapping_chunk *chunk,uint32_t *offset); 4676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int parse_data_run(const void *stream, uint32_t *offset, uint8_t *attr_len, struct mapping_chunk *chunk); 4776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 4876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/*** Function definitions */ 4976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 5076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Check if there are specific zero fields in an NTFS boot sector */ 5176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic inline int ntfs_check_zero_fields(const struct ntfs_bpb *sb) 5276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 5376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return !sb->res_sectors && (!sb->zero_0[0] && !sb->zero_0[1] && 5476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman !sb->zero_0[2]) && !sb->zero_1 && !sb->zero_2 && 5576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman !sb->zero_3; 5676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 5776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 5876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic inline int ntfs_check_sb_fields(const struct ntfs_bpb *sb) 5976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 6076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return ntfs_check_zero_fields(sb) && 6176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman (!memcmp(sb->oem_name, "NTFS ", 8) || 6276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman !memcmp(sb->oem_name, "MSWIN4.0", 8) || 6376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman !memcmp(sb->oem_name, "MSWIN4.1", 8)); 6476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 6576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 6676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic inline struct inode *new_ntfs_inode(struct fs_info *fs) 6776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 6876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct inode *inode; 6976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 7076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman inode = alloc_inode(fs, 0, sizeof(struct ntfs_inode)); 7176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!inode) 7276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman malloc_error("inode structure"); 7376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 7476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return inode; 7576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 7676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 7776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void ntfs_fixups_writeback(struct fs_info *fs, struct ntfs_record *nrec) 7876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 7976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint16_t *usa; 8076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint16_t usa_no; 8176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint16_t usa_count; 8276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint16_t *blk; 8376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 8476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman dprintf("in %s()\n", __func__); 8576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 8676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (nrec->magic != NTFS_MAGIC_FILE && nrec->magic != NTFS_MAGIC_INDX) 8776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return; 8876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 8976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* get the Update Sequence Array offset */ 9076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman usa = (uint16_t *)((uint8_t *)nrec + nrec->usa_ofs); 9176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* get the Update Sequence Array Number and skip it */ 9276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman usa_no = *usa++; 9376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* get the Update Sequene Array count */ 9476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman usa_count = nrec->usa_count - 1; /* exclude the USA number */ 9576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* make it to point to the last two bytes of the RECORD's first sector */ 9676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman blk = (uint16_t *)((uint8_t *)nrec + SECTOR_SIZE(fs) - 2); 9776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 9876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman while (usa_count--) { 9976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (*blk != usa_no) 10076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 10176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 10276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *blk = *usa++; 10376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman blk = (uint16_t *)((uint8_t *)blk + SECTOR_SIZE(fs)); 10476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 10576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 10676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 10776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* read content from cache */ 10876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int ntfs_read(struct fs_info *fs, void *buf, size_t len, uint64_t count, 10976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman block_t *blk, uint64_t *blk_offset, 11076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint64_t *blk_next_offset, uint64_t *lcn) 11176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 11276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint8_t *data; 11376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint64_t offset = *blk_offset; 11476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman const uint32_t clust_byte_shift = NTFS_SB(fs)->clust_byte_shift; 11576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman const uint64_t blk_size = UINT64_C(1) << BLOCK_SHIFT(fs); 11676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint64_t bytes; 11776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint64_t lbytes; 11876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint64_t loffset; 11976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint64_t k; 12076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 12176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman dprintf("in %s()\n", __func__); 12276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 12376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (count > len) 12476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto out; 12576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 12676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman data = (uint8_t *)get_cache(fs->fs_dev, *blk); 12776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!data) 12876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto out; 12976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 13076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!offset) 13176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman offset = (*lcn << clust_byte_shift) % blk_size; 13276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 13376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman dprintf("LCN: 0x%X\n", *lcn); 13476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman dprintf("offset: 0x%X\n", offset); 13576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 13676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman bytes = count; /* bytes to copy */ 13776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman lbytes = blk_size - offset; /* bytes left to copy */ 13876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (lbytes >= bytes) { 13976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* so there's room enough, then copy the whole content */ 14076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman memcpy(buf, data + offset, bytes); 14176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman loffset = offset; 14276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman offset += count; 14376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else { 14476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman dprintf("bytes: %u\n", bytes); 14576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman dprintf("bytes left: %u\n", lbytes); 14676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* otherwise, let's copy it partially... */ 14776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman k = 0; 14876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman while (bytes) { 14976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman memcpy(buf + k, data + offset, lbytes); 15076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman bytes -= lbytes; 15176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman loffset = offset; 15276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman offset += lbytes; 15376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman k += lbytes; 15476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (offset >= blk_size) { 15576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* then fetch a new FS block */ 15676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman data = (uint8_t *)get_cache(fs->fs_dev, ++*blk); 15776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!data) 15876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto out; 15976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 16076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman lbytes = bytes; 16176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman loffset = offset; 16276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman offset = 0; 16376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 16476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 16576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 16676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 16776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (loffset >= blk_size) 16876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman loffset = 0; /* it must be aligned on a block boundary */ 16976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 17076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *blk_offset = loffset; 17176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 17276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (blk_next_offset) 17376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *blk_next_offset = offset; 17476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 17576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *lcn += blk_size / count; /* update LCN */ 17676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 17776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 0; 17876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 17976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanout: 18076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return -1; 18176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 18276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 18376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* AndyAlex: read and validate single MFT record. Keep in mind that MFT itself can be fragmented */ 18476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic struct ntfs_mft_record *ntfs_mft_record_lookup_any(struct fs_info *fs, 18576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint32_t file, block_t *out_blk, bool is_v31) 18676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 18776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman const uint64_t mft_record_size = NTFS_SB(fs)->mft_record_size; 18876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint8_t *buf = NULL; 18976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman const uint32_t mft_record_shift = ilog2(mft_record_size); 19076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman const uint32_t clust_byte_shift = NTFS_SB(fs)->clust_byte_shift; 19176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint64_t next_offset = 0; 19276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint64_t lcn = 0; 19376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman block_t blk = 0; 19476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint64_t offset = 0; 19576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 19676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ntfs_mft_record *mrec = NULL, *lmrec = NULL; 19776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint64_t start_blk = 0; 19876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ntfs_attr_record *attr = NULL; 19976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint8_t *stream = NULL; 20076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint32_t attr_offset = 0; 20176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint8_t *attr_len = NULL; 20276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct mapping_chunk chunk; 20376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 20476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int err = 0; 20576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 20676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* determine MFT record's LCN */ 20776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint64_t vcn = (file << mft_record_shift >> clust_byte_shift); 20876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman dprintf("in %s(%s)\n", __func__,(is_v31?"v3.1":"v3.0")); 20976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (0==vcn) { 21076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman lcn = NTFS_SB(fs)->mft_lcn; 21176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else do { 21276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman dprintf("%s: looking for VCN %u for MFT record %u\n", __func__,(unsigned)vcn,(unsigned)file); 21376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mrec = NTFS_SB(fs)->mft_record_lookup(fs, 0, &start_blk); 21476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!mrec) {dprintf("%s: read MFT(0) failed\n", __func__); break;} 21576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman lmrec = mrec; 21676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (get_inode_mode(mrec) != DT_REG) {dprintf("%s: $MFT is not a file\n", __func__); break;} 21776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman attr = ntfs_attr_lookup(fs, NTFS_AT_DATA, &mrec, lmrec); 21876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!attr) {dprintf("%s: $MFT have no data attr\n", __func__); break;} 21976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!attr->non_resident) {dprintf("%s: $MFT data attr is resident\n", __func__); break;} 22076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman attr_len = (uint8_t *)attr + attr->len; 22176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman stream = mapping_chunk_init(attr, &chunk, &attr_offset); 22276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman while (true) { 22376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman err = parse_data_run(stream, &attr_offset, attr_len, &chunk); 22476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (err) {dprintf("%s: $MFT data run parse failed with error %d\n", __func__,err); break;} 22576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (chunk.flags & MAP_UNALLOCATED) continue; 22676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (chunk.flags & MAP_END) break; 22776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (chunk.flags & MAP_ALLOCATED) { 22876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman dprintf("%s: Chunk: VCN=%u, LCN=%u, len=%u\n", __func__,(unsigned)chunk.vcn,(unsigned)chunk.lcn,(unsigned)chunk.len); 22976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ((vcn>=chunk.vcn)&&(vcn<chunk.vcn+chunk.len)) { 23076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman lcn=vcn-chunk.vcn+chunk.lcn; 23176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman dprintf("%s: VCN %u for MFT record %u maps to lcn %u\n", __func__,(unsigned)vcn,(unsigned)file,(unsigned)lcn); 23276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 23376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 23476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman chunk.vcn += chunk.len; 23576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 23676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 23776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } while(false); 23876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (mrec!=NULL) free(mrec); 23976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mrec = NULL; 24076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (0==lcn) { 24176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman dprintf("%s: unable to map VCN %u for MFT record %u\n", __func__,(unsigned)vcn,(unsigned)file); 24276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return NULL; 24376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 24476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 24576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* determine MFT record's block number */ 24676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman blk = (lcn << clust_byte_shift >> BLOCK_SHIFT(fs)); 24776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman offset = (file << mft_record_shift) % BLOCK_SIZE(fs); 24876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 24976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Allocate buffer */ 25076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman buf = (uint8_t *)malloc(mft_record_size); 25176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!buf) {malloc_error("uint8_t *");return 0;} 25276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 25376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Read block */ 25476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman err = ntfs_read(fs, buf, mft_record_size, mft_record_size, &blk, 25576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman &offset, &next_offset, &lcn); 25676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (err) { 25776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman dprintf("%s: error read block %u from cache\n", __func__, blk); 25876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman printf("Error while reading from cache.\n"); 25976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman free(buf); 26076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return NULL; 26176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 26276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 26376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Process fixups and make structure pointer */ 26476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ntfs_fixups_writeback(fs, (struct ntfs_record *)buf); 26576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mrec = (struct ntfs_mft_record *)buf; 26676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 26776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* check if it has a valid magic number and record number */ 26876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (mrec->magic != NTFS_MAGIC_FILE) mrec = NULL; 26976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (mrec && is_v31) if (mrec->mft_record_no != file) mrec = NULL; 27076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (mrec!=NULL) { 27176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (out_blk) { 27276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *out_blk = (file << mft_record_shift >> BLOCK_SHIFT(fs)); /* update record starting block */ 27376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 27476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return mrec; /* found MFT record */ 27576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 27676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 27776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Invalid record */ 27876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman dprintf("%s: MFT record %u is invalid\n", __func__, (unsigned)file); 27976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman free(buf); 28076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return NULL; 28176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 28276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 28376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic struct ntfs_mft_record *ntfs_mft_record_lookup_3_0(struct fs_info *fs, 28476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint32_t file, block_t *blk) 28576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 28676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return ntfs_mft_record_lookup_any(fs,file,blk,false); 28776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 28876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 28976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic struct ntfs_mft_record *ntfs_mft_record_lookup_3_1(struct fs_info *fs, 29076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint32_t file, block_t *blk) 29176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 29276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return ntfs_mft_record_lookup_any(fs,file,blk,true); 29376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 29476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 29576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic bool ntfs_filename_cmp(const char *dname, struct ntfs_idx_entry *ie) 29676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 29776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman const uint16_t *entry_fn; 29876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint8_t entry_fn_len; 29976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman unsigned i; 30076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 30176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman dprintf("in %s()\n", __func__); 30276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 30376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman entry_fn = ie->key.file_name.file_name; 30476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman entry_fn_len = ie->key.file_name.file_name_len; 30576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 30676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (strlen(dname) != entry_fn_len) 30776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return false; 30876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 30976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Do case-sensitive compares for Posix file names */ 31076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (ie->key.file_name.file_name_type == FILE_NAME_POSIX) { 31176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman for (i = 0; i < entry_fn_len; i++) 31276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (entry_fn[i] != dname[i]) 31376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return false; 31476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else { 31576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman for (i = 0; i < entry_fn_len; i++) 31676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (tolower(entry_fn[i]) != tolower(dname[i])) 31776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return false; 31876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 31976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 32076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return true; 32176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 32276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 32376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic inline uint8_t *mapping_chunk_init(struct ntfs_attr_record *attr, 32476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct mapping_chunk *chunk, 32576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint32_t *offset) 32676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 32776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman memset(chunk, 0, sizeof *chunk); 32876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *offset = 0U; 32976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 33076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return (uint8_t *)attr + attr->data.non_resident.mapping_pairs_offset; 33176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 33276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 33376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Parse data runs. 33476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 33576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * return 0 on success or -1 on failure. 33676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 33776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int parse_data_run(const void *stream, uint32_t *offset, 33876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint8_t *attr_len, struct mapping_chunk *chunk) 33976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 34076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint8_t *buf; /* Pointer to the zero-terminated byte stream */ 34176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint8_t count; /* The count byte */ 34276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint8_t v, l; /* v is the number of changed low-order VCN bytes; 34376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * l is the number of changed low-order LCN bytes 34476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 34576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint8_t *byte; 34676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman const int byte_shift = 8; 34776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int mask; 34876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int64_t res; 34976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 35076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman (void)attr_len; 35176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 35276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman dprintf("in %s()\n", __func__); 35376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 35476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman chunk->flags &= ~MAP_MASK; 35576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 35676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman buf = (uint8_t *)stream + *offset; 35776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (buf > attr_len || !*buf) { 35876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman chunk->flags |= MAP_END; /* we're done */ 35976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 0; 36076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 36176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 36276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!*offset) 36376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman chunk->flags |= MAP_START; /* initial chunk */ 36476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 36576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman count = *buf; 36676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman v = count & 0x0F; 36776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman l = count >> 4; 36876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 36976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (v > 8 || l > 8) /* more than 8 bytes ? */ 37076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto out; 37176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 37276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman byte = (uint8_t *)buf + v; 37376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman count = v; 37476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 37576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman res = 0LL; 37676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman while (count--) 37776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman res = (res << byte_shift) | *byte--; 37876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 37976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman chunk->len = res; /* get length data */ 38076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 38176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman byte = (uint8_t *)buf + v + l; 38276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman count = l; 38376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 38476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mask = 0xFFFFFFFF; 38576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman res = 0LL; 38676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (*byte & 0x80) 38776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman res |= (int64_t)mask; /* sign-extend it */ 38876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 38976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman while (count--) 39076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman res = (res << byte_shift) | *byte--; 39176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 39276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman chunk->lcn += res; 39376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* are VCNS from cur_vcn to next_vcn - 1 unallocated ? */ 39476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!chunk->lcn) 39576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman chunk->flags |= MAP_UNALLOCATED; 39676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman else 39776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman chunk->flags |= MAP_ALLOCATED; 39876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 39976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *offset += v + l + 1; 40076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 40176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 0; 40276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 40376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanout: 40476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return -1; 40576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 40676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 40776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic struct ntfs_mft_record * 40876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanntfs_attr_list_lookup(struct fs_info *fs, struct ntfs_attr_record *attr, 40976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint32_t type, struct ntfs_mft_record *mrec) 41076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 41176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint8_t *attr_len; 41276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct mapping_chunk chunk; 41376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint32_t offset; 41476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint8_t *stream; 41576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int err; 41676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman const uint64_t blk_size = UINT64_C(1) << BLOCK_SHIFT(fs); 41776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint8_t buf[blk_size]; 41876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint64_t blk_offset; 41976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int64_t vcn; 42076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int64_t lcn; 42176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int64_t last_lcn; 42276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman block_t blk; 42376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ntfs_attr_list_entry *attr_entry; 42476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint32_t len = 0; 42576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ntfs_mft_record *retval; 42676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint64_t start_blk = 0; 42776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 42876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman dprintf("in %s()\n", __func__); 42976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 43076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (attr->non_resident) 43176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto handle_non_resident_attr; 43276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 43376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman attr_entry = (struct ntfs_attr_list_entry *) 43476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ((uint8_t *)attr + attr->data.resident.value_offset); 43576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman len = attr->data.resident.value_len; 43676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman for (; (uint8_t *)attr_entry < (uint8_t *)attr + len; 43776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman attr_entry = (struct ntfs_attr_list_entry *)((uint8_t *)attr_entry + 43876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman attr_entry->length)) { 43976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman dprintf("<$ATTRIBUTE_LIST> Attribute type: 0x%X\n", 44076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman attr_entry->type); 44176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (attr_entry->type == type) 44276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto found; /* We got the attribute! :-) */ 44376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 44476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 44576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman printf("No attribute found.\n"); 44676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto out; 44776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 44876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanhandle_non_resident_attr: 44976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman attr_len = (uint8_t *)attr + attr->len; 45076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman stream = mapping_chunk_init(attr, &chunk, &offset); 45176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman do { 45276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman err = parse_data_run(stream, &offset, attr_len, &chunk); 45376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (err) { 45476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman printf("parse_data_run()\n"); 45576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto out; 45676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 45776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 45876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (chunk.flags & MAP_UNALLOCATED) 45976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman continue; 46076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (chunk.flags & MAP_END) 46176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 46276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (chunk.flags & MAP_ALLOCATED) { 46376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman vcn = 0; 46476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman lcn = chunk.lcn; 46576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman while (vcn < chunk.len) { 46676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman blk = (lcn + vcn) << NTFS_SB(fs)->clust_byte_shift >> 46776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman BLOCK_SHIFT(fs); 46876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman blk_offset = 0; 46976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman last_lcn = lcn; 47076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman lcn += vcn; 47176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman err = ntfs_read(fs, buf, blk_size, blk_size, &blk, 47276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman &blk_offset, NULL, (uint64_t *)&lcn); 47376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (err) { 47476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman printf("Error while reading from cache.\n"); 47576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto out; 47676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 47776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 47876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman attr_entry = (struct ntfs_attr_list_entry *)&buf; 47976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman len = attr->data.non_resident.data_size; 48076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman for (; (uint8_t *)attr_entry < (uint8_t *)&buf[0] + len; 48176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman attr_entry = (struct ntfs_attr_list_entry *) 48276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ((uint8_t *)attr_entry + attr_entry->length)) { 48376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman dprintf("<$ATTRIBUTE_LIST> Attribute type: 0x%x\n", 48476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman attr_entry->type); 48576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (attr_entry->type == type) 48676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto found; /* We got the attribute! :-) */ 48776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 48876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 48976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman lcn = last_lcn; /* restore original LCN */ 49076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* go to the next VCN */ 49176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman vcn += (blk_size / (1 << NTFS_SB(fs)->clust_byte_shift)); 49276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 49376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 49476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } while (!(chunk.flags & MAP_END)); 49576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 49676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman printf("No attribute found.\n"); 49776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 49876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanout: 49976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return NULL; 50076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 50176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanfound: 50276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* At this point we have the attribute we were looking for. Now we 50376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * will look for the MFT record that stores information about this 50476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * attribute. 50576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 50676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 50776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Check if the attribute type we're looking for is in the same 50876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * MFT record. If so, we do not need to look it up again - return it. 50976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 51076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (mrec->mft_record_no == attr_entry->mft_ref) 51176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return mrec; 51276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 51376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman retval = NTFS_SB(fs)->mft_record_lookup(fs, attr_entry->mft_ref, 51476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman &start_blk); 51576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!retval) { 51676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman printf("No MFT record found!\n"); 51776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto out; 51876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 51976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 52076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* return the found MFT record */ 52176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return retval; 52276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 52376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 52476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic struct ntfs_attr_record * 52576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman__ntfs_attr_lookup(struct fs_info *fs, uint32_t type, 52676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ntfs_mft_record **mrec) 52776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 52876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ntfs_mft_record *_mrec = *mrec; 52976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ntfs_attr_record *attr; 53076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ntfs_attr_record *attr_list_attr; 53176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 53276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman dprintf("in %s()\n", __func__); 53376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 53476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!_mrec || type == NTFS_AT_END) 53576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto out; 53676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 53776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanagain: 53876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman attr_list_attr = NULL; 53976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 54076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman attr = (struct ntfs_attr_record *)((uint8_t *)_mrec + _mrec->attrs_offset); 54176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* walk through the file attribute records */ 54276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman for (;; attr = (struct ntfs_attr_record *)((uint8_t *)attr + attr->len)) { 54376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (attr->type == NTFS_AT_END) 54476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 54576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 54676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (attr->type == NTFS_AT_ATTR_LIST) { 54776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman dprintf("MFT record #%lu has an $ATTRIBUTE_LIST attribute.\n", 54876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman _mrec->mft_record_no); 54976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman attr_list_attr = attr; 55076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman continue; 55176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 55276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 55376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (attr->type == type) 55476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 55576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 55676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 55776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* if the record has an $ATTRIBUTE_LIST attribute associated 55876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * with it, then we need to look for the wanted attribute in 55976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * it as well. 56076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 56176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (attr->type == NTFS_AT_END && attr_list_attr) { 56276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ntfs_mft_record *retval; 56376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 56476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman retval = ntfs_attr_list_lookup(fs, attr_list_attr, type, _mrec); 56576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!retval) 56676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto out; 56776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 56876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman _mrec = retval; 56976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto again; 57076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else if (attr->type == NTFS_AT_END && !attr_list_attr) { 57176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman attr = NULL; 57276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 57376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 57476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return attr; 57576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 57676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanout: 57776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return NULL; 57876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 57976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 58076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic inline struct ntfs_attr_record * 58176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanntfs_attr_lookup(struct fs_info *fs, uint32_t type, 58276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ntfs_mft_record **mmrec, 58376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ntfs_mft_record *mrec) 58476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 58576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ntfs_mft_record *_mrec = mrec; 58676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ntfs_mft_record *other = *mmrec; 58776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ntfs_attr_record *retval = NULL; 58876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 58976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (mrec == other) 59076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return __ntfs_attr_lookup(fs, type, &other); 59176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 59276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman retval = __ntfs_attr_lookup(fs, type, &_mrec); 59376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!retval) { 59476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman _mrec = other; 59576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman retval = __ntfs_attr_lookup(fs, type, &other); 59676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!retval) 59776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman other = _mrec; 59876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else if (retval && (_mrec != mrec)) { 59976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman other = _mrec; 60076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 60176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 60276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return retval; 60376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 60476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 60576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic inline enum dirent_type get_inode_mode(struct ntfs_mft_record *mrec) 60676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 60776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return mrec->flags & MFT_RECORD_IS_DIRECTORY ? DT_DIR : DT_REG; 60876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 60976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 61076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int index_inode_setup(struct fs_info *fs, unsigned long mft_no, 61176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct inode *inode) 61276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 61376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint64_t start_blk = 0; 61476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ntfs_mft_record *mrec, *lmrec; 61576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ntfs_attr_record *attr; 61676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman enum dirent_type d_type; 61776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint8_t *attr_len; 61876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct mapping_chunk chunk; 61976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int err; 62076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint8_t *stream; 62176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint32_t offset; 62276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 62376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman dprintf("in %s()\n", __func__); 62476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 62576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mrec = NTFS_SB(fs)->mft_record_lookup(fs, mft_no, &start_blk); 62676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!mrec) { 62776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman printf("No MFT record found.\n"); 62876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto out; 62976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 63076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 63176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman lmrec = mrec; 63276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 63376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman NTFS_PVT(inode)->mft_no = mft_no; 63476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman NTFS_PVT(inode)->seq_no = mrec->seq_no; 63576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 63676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman NTFS_PVT(inode)->start_cluster = start_blk >> NTFS_SB(fs)->clust_shift; 63776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman NTFS_PVT(inode)->here = start_blk; 63876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 63976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman d_type = get_inode_mode(mrec); 64076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (d_type == DT_DIR) { /* directory stuff */ 64176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman dprintf("Got a directory.\n"); 64276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman attr = ntfs_attr_lookup(fs, NTFS_AT_INDEX_ROOT, &mrec, lmrec); 64376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!attr) { 64476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman printf("No attribute found.\n"); 64576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto out; 64676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 64776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 64876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* check if we have a previous allocated state structure */ 64976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (readdir_state) { 65076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman free(readdir_state); 65176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman readdir_state = NULL; 65276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 65376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 65476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* allocate our state structure */ 65576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman readdir_state = malloc(sizeof *readdir_state); 65676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!readdir_state) 65776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman malloc_error("ntfs_readdir_state structure"); 65876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 65976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman readdir_state->mft_no = mft_no; 66076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* obviously, the ntfs_readdir() caller will start from INDEX root */ 66176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman readdir_state->in_idx_root = true; 66276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else if (d_type == DT_REG) { /* file stuff */ 66376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman dprintf("Got a file.\n"); 66476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman attr = ntfs_attr_lookup(fs, NTFS_AT_DATA, &mrec, lmrec); 66576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!attr) { 66676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman printf("No attribute found.\n"); 66776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto out; 66876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 66976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 67076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman NTFS_PVT(inode)->non_resident = attr->non_resident; 67176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman NTFS_PVT(inode)->type = attr->type; 67276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 67376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!attr->non_resident) { 67476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman NTFS_PVT(inode)->data.resident.offset = 67576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman (uint32_t)((uint8_t *)attr + attr->data.resident.value_offset); 67676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman inode->size = attr->data.resident.value_len; 67776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else { 67876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman attr_len = (uint8_t *)attr + attr->len; 67976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 68076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman stream = mapping_chunk_init(attr, &chunk, &offset); 68176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman NTFS_PVT(inode)->data.non_resident.rlist = NULL; 68276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman for (;;) { 68376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman err = parse_data_run(stream, &offset, attr_len, &chunk); 68476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (err) { 68576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman printf("parse_data_run()\n"); 68676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto out; 68776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 68876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 68976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (chunk.flags & MAP_UNALLOCATED) 69076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman continue; 69176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (chunk.flags & MAP_END) 69276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 69376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (chunk.flags & MAP_ALLOCATED) { 69476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* append new run to the runlist */ 69576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman runlist_append(&NTFS_PVT(inode)->data.non_resident.rlist, 69676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman (struct runlist_element *)&chunk); 69776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* update for next VCN */ 69876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman chunk.vcn += chunk.len; 69976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 70076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 70176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 70276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (runlist_is_empty(NTFS_PVT(inode)->data.non_resident.rlist)) { 70376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman printf("No mapping found\n"); 70476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto out; 70576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 70676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 70776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman inode->size = attr->data.non_resident.initialized_size; 70876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 70976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 71076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 71176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman inode->mode = d_type; 71276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 71376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman free(mrec); 71476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 71576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 0; 71676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 71776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanout: 71876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman free(mrec); 71976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 72076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return -1; 72176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 72276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 72376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic struct inode *ntfs_index_lookup(const char *dname, struct inode *dir) 72476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 72576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct fs_info *fs = dir->fs; 72676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ntfs_mft_record *mrec, *lmrec; 72776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman block_t blk; 72876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint64_t blk_offset; 72976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ntfs_attr_record *attr; 73076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ntfs_idx_root *ir; 73176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ntfs_idx_entry *ie; 73276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman const uint64_t blk_size = UINT64_C(1) << BLOCK_SHIFT(fs); 73376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint8_t buf[blk_size]; 73476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ntfs_idx_allocation *iblk; 73576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int err; 73676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint8_t *stream; 73776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint8_t *attr_len; 73876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct mapping_chunk chunk; 73976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint32_t offset; 74076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int64_t vcn; 74176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int64_t lcn; 74276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int64_t last_lcn; 74376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct inode *inode; 74476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 74576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman dprintf("in %s()\n", __func__); 74676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 74776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mrec = NTFS_SB(fs)->mft_record_lookup(fs, NTFS_PVT(dir)->mft_no, NULL); 74876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!mrec) { 74976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman printf("No MFT record found.\n"); 75076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto out; 75176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 75276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 75376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman lmrec = mrec; 75476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman attr = ntfs_attr_lookup(fs, NTFS_AT_INDEX_ROOT, &mrec, lmrec); 75576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!attr) { 75676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman printf("No attribute found.\n"); 75776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto out; 75876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 75976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 76076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ir = (struct ntfs_idx_root *)((uint8_t *)attr + 76176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman attr->data.resident.value_offset); 76276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ie = (struct ntfs_idx_entry *)((uint8_t *)&ir->index + 76376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ir->index.entries_offset); 76476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman for (;; ie = (struct ntfs_idx_entry *)((uint8_t *)ie + ie->len)) { 76576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* bounds checks */ 76676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ((uint8_t *)ie < (uint8_t *)mrec || 76776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman (uint8_t *)ie + sizeof(struct ntfs_idx_entry_header) > 76876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman (uint8_t *)&ir->index + ir->index.index_len || 76976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman (uint8_t *)ie + ie->len > 77076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman (uint8_t *)&ir->index + ir->index.index_len) 77176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto index_err; 77276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 77376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* last entry cannot contain a key. it can however contain 77476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * a pointer to a child node in the B+ tree so we just break out 77576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 77676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (ie->flags & INDEX_ENTRY_END) 77776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 77876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 77976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (ntfs_filename_cmp(dname, ie)) 78076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto found; 78176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 78276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 78376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* check for the presence of a child node */ 78476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!(ie->flags & INDEX_ENTRY_NODE)) { 78576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman printf("No child node, aborting...\n"); 78676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto out; 78776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 78876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 78976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* then descend into child node */ 79076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 79176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman attr = ntfs_attr_lookup(fs, NTFS_AT_INDEX_ALLOCATION, &mrec, lmrec); 79276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!attr) { 79376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman printf("No attribute found.\n"); 79476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto out; 79576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 79676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 79776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!attr->non_resident) { 79876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman printf("WTF ?! $INDEX_ALLOCATION isn't really resident.\n"); 79976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto out; 80076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 80176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 80276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman attr_len = (uint8_t *)attr + attr->len; 80376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman stream = mapping_chunk_init(attr, &chunk, &offset); 80476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman do { 80576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman err = parse_data_run(stream, &offset, attr_len, &chunk); 80676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (err) 80776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 80876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 80976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (chunk.flags & MAP_UNALLOCATED) 81076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman continue; 81176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 81276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (chunk.flags & MAP_ALLOCATED) { 81376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman dprintf("%d cluster(s) starting at 0x%08llX\n", chunk.len, 81476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman chunk.lcn); 81576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 81676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman vcn = 0; 81776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman lcn = chunk.lcn; 81876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman while (vcn < chunk.len) { 81976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman blk = (lcn + vcn) << NTFS_SB(fs)->clust_shift << 82076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman SECTOR_SHIFT(fs) >> BLOCK_SHIFT(fs); 82176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 82276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman blk_offset = 0; 82376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman last_lcn = lcn; 82476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman lcn += vcn; 82576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman err = ntfs_read(fs, &buf, blk_size, blk_size, &blk, 82676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman &blk_offset, NULL, (uint64_t *)&lcn); 82776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (err) { 82876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman printf("Error while reading from cache.\n"); 82976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto not_found; 83076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 83176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 83276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ntfs_fixups_writeback(fs, (struct ntfs_record *)&buf); 83376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 83476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman iblk = (struct ntfs_idx_allocation *)&buf; 83576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (iblk->magic != NTFS_MAGIC_INDX) { 83676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman printf("Not a valid INDX record.\n"); 83776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto not_found; 83876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 83976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 84076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ie = (struct ntfs_idx_entry *)((uint8_t *)&iblk->index + 84176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman iblk->index.entries_offset); 84276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman for (;; ie = (struct ntfs_idx_entry *)((uint8_t *)ie + 84376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ie->len)) { 84476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* bounds checks */ 84576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ((uint8_t *)ie < (uint8_t *)iblk || (uint8_t *)ie + 84676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman sizeof(struct ntfs_idx_entry_header) > 84776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman (uint8_t *)&iblk->index + iblk->index.index_len || 84876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman (uint8_t *)ie + ie->len > 84976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman (uint8_t *)&iblk->index + iblk->index.index_len) 85076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto index_err; 85176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 85276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* last entry cannot contain a key */ 85376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (ie->flags & INDEX_ENTRY_END) 85476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 85576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 85676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (ntfs_filename_cmp(dname, ie)) 85776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto found; 85876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 85976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 86076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman lcn = last_lcn; /* restore the original LCN */ 86176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* go to the next VCN */ 86276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman vcn += (blk_size / (1 << NTFS_SB(fs)->clust_byte_shift)); 86376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 86476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 86576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } while (!(chunk.flags & MAP_END)); 86676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 86776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmannot_found: 86876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman dprintf("Index not found\n"); 86976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 87076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanout: 87176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman free(mrec); 87276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 87376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return NULL; 87476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 87576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanfound: 87676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman dprintf("Index found\n"); 87776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman inode = new_ntfs_inode(fs); 87876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman err = index_inode_setup(fs, ie->data.dir.indexed_file, inode); 87976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (err) { 88076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman printf("Error in index_inode_setup()\n"); 88176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman free(inode); 88276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto out; 88376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 88476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 88576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman free(mrec); 88676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 88776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return inode; 88876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 88976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanindex_err: 89076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman printf("Corrupt index. Aborting lookup...\n"); 89176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto out; 89276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 89376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 89476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Convert an UTF-16LE LFN to OEM LFN */ 89576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic uint8_t ntfs_cvt_filename(char *filename, 89676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman const struct ntfs_idx_entry *ie) 89776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 89876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman const uint16_t *entry_fn; 89976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint8_t entry_fn_len; 90076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman unsigned i; 90176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 90276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman entry_fn = ie->key.file_name.file_name; 90376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman entry_fn_len = ie->key.file_name.file_name_len; 90476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 90576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman for (i = 0; i < entry_fn_len; i++) 90676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman filename[i] = (char)entry_fn[i]; 90776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 90876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman filename[i] = '\0'; 90976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 91076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return entry_fn_len; 91176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 91276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 91376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int ntfs_next_extent(struct inode *inode, uint32_t lstart) 91476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 91576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct fs_info *fs = inode->fs; 91676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ntfs_sb_info *sbi = NTFS_SB(fs); 91776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman sector_t pstart = 0; 91876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct runlist *rlist; 91976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct runlist *ret; 92076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman const uint32_t sec_size = SECTOR_SIZE(fs); 92176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman const uint32_t sec_shift = SECTOR_SHIFT(fs); 92276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 92376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman dprintf("in %s()\n", __func__); 92476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 92576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!NTFS_PVT(inode)->non_resident) { 92676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pstart = (sbi->mft_blk + NTFS_PVT(inode)->here) << BLOCK_SHIFT(fs) >> 92776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman sec_shift; 92876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman inode->next_extent.len = (inode->size + sec_size - 1) >> sec_shift; 92976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else { 93076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rlist = NTFS_PVT(inode)->data.non_resident.rlist; 93176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 93276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!lstart || lstart >= NTFS_PVT(inode)->here) { 93376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (runlist_is_empty(rlist)) 93476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto out; /* nothing to do ;-) */ 93576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 93676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ret = runlist_remove(&rlist); 93776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 93876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman NTFS_PVT(inode)->here = 93976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ((ret->run.len << sbi->clust_byte_shift) >> sec_shift); 94076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 94176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pstart = ret->run.lcn << sbi->clust_shift; 94276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman inode->next_extent.len = 94376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ((ret->run.len << sbi->clust_byte_shift) + sec_size - 1) >> 94476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman sec_shift; 94576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 94676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman NTFS_PVT(inode)->data.non_resident.rlist = rlist; 94776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 94876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman free(ret); 94976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ret = NULL; 95076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 95176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 95276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 95376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman inode->next_extent.pstart = pstart; 95476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 95576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 0; 95676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 95776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanout: 95876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return -1; 95976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 96076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 96176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic uint32_t ntfs_getfssec(struct file *file, char *buf, int sectors, 96276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman bool *have_more) 96376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 96476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint8_t non_resident; 96576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint32_t ret; 96676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct fs_info *fs = file->fs; 96776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct inode *inode = file->inode; 96876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ntfs_mft_record *mrec, *lmrec; 96976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ntfs_attr_record *attr; 97076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman char *p; 97176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 97276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman dprintf("in %s()\n", __func__); 97376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 97476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman non_resident = NTFS_PVT(inode)->non_resident; 97576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 97676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ret = generic_getfssec(file, buf, sectors, have_more); 97776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!ret) 97876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return ret; 97976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 98076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!non_resident) { 98176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mrec = NTFS_SB(fs)->mft_record_lookup(fs, NTFS_PVT(inode)->mft_no, 98276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman NULL); 98376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!mrec) { 98476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman printf("No MFT record found.\n"); 98576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto out; 98676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 98776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 98876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman lmrec = mrec; 98976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman attr = ntfs_attr_lookup(fs, NTFS_AT_DATA, &mrec, lmrec); 99076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!attr) { 99176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman printf("No attribute found.\n"); 99276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto out; 99376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 99476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 99576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman p = (char *)((uint8_t *)attr + attr->data.resident.value_offset); 99676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 99776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* p now points to the data offset, so let's copy it into buf */ 99876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman memcpy(buf, p, inode->size); 99976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 100076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ret = inode->size; 100176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 100276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman free(mrec); 100376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 100476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 100576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return ret; 100676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 100776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanout: 100876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman free(mrec); 100976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 101076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 0; 101176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 101276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 101376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic inline bool is_filename_printable(const char *s) 101476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 101576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return s && (*s != '.' && *s != '$'); 101676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 101776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 101876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int ntfs_readdir(struct file *file, struct dirent *dirent) 101976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 102076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct fs_info *fs = file->fs; 102176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct inode *inode = file->inode; 102276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ntfs_mft_record *mrec, *lmrec; 102376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman block_t blk; 102476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint64_t blk_offset; 102576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman const uint64_t blk_size = UINT64_C(1) << BLOCK_SHIFT(fs); 102676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ntfs_attr_record *attr; 102776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ntfs_idx_root *ir; 102876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint32_t count; 102976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int len; 103076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ntfs_idx_entry *ie = NULL; 103176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint8_t buf[BLOCK_SIZE(fs)]; 103276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ntfs_idx_allocation *iblk; 103376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int err; 103476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint8_t *stream; 103576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint8_t *attr_len; 103676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct mapping_chunk chunk; 103776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint32_t offset; 103876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int64_t vcn; 103976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int64_t lcn; 104076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman char filename[NTFS_MAX_FILE_NAME_LEN + 1]; 104176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 104276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman dprintf("in %s()\n", __func__); 104376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 104476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mrec = NTFS_SB(fs)->mft_record_lookup(fs, NTFS_PVT(inode)->mft_no, NULL); 104576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!mrec) { 104676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman printf("No MFT record found.\n"); 104776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto out; 104876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 104976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 105076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman lmrec = mrec; 105176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman attr = ntfs_attr_lookup(fs, NTFS_AT_INDEX_ROOT, &mrec, lmrec); 105276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!attr) { 105376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman printf("No attribute found.\n"); 105476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto out; 105576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 105676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 105776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ir = (struct ntfs_idx_root *)((uint8_t *)attr + 105876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman attr->data.resident.value_offset); 105976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 106076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!file->offset && readdir_state->in_idx_root) 106176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman file->offset = ir->index.entries_offset; 106276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 106376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanidx_root_next_entry: 106476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (readdir_state->in_idx_root) { 106576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ie = (struct ntfs_idx_entry *)((uint8_t *)&ir->index + file->offset); 106676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (ie->flags & INDEX_ENTRY_END) { 106776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman file->offset = 0; 106876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman readdir_state->in_idx_root = false; 106976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman readdir_state->idx_blks_count = 1; 107076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman readdir_state->entries_count = 0; 107176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman readdir_state->last_vcn = 0; 107276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto descend_into_child_node; 107376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 107476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 107576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman file->offset += ie->len; 107676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman len = ntfs_cvt_filename(filename, ie); 107776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!is_filename_printable(filename)) 107876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto idx_root_next_entry; 107976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 108076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto done; 108176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 108276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 108376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmandescend_into_child_node: 108476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!(ie->flags & INDEX_ENTRY_NODE)) 108576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto out; 108676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 108776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman attr = ntfs_attr_lookup(fs, NTFS_AT_INDEX_ALLOCATION, &mrec, lmrec); 108876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!attr) 108976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto out; 109076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 109176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!attr->non_resident) { 109276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman printf("WTF ?! $INDEX_ALLOCATION isn't really resident.\n"); 109376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto out; 109476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 109576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 109676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman attr_len = (uint8_t *)attr + attr->len; 109776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 109876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmannext_run: 109976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman stream = mapping_chunk_init(attr, &chunk, &offset); 110076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman count = readdir_state->idx_blks_count; 110176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman while (count--) { 110276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman err = parse_data_run(stream, &offset, attr_len, &chunk); 110376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (err) { 110476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman printf("Error while parsing data runs.\n"); 110576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto out; 110676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 110776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 110876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (chunk.flags & MAP_UNALLOCATED) 110976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 111076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (chunk.flags & MAP_END) 111176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto out; 111276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 111376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 111476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (chunk.flags & MAP_UNALLOCATED) { 111576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman readdir_state->idx_blks_count++; 111676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto next_run; 111776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 111876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 111976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmannext_vcn: 112076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman vcn = readdir_state->last_vcn; 112176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (vcn >= chunk.len) { 112276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman readdir_state->last_vcn = 0; 112376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman readdir_state->idx_blks_count++; 112476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto next_run; 112576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 112676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 112776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman lcn = chunk.lcn; 112876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman blk = (lcn + vcn) << NTFS_SB(fs)->clust_shift << SECTOR_SHIFT(fs) >> 112976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman BLOCK_SHIFT(fs); 113076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 113176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman blk_offset = 0; 113276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman err = ntfs_read(fs, &buf, blk_size, blk_size, &blk, &blk_offset, NULL, 113376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman (uint64_t *)&lcn); 113476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (err) { 113576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman printf("Error while reading from cache.\n"); 113676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto not_found; 113776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 113876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 113976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ntfs_fixups_writeback(fs, (struct ntfs_record *)&buf); 114076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 114176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman iblk = (struct ntfs_idx_allocation *)&buf; 114276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (iblk->magic != NTFS_MAGIC_INDX) { 114376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman printf("Not a valid INDX record.\n"); 114476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto not_found; 114576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 114676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 114776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanidx_block_next_entry: 114876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ie = (struct ntfs_idx_entry *)((uint8_t *)&iblk->index + 114976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman iblk->index.entries_offset); 115076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman count = readdir_state->entries_count; 115176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman for ( ; count--; ie = (struct ntfs_idx_entry *)((uint8_t *)ie + ie->len)) { 115276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* bounds checks */ 115376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ((uint8_t *)ie < (uint8_t *)iblk || (uint8_t *)ie + 115476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman sizeof(struct ntfs_idx_entry_header) > 115576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman (uint8_t *)&iblk->index + iblk->index.index_len || 115676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman (uint8_t *)ie + ie->len > 115776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman (uint8_t *)&iblk->index + iblk->index.index_len) 115876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto index_err; 115976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 116076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* last entry cannot contain a key */ 116176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (ie->flags & INDEX_ENTRY_END) { 116276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* go to the next VCN */ 116376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman readdir_state->last_vcn += (blk_size / (1 << 116476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman NTFS_SB(fs)->clust_byte_shift)); 116576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman readdir_state->entries_count = 0; 116676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto next_vcn; 116776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 116876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 116976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 117076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman readdir_state->entries_count++; 117176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 117276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Need to check if this entry has INDEX_ENTRY_END flag set. If 117376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * so, then it won't contain a indexed_file file, so continue the 117476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * lookup on the next VCN/LCN (if any). 117576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 117676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (ie->flags & INDEX_ENTRY_END) 117776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto next_vcn; 117876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 117976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman len = ntfs_cvt_filename(filename, ie); 118076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!is_filename_printable(filename)) 118176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto idx_block_next_entry; 118276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 118376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto done; 118476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 118576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanout: 118676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman readdir_state->in_idx_root = true; 118776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 118876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman free(mrec); 118976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 119076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return -1; 119176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 119276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmandone: 119376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman dirent->d_ino = ie->data.dir.indexed_file; 119476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman dirent->d_off = file->offset; 119576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman dirent->d_reclen = offsetof(struct dirent, d_name) + len + 1; 119676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 119776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman free(mrec); 119876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 119976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mrec = NTFS_SB(fs)->mft_record_lookup(fs, ie->data.dir.indexed_file, NULL); 120076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!mrec) { 120176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman printf("No MFT record found.\n"); 120276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto out; 120376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 120476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 120576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman dirent->d_type = get_inode_mode(mrec); 120676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman memcpy(dirent->d_name, filename, len + 1); 120776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 120876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman free(mrec); 120976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 121076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 0; 121176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 121276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmannot_found: 121376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman printf("Index not found\n"); 121476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto out; 121576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 121676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanindex_err: 121776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman printf("Corrupt index. Aborting lookup...\n"); 121876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto out; 121976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 122076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 122176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic inline struct inode *ntfs_iget(const char *dname, struct inode *parent) 122276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 122376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return ntfs_index_lookup(dname, parent); 122476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 122576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 122676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic struct inode *ntfs_iget_root(struct fs_info *fs) 122776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 122876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint64_t start_blk; 122976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ntfs_mft_record *mrec, *lmrec; 123076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ntfs_attr_record *attr; 123176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ntfs_vol_info *vol_info; 123276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct inode *inode; 123376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int err; 123476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 123576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman dprintf("in %s()\n", __func__); 123676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 123776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Fetch the $Volume MFT record */ 123876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman start_blk = 0; 123976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mrec = NTFS_SB(fs)->mft_record_lookup(fs, FILE_Volume, &start_blk); 124076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!mrec) { 124176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman printf("Could not fetch $Volume MFT record!\n"); 124276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto err_mrec; 124376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 124476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 124576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman lmrec = mrec; 124676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 124776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Fetch the volume information attribute */ 124876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman attr = ntfs_attr_lookup(fs, NTFS_AT_VOL_INFO, &mrec, lmrec); 124976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!attr) { 125076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman printf("Could not find volume info attribute!\n"); 125176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto err_attr; 125276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 125376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 125476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Note NTFS version and choose version-dependent functions */ 125576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman vol_info = (void *)((char *)attr + attr->data.resident.value_offset); 125676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman NTFS_SB(fs)->major_ver = vol_info->major_ver; 125776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman NTFS_SB(fs)->minor_ver = vol_info->minor_ver; 125876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (vol_info->major_ver == 3 && vol_info->minor_ver == 0) 125976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman NTFS_SB(fs)->mft_record_lookup = ntfs_mft_record_lookup_3_0; 126076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman else if (vol_info->major_ver == 3 && vol_info->minor_ver == 1 && 126176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mrec->mft_record_no == FILE_Volume) 126276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman NTFS_SB(fs)->mft_record_lookup = ntfs_mft_record_lookup_3_1; 126376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 126476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Free MFT record */ 126576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman free(mrec); 126676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mrec = NULL; 126776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 126876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman inode = new_ntfs_inode(fs); 126976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman inode->fs = fs; 127076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 127176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman err = index_inode_setup(fs, FILE_root, inode); 127276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (err) 127376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto err_setup; 127476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 127576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman NTFS_PVT(inode)->start = NTFS_PVT(inode)->here; 127676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 127776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return inode; 127876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 127976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanerr_setup: 128076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 128176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman free(inode); 128276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanerr_attr: 128376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 128476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman free(mrec); 128576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanerr_mrec: 128676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 128776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return NULL; 128876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 128976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 129076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Initialize the filesystem metadata and return blk size in bits */ 129176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int ntfs_fs_init(struct fs_info *fs) 129276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 129376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int read_count; 129476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ntfs_bpb ntfs; 129576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct ntfs_sb_info *sbi; 129676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct disk *disk = fs->fs_dev->disk; 129776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman uint8_t mft_record_shift; 129876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 129976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman dprintf("in %s()\n", __func__); 130076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 130176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman read_count = disk->rdwr_sectors(disk, &ntfs, 0, 1, 0); 130276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!read_count) 130376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return -1; 130476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 130576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!ntfs_check_sb_fields(&ntfs)) 130676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return -1; 130776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 130876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman SECTOR_SHIFT(fs) = disk->sector_shift; 130976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 131076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Note: ntfs.clust_per_mft_record can be a negative number. 131176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * If negative, it represents a shift count, else it represents 131276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * a multiplier for the cluster size. 131376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 131476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mft_record_shift = ntfs.clust_per_mft_record < 0 ? 131576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman -ntfs.clust_per_mft_record : 131676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ilog2(ntfs.sec_per_clust) + SECTOR_SHIFT(fs) + 131776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ilog2(ntfs.clust_per_mft_record); 131876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 131976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman SECTOR_SIZE(fs) = 1 << SECTOR_SHIFT(fs); 132076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 132176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman sbi = malloc(sizeof *sbi); 132276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!sbi) 132376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman malloc_error("ntfs_sb_info structure"); 132476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 132576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman fs->fs_info = sbi; 132676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 132776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman sbi->clust_shift = ilog2(ntfs.sec_per_clust); 132876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman sbi->clust_byte_shift = sbi->clust_shift + SECTOR_SHIFT(fs); 132976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman sbi->clust_mask = ntfs.sec_per_clust - 1; 133076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman sbi->clust_size = ntfs.sec_per_clust << SECTOR_SHIFT(fs); 133176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman sbi->mft_record_size = 1 << mft_record_shift; 133276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman sbi->clust_per_idx_record = ntfs.clust_per_idx_record; 133376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 133476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman BLOCK_SHIFT(fs) = ilog2(ntfs.clust_per_idx_record) + sbi->clust_byte_shift; 133576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman BLOCK_SIZE(fs) = 1 << BLOCK_SHIFT(fs); 133676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 133776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman sbi->mft_lcn = ntfs.mft_lclust; 133876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman sbi->mft_blk = ntfs.mft_lclust << sbi->clust_shift << SECTOR_SHIFT(fs) >> 133976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman BLOCK_SHIFT(fs); 134076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* 16 MFT entries reserved for metadata files (approximately 16 KiB) */ 134176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman sbi->mft_size = mft_record_shift << sbi->clust_shift << 4; 134276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 134376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman sbi->clusters = ntfs.total_sectors << SECTOR_SHIFT(fs) >> sbi->clust_shift; 134476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (sbi->clusters > 0xFFFFFFFFFFF4ULL) 134576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman sbi->clusters = 0xFFFFFFFFFFF4ULL; 134676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 134776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* 134876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Assume NTFS version 3.0 to begin with. If we find that the 134976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * volume is a different version later on, we will adjust at 135076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * that time. 135176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 135276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman sbi->major_ver = 3; 135376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman sbi->minor_ver = 0; 135476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman sbi->mft_record_lookup = ntfs_mft_record_lookup_3_0; 135576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 135676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Initialize the cache */ 135776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman cache_init(fs->fs_dev, BLOCK_SHIFT(fs)); 135876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 135976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return BLOCK_SHIFT(fs); 136076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 136176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 136276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanconst struct fs_ops ntfs_fs_ops = { 136376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman .fs_name = "ntfs", 136476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman .fs_flags = FS_USEMEM | FS_THISIND, 136576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman .fs_init = ntfs_fs_init, 136676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman .searchdir = NULL, 136776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman .getfssec = ntfs_getfssec, 136876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman .close_file = generic_close_file, 136976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman .mangle_name = generic_mangle_name, 137076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman .open_config = generic_open_config, 137176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman .readdir = ntfs_readdir, 137276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman .iget_root = ntfs_iget_root, 137376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman .iget = ntfs_iget, 137476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman .next_extent = ntfs_next_extent, 137576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman .fs_uuid = NULL, 137676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}; 1377