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