1a1d312deSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2aa0b42b7SRandy Dunlap /*
31da177e4SLinus Torvalds * dir.c - NTFS kernel directory operations. Part of the Linux-NTFS project.
41da177e4SLinus Torvalds *
58331191eSAnton Altaparmakov * Copyright (c) 2001-2007 Anton Altaparmakov
61da177e4SLinus Torvalds * Copyright (c) 2002 Richard Russon
71da177e4SLinus Torvalds */
81da177e4SLinus Torvalds
91da177e4SLinus Torvalds #include <linux/buffer_head.h>
105a0e3ad6STejun Heo #include <linux/slab.h>
113f1266f1SChristoph Hellwig #include <linux/blkdev.h>
121da177e4SLinus Torvalds
131da177e4SLinus Torvalds #include "dir.h"
141da177e4SLinus Torvalds #include "aops.h"
151da177e4SLinus Torvalds #include "attrib.h"
161da177e4SLinus Torvalds #include "mft.h"
171da177e4SLinus Torvalds #include "debug.h"
181da177e4SLinus Torvalds #include "ntfs.h"
191da177e4SLinus Torvalds
20aa0b42b7SRandy Dunlap /*
211da177e4SLinus Torvalds * The little endian Unicode string $I30 as a global constant.
221da177e4SLinus Torvalds */
2363cd8854SHarvey Harrison ntfschar I30[5] = { cpu_to_le16('$'), cpu_to_le16('I'),
2463cd8854SHarvey Harrison cpu_to_le16('3'), cpu_to_le16('0'), 0 };
251da177e4SLinus Torvalds
261da177e4SLinus Torvalds /**
271da177e4SLinus Torvalds * ntfs_lookup_inode_by_name - find an inode in a directory given its name
281da177e4SLinus Torvalds * @dir_ni: ntfs inode of the directory in which to search for the name
291da177e4SLinus Torvalds * @uname: Unicode name for which to search in the directory
301da177e4SLinus Torvalds * @uname_len: length of the name @uname in Unicode characters
311da177e4SLinus Torvalds * @res: return the found file name if necessary (see below)
321da177e4SLinus Torvalds *
331da177e4SLinus Torvalds * Look for an inode with name @uname in the directory with inode @dir_ni.
341da177e4SLinus Torvalds * ntfs_lookup_inode_by_name() walks the contents of the directory looking for
351da177e4SLinus Torvalds * the Unicode name. If the name is found in the directory, the corresponding
361da177e4SLinus Torvalds * inode number (>= 0) is returned as a mft reference in cpu format, i.e. it
371da177e4SLinus Torvalds * is a 64-bit number containing the sequence number.
381da177e4SLinus Torvalds *
391da177e4SLinus Torvalds * On error, a negative value is returned corresponding to the error code. In
401da177e4SLinus Torvalds * particular if the inode is not found -ENOENT is returned. Note that you
411da177e4SLinus Torvalds * can't just check the return value for being negative, you have to check the
421da177e4SLinus Torvalds * inode number for being negative which you can extract using MREC(return
431da177e4SLinus Torvalds * value).
441da177e4SLinus Torvalds *
451da177e4SLinus Torvalds * Note, @uname_len does not include the (optional) terminating NULL character.
461da177e4SLinus Torvalds *
471da177e4SLinus Torvalds * Note, we look for a case sensitive match first but we also look for a case
481da177e4SLinus Torvalds * insensitive match at the same time. If we find a case insensitive match, we
491da177e4SLinus Torvalds * save that for the case that we don't find an exact match, where we return
501da177e4SLinus Torvalds * the case insensitive match and setup @res (which we allocate!) with the mft
511da177e4SLinus Torvalds * reference, the file name type, length and with a copy of the little endian
521da177e4SLinus Torvalds * Unicode file name itself. If we match a file name which is in the DOS name
531da177e4SLinus Torvalds * space, we only return the mft reference and file name type in @res.
541da177e4SLinus Torvalds * ntfs_lookup() then uses this to find the long file name in the inode itself.
551da177e4SLinus Torvalds * This is to avoid polluting the dcache with short file names. We want them to
561da177e4SLinus Torvalds * work but we don't care for how quickly one can access them. This also fixes
571da177e4SLinus Torvalds * the dcache aliasing issues.
581da177e4SLinus Torvalds *
591b1dcc1bSJes Sorensen * Locking: - Caller must hold i_mutex on the directory.
601da177e4SLinus Torvalds * - Each page cache page in the index allocation mapping must be
611da177e4SLinus Torvalds * locked whilst being accessed otherwise we may find a corrupt
621da177e4SLinus Torvalds * page due to it being under ->writepage at the moment which
631da177e4SLinus Torvalds * applies the mst protection fixups before writing out and then
641da177e4SLinus Torvalds * removes them again after the write is complete after which it
651da177e4SLinus Torvalds * unlocks the page.
661da177e4SLinus Torvalds */
ntfs_lookup_inode_by_name(ntfs_inode * dir_ni,const ntfschar * uname,const int uname_len,ntfs_name ** res)671da177e4SLinus Torvalds MFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const ntfschar *uname,
681da177e4SLinus Torvalds const int uname_len, ntfs_name **res)
691da177e4SLinus Torvalds {
701da177e4SLinus Torvalds ntfs_volume *vol = dir_ni->vol;
711da177e4SLinus Torvalds struct super_block *sb = vol->sb;
721da177e4SLinus Torvalds MFT_RECORD *m;
731da177e4SLinus Torvalds INDEX_ROOT *ir;
741da177e4SLinus Torvalds INDEX_ENTRY *ie;
751da177e4SLinus Torvalds INDEX_ALLOCATION *ia;
761da177e4SLinus Torvalds u8 *index_end;
771da177e4SLinus Torvalds u64 mref;
781da177e4SLinus Torvalds ntfs_attr_search_ctx *ctx;
791da177e4SLinus Torvalds int err, rc;
801da177e4SLinus Torvalds VCN vcn, old_vcn;
811da177e4SLinus Torvalds struct address_space *ia_mapping;
821da177e4SLinus Torvalds struct page *page;
831da177e4SLinus Torvalds u8 *kaddr;
841da177e4SLinus Torvalds ntfs_name *name = NULL;
851da177e4SLinus Torvalds
861da177e4SLinus Torvalds BUG_ON(!S_ISDIR(VFS_I(dir_ni)->i_mode));
871da177e4SLinus Torvalds BUG_ON(NInoAttr(dir_ni));
881da177e4SLinus Torvalds /* Get hold of the mft record for the directory. */
891da177e4SLinus Torvalds m = map_mft_record(dir_ni);
901da177e4SLinus Torvalds if (IS_ERR(m)) {
911da177e4SLinus Torvalds ntfs_error(sb, "map_mft_record() failed with error code %ld.",
921da177e4SLinus Torvalds -PTR_ERR(m));
931da177e4SLinus Torvalds return ERR_MREF(PTR_ERR(m));
941da177e4SLinus Torvalds }
951da177e4SLinus Torvalds ctx = ntfs_attr_get_search_ctx(dir_ni, m);
961da177e4SLinus Torvalds if (unlikely(!ctx)) {
971da177e4SLinus Torvalds err = -ENOMEM;
981da177e4SLinus Torvalds goto err_out;
991da177e4SLinus Torvalds }
1001da177e4SLinus Torvalds /* Find the index root attribute in the mft record. */
1011da177e4SLinus Torvalds err = ntfs_attr_lookup(AT_INDEX_ROOT, I30, 4, CASE_SENSITIVE, 0, NULL,
1021da177e4SLinus Torvalds 0, ctx);
1031da177e4SLinus Torvalds if (unlikely(err)) {
1041da177e4SLinus Torvalds if (err == -ENOENT) {
1051da177e4SLinus Torvalds ntfs_error(sb, "Index root attribute missing in "
1061da177e4SLinus Torvalds "directory inode 0x%lx.",
1071da177e4SLinus Torvalds dir_ni->mft_no);
1081da177e4SLinus Torvalds err = -EIO;
1091da177e4SLinus Torvalds }
1101da177e4SLinus Torvalds goto err_out;
1111da177e4SLinus Torvalds }
1121da177e4SLinus Torvalds /* Get to the index root value (it's been verified in read_inode). */
1131da177e4SLinus Torvalds ir = (INDEX_ROOT*)((u8*)ctx->attr +
1141da177e4SLinus Torvalds le16_to_cpu(ctx->attr->data.resident.value_offset));
1151da177e4SLinus Torvalds index_end = (u8*)&ir->index + le32_to_cpu(ir->index.index_length);
1161da177e4SLinus Torvalds /* The first index entry. */
1171da177e4SLinus Torvalds ie = (INDEX_ENTRY*)((u8*)&ir->index +
1181da177e4SLinus Torvalds le32_to_cpu(ir->index.entries_offset));
1191da177e4SLinus Torvalds /*
1201da177e4SLinus Torvalds * Loop until we exceed valid memory (corruption case) or until we
1211da177e4SLinus Torvalds * reach the last entry.
1221da177e4SLinus Torvalds */
1231da177e4SLinus Torvalds for (;; ie = (INDEX_ENTRY*)((u8*)ie + le16_to_cpu(ie->length))) {
1241da177e4SLinus Torvalds /* Bounds checks. */
1251da177e4SLinus Torvalds if ((u8*)ie < (u8*)ctx->mrec || (u8*)ie +
1261da177e4SLinus Torvalds sizeof(INDEX_ENTRY_HEADER) > index_end ||
1271da177e4SLinus Torvalds (u8*)ie + le16_to_cpu(ie->key_length) >
1281da177e4SLinus Torvalds index_end)
1291da177e4SLinus Torvalds goto dir_err_out;
1301da177e4SLinus Torvalds /*
1311da177e4SLinus Torvalds * The last entry cannot contain a name. It can however contain
1321da177e4SLinus Torvalds * a pointer to a child node in the B+tree so we just break out.
1331da177e4SLinus Torvalds */
1341da177e4SLinus Torvalds if (ie->flags & INDEX_ENTRY_END)
1351da177e4SLinus Torvalds break;
1361da177e4SLinus Torvalds /*
1371da177e4SLinus Torvalds * We perform a case sensitive comparison and if that matches
1381da177e4SLinus Torvalds * we are done and return the mft reference of the inode (i.e.
1391da177e4SLinus Torvalds * the inode number together with the sequence number for
1401da177e4SLinus Torvalds * consistency checking). We convert it to cpu format before
1411da177e4SLinus Torvalds * returning.
1421da177e4SLinus Torvalds */
1431da177e4SLinus Torvalds if (ntfs_are_names_equal(uname, uname_len,
1441da177e4SLinus Torvalds (ntfschar*)&ie->key.file_name.file_name,
1451da177e4SLinus Torvalds ie->key.file_name.file_name_length,
1461da177e4SLinus Torvalds CASE_SENSITIVE, vol->upcase, vol->upcase_len)) {
1471da177e4SLinus Torvalds found_it:
1481da177e4SLinus Torvalds /*
1491da177e4SLinus Torvalds * We have a perfect match, so we don't need to care
1501da177e4SLinus Torvalds * about having matched imperfectly before, so we can
1511da177e4SLinus Torvalds * free name and set *res to NULL.
1521da177e4SLinus Torvalds * However, if the perfect match is a short file name,
1531da177e4SLinus Torvalds * we need to signal this through *res, so that
1541da177e4SLinus Torvalds * ntfs_lookup() can fix dcache aliasing issues.
1551da177e4SLinus Torvalds * As an optimization we just reuse an existing
1561da177e4SLinus Torvalds * allocation of *res.
1571da177e4SLinus Torvalds */
1581da177e4SLinus Torvalds if (ie->key.file_name.file_name_type == FILE_NAME_DOS) {
1591da177e4SLinus Torvalds if (!name) {
1601da177e4SLinus Torvalds name = kmalloc(sizeof(ntfs_name),
1611da177e4SLinus Torvalds GFP_NOFS);
1621da177e4SLinus Torvalds if (!name) {
1631da177e4SLinus Torvalds err = -ENOMEM;
1641da177e4SLinus Torvalds goto err_out;
1651da177e4SLinus Torvalds }
1661da177e4SLinus Torvalds }
1671da177e4SLinus Torvalds name->mref = le64_to_cpu(
1681da177e4SLinus Torvalds ie->data.dir.indexed_file);
1691da177e4SLinus Torvalds name->type = FILE_NAME_DOS;
1701da177e4SLinus Torvalds name->len = 0;
1711da177e4SLinus Torvalds *res = name;
1721da177e4SLinus Torvalds } else {
1731da177e4SLinus Torvalds kfree(name);
1741da177e4SLinus Torvalds *res = NULL;
1751da177e4SLinus Torvalds }
1761da177e4SLinus Torvalds mref = le64_to_cpu(ie->data.dir.indexed_file);
1771da177e4SLinus Torvalds ntfs_attr_put_search_ctx(ctx);
1781da177e4SLinus Torvalds unmap_mft_record(dir_ni);
1791da177e4SLinus Torvalds return mref;
1801da177e4SLinus Torvalds }
1811da177e4SLinus Torvalds /*
1821da177e4SLinus Torvalds * For a case insensitive mount, we also perform a case
1831da177e4SLinus Torvalds * insensitive comparison (provided the file name is not in the
1841da177e4SLinus Torvalds * POSIX namespace). If the comparison matches, and the name is
1851da177e4SLinus Torvalds * in the WIN32 namespace, we cache the filename in *res so
1861da177e4SLinus Torvalds * that the caller, ntfs_lookup(), can work on it. If the
1871da177e4SLinus Torvalds * comparison matches, and the name is in the DOS namespace, we
1881da177e4SLinus Torvalds * only cache the mft reference and the file name type (we set
1891da177e4SLinus Torvalds * the name length to zero for simplicity).
1901da177e4SLinus Torvalds */
1911da177e4SLinus Torvalds if (!NVolCaseSensitive(vol) &&
1921da177e4SLinus Torvalds ie->key.file_name.file_name_type &&
1931da177e4SLinus Torvalds ntfs_are_names_equal(uname, uname_len,
1941da177e4SLinus Torvalds (ntfschar*)&ie->key.file_name.file_name,
1951da177e4SLinus Torvalds ie->key.file_name.file_name_length,
1961da177e4SLinus Torvalds IGNORE_CASE, vol->upcase, vol->upcase_len)) {
1971da177e4SLinus Torvalds int name_size = sizeof(ntfs_name);
1981da177e4SLinus Torvalds u8 type = ie->key.file_name.file_name_type;
1991da177e4SLinus Torvalds u8 len = ie->key.file_name.file_name_length;
2001da177e4SLinus Torvalds
2011da177e4SLinus Torvalds /* Only one case insensitive matching name allowed. */
2021da177e4SLinus Torvalds if (name) {
2031da177e4SLinus Torvalds ntfs_error(sb, "Found already allocated name "
2041da177e4SLinus Torvalds "in phase 1. Please run chkdsk "
2051da177e4SLinus Torvalds "and if that doesn't find any "
2061da177e4SLinus Torvalds "errors please report you saw "
2071da177e4SLinus Torvalds "this message to "
2081da177e4SLinus Torvalds "linux-ntfs-dev@lists."
2091da177e4SLinus Torvalds "sourceforge.net.");
2101da177e4SLinus Torvalds goto dir_err_out;
2111da177e4SLinus Torvalds }
2121da177e4SLinus Torvalds
2131da177e4SLinus Torvalds if (type != FILE_NAME_DOS)
2141da177e4SLinus Torvalds name_size += len * sizeof(ntfschar);
2151da177e4SLinus Torvalds name = kmalloc(name_size, GFP_NOFS);
2161da177e4SLinus Torvalds if (!name) {
2171da177e4SLinus Torvalds err = -ENOMEM;
2181da177e4SLinus Torvalds goto err_out;
2191da177e4SLinus Torvalds }
2201da177e4SLinus Torvalds name->mref = le64_to_cpu(ie->data.dir.indexed_file);
2211da177e4SLinus Torvalds name->type = type;
2221da177e4SLinus Torvalds if (type != FILE_NAME_DOS) {
2231da177e4SLinus Torvalds name->len = len;
2241da177e4SLinus Torvalds memcpy(name->name, ie->key.file_name.file_name,
2251da177e4SLinus Torvalds len * sizeof(ntfschar));
2261da177e4SLinus Torvalds } else
2271da177e4SLinus Torvalds name->len = 0;
2281da177e4SLinus Torvalds *res = name;
2291da177e4SLinus Torvalds }
2301da177e4SLinus Torvalds /*
2311da177e4SLinus Torvalds * Not a perfect match, need to do full blown collation so we
2321da177e4SLinus Torvalds * know which way in the B+tree we have to go.
2331da177e4SLinus Torvalds */
2341da177e4SLinus Torvalds rc = ntfs_collate_names(uname, uname_len,
2351da177e4SLinus Torvalds (ntfschar*)&ie->key.file_name.file_name,
2361da177e4SLinus Torvalds ie->key.file_name.file_name_length, 1,
2371da177e4SLinus Torvalds IGNORE_CASE, vol->upcase, vol->upcase_len);
2381da177e4SLinus Torvalds /*
2391da177e4SLinus Torvalds * If uname collates before the name of the current entry, there
2401da177e4SLinus Torvalds * is definitely no such name in this index but we might need to
2411da177e4SLinus Torvalds * descend into the B+tree so we just break out of the loop.
2421da177e4SLinus Torvalds */
2431da177e4SLinus Torvalds if (rc == -1)
2441da177e4SLinus Torvalds break;
2451da177e4SLinus Torvalds /* The names are not equal, continue the search. */
2461da177e4SLinus Torvalds if (rc)
2471da177e4SLinus Torvalds continue;
2481da177e4SLinus Torvalds /*
2491da177e4SLinus Torvalds * Names match with case insensitive comparison, now try the
2501da177e4SLinus Torvalds * case sensitive comparison, which is required for proper
2511da177e4SLinus Torvalds * collation.
2521da177e4SLinus Torvalds */
2531da177e4SLinus Torvalds rc = ntfs_collate_names(uname, uname_len,
2541da177e4SLinus Torvalds (ntfschar*)&ie->key.file_name.file_name,
2551da177e4SLinus Torvalds ie->key.file_name.file_name_length, 1,
2561da177e4SLinus Torvalds CASE_SENSITIVE, vol->upcase, vol->upcase_len);
2571da177e4SLinus Torvalds if (rc == -1)
2581da177e4SLinus Torvalds break;
2591da177e4SLinus Torvalds if (rc)
2601da177e4SLinus Torvalds continue;
2611da177e4SLinus Torvalds /*
2621da177e4SLinus Torvalds * Perfect match, this will never happen as the
2631da177e4SLinus Torvalds * ntfs_are_names_equal() call will have gotten a match but we
2641da177e4SLinus Torvalds * still treat it correctly.
2651da177e4SLinus Torvalds */
2661da177e4SLinus Torvalds goto found_it;
2671da177e4SLinus Torvalds }
2681da177e4SLinus Torvalds /*
2691da177e4SLinus Torvalds * We have finished with this index without success. Check for the
2701da177e4SLinus Torvalds * presence of a child node and if not present return -ENOENT, unless
2711da177e4SLinus Torvalds * we have got a matching name cached in name in which case return the
2721da177e4SLinus Torvalds * mft reference associated with it.
2731da177e4SLinus Torvalds */
2741da177e4SLinus Torvalds if (!(ie->flags & INDEX_ENTRY_NODE)) {
2751da177e4SLinus Torvalds if (name) {
2761da177e4SLinus Torvalds ntfs_attr_put_search_ctx(ctx);
2771da177e4SLinus Torvalds unmap_mft_record(dir_ni);
2781da177e4SLinus Torvalds return name->mref;
2791da177e4SLinus Torvalds }
2801da177e4SLinus Torvalds ntfs_debug("Entry not found.");
2811da177e4SLinus Torvalds err = -ENOENT;
2821da177e4SLinus Torvalds goto err_out;
2831da177e4SLinus Torvalds } /* Child node present, descend into it. */
2841da177e4SLinus Torvalds /* Consistency check: Verify that an index allocation exists. */
2851da177e4SLinus Torvalds if (!NInoIndexAllocPresent(dir_ni)) {
2861da177e4SLinus Torvalds ntfs_error(sb, "No index allocation attribute but index entry "
2871da177e4SLinus Torvalds "requires one. Directory inode 0x%lx is "
2881da177e4SLinus Torvalds "corrupt or driver bug.", dir_ni->mft_no);
2891da177e4SLinus Torvalds goto err_out;
2901da177e4SLinus Torvalds }
2911da177e4SLinus Torvalds /* Get the starting vcn of the index_block holding the child node. */
2921da177e4SLinus Torvalds vcn = sle64_to_cpup((sle64*)((u8*)ie + le16_to_cpu(ie->length) - 8));
2931da177e4SLinus Torvalds ia_mapping = VFS_I(dir_ni)->i_mapping;
2941da177e4SLinus Torvalds /*
2951da177e4SLinus Torvalds * We are done with the index root and the mft record. Release them,
2961da177e4SLinus Torvalds * otherwise we deadlock with ntfs_map_page().
2971da177e4SLinus Torvalds */
2981da177e4SLinus Torvalds ntfs_attr_put_search_ctx(ctx);
2991da177e4SLinus Torvalds unmap_mft_record(dir_ni);
3001da177e4SLinus Torvalds m = NULL;
3011da177e4SLinus Torvalds ctx = NULL;
3021da177e4SLinus Torvalds descend_into_child_node:
3031da177e4SLinus Torvalds /*
3041da177e4SLinus Torvalds * Convert vcn to index into the index allocation attribute in units
305ea1754a0SKirill A. Shutemov * of PAGE_SIZE and map the page cache page, reading it from
3061da177e4SLinus Torvalds * disk if necessary.
3071da177e4SLinus Torvalds */
3081da177e4SLinus Torvalds page = ntfs_map_page(ia_mapping, vcn <<
30909cbfeafSKirill A. Shutemov dir_ni->itype.index.vcn_size_bits >> PAGE_SHIFT);
3101da177e4SLinus Torvalds if (IS_ERR(page)) {
3111da177e4SLinus Torvalds ntfs_error(sb, "Failed to map directory index page, error %ld.",
3121da177e4SLinus Torvalds -PTR_ERR(page));
3131da177e4SLinus Torvalds err = PTR_ERR(page);
3141da177e4SLinus Torvalds goto err_out;
3151da177e4SLinus Torvalds }
3161da177e4SLinus Torvalds lock_page(page);
3171da177e4SLinus Torvalds kaddr = (u8*)page_address(page);
3181da177e4SLinus Torvalds fast_descend_into_child_node:
3191da177e4SLinus Torvalds /* Get to the index allocation block. */
3201da177e4SLinus Torvalds ia = (INDEX_ALLOCATION*)(kaddr + ((vcn <<
32109cbfeafSKirill A. Shutemov dir_ni->itype.index.vcn_size_bits) & ~PAGE_MASK));
3221da177e4SLinus Torvalds /* Bounds checks. */
32309cbfeafSKirill A. Shutemov if ((u8*)ia < kaddr || (u8*)ia > kaddr + PAGE_SIZE) {
3241da177e4SLinus Torvalds ntfs_error(sb, "Out of bounds check failed. Corrupt directory "
3251da177e4SLinus Torvalds "inode 0x%lx or driver bug.", dir_ni->mft_no);
3261da177e4SLinus Torvalds goto unm_err_out;
3271da177e4SLinus Torvalds }
3281da177e4SLinus Torvalds /* Catch multi sector transfer fixup errors. */
3291da177e4SLinus Torvalds if (unlikely(!ntfs_is_indx_record(ia->magic))) {
3301da177e4SLinus Torvalds ntfs_error(sb, "Directory index record with vcn 0x%llx is "
3311da177e4SLinus Torvalds "corrupt. Corrupt inode 0x%lx. Run chkdsk.",
3321da177e4SLinus Torvalds (unsigned long long)vcn, dir_ni->mft_no);
3331da177e4SLinus Torvalds goto unm_err_out;
3341da177e4SLinus Torvalds }
3351da177e4SLinus Torvalds if (sle64_to_cpu(ia->index_block_vcn) != vcn) {
3361da177e4SLinus Torvalds ntfs_error(sb, "Actual VCN (0x%llx) of index buffer is "
3371da177e4SLinus Torvalds "different from expected VCN (0x%llx). "
3381da177e4SLinus Torvalds "Directory inode 0x%lx is corrupt or driver "
3391da177e4SLinus Torvalds "bug.", (unsigned long long)
3401da177e4SLinus Torvalds sle64_to_cpu(ia->index_block_vcn),
3411da177e4SLinus Torvalds (unsigned long long)vcn, dir_ni->mft_no);
3421da177e4SLinus Torvalds goto unm_err_out;
3431da177e4SLinus Torvalds }
3441da177e4SLinus Torvalds if (le32_to_cpu(ia->index.allocated_size) + 0x18 !=
3451da177e4SLinus Torvalds dir_ni->itype.index.block_size) {
3461da177e4SLinus Torvalds ntfs_error(sb, "Index buffer (VCN 0x%llx) of directory inode "
3471da177e4SLinus Torvalds "0x%lx has a size (%u) differing from the "
3481da177e4SLinus Torvalds "directory specified size (%u). Directory "
3491da177e4SLinus Torvalds "inode is corrupt or driver bug.",
3501da177e4SLinus Torvalds (unsigned long long)vcn, dir_ni->mft_no,
3511da177e4SLinus Torvalds le32_to_cpu(ia->index.allocated_size) + 0x18,
3521da177e4SLinus Torvalds dir_ni->itype.index.block_size);
3531da177e4SLinus Torvalds goto unm_err_out;
3541da177e4SLinus Torvalds }
3551da177e4SLinus Torvalds index_end = (u8*)ia + dir_ni->itype.index.block_size;
35609cbfeafSKirill A. Shutemov if (index_end > kaddr + PAGE_SIZE) {
3571da177e4SLinus Torvalds ntfs_error(sb, "Index buffer (VCN 0x%llx) of directory inode "
3581da177e4SLinus Torvalds "0x%lx crosses page boundary. Impossible! "
3591da177e4SLinus Torvalds "Cannot access! This is probably a bug in the "
3601da177e4SLinus Torvalds "driver.", (unsigned long long)vcn,
3611da177e4SLinus Torvalds dir_ni->mft_no);
3621da177e4SLinus Torvalds goto unm_err_out;
3631da177e4SLinus Torvalds }
3641da177e4SLinus Torvalds index_end = (u8*)&ia->index + le32_to_cpu(ia->index.index_length);
3651da177e4SLinus Torvalds if (index_end > (u8*)ia + dir_ni->itype.index.block_size) {
3661da177e4SLinus Torvalds ntfs_error(sb, "Size of index buffer (VCN 0x%llx) of directory "
3671da177e4SLinus Torvalds "inode 0x%lx exceeds maximum size.",
3681da177e4SLinus Torvalds (unsigned long long)vcn, dir_ni->mft_no);
3691da177e4SLinus Torvalds goto unm_err_out;
3701da177e4SLinus Torvalds }
3711da177e4SLinus Torvalds /* The first index entry. */
3721da177e4SLinus Torvalds ie = (INDEX_ENTRY*)((u8*)&ia->index +
3731da177e4SLinus Torvalds le32_to_cpu(ia->index.entries_offset));
3741da177e4SLinus Torvalds /*
3751da177e4SLinus Torvalds * Iterate similar to above big loop but applied to index buffer, thus
3761da177e4SLinus Torvalds * loop until we exceed valid memory (corruption case) or until we
3771da177e4SLinus Torvalds * reach the last entry.
3781da177e4SLinus Torvalds */
3791da177e4SLinus Torvalds for (;; ie = (INDEX_ENTRY*)((u8*)ie + le16_to_cpu(ie->length))) {
3801da177e4SLinus Torvalds /* Bounds check. */
3811da177e4SLinus Torvalds if ((u8*)ie < (u8*)ia || (u8*)ie +
3821da177e4SLinus Torvalds sizeof(INDEX_ENTRY_HEADER) > index_end ||
3831da177e4SLinus Torvalds (u8*)ie + le16_to_cpu(ie->key_length) >
3841da177e4SLinus Torvalds index_end) {
3851da177e4SLinus Torvalds ntfs_error(sb, "Index entry out of bounds in "
3861da177e4SLinus Torvalds "directory inode 0x%lx.",
3871da177e4SLinus Torvalds dir_ni->mft_no);
3881da177e4SLinus Torvalds goto unm_err_out;
3891da177e4SLinus Torvalds }
3901da177e4SLinus Torvalds /*
3911da177e4SLinus Torvalds * The last entry cannot contain a name. It can however contain
3921da177e4SLinus Torvalds * a pointer to a child node in the B+tree so we just break out.
3931da177e4SLinus Torvalds */
3941da177e4SLinus Torvalds if (ie->flags & INDEX_ENTRY_END)
3951da177e4SLinus Torvalds break;
3961da177e4SLinus Torvalds /*
3971da177e4SLinus Torvalds * We perform a case sensitive comparison and if that matches
3981da177e4SLinus Torvalds * we are done and return the mft reference of the inode (i.e.
3991da177e4SLinus Torvalds * the inode number together with the sequence number for
4001da177e4SLinus Torvalds * consistency checking). We convert it to cpu format before
4011da177e4SLinus Torvalds * returning.
4021da177e4SLinus Torvalds */
4031da177e4SLinus Torvalds if (ntfs_are_names_equal(uname, uname_len,
4041da177e4SLinus Torvalds (ntfschar*)&ie->key.file_name.file_name,
4051da177e4SLinus Torvalds ie->key.file_name.file_name_length,
4061da177e4SLinus Torvalds CASE_SENSITIVE, vol->upcase, vol->upcase_len)) {
4071da177e4SLinus Torvalds found_it2:
4081da177e4SLinus Torvalds /*
4091da177e4SLinus Torvalds * We have a perfect match, so we don't need to care
4101da177e4SLinus Torvalds * about having matched imperfectly before, so we can
4111da177e4SLinus Torvalds * free name and set *res to NULL.
4121da177e4SLinus Torvalds * However, if the perfect match is a short file name,
4131da177e4SLinus Torvalds * we need to signal this through *res, so that
4141da177e4SLinus Torvalds * ntfs_lookup() can fix dcache aliasing issues.
4151da177e4SLinus Torvalds * As an optimization we just reuse an existing
4161da177e4SLinus Torvalds * allocation of *res.
4171da177e4SLinus Torvalds */
4181da177e4SLinus Torvalds if (ie->key.file_name.file_name_type == FILE_NAME_DOS) {
4191da177e4SLinus Torvalds if (!name) {
4201da177e4SLinus Torvalds name = kmalloc(sizeof(ntfs_name),
4211da177e4SLinus Torvalds GFP_NOFS);
4221da177e4SLinus Torvalds if (!name) {
4231da177e4SLinus Torvalds err = -ENOMEM;
4241da177e4SLinus Torvalds goto unm_err_out;
4251da177e4SLinus Torvalds }
4261da177e4SLinus Torvalds }
4271da177e4SLinus Torvalds name->mref = le64_to_cpu(
4281da177e4SLinus Torvalds ie->data.dir.indexed_file);
4291da177e4SLinus Torvalds name->type = FILE_NAME_DOS;
4301da177e4SLinus Torvalds name->len = 0;
4311da177e4SLinus Torvalds *res = name;
4321da177e4SLinus Torvalds } else {
4331da177e4SLinus Torvalds kfree(name);
4341da177e4SLinus Torvalds *res = NULL;
4351da177e4SLinus Torvalds }
4361da177e4SLinus Torvalds mref = le64_to_cpu(ie->data.dir.indexed_file);
4371da177e4SLinus Torvalds unlock_page(page);
4381da177e4SLinus Torvalds ntfs_unmap_page(page);
4391da177e4SLinus Torvalds return mref;
4401da177e4SLinus Torvalds }
4411da177e4SLinus Torvalds /*
4421da177e4SLinus Torvalds * For a case insensitive mount, we also perform a case
4431da177e4SLinus Torvalds * insensitive comparison (provided the file name is not in the
4441da177e4SLinus Torvalds * POSIX namespace). If the comparison matches, and the name is
4451da177e4SLinus Torvalds * in the WIN32 namespace, we cache the filename in *res so
4461da177e4SLinus Torvalds * that the caller, ntfs_lookup(), can work on it. If the
4471da177e4SLinus Torvalds * comparison matches, and the name is in the DOS namespace, we
4481da177e4SLinus Torvalds * only cache the mft reference and the file name type (we set
4491da177e4SLinus Torvalds * the name length to zero for simplicity).
4501da177e4SLinus Torvalds */
4511da177e4SLinus Torvalds if (!NVolCaseSensitive(vol) &&
4521da177e4SLinus Torvalds ie->key.file_name.file_name_type &&
4531da177e4SLinus Torvalds ntfs_are_names_equal(uname, uname_len,
4541da177e4SLinus Torvalds (ntfschar*)&ie->key.file_name.file_name,
4551da177e4SLinus Torvalds ie->key.file_name.file_name_length,
4561da177e4SLinus Torvalds IGNORE_CASE, vol->upcase, vol->upcase_len)) {
4571da177e4SLinus Torvalds int name_size = sizeof(ntfs_name);
4581da177e4SLinus Torvalds u8 type = ie->key.file_name.file_name_type;
4591da177e4SLinus Torvalds u8 len = ie->key.file_name.file_name_length;
4601da177e4SLinus Torvalds
4611da177e4SLinus Torvalds /* Only one case insensitive matching name allowed. */
4621da177e4SLinus Torvalds if (name) {
4631da177e4SLinus Torvalds ntfs_error(sb, "Found already allocated name "
4641da177e4SLinus Torvalds "in phase 2. Please run chkdsk "
4651da177e4SLinus Torvalds "and if that doesn't find any "
4661da177e4SLinus Torvalds "errors please report you saw "
4671da177e4SLinus Torvalds "this message to "
4681da177e4SLinus Torvalds "linux-ntfs-dev@lists."
4691da177e4SLinus Torvalds "sourceforge.net.");
4701da177e4SLinus Torvalds unlock_page(page);
4711da177e4SLinus Torvalds ntfs_unmap_page(page);
4721da177e4SLinus Torvalds goto dir_err_out;
4731da177e4SLinus Torvalds }
4741da177e4SLinus Torvalds
4751da177e4SLinus Torvalds if (type != FILE_NAME_DOS)
4761da177e4SLinus Torvalds name_size += len * sizeof(ntfschar);
4771da177e4SLinus Torvalds name = kmalloc(name_size, GFP_NOFS);
4781da177e4SLinus Torvalds if (!name) {
4791da177e4SLinus Torvalds err = -ENOMEM;
4801da177e4SLinus Torvalds goto unm_err_out;
4811da177e4SLinus Torvalds }
4821da177e4SLinus Torvalds name->mref = le64_to_cpu(ie->data.dir.indexed_file);
4831da177e4SLinus Torvalds name->type = type;
4841da177e4SLinus Torvalds if (type != FILE_NAME_DOS) {
4851da177e4SLinus Torvalds name->len = len;
4861da177e4SLinus Torvalds memcpy(name->name, ie->key.file_name.file_name,
4871da177e4SLinus Torvalds len * sizeof(ntfschar));
4881da177e4SLinus Torvalds } else
4891da177e4SLinus Torvalds name->len = 0;
4901da177e4SLinus Torvalds *res = name;
4911da177e4SLinus Torvalds }
4921da177e4SLinus Torvalds /*
4931da177e4SLinus Torvalds * Not a perfect match, need to do full blown collation so we
4941da177e4SLinus Torvalds * know which way in the B+tree we have to go.
4951da177e4SLinus Torvalds */
4961da177e4SLinus Torvalds rc = ntfs_collate_names(uname, uname_len,
4971da177e4SLinus Torvalds (ntfschar*)&ie->key.file_name.file_name,
4981da177e4SLinus Torvalds ie->key.file_name.file_name_length, 1,
4991da177e4SLinus Torvalds IGNORE_CASE, vol->upcase, vol->upcase_len);
5001da177e4SLinus Torvalds /*
5011da177e4SLinus Torvalds * If uname collates before the name of the current entry, there
5021da177e4SLinus Torvalds * is definitely no such name in this index but we might need to
5031da177e4SLinus Torvalds * descend into the B+tree so we just break out of the loop.
5041da177e4SLinus Torvalds */
5051da177e4SLinus Torvalds if (rc == -1)
5061da177e4SLinus Torvalds break;
5071da177e4SLinus Torvalds /* The names are not equal, continue the search. */
5081da177e4SLinus Torvalds if (rc)
5091da177e4SLinus Torvalds continue;
5101da177e4SLinus Torvalds /*
5111da177e4SLinus Torvalds * Names match with case insensitive comparison, now try the
5121da177e4SLinus Torvalds * case sensitive comparison, which is required for proper
5131da177e4SLinus Torvalds * collation.
5141da177e4SLinus Torvalds */
5151da177e4SLinus Torvalds rc = ntfs_collate_names(uname, uname_len,
5161da177e4SLinus Torvalds (ntfschar*)&ie->key.file_name.file_name,
5171da177e4SLinus Torvalds ie->key.file_name.file_name_length, 1,
5181da177e4SLinus Torvalds CASE_SENSITIVE, vol->upcase, vol->upcase_len);
5191da177e4SLinus Torvalds if (rc == -1)
5201da177e4SLinus Torvalds break;
5211da177e4SLinus Torvalds if (rc)
5221da177e4SLinus Torvalds continue;
5231da177e4SLinus Torvalds /*
5241da177e4SLinus Torvalds * Perfect match, this will never happen as the
5251da177e4SLinus Torvalds * ntfs_are_names_equal() call will have gotten a match but we
5261da177e4SLinus Torvalds * still treat it correctly.
5271da177e4SLinus Torvalds */
5281da177e4SLinus Torvalds goto found_it2;
5291da177e4SLinus Torvalds }
5301da177e4SLinus Torvalds /*
5311da177e4SLinus Torvalds * We have finished with this index buffer without success. Check for
5321da177e4SLinus Torvalds * the presence of a child node.
5331da177e4SLinus Torvalds */
5341da177e4SLinus Torvalds if (ie->flags & INDEX_ENTRY_NODE) {
5351da177e4SLinus Torvalds if ((ia->index.flags & NODE_MASK) == LEAF_NODE) {
5361da177e4SLinus Torvalds ntfs_error(sb, "Index entry with child node found in "
5371da177e4SLinus Torvalds "a leaf node in directory inode 0x%lx.",
5381da177e4SLinus Torvalds dir_ni->mft_no);
5391da177e4SLinus Torvalds goto unm_err_out;
5401da177e4SLinus Torvalds }
5411da177e4SLinus Torvalds /* Child node present, descend into it. */
5421da177e4SLinus Torvalds old_vcn = vcn;
5431da177e4SLinus Torvalds vcn = sle64_to_cpup((sle64*)((u8*)ie +
5441da177e4SLinus Torvalds le16_to_cpu(ie->length) - 8));
5451da177e4SLinus Torvalds if (vcn >= 0) {
5461da177e4SLinus Torvalds /* If vcn is in the same page cache page as old_vcn we
5471da177e4SLinus Torvalds * recycle the mapped page. */
5481da177e4SLinus Torvalds if (old_vcn << vol->cluster_size_bits >>
54909cbfeafSKirill A. Shutemov PAGE_SHIFT == vcn <<
5501da177e4SLinus Torvalds vol->cluster_size_bits >>
55109cbfeafSKirill A. Shutemov PAGE_SHIFT)
5521da177e4SLinus Torvalds goto fast_descend_into_child_node;
5531da177e4SLinus Torvalds unlock_page(page);
5541da177e4SLinus Torvalds ntfs_unmap_page(page);
5551da177e4SLinus Torvalds goto descend_into_child_node;
5561da177e4SLinus Torvalds }
5571da177e4SLinus Torvalds ntfs_error(sb, "Negative child node vcn in directory inode "
5581da177e4SLinus Torvalds "0x%lx.", dir_ni->mft_no);
5591da177e4SLinus Torvalds goto unm_err_out;
5601da177e4SLinus Torvalds }
5611da177e4SLinus Torvalds /*
5621da177e4SLinus Torvalds * No child node present, return -ENOENT, unless we have got a matching
5631da177e4SLinus Torvalds * name cached in name in which case return the mft reference
5641da177e4SLinus Torvalds * associated with it.
5651da177e4SLinus Torvalds */
5661da177e4SLinus Torvalds if (name) {
5671da177e4SLinus Torvalds unlock_page(page);
5681da177e4SLinus Torvalds ntfs_unmap_page(page);
5691da177e4SLinus Torvalds return name->mref;
5701da177e4SLinus Torvalds }
5711da177e4SLinus Torvalds ntfs_debug("Entry not found.");
5721da177e4SLinus Torvalds err = -ENOENT;
5731da177e4SLinus Torvalds unm_err_out:
5741da177e4SLinus Torvalds unlock_page(page);
5751da177e4SLinus Torvalds ntfs_unmap_page(page);
5761da177e4SLinus Torvalds err_out:
5771da177e4SLinus Torvalds if (!err)
5781da177e4SLinus Torvalds err = -EIO;
5791da177e4SLinus Torvalds if (ctx)
5801da177e4SLinus Torvalds ntfs_attr_put_search_ctx(ctx);
5811da177e4SLinus Torvalds if (m)
5821da177e4SLinus Torvalds unmap_mft_record(dir_ni);
5831da177e4SLinus Torvalds if (name) {
5841da177e4SLinus Torvalds kfree(name);
5851da177e4SLinus Torvalds *res = NULL;
5861da177e4SLinus Torvalds }
5871da177e4SLinus Torvalds return ERR_MREF(err);
5881da177e4SLinus Torvalds dir_err_out:
5891da177e4SLinus Torvalds ntfs_error(sb, "Corrupt directory. Aborting lookup.");
5901da177e4SLinus Torvalds goto err_out;
5911da177e4SLinus Torvalds }
5921da177e4SLinus Torvalds
5931da177e4SLinus Torvalds #if 0
5941da177e4SLinus Torvalds
5951da177e4SLinus Torvalds // TODO: (AIA)
5961da177e4SLinus Torvalds // The algorithm embedded in this code will be required for the time when we
5971da177e4SLinus Torvalds // want to support adding of entries to directories, where we require correct
5981da177e4SLinus Torvalds // collation of file names in order not to cause corruption of the filesystem.
5991da177e4SLinus Torvalds
6001da177e4SLinus Torvalds /**
6011da177e4SLinus Torvalds * ntfs_lookup_inode_by_name - find an inode in a directory given its name
6021da177e4SLinus Torvalds * @dir_ni: ntfs inode of the directory in which to search for the name
6031da177e4SLinus Torvalds * @uname: Unicode name for which to search in the directory
6041da177e4SLinus Torvalds * @uname_len: length of the name @uname in Unicode characters
6051da177e4SLinus Torvalds *
6061da177e4SLinus Torvalds * Look for an inode with name @uname in the directory with inode @dir_ni.
6071da177e4SLinus Torvalds * ntfs_lookup_inode_by_name() walks the contents of the directory looking for
6081da177e4SLinus Torvalds * the Unicode name. If the name is found in the directory, the corresponding
6091da177e4SLinus Torvalds * inode number (>= 0) is returned as a mft reference in cpu format, i.e. it
6101da177e4SLinus Torvalds * is a 64-bit number containing the sequence number.
6111da177e4SLinus Torvalds *
6121da177e4SLinus Torvalds * On error, a negative value is returned corresponding to the error code. In
6131da177e4SLinus Torvalds * particular if the inode is not found -ENOENT is returned. Note that you
6141da177e4SLinus Torvalds * can't just check the return value for being negative, you have to check the
6151da177e4SLinus Torvalds * inode number for being negative which you can extract using MREC(return
6161da177e4SLinus Torvalds * value).
6171da177e4SLinus Torvalds *
6181da177e4SLinus Torvalds * Note, @uname_len does not include the (optional) terminating NULL character.
6191da177e4SLinus Torvalds */
6201da177e4SLinus Torvalds u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const ntfschar *uname,
6211da177e4SLinus Torvalds const int uname_len)
6221da177e4SLinus Torvalds {
6231da177e4SLinus Torvalds ntfs_volume *vol = dir_ni->vol;
6241da177e4SLinus Torvalds struct super_block *sb = vol->sb;
6251da177e4SLinus Torvalds MFT_RECORD *m;
6261da177e4SLinus Torvalds INDEX_ROOT *ir;
6271da177e4SLinus Torvalds INDEX_ENTRY *ie;
6281da177e4SLinus Torvalds INDEX_ALLOCATION *ia;
6291da177e4SLinus Torvalds u8 *index_end;
6301da177e4SLinus Torvalds u64 mref;
6311da177e4SLinus Torvalds ntfs_attr_search_ctx *ctx;
6321da177e4SLinus Torvalds int err, rc;
6331da177e4SLinus Torvalds IGNORE_CASE_BOOL ic;
6341da177e4SLinus Torvalds VCN vcn, old_vcn;
6351da177e4SLinus Torvalds struct address_space *ia_mapping;
6361da177e4SLinus Torvalds struct page *page;
6371da177e4SLinus Torvalds u8 *kaddr;
6381da177e4SLinus Torvalds
6391da177e4SLinus Torvalds /* Get hold of the mft record for the directory. */
6401da177e4SLinus Torvalds m = map_mft_record(dir_ni);
6411da177e4SLinus Torvalds if (IS_ERR(m)) {
6421da177e4SLinus Torvalds ntfs_error(sb, "map_mft_record() failed with error code %ld.",
6431da177e4SLinus Torvalds -PTR_ERR(m));
6441da177e4SLinus Torvalds return ERR_MREF(PTR_ERR(m));
6451da177e4SLinus Torvalds }
6461da177e4SLinus Torvalds ctx = ntfs_attr_get_search_ctx(dir_ni, m);
6471da177e4SLinus Torvalds if (!ctx) {
6481da177e4SLinus Torvalds err = -ENOMEM;
6491da177e4SLinus Torvalds goto err_out;
6501da177e4SLinus Torvalds }
6511da177e4SLinus Torvalds /* Find the index root attribute in the mft record. */
6521da177e4SLinus Torvalds err = ntfs_attr_lookup(AT_INDEX_ROOT, I30, 4, CASE_SENSITIVE, 0, NULL,
6531da177e4SLinus Torvalds 0, ctx);
6541da177e4SLinus Torvalds if (unlikely(err)) {
6551da177e4SLinus Torvalds if (err == -ENOENT) {
6561da177e4SLinus Torvalds ntfs_error(sb, "Index root attribute missing in "
6571da177e4SLinus Torvalds "directory inode 0x%lx.",
6581da177e4SLinus Torvalds dir_ni->mft_no);
6591da177e4SLinus Torvalds err = -EIO;
6601da177e4SLinus Torvalds }
6611da177e4SLinus Torvalds goto err_out;
6621da177e4SLinus Torvalds }
6631da177e4SLinus Torvalds /* Get to the index root value (it's been verified in read_inode). */
6641da177e4SLinus Torvalds ir = (INDEX_ROOT*)((u8*)ctx->attr +
6651da177e4SLinus Torvalds le16_to_cpu(ctx->attr->data.resident.value_offset));
6661da177e4SLinus Torvalds index_end = (u8*)&ir->index + le32_to_cpu(ir->index.index_length);
6671da177e4SLinus Torvalds /* The first index entry. */
6681da177e4SLinus Torvalds ie = (INDEX_ENTRY*)((u8*)&ir->index +
6691da177e4SLinus Torvalds le32_to_cpu(ir->index.entries_offset));
6701da177e4SLinus Torvalds /*
6711da177e4SLinus Torvalds * Loop until we exceed valid memory (corruption case) or until we
6721da177e4SLinus Torvalds * reach the last entry.
6731da177e4SLinus Torvalds */
6741da177e4SLinus Torvalds for (;; ie = (INDEX_ENTRY*)((u8*)ie + le16_to_cpu(ie->length))) {
6751da177e4SLinus Torvalds /* Bounds checks. */
6761da177e4SLinus Torvalds if ((u8*)ie < (u8*)ctx->mrec || (u8*)ie +
6771da177e4SLinus Torvalds sizeof(INDEX_ENTRY_HEADER) > index_end ||
6781da177e4SLinus Torvalds (u8*)ie + le16_to_cpu(ie->key_length) >
6791da177e4SLinus Torvalds index_end)
6801da177e4SLinus Torvalds goto dir_err_out;
6811da177e4SLinus Torvalds /*
6821da177e4SLinus Torvalds * The last entry cannot contain a name. It can however contain
6831da177e4SLinus Torvalds * a pointer to a child node in the B+tree so we just break out.
6841da177e4SLinus Torvalds */
6851da177e4SLinus Torvalds if (ie->flags & INDEX_ENTRY_END)
6861da177e4SLinus Torvalds break;
6871da177e4SLinus Torvalds /*
6881da177e4SLinus Torvalds * If the current entry has a name type of POSIX, the name is
6891da177e4SLinus Torvalds * case sensitive and not otherwise. This has the effect of us
6901da177e4SLinus Torvalds * not being able to access any POSIX file names which collate
6911da177e4SLinus Torvalds * after the non-POSIX one when they only differ in case, but
6921da177e4SLinus Torvalds * anyone doing screwy stuff like that deserves to burn in
6931da177e4SLinus Torvalds * hell... Doing that kind of stuff on NT4 actually causes
6941da177e4SLinus Torvalds * corruption on the partition even when using SP6a and Linux
6951da177e4SLinus Torvalds * is not involved at all.
6961da177e4SLinus Torvalds */
6971da177e4SLinus Torvalds ic = ie->key.file_name.file_name_type ? IGNORE_CASE :
6981da177e4SLinus Torvalds CASE_SENSITIVE;
6991da177e4SLinus Torvalds /*
7001da177e4SLinus Torvalds * If the names match perfectly, we are done and return the
7011da177e4SLinus Torvalds * mft reference of the inode (i.e. the inode number together
7021da177e4SLinus Torvalds * with the sequence number for consistency checking. We
7031da177e4SLinus Torvalds * convert it to cpu format before returning.
7041da177e4SLinus Torvalds */
7051da177e4SLinus Torvalds if (ntfs_are_names_equal(uname, uname_len,
7061da177e4SLinus Torvalds (ntfschar*)&ie->key.file_name.file_name,
7071da177e4SLinus Torvalds ie->key.file_name.file_name_length, ic,
7081da177e4SLinus Torvalds vol->upcase, vol->upcase_len)) {
7091da177e4SLinus Torvalds found_it:
7101da177e4SLinus Torvalds mref = le64_to_cpu(ie->data.dir.indexed_file);
7111da177e4SLinus Torvalds ntfs_attr_put_search_ctx(ctx);
7121da177e4SLinus Torvalds unmap_mft_record(dir_ni);
7131da177e4SLinus Torvalds return mref;
7141da177e4SLinus Torvalds }
7151da177e4SLinus Torvalds /*
7161da177e4SLinus Torvalds * Not a perfect match, need to do full blown collation so we
7171da177e4SLinus Torvalds * know which way in the B+tree we have to go.
7181da177e4SLinus Torvalds */
7191da177e4SLinus Torvalds rc = ntfs_collate_names(uname, uname_len,
7201da177e4SLinus Torvalds (ntfschar*)&ie->key.file_name.file_name,
7211da177e4SLinus Torvalds ie->key.file_name.file_name_length, 1,
7221da177e4SLinus Torvalds IGNORE_CASE, vol->upcase, vol->upcase_len);
7231da177e4SLinus Torvalds /*
7241da177e4SLinus Torvalds * If uname collates before the name of the current entry, there
7251da177e4SLinus Torvalds * is definitely no such name in this index but we might need to
7261da177e4SLinus Torvalds * descend into the B+tree so we just break out of the loop.
7271da177e4SLinus Torvalds */
7281da177e4SLinus Torvalds if (rc == -1)
7291da177e4SLinus Torvalds break;
7301da177e4SLinus Torvalds /* The names are not equal, continue the search. */
7311da177e4SLinus Torvalds if (rc)
7321da177e4SLinus Torvalds continue;
7331da177e4SLinus Torvalds /*
7341da177e4SLinus Torvalds * Names match with case insensitive comparison, now try the
7351da177e4SLinus Torvalds * case sensitive comparison, which is required for proper
7361da177e4SLinus Torvalds * collation.
7371da177e4SLinus Torvalds */
7381da177e4SLinus Torvalds rc = ntfs_collate_names(uname, uname_len,
7391da177e4SLinus Torvalds (ntfschar*)&ie->key.file_name.file_name,
7401da177e4SLinus Torvalds ie->key.file_name.file_name_length, 1,
7411da177e4SLinus Torvalds CASE_SENSITIVE, vol->upcase, vol->upcase_len);
7421da177e4SLinus Torvalds if (rc == -1)
7431da177e4SLinus Torvalds break;
7441da177e4SLinus Torvalds if (rc)
7451da177e4SLinus Torvalds continue;
7461da177e4SLinus Torvalds /*
7471da177e4SLinus Torvalds * Perfect match, this will never happen as the
7481da177e4SLinus Torvalds * ntfs_are_names_equal() call will have gotten a match but we
7491da177e4SLinus Torvalds * still treat it correctly.
7501da177e4SLinus Torvalds */
7511da177e4SLinus Torvalds goto found_it;
7521da177e4SLinus Torvalds }
7531da177e4SLinus Torvalds /*
7541da177e4SLinus Torvalds * We have finished with this index without success. Check for the
7551da177e4SLinus Torvalds * presence of a child node.
7561da177e4SLinus Torvalds */
7571da177e4SLinus Torvalds if (!(ie->flags & INDEX_ENTRY_NODE)) {
7581da177e4SLinus Torvalds /* No child node, return -ENOENT. */
7591da177e4SLinus Torvalds err = -ENOENT;
7601da177e4SLinus Torvalds goto err_out;
7611da177e4SLinus Torvalds } /* Child node present, descend into it. */
7621da177e4SLinus Torvalds /* Consistency check: Verify that an index allocation exists. */
7631da177e4SLinus Torvalds if (!NInoIndexAllocPresent(dir_ni)) {
7641da177e4SLinus Torvalds ntfs_error(sb, "No index allocation attribute but index entry "
7651da177e4SLinus Torvalds "requires one. Directory inode 0x%lx is "
7661da177e4SLinus Torvalds "corrupt or driver bug.", dir_ni->mft_no);
7671da177e4SLinus Torvalds goto err_out;
7681da177e4SLinus Torvalds }
7691da177e4SLinus Torvalds /* Get the starting vcn of the index_block holding the child node. */
7701da177e4SLinus Torvalds vcn = sle64_to_cpup((u8*)ie + le16_to_cpu(ie->length) - 8);
7711da177e4SLinus Torvalds ia_mapping = VFS_I(dir_ni)->i_mapping;
7721da177e4SLinus Torvalds /*
7731da177e4SLinus Torvalds * We are done with the index root and the mft record. Release them,
7741da177e4SLinus Torvalds * otherwise we deadlock with ntfs_map_page().
7751da177e4SLinus Torvalds */
7761da177e4SLinus Torvalds ntfs_attr_put_search_ctx(ctx);
7771da177e4SLinus Torvalds unmap_mft_record(dir_ni);
7781da177e4SLinus Torvalds m = NULL;
7791da177e4SLinus Torvalds ctx = NULL;
7801da177e4SLinus Torvalds descend_into_child_node:
7811da177e4SLinus Torvalds /*
7821da177e4SLinus Torvalds * Convert vcn to index into the index allocation attribute in units
783ea1754a0SKirill A. Shutemov * of PAGE_SIZE and map the page cache page, reading it from
7841da177e4SLinus Torvalds * disk if necessary.
7851da177e4SLinus Torvalds */
7861da177e4SLinus Torvalds page = ntfs_map_page(ia_mapping, vcn <<
787ea1754a0SKirill A. Shutemov dir_ni->itype.index.vcn_size_bits >> PAGE_SHIFT);
7881da177e4SLinus Torvalds if (IS_ERR(page)) {
7891da177e4SLinus Torvalds ntfs_error(sb, "Failed to map directory index page, error %ld.",
7901da177e4SLinus Torvalds -PTR_ERR(page));
7911da177e4SLinus Torvalds err = PTR_ERR(page);
7921da177e4SLinus Torvalds goto err_out;
7931da177e4SLinus Torvalds }
7941da177e4SLinus Torvalds lock_page(page);
7951da177e4SLinus Torvalds kaddr = (u8*)page_address(page);
7961da177e4SLinus Torvalds fast_descend_into_child_node:
7971da177e4SLinus Torvalds /* Get to the index allocation block. */
7981da177e4SLinus Torvalds ia = (INDEX_ALLOCATION*)(kaddr + ((vcn <<
799ea1754a0SKirill A. Shutemov dir_ni->itype.index.vcn_size_bits) & ~PAGE_MASK));
8001da177e4SLinus Torvalds /* Bounds checks. */
801ea1754a0SKirill A. Shutemov if ((u8*)ia < kaddr || (u8*)ia > kaddr + PAGE_SIZE) {
8021da177e4SLinus Torvalds ntfs_error(sb, "Out of bounds check failed. Corrupt directory "
8031da177e4SLinus Torvalds "inode 0x%lx or driver bug.", dir_ni->mft_no);
8041da177e4SLinus Torvalds goto unm_err_out;
8051da177e4SLinus Torvalds }
8061da177e4SLinus Torvalds /* Catch multi sector transfer fixup errors. */
8071da177e4SLinus Torvalds if (unlikely(!ntfs_is_indx_record(ia->magic))) {
8081da177e4SLinus Torvalds ntfs_error(sb, "Directory index record with vcn 0x%llx is "
8091da177e4SLinus Torvalds "corrupt. Corrupt inode 0x%lx. Run chkdsk.",
8101da177e4SLinus Torvalds (unsigned long long)vcn, dir_ni->mft_no);
8111da177e4SLinus Torvalds goto unm_err_out;
8121da177e4SLinus Torvalds }
8131da177e4SLinus Torvalds if (sle64_to_cpu(ia->index_block_vcn) != vcn) {
8141da177e4SLinus Torvalds ntfs_error(sb, "Actual VCN (0x%llx) of index buffer is "
8151da177e4SLinus Torvalds "different from expected VCN (0x%llx). "
8161da177e4SLinus Torvalds "Directory inode 0x%lx is corrupt or driver "
8171da177e4SLinus Torvalds "bug.", (unsigned long long)
8181da177e4SLinus Torvalds sle64_to_cpu(ia->index_block_vcn),
8191da177e4SLinus Torvalds (unsigned long long)vcn, dir_ni->mft_no);
8201da177e4SLinus Torvalds goto unm_err_out;
8211da177e4SLinus Torvalds }
8221da177e4SLinus Torvalds if (le32_to_cpu(ia->index.allocated_size) + 0x18 !=
8231da177e4SLinus Torvalds dir_ni->itype.index.block_size) {
8241da177e4SLinus Torvalds ntfs_error(sb, "Index buffer (VCN 0x%llx) of directory inode "
8251da177e4SLinus Torvalds "0x%lx has a size (%u) differing from the "
8261da177e4SLinus Torvalds "directory specified size (%u). Directory "
8271da177e4SLinus Torvalds "inode is corrupt or driver bug.",
8281da177e4SLinus Torvalds (unsigned long long)vcn, dir_ni->mft_no,
8291da177e4SLinus Torvalds le32_to_cpu(ia->index.allocated_size) + 0x18,
8301da177e4SLinus Torvalds dir_ni->itype.index.block_size);
8311da177e4SLinus Torvalds goto unm_err_out;
8321da177e4SLinus Torvalds }
8331da177e4SLinus Torvalds index_end = (u8*)ia + dir_ni->itype.index.block_size;
834ea1754a0SKirill A. Shutemov if (index_end > kaddr + PAGE_SIZE) {
8351da177e4SLinus Torvalds ntfs_error(sb, "Index buffer (VCN 0x%llx) of directory inode "
8361da177e4SLinus Torvalds "0x%lx crosses page boundary. Impossible! "
8371da177e4SLinus Torvalds "Cannot access! This is probably a bug in the "
8381da177e4SLinus Torvalds "driver.", (unsigned long long)vcn,
8391da177e4SLinus Torvalds dir_ni->mft_no);
8401da177e4SLinus Torvalds goto unm_err_out;
8411da177e4SLinus Torvalds }
8421da177e4SLinus Torvalds index_end = (u8*)&ia->index + le32_to_cpu(ia->index.index_length);
8431da177e4SLinus Torvalds if (index_end > (u8*)ia + dir_ni->itype.index.block_size) {
8441da177e4SLinus Torvalds ntfs_error(sb, "Size of index buffer (VCN 0x%llx) of directory "
8451da177e4SLinus Torvalds "inode 0x%lx exceeds maximum size.",
8461da177e4SLinus Torvalds (unsigned long long)vcn, dir_ni->mft_no);
8471da177e4SLinus Torvalds goto unm_err_out;
8481da177e4SLinus Torvalds }
8491da177e4SLinus Torvalds /* The first index entry. */
8501da177e4SLinus Torvalds ie = (INDEX_ENTRY*)((u8*)&ia->index +
8511da177e4SLinus Torvalds le32_to_cpu(ia->index.entries_offset));
8521da177e4SLinus Torvalds /*
8531da177e4SLinus Torvalds * Iterate similar to above big loop but applied to index buffer, thus
8541da177e4SLinus Torvalds * loop until we exceed valid memory (corruption case) or until we
8551da177e4SLinus Torvalds * reach the last entry.
8561da177e4SLinus Torvalds */
8571da177e4SLinus Torvalds for (;; ie = (INDEX_ENTRY*)((u8*)ie + le16_to_cpu(ie->length))) {
8581da177e4SLinus Torvalds /* Bounds check. */
8591da177e4SLinus Torvalds if ((u8*)ie < (u8*)ia || (u8*)ie +
8601da177e4SLinus Torvalds sizeof(INDEX_ENTRY_HEADER) > index_end ||
8611da177e4SLinus Torvalds (u8*)ie + le16_to_cpu(ie->key_length) >
8621da177e4SLinus Torvalds index_end) {
8631da177e4SLinus Torvalds ntfs_error(sb, "Index entry out of bounds in "
8641da177e4SLinus Torvalds "directory inode 0x%lx.",
8651da177e4SLinus Torvalds dir_ni->mft_no);
8661da177e4SLinus Torvalds goto unm_err_out;
8671da177e4SLinus Torvalds }
8681da177e4SLinus Torvalds /*
8691da177e4SLinus Torvalds * The last entry cannot contain a name. It can however contain
8701da177e4SLinus Torvalds * a pointer to a child node in the B+tree so we just break out.
8711da177e4SLinus Torvalds */
8721da177e4SLinus Torvalds if (ie->flags & INDEX_ENTRY_END)
8731da177e4SLinus Torvalds break;
8741da177e4SLinus Torvalds /*
8751da177e4SLinus Torvalds * If the current entry has a name type of POSIX, the name is
8761da177e4SLinus Torvalds * case sensitive and not otherwise. This has the effect of us
8771da177e4SLinus Torvalds * not being able to access any POSIX file names which collate
8781da177e4SLinus Torvalds * after the non-POSIX one when they only differ in case, but
8791da177e4SLinus Torvalds * anyone doing screwy stuff like that deserves to burn in
8801da177e4SLinus Torvalds * hell... Doing that kind of stuff on NT4 actually causes
8811da177e4SLinus Torvalds * corruption on the partition even when using SP6a and Linux
8821da177e4SLinus Torvalds * is not involved at all.
8831da177e4SLinus Torvalds */
8841da177e4SLinus Torvalds ic = ie->key.file_name.file_name_type ? IGNORE_CASE :
8851da177e4SLinus Torvalds CASE_SENSITIVE;
8861da177e4SLinus Torvalds /*
8871da177e4SLinus Torvalds * If the names match perfectly, we are done and return the
8881da177e4SLinus Torvalds * mft reference of the inode (i.e. the inode number together
8891da177e4SLinus Torvalds * with the sequence number for consistency checking. We
8901da177e4SLinus Torvalds * convert it to cpu format before returning.
8911da177e4SLinus Torvalds */
8921da177e4SLinus Torvalds if (ntfs_are_names_equal(uname, uname_len,
8931da177e4SLinus Torvalds (ntfschar*)&ie->key.file_name.file_name,
8941da177e4SLinus Torvalds ie->key.file_name.file_name_length, ic,
8951da177e4SLinus Torvalds vol->upcase, vol->upcase_len)) {
8961da177e4SLinus Torvalds found_it2:
8971da177e4SLinus Torvalds mref = le64_to_cpu(ie->data.dir.indexed_file);
8981da177e4SLinus Torvalds unlock_page(page);
8991da177e4SLinus Torvalds ntfs_unmap_page(page);
9001da177e4SLinus Torvalds return mref;
9011da177e4SLinus Torvalds }
9021da177e4SLinus Torvalds /*
9031da177e4SLinus Torvalds * Not a perfect match, need to do full blown collation so we
9041da177e4SLinus Torvalds * know which way in the B+tree we have to go.
9051da177e4SLinus Torvalds */
9061da177e4SLinus Torvalds rc = ntfs_collate_names(uname, uname_len,
9071da177e4SLinus Torvalds (ntfschar*)&ie->key.file_name.file_name,
9081da177e4SLinus Torvalds ie->key.file_name.file_name_length, 1,
9091da177e4SLinus Torvalds IGNORE_CASE, vol->upcase, vol->upcase_len);
9101da177e4SLinus Torvalds /*
9111da177e4SLinus Torvalds * If uname collates before the name of the current entry, there
9121da177e4SLinus Torvalds * is definitely no such name in this index but we might need to
9131da177e4SLinus Torvalds * descend into the B+tree so we just break out of the loop.
9141da177e4SLinus Torvalds */
9151da177e4SLinus Torvalds if (rc == -1)
9161da177e4SLinus Torvalds break;
9171da177e4SLinus Torvalds /* The names are not equal, continue the search. */
9181da177e4SLinus Torvalds if (rc)
9191da177e4SLinus Torvalds continue;
9201da177e4SLinus Torvalds /*
9211da177e4SLinus Torvalds * Names match with case insensitive comparison, now try the
9221da177e4SLinus Torvalds * case sensitive comparison, which is required for proper
9231da177e4SLinus Torvalds * collation.
9241da177e4SLinus Torvalds */
9251da177e4SLinus Torvalds rc = ntfs_collate_names(uname, uname_len,
9261da177e4SLinus Torvalds (ntfschar*)&ie->key.file_name.file_name,
9271da177e4SLinus Torvalds ie->key.file_name.file_name_length, 1,
9281da177e4SLinus Torvalds CASE_SENSITIVE, vol->upcase, vol->upcase_len);
9291da177e4SLinus Torvalds if (rc == -1)
9301da177e4SLinus Torvalds break;
9311da177e4SLinus Torvalds if (rc)
9321da177e4SLinus Torvalds continue;
9331da177e4SLinus Torvalds /*
9341da177e4SLinus Torvalds * Perfect match, this will never happen as the
9351da177e4SLinus Torvalds * ntfs_are_names_equal() call will have gotten a match but we
9361da177e4SLinus Torvalds * still treat it correctly.
9371da177e4SLinus Torvalds */
9381da177e4SLinus Torvalds goto found_it2;
9391da177e4SLinus Torvalds }
9401da177e4SLinus Torvalds /*
9411da177e4SLinus Torvalds * We have finished with this index buffer without success. Check for
9421da177e4SLinus Torvalds * the presence of a child node.
9431da177e4SLinus Torvalds */
9441da177e4SLinus Torvalds if (ie->flags & INDEX_ENTRY_NODE) {
9451da177e4SLinus Torvalds if ((ia->index.flags & NODE_MASK) == LEAF_NODE) {
9461da177e4SLinus Torvalds ntfs_error(sb, "Index entry with child node found in "
9471da177e4SLinus Torvalds "a leaf node in directory inode 0x%lx.",
9481da177e4SLinus Torvalds dir_ni->mft_no);
9491da177e4SLinus Torvalds goto unm_err_out;
9501da177e4SLinus Torvalds }
9511da177e4SLinus Torvalds /* Child node present, descend into it. */
9521da177e4SLinus Torvalds old_vcn = vcn;
9531da177e4SLinus Torvalds vcn = sle64_to_cpup((u8*)ie + le16_to_cpu(ie->length) - 8);
9541da177e4SLinus Torvalds if (vcn >= 0) {
9551da177e4SLinus Torvalds /* If vcn is in the same page cache page as old_vcn we
9561da177e4SLinus Torvalds * recycle the mapped page. */
9571da177e4SLinus Torvalds if (old_vcn << vol->cluster_size_bits >>
958ea1754a0SKirill A. Shutemov PAGE_SHIFT == vcn <<
9591da177e4SLinus Torvalds vol->cluster_size_bits >>
960ea1754a0SKirill A. Shutemov PAGE_SHIFT)
9611da177e4SLinus Torvalds goto fast_descend_into_child_node;
9621da177e4SLinus Torvalds unlock_page(page);
9631da177e4SLinus Torvalds ntfs_unmap_page(page);
9641da177e4SLinus Torvalds goto descend_into_child_node;
9651da177e4SLinus Torvalds }
9661da177e4SLinus Torvalds ntfs_error(sb, "Negative child node vcn in directory inode "
9671da177e4SLinus Torvalds "0x%lx.", dir_ni->mft_no);
9681da177e4SLinus Torvalds goto unm_err_out;
9691da177e4SLinus Torvalds }
9701da177e4SLinus Torvalds /* No child node, return -ENOENT. */
9711da177e4SLinus Torvalds ntfs_debug("Entry not found.");
9721da177e4SLinus Torvalds err = -ENOENT;
9731da177e4SLinus Torvalds unm_err_out:
9741da177e4SLinus Torvalds unlock_page(page);
9751da177e4SLinus Torvalds ntfs_unmap_page(page);
9761da177e4SLinus Torvalds err_out:
9771da177e4SLinus Torvalds if (!err)
9781da177e4SLinus Torvalds err = -EIO;
9791da177e4SLinus Torvalds if (ctx)
9801da177e4SLinus Torvalds ntfs_attr_put_search_ctx(ctx);
9811da177e4SLinus Torvalds if (m)
9821da177e4SLinus Torvalds unmap_mft_record(dir_ni);
9831da177e4SLinus Torvalds return ERR_MREF(err);
9841da177e4SLinus Torvalds dir_err_out:
9851da177e4SLinus Torvalds ntfs_error(sb, "Corrupt directory. Aborting lookup.");
9861da177e4SLinus Torvalds goto err_out;
9871da177e4SLinus Torvalds }
9881da177e4SLinus Torvalds
9891da177e4SLinus Torvalds #endif
9901da177e4SLinus Torvalds
9911da177e4SLinus Torvalds /**
9921da177e4SLinus Torvalds * ntfs_filldir - ntfs specific filldir method
9931da177e4SLinus Torvalds * @vol: current ntfs volume
9941da177e4SLinus Torvalds * @ndir: ntfs inode of current directory
9951da177e4SLinus Torvalds * @ia_page: page in which the index allocation buffer @ie is in resides
9961da177e4SLinus Torvalds * @ie: current index entry
9971da177e4SLinus Torvalds * @name: buffer to use for the converted name
998956ce208SAl Viro * @actor: what to feed the entries to
9991da177e4SLinus Torvalds *
10001da177e4SLinus Torvalds * Convert the Unicode @name to the loaded NLS and pass it to the @filldir
10011da177e4SLinus Torvalds * callback.
10021da177e4SLinus Torvalds *
10031da177e4SLinus Torvalds * If @ia_page is not NULL it is the locked page containing the index
10041da177e4SLinus Torvalds * allocation block containing the index entry @ie.
10051da177e4SLinus Torvalds *
10061da177e4SLinus Torvalds * Note, we drop (and then reacquire) the page lock on @ia_page across the
10071da177e4SLinus Torvalds * @filldir() call otherwise we would deadlock with NFSd when it calls ->lookup
10081da177e4SLinus Torvalds * since ntfs_lookup() will lock the same page. As an optimization, we do not
10091da177e4SLinus Torvalds * retake the lock if we are returning a non-zero value as ntfs_readdir()
10101da177e4SLinus Torvalds * would need to drop the lock immediately anyway.
10111da177e4SLinus Torvalds */
ntfs_filldir(ntfs_volume * vol,ntfs_inode * ndir,struct page * ia_page,INDEX_ENTRY * ie,u8 * name,struct dir_context * actor)1012956ce208SAl Viro static inline int ntfs_filldir(ntfs_volume *vol,
10131da177e4SLinus Torvalds ntfs_inode *ndir, struct page *ia_page, INDEX_ENTRY *ie,
1014956ce208SAl Viro u8 *name, struct dir_context *actor)
10151da177e4SLinus Torvalds {
10161da177e4SLinus Torvalds unsigned long mref;
1017956ce208SAl Viro int name_len;
10181da177e4SLinus Torvalds unsigned dt_type;
10191da177e4SLinus Torvalds FILE_NAME_TYPE_FLAGS name_type;
10201da177e4SLinus Torvalds
10211da177e4SLinus Torvalds name_type = ie->key.file_name.file_name_type;
10221da177e4SLinus Torvalds if (name_type == FILE_NAME_DOS) {
10231da177e4SLinus Torvalds ntfs_debug("Skipping DOS name space entry.");
10241da177e4SLinus Torvalds return 0;
10251da177e4SLinus Torvalds }
10261da177e4SLinus Torvalds if (MREF_LE(ie->data.dir.indexed_file) == FILE_root) {
10271da177e4SLinus Torvalds ntfs_debug("Skipping root directory self reference entry.");
10281da177e4SLinus Torvalds return 0;
10291da177e4SLinus Torvalds }
10301da177e4SLinus Torvalds if (MREF_LE(ie->data.dir.indexed_file) < FILE_first_user &&
10311da177e4SLinus Torvalds !NVolShowSystemFiles(vol)) {
10321da177e4SLinus Torvalds ntfs_debug("Skipping system file.");
10331da177e4SLinus Torvalds return 0;
10341da177e4SLinus Torvalds }
10351da177e4SLinus Torvalds name_len = ntfs_ucstonls(vol, (ntfschar*)&ie->key.file_name.file_name,
10361da177e4SLinus Torvalds ie->key.file_name.file_name_length, &name,
10371da177e4SLinus Torvalds NTFS_MAX_NAME_LEN * NLS_MAX_CHARSET_SIZE + 1);
10381da177e4SLinus Torvalds if (name_len <= 0) {
1039f94ad38eSAnton Altaparmakov ntfs_warning(vol->sb, "Skipping unrepresentable inode 0x%llx.",
1040f94ad38eSAnton Altaparmakov (long long)MREF_LE(ie->data.dir.indexed_file));
10411da177e4SLinus Torvalds return 0;
10421da177e4SLinus Torvalds }
10431da177e4SLinus Torvalds if (ie->key.file_name.file_attributes &
10441da177e4SLinus Torvalds FILE_ATTR_DUP_FILE_NAME_INDEX_PRESENT)
10451da177e4SLinus Torvalds dt_type = DT_DIR;
10461da177e4SLinus Torvalds else
10471da177e4SLinus Torvalds dt_type = DT_REG;
10481da177e4SLinus Torvalds mref = MREF_LE(ie->data.dir.indexed_file);
10491da177e4SLinus Torvalds /*
10501da177e4SLinus Torvalds * Drop the page lock otherwise we deadlock with NFS when it calls
10511da177e4SLinus Torvalds * ->lookup since ntfs_lookup() will lock the same page.
10521da177e4SLinus Torvalds */
10531da177e4SLinus Torvalds if (ia_page)
10541da177e4SLinus Torvalds unlock_page(ia_page);
10551da177e4SLinus Torvalds ntfs_debug("Calling filldir for %s with len %i, fpos 0x%llx, inode "
1056956ce208SAl Viro "0x%lx, DT_%s.", name, name_len, actor->pos, mref,
10571da177e4SLinus Torvalds dt_type == DT_DIR ? "DIR" : "REG");
1058956ce208SAl Viro if (!dir_emit(actor, name, name_len, mref, dt_type))
1059956ce208SAl Viro return 1;
10601da177e4SLinus Torvalds /* Relock the page but not if we are aborting ->readdir. */
1061956ce208SAl Viro if (ia_page)
10621da177e4SLinus Torvalds lock_page(ia_page);
1063956ce208SAl Viro return 0;
10641da177e4SLinus Torvalds }
10651da177e4SLinus Torvalds
10661da177e4SLinus Torvalds /*
10671da177e4SLinus Torvalds * We use the same basic approach as the old NTFS driver, i.e. we parse the
10681da177e4SLinus Torvalds * index root entries and then the index allocation entries that are marked
10691da177e4SLinus Torvalds * as in use in the index bitmap.
10701da177e4SLinus Torvalds *
10711da177e4SLinus Torvalds * While this will return the names in random order this doesn't matter for
10721da177e4SLinus Torvalds * ->readdir but OTOH results in a faster ->readdir.
10731da177e4SLinus Torvalds *
10741b1dcc1bSJes Sorensen * VFS calls ->readdir without BKL but with i_mutex held. This protects the VFS
10751da177e4SLinus Torvalds * parts (e.g. ->f_pos and ->i_size, and it also protects against directory
10761da177e4SLinus Torvalds * modifications).
10771da177e4SLinus Torvalds *
10781b1dcc1bSJes Sorensen * Locking: - Caller must hold i_mutex on the directory.
10791da177e4SLinus Torvalds * - Each page cache page in the index allocation mapping must be
10801da177e4SLinus Torvalds * locked whilst being accessed otherwise we may find a corrupt
10811da177e4SLinus Torvalds * page due to it being under ->writepage at the moment which
10821da177e4SLinus Torvalds * applies the mst protection fixups before writing out and then
10831da177e4SLinus Torvalds * removes them again after the write is complete after which it
10841da177e4SLinus Torvalds * unlocks the page.
10851da177e4SLinus Torvalds */
ntfs_readdir(struct file * file,struct dir_context * actor)1086956ce208SAl Viro static int ntfs_readdir(struct file *file, struct dir_context *actor)
10871da177e4SLinus Torvalds {
10881da177e4SLinus Torvalds s64 ia_pos, ia_start, prev_ia_pos, bmp_pos;
1089956ce208SAl Viro loff_t i_size;
1090956ce208SAl Viro struct inode *bmp_vi, *vdir = file_inode(file);
10911da177e4SLinus Torvalds struct super_block *sb = vdir->i_sb;
10921da177e4SLinus Torvalds ntfs_inode *ndir = NTFS_I(vdir);
10931da177e4SLinus Torvalds ntfs_volume *vol = NTFS_SB(sb);
10941da177e4SLinus Torvalds MFT_RECORD *m;
10951da177e4SLinus Torvalds INDEX_ROOT *ir = NULL;
10961da177e4SLinus Torvalds INDEX_ENTRY *ie;
10971da177e4SLinus Torvalds INDEX_ALLOCATION *ia;
10981da177e4SLinus Torvalds u8 *name = NULL;
10991da177e4SLinus Torvalds int rc, err, ir_pos, cur_bmp_pos;
11001da177e4SLinus Torvalds struct address_space *ia_mapping, *bmp_mapping;
11011da177e4SLinus Torvalds struct page *bmp_page = NULL, *ia_page = NULL;
11021da177e4SLinus Torvalds u8 *kaddr, *bmp, *index_end;
11031da177e4SLinus Torvalds ntfs_attr_search_ctx *ctx;
11041da177e4SLinus Torvalds
11051da177e4SLinus Torvalds ntfs_debug("Entering for inode 0x%lx, fpos 0x%llx.",
1106956ce208SAl Viro vdir->i_ino, actor->pos);
11071da177e4SLinus Torvalds rc = err = 0;
11081da177e4SLinus Torvalds /* Are we at end of dir yet? */
1109206f9f35SAnton Altaparmakov i_size = i_size_read(vdir);
1110956ce208SAl Viro if (actor->pos >= i_size + vol->mft_record_size)
1111956ce208SAl Viro return 0;
11121da177e4SLinus Torvalds /* Emulate . and .. for all directories. */
1113956ce208SAl Viro if (!dir_emit_dots(file, actor))
1114956ce208SAl Viro return 0;
11151da177e4SLinus Torvalds m = NULL;
11161da177e4SLinus Torvalds ctx = NULL;
11171da177e4SLinus Torvalds /*
11181da177e4SLinus Torvalds * Allocate a buffer to store the current name being processed
11191da177e4SLinus Torvalds * converted to format determined by current NLS.
11201da177e4SLinus Torvalds */
1121f52720caSPanagiotis Issaris name = kmalloc(NTFS_MAX_NAME_LEN * NLS_MAX_CHARSET_SIZE + 1, GFP_NOFS);
11221da177e4SLinus Torvalds if (unlikely(!name)) {
11231da177e4SLinus Torvalds err = -ENOMEM;
11241da177e4SLinus Torvalds goto err_out;
11251da177e4SLinus Torvalds }
11261da177e4SLinus Torvalds /* Are we jumping straight into the index allocation attribute? */
1127956ce208SAl Viro if (actor->pos >= vol->mft_record_size)
11281da177e4SLinus Torvalds goto skip_index_root;
11291da177e4SLinus Torvalds /* Get hold of the mft record for the directory. */
11301da177e4SLinus Torvalds m = map_mft_record(ndir);
11311da177e4SLinus Torvalds if (IS_ERR(m)) {
11321da177e4SLinus Torvalds err = PTR_ERR(m);
11331da177e4SLinus Torvalds m = NULL;
11341da177e4SLinus Torvalds goto err_out;
11351da177e4SLinus Torvalds }
11361da177e4SLinus Torvalds ctx = ntfs_attr_get_search_ctx(ndir, m);
11371da177e4SLinus Torvalds if (unlikely(!ctx)) {
11381da177e4SLinus Torvalds err = -ENOMEM;
11391da177e4SLinus Torvalds goto err_out;
11401da177e4SLinus Torvalds }
11411da177e4SLinus Torvalds /* Get the offset into the index root attribute. */
1142956ce208SAl Viro ir_pos = (s64)actor->pos;
11431da177e4SLinus Torvalds /* Find the index root attribute in the mft record. */
11441da177e4SLinus Torvalds err = ntfs_attr_lookup(AT_INDEX_ROOT, I30, 4, CASE_SENSITIVE, 0, NULL,
11451da177e4SLinus Torvalds 0, ctx);
11461da177e4SLinus Torvalds if (unlikely(err)) {
11471da177e4SLinus Torvalds ntfs_error(sb, "Index root attribute missing in directory "
11481da177e4SLinus Torvalds "inode 0x%lx.", vdir->i_ino);
11491da177e4SLinus Torvalds goto err_out;
11501da177e4SLinus Torvalds }
11511da177e4SLinus Torvalds /*
11521da177e4SLinus Torvalds * Copy the index root attribute value to a buffer so that we can put
11531da177e4SLinus Torvalds * the search context and unmap the mft record before calling the
11541da177e4SLinus Torvalds * filldir() callback. We need to do this because of NFSd which calls
11551da177e4SLinus Torvalds * ->lookup() from its filldir callback() and this causes NTFS to
11561da177e4SLinus Torvalds * deadlock as ntfs_lookup() maps the mft record of the directory and
11571da177e4SLinus Torvalds * we have got it mapped here already. The only solution is for us to
11581da177e4SLinus Torvalds * unmap the mft record here so that a call to ntfs_lookup() is able to
11591da177e4SLinus Torvalds * map the mft record without deadlocking.
11601da177e4SLinus Torvalds */
11611da177e4SLinus Torvalds rc = le32_to_cpu(ctx->attr->data.resident.value_length);
1162f52720caSPanagiotis Issaris ir = kmalloc(rc, GFP_NOFS);
11631da177e4SLinus Torvalds if (unlikely(!ir)) {
11641da177e4SLinus Torvalds err = -ENOMEM;
11651da177e4SLinus Torvalds goto err_out;
11661da177e4SLinus Torvalds }
11671da177e4SLinus Torvalds /* Copy the index root value (it has been verified in read_inode). */
11681da177e4SLinus Torvalds memcpy(ir, (u8*)ctx->attr +
11691da177e4SLinus Torvalds le16_to_cpu(ctx->attr->data.resident.value_offset), rc);
11701da177e4SLinus Torvalds ntfs_attr_put_search_ctx(ctx);
11711da177e4SLinus Torvalds unmap_mft_record(ndir);
11721da177e4SLinus Torvalds ctx = NULL;
11731da177e4SLinus Torvalds m = NULL;
11741da177e4SLinus Torvalds index_end = (u8*)&ir->index + le32_to_cpu(ir->index.index_length);
11751da177e4SLinus Torvalds /* The first index entry. */
11761da177e4SLinus Torvalds ie = (INDEX_ENTRY*)((u8*)&ir->index +
11771da177e4SLinus Torvalds le32_to_cpu(ir->index.entries_offset));
11781da177e4SLinus Torvalds /*
11791da177e4SLinus Torvalds * Loop until we exceed valid memory (corruption case) or until we
11801da177e4SLinus Torvalds * reach the last entry or until filldir tells us it has had enough
11811da177e4SLinus Torvalds * or signals an error (both covered by the rc test).
11821da177e4SLinus Torvalds */
11831da177e4SLinus Torvalds for (;; ie = (INDEX_ENTRY*)((u8*)ie + le16_to_cpu(ie->length))) {
11841da177e4SLinus Torvalds ntfs_debug("In index root, offset 0x%zx.", (u8*)ie - (u8*)ir);
11851da177e4SLinus Torvalds /* Bounds checks. */
11861da177e4SLinus Torvalds if (unlikely((u8*)ie < (u8*)ir || (u8*)ie +
11871da177e4SLinus Torvalds sizeof(INDEX_ENTRY_HEADER) > index_end ||
11881da177e4SLinus Torvalds (u8*)ie + le16_to_cpu(ie->key_length) >
11891da177e4SLinus Torvalds index_end))
11901da177e4SLinus Torvalds goto err_out;
11911da177e4SLinus Torvalds /* The last entry cannot contain a name. */
11921da177e4SLinus Torvalds if (ie->flags & INDEX_ENTRY_END)
11931da177e4SLinus Torvalds break;
11941da177e4SLinus Torvalds /* Skip index root entry if continuing previous readdir. */
11951da177e4SLinus Torvalds if (ir_pos > (u8*)ie - (u8*)ir)
11961da177e4SLinus Torvalds continue;
11971da177e4SLinus Torvalds /* Advance the position even if going to skip the entry. */
1198956ce208SAl Viro actor->pos = (u8*)ie - (u8*)ir;
11991da177e4SLinus Torvalds /* Submit the name to the filldir callback. */
1200956ce208SAl Viro rc = ntfs_filldir(vol, ndir, NULL, ie, name, actor);
12011da177e4SLinus Torvalds if (rc) {
12021da177e4SLinus Torvalds kfree(ir);
12031da177e4SLinus Torvalds goto abort;
12041da177e4SLinus Torvalds }
12051da177e4SLinus Torvalds }
12061da177e4SLinus Torvalds /* We are done with the index root and can free the buffer. */
12071da177e4SLinus Torvalds kfree(ir);
12081da177e4SLinus Torvalds ir = NULL;
12091da177e4SLinus Torvalds /* If there is no index allocation attribute we are finished. */
12101da177e4SLinus Torvalds if (!NInoIndexAllocPresent(ndir))
12111da177e4SLinus Torvalds goto EOD;
12121da177e4SLinus Torvalds /* Advance fpos to the beginning of the index allocation. */
1213956ce208SAl Viro actor->pos = vol->mft_record_size;
12141da177e4SLinus Torvalds skip_index_root:
12151da177e4SLinus Torvalds kaddr = NULL;
12161da177e4SLinus Torvalds prev_ia_pos = -1LL;
12171da177e4SLinus Torvalds /* Get the offset into the index allocation attribute. */
1218956ce208SAl Viro ia_pos = (s64)actor->pos - vol->mft_record_size;
12191da177e4SLinus Torvalds ia_mapping = vdir->i_mapping;
12208331191eSAnton Altaparmakov ntfs_debug("Inode 0x%lx, getting index bitmap.", vdir->i_ino);
12211da177e4SLinus Torvalds bmp_vi = ntfs_attr_iget(vdir, AT_BITMAP, I30, 4);
12221da177e4SLinus Torvalds if (IS_ERR(bmp_vi)) {
12231da177e4SLinus Torvalds ntfs_error(sb, "Failed to get bitmap attribute.");
12241da177e4SLinus Torvalds err = PTR_ERR(bmp_vi);
12251da177e4SLinus Torvalds goto err_out;
12261da177e4SLinus Torvalds }
12271da177e4SLinus Torvalds bmp_mapping = bmp_vi->i_mapping;
12281da177e4SLinus Torvalds /* Get the starting bitmap bit position and sanity check it. */
12291da177e4SLinus Torvalds bmp_pos = ia_pos >> ndir->itype.index.block_size_bits;
1230206f9f35SAnton Altaparmakov if (unlikely(bmp_pos >> 3 >= i_size_read(bmp_vi))) {
12311da177e4SLinus Torvalds ntfs_error(sb, "Current index allocation position exceeds "
12321da177e4SLinus Torvalds "index bitmap size.");
12338331191eSAnton Altaparmakov goto iput_err_out;
12341da177e4SLinus Torvalds }
12351da177e4SLinus Torvalds /* Get the starting bit position in the current bitmap page. */
123609cbfeafSKirill A. Shutemov cur_bmp_pos = bmp_pos & ((PAGE_SIZE * 8) - 1);
123709cbfeafSKirill A. Shutemov bmp_pos &= ~(u64)((PAGE_SIZE * 8) - 1);
12381da177e4SLinus Torvalds get_next_bmp_page:
12391da177e4SLinus Torvalds ntfs_debug("Reading bitmap with page index 0x%llx, bit ofs 0x%llx",
124009cbfeafSKirill A. Shutemov (unsigned long long)bmp_pos >> (3 + PAGE_SHIFT),
12411da177e4SLinus Torvalds (unsigned long long)bmp_pos &
124209cbfeafSKirill A. Shutemov (unsigned long long)((PAGE_SIZE * 8) - 1));
12431da177e4SLinus Torvalds bmp_page = ntfs_map_page(bmp_mapping,
124409cbfeafSKirill A. Shutemov bmp_pos >> (3 + PAGE_SHIFT));
12451da177e4SLinus Torvalds if (IS_ERR(bmp_page)) {
12461da177e4SLinus Torvalds ntfs_error(sb, "Reading index bitmap failed.");
12471da177e4SLinus Torvalds err = PTR_ERR(bmp_page);
12481da177e4SLinus Torvalds bmp_page = NULL;
12498331191eSAnton Altaparmakov goto iput_err_out;
12501da177e4SLinus Torvalds }
12511da177e4SLinus Torvalds bmp = (u8*)page_address(bmp_page);
12521da177e4SLinus Torvalds /* Find next index block in use. */
12531da177e4SLinus Torvalds while (!(bmp[cur_bmp_pos >> 3] & (1 << (cur_bmp_pos & 7)))) {
12541da177e4SLinus Torvalds find_next_index_buffer:
12551da177e4SLinus Torvalds cur_bmp_pos++;
12561da177e4SLinus Torvalds /*
12571da177e4SLinus Torvalds * If we have reached the end of the bitmap page, get the next
12581da177e4SLinus Torvalds * page, and put away the old one.
12591da177e4SLinus Torvalds */
126009cbfeafSKirill A. Shutemov if (unlikely((cur_bmp_pos >> 3) >= PAGE_SIZE)) {
12611da177e4SLinus Torvalds ntfs_unmap_page(bmp_page);
126209cbfeafSKirill A. Shutemov bmp_pos += PAGE_SIZE * 8;
12631da177e4SLinus Torvalds cur_bmp_pos = 0;
12641da177e4SLinus Torvalds goto get_next_bmp_page;
12651da177e4SLinus Torvalds }
12661da177e4SLinus Torvalds /* If we have reached the end of the bitmap, we are done. */
1267206f9f35SAnton Altaparmakov if (unlikely(((bmp_pos + cur_bmp_pos) >> 3) >= i_size))
12681da177e4SLinus Torvalds goto unm_EOD;
12691da177e4SLinus Torvalds ia_pos = (bmp_pos + cur_bmp_pos) <<
12701da177e4SLinus Torvalds ndir->itype.index.block_size_bits;
12711da177e4SLinus Torvalds }
12721da177e4SLinus Torvalds ntfs_debug("Handling index buffer 0x%llx.",
12731da177e4SLinus Torvalds (unsigned long long)bmp_pos + cur_bmp_pos);
12741da177e4SLinus Torvalds /* If the current index buffer is in the same page we reuse the page. */
127509cbfeafSKirill A. Shutemov if ((prev_ia_pos & (s64)PAGE_MASK) !=
127609cbfeafSKirill A. Shutemov (ia_pos & (s64)PAGE_MASK)) {
12771da177e4SLinus Torvalds prev_ia_pos = ia_pos;
12781da177e4SLinus Torvalds if (likely(ia_page != NULL)) {
12791da177e4SLinus Torvalds unlock_page(ia_page);
12801da177e4SLinus Torvalds ntfs_unmap_page(ia_page);
12811da177e4SLinus Torvalds }
12821da177e4SLinus Torvalds /*
12831da177e4SLinus Torvalds * Map the page cache page containing the current ia_pos,
12841da177e4SLinus Torvalds * reading it from disk if necessary.
12851da177e4SLinus Torvalds */
128609cbfeafSKirill A. Shutemov ia_page = ntfs_map_page(ia_mapping, ia_pos >> PAGE_SHIFT);
12871da177e4SLinus Torvalds if (IS_ERR(ia_page)) {
12881da177e4SLinus Torvalds ntfs_error(sb, "Reading index allocation data failed.");
12891da177e4SLinus Torvalds err = PTR_ERR(ia_page);
12901da177e4SLinus Torvalds ia_page = NULL;
12911da177e4SLinus Torvalds goto err_out;
12921da177e4SLinus Torvalds }
12931da177e4SLinus Torvalds lock_page(ia_page);
12941da177e4SLinus Torvalds kaddr = (u8*)page_address(ia_page);
12951da177e4SLinus Torvalds }
12961da177e4SLinus Torvalds /* Get the current index buffer. */
129709cbfeafSKirill A. Shutemov ia = (INDEX_ALLOCATION*)(kaddr + (ia_pos & ~PAGE_MASK &
12981da177e4SLinus Torvalds ~(s64)(ndir->itype.index.block_size - 1)));
12991da177e4SLinus Torvalds /* Bounds checks. */
130009cbfeafSKirill A. Shutemov if (unlikely((u8*)ia < kaddr || (u8*)ia > kaddr + PAGE_SIZE)) {
13011da177e4SLinus Torvalds ntfs_error(sb, "Out of bounds check failed. Corrupt directory "
13021da177e4SLinus Torvalds "inode 0x%lx or driver bug.", vdir->i_ino);
13031da177e4SLinus Torvalds goto err_out;
13041da177e4SLinus Torvalds }
13051da177e4SLinus Torvalds /* Catch multi sector transfer fixup errors. */
13061da177e4SLinus Torvalds if (unlikely(!ntfs_is_indx_record(ia->magic))) {
13071da177e4SLinus Torvalds ntfs_error(sb, "Directory index record with vcn 0x%llx is "
13081da177e4SLinus Torvalds "corrupt. Corrupt inode 0x%lx. Run chkdsk.",
13091da177e4SLinus Torvalds (unsigned long long)ia_pos >>
13101da177e4SLinus Torvalds ndir->itype.index.vcn_size_bits, vdir->i_ino);
13111da177e4SLinus Torvalds goto err_out;
13121da177e4SLinus Torvalds }
13131da177e4SLinus Torvalds if (unlikely(sle64_to_cpu(ia->index_block_vcn) != (ia_pos &
13141da177e4SLinus Torvalds ~(s64)(ndir->itype.index.block_size - 1)) >>
13151da177e4SLinus Torvalds ndir->itype.index.vcn_size_bits)) {
13161da177e4SLinus Torvalds ntfs_error(sb, "Actual VCN (0x%llx) of index buffer is "
13171da177e4SLinus Torvalds "different from expected VCN (0x%llx). "
13181da177e4SLinus Torvalds "Directory inode 0x%lx is corrupt or driver "
13191da177e4SLinus Torvalds "bug. ", (unsigned long long)
13201da177e4SLinus Torvalds sle64_to_cpu(ia->index_block_vcn),
13211da177e4SLinus Torvalds (unsigned long long)ia_pos >>
13221da177e4SLinus Torvalds ndir->itype.index.vcn_size_bits, vdir->i_ino);
13231da177e4SLinus Torvalds goto err_out;
13241da177e4SLinus Torvalds }
13251da177e4SLinus Torvalds if (unlikely(le32_to_cpu(ia->index.allocated_size) + 0x18 !=
13261da177e4SLinus Torvalds ndir->itype.index.block_size)) {
13271da177e4SLinus Torvalds ntfs_error(sb, "Index buffer (VCN 0x%llx) of directory inode "
13281da177e4SLinus Torvalds "0x%lx has a size (%u) differing from the "
13291da177e4SLinus Torvalds "directory specified size (%u). Directory "
13301da177e4SLinus Torvalds "inode is corrupt or driver bug.",
13311da177e4SLinus Torvalds (unsigned long long)ia_pos >>
13321da177e4SLinus Torvalds ndir->itype.index.vcn_size_bits, vdir->i_ino,
13331da177e4SLinus Torvalds le32_to_cpu(ia->index.allocated_size) + 0x18,
13341da177e4SLinus Torvalds ndir->itype.index.block_size);
13351da177e4SLinus Torvalds goto err_out;
13361da177e4SLinus Torvalds }
13371da177e4SLinus Torvalds index_end = (u8*)ia + ndir->itype.index.block_size;
133809cbfeafSKirill A. Shutemov if (unlikely(index_end > kaddr + PAGE_SIZE)) {
13391da177e4SLinus Torvalds ntfs_error(sb, "Index buffer (VCN 0x%llx) of directory inode "
13401da177e4SLinus Torvalds "0x%lx crosses page boundary. Impossible! "
13411da177e4SLinus Torvalds "Cannot access! This is probably a bug in the "
13421da177e4SLinus Torvalds "driver.", (unsigned long long)ia_pos >>
13431da177e4SLinus Torvalds ndir->itype.index.vcn_size_bits, vdir->i_ino);
13441da177e4SLinus Torvalds goto err_out;
13451da177e4SLinus Torvalds }
13461da177e4SLinus Torvalds ia_start = ia_pos & ~(s64)(ndir->itype.index.block_size - 1);
13471da177e4SLinus Torvalds index_end = (u8*)&ia->index + le32_to_cpu(ia->index.index_length);
13481da177e4SLinus Torvalds if (unlikely(index_end > (u8*)ia + ndir->itype.index.block_size)) {
13491da177e4SLinus Torvalds ntfs_error(sb, "Size of index buffer (VCN 0x%llx) of directory "
13501da177e4SLinus Torvalds "inode 0x%lx exceeds maximum size.",
13511da177e4SLinus Torvalds (unsigned long long)ia_pos >>
13521da177e4SLinus Torvalds ndir->itype.index.vcn_size_bits, vdir->i_ino);
13531da177e4SLinus Torvalds goto err_out;
13541da177e4SLinus Torvalds }
13551da177e4SLinus Torvalds /* The first index entry in this index buffer. */
13561da177e4SLinus Torvalds ie = (INDEX_ENTRY*)((u8*)&ia->index +
13571da177e4SLinus Torvalds le32_to_cpu(ia->index.entries_offset));
13581da177e4SLinus Torvalds /*
13591da177e4SLinus Torvalds * Loop until we exceed valid memory (corruption case) or until we
13601da177e4SLinus Torvalds * reach the last entry or until filldir tells us it has had enough
13611da177e4SLinus Torvalds * or signals an error (both covered by the rc test).
13621da177e4SLinus Torvalds */
13631da177e4SLinus Torvalds for (;; ie = (INDEX_ENTRY*)((u8*)ie + le16_to_cpu(ie->length))) {
13641da177e4SLinus Torvalds ntfs_debug("In index allocation, offset 0x%llx.",
13651da177e4SLinus Torvalds (unsigned long long)ia_start +
13661da177e4SLinus Torvalds (unsigned long long)((u8*)ie - (u8*)ia));
13671da177e4SLinus Torvalds /* Bounds checks. */
13681da177e4SLinus Torvalds if (unlikely((u8*)ie < (u8*)ia || (u8*)ie +
13691da177e4SLinus Torvalds sizeof(INDEX_ENTRY_HEADER) > index_end ||
13701da177e4SLinus Torvalds (u8*)ie + le16_to_cpu(ie->key_length) >
13711da177e4SLinus Torvalds index_end))
13721da177e4SLinus Torvalds goto err_out;
13731da177e4SLinus Torvalds /* The last entry cannot contain a name. */
13741da177e4SLinus Torvalds if (ie->flags & INDEX_ENTRY_END)
13751da177e4SLinus Torvalds break;
13761da177e4SLinus Torvalds /* Skip index block entry if continuing previous readdir. */
13771da177e4SLinus Torvalds if (ia_pos - ia_start > (u8*)ie - (u8*)ia)
13781da177e4SLinus Torvalds continue;
13791da177e4SLinus Torvalds /* Advance the position even if going to skip the entry. */
1380956ce208SAl Viro actor->pos = (u8*)ie - (u8*)ia +
13811da177e4SLinus Torvalds (sle64_to_cpu(ia->index_block_vcn) <<
13821da177e4SLinus Torvalds ndir->itype.index.vcn_size_bits) +
13831da177e4SLinus Torvalds vol->mft_record_size;
13841da177e4SLinus Torvalds /*
13851da177e4SLinus Torvalds * Submit the name to the @filldir callback. Note,
13861da177e4SLinus Torvalds * ntfs_filldir() drops the lock on @ia_page but it retakes it
13871da177e4SLinus Torvalds * before returning, unless a non-zero value is returned in
13881da177e4SLinus Torvalds * which case the page is left unlocked.
13891da177e4SLinus Torvalds */
1390956ce208SAl Viro rc = ntfs_filldir(vol, ndir, ia_page, ie, name, actor);
13911da177e4SLinus Torvalds if (rc) {
13921da177e4SLinus Torvalds /* @ia_page is already unlocked in this case. */
13931da177e4SLinus Torvalds ntfs_unmap_page(ia_page);
13941da177e4SLinus Torvalds ntfs_unmap_page(bmp_page);
13958331191eSAnton Altaparmakov iput(bmp_vi);
13961da177e4SLinus Torvalds goto abort;
13971da177e4SLinus Torvalds }
13981da177e4SLinus Torvalds }
13991da177e4SLinus Torvalds goto find_next_index_buffer;
14001da177e4SLinus Torvalds unm_EOD:
14011da177e4SLinus Torvalds if (ia_page) {
14021da177e4SLinus Torvalds unlock_page(ia_page);
14031da177e4SLinus Torvalds ntfs_unmap_page(ia_page);
14041da177e4SLinus Torvalds }
14051da177e4SLinus Torvalds ntfs_unmap_page(bmp_page);
14068331191eSAnton Altaparmakov iput(bmp_vi);
14071da177e4SLinus Torvalds EOD:
14081da177e4SLinus Torvalds /* We are finished, set fpos to EOD. */
1409956ce208SAl Viro actor->pos = i_size + vol->mft_record_size;
14101da177e4SLinus Torvalds abort:
14111da177e4SLinus Torvalds kfree(name);
14121da177e4SLinus Torvalds return 0;
14131da177e4SLinus Torvalds err_out:
14148331191eSAnton Altaparmakov if (bmp_page) {
14151da177e4SLinus Torvalds ntfs_unmap_page(bmp_page);
14168331191eSAnton Altaparmakov iput_err_out:
14178331191eSAnton Altaparmakov iput(bmp_vi);
14188331191eSAnton Altaparmakov }
14191da177e4SLinus Torvalds if (ia_page) {
14201da177e4SLinus Torvalds unlock_page(ia_page);
14211da177e4SLinus Torvalds ntfs_unmap_page(ia_page);
14221da177e4SLinus Torvalds }
14231da177e4SLinus Torvalds kfree(ir);
14241da177e4SLinus Torvalds kfree(name);
14251da177e4SLinus Torvalds if (ctx)
14261da177e4SLinus Torvalds ntfs_attr_put_search_ctx(ctx);
14271da177e4SLinus Torvalds if (m)
14281da177e4SLinus Torvalds unmap_mft_record(ndir);
14291da177e4SLinus Torvalds if (!err)
14301da177e4SLinus Torvalds err = -EIO;
14311da177e4SLinus Torvalds ntfs_debug("Failed. Returning error code %i.", -err);
14321da177e4SLinus Torvalds return err;
14331da177e4SLinus Torvalds }
14341da177e4SLinus Torvalds
14351da177e4SLinus Torvalds /**
14361da177e4SLinus Torvalds * ntfs_dir_open - called when an inode is about to be opened
14371da177e4SLinus Torvalds * @vi: inode to be opened
14381da177e4SLinus Torvalds * @filp: file structure describing the inode
14391da177e4SLinus Torvalds *
14401da177e4SLinus Torvalds * Limit directory size to the page cache limit on architectures where unsigned
14411da177e4SLinus Torvalds * long is 32-bits. This is the most we can do for now without overflowing the
14421da177e4SLinus Torvalds * page cache page index. Doing it this way means we don't run into problems
14431da177e4SLinus Torvalds * because of existing too large directories. It would be better to allow the
14441da177e4SLinus Torvalds * user to read the accessible part of the directory but I doubt very much
14451da177e4SLinus Torvalds * anyone is going to hit this check on a 32-bit architecture, so there is no
14461da177e4SLinus Torvalds * point in adding the extra complexity required to support this.
14471da177e4SLinus Torvalds *
14481da177e4SLinus Torvalds * On 64-bit architectures, the check is hopefully optimized away by the
14491da177e4SLinus Torvalds * compiler.
14501da177e4SLinus Torvalds */
ntfs_dir_open(struct inode * vi,struct file * filp)14511da177e4SLinus Torvalds static int ntfs_dir_open(struct inode *vi, struct file *filp)
14521da177e4SLinus Torvalds {
14531da177e4SLinus Torvalds if (sizeof(unsigned long) < 8) {
1454206f9f35SAnton Altaparmakov if (i_size_read(vi) > MAX_LFS_FILESIZE)
14551da177e4SLinus Torvalds return -EFBIG;
14561da177e4SLinus Torvalds }
14571da177e4SLinus Torvalds return 0;
14581da177e4SLinus Torvalds }
14591da177e4SLinus Torvalds
14601da177e4SLinus Torvalds #ifdef NTFS_RW
14611da177e4SLinus Torvalds
14621da177e4SLinus Torvalds /**
14631da177e4SLinus Torvalds * ntfs_dir_fsync - sync a directory to disk
14641da177e4SLinus Torvalds * @filp: directory to be synced
14651da177e4SLinus Torvalds * @dentry: dentry describing the directory to sync
14661da177e4SLinus Torvalds * @datasync: if non-zero only flush user data and not metadata
14671da177e4SLinus Torvalds *
14681da177e4SLinus Torvalds * Data integrity sync of a directory to disk. Used for fsync, fdatasync, and
14691da177e4SLinus Torvalds * msync system calls. This function is based on file.c::ntfs_file_fsync().
14701da177e4SLinus Torvalds *
14711da177e4SLinus Torvalds * Write the mft record and all associated extent mft records as well as the
14721da177e4SLinus Torvalds * $INDEX_ALLOCATION and $BITMAP attributes and then sync the block device.
14731da177e4SLinus Torvalds *
14741da177e4SLinus Torvalds * If @datasync is true, we do not wait on the inode(s) to be written out
14751da177e4SLinus Torvalds * but we always wait on the page cache pages to be written out.
14761da177e4SLinus Torvalds *
14771da177e4SLinus Torvalds * Note: In the past @filp could be NULL so we ignore it as we don't need it
14781da177e4SLinus Torvalds * anyway.
14791da177e4SLinus Torvalds *
14801b1dcc1bSJes Sorensen * Locking: Caller must hold i_mutex on the inode.
14811da177e4SLinus Torvalds *
14821da177e4SLinus Torvalds * TODO: We should probably also write all attribute/index inodes associated
14831da177e4SLinus Torvalds * with this inode but since we have no simple way of getting to them we ignore
14841da177e4SLinus Torvalds * this problem for now. We do write the $BITMAP attribute if it is present
14851da177e4SLinus Torvalds * which is the important one for a directory so things are not too bad.
14861da177e4SLinus Torvalds */
ntfs_dir_fsync(struct file * filp,loff_t start,loff_t end,int datasync)148702c24a82SJosef Bacik static int ntfs_dir_fsync(struct file *filp, loff_t start, loff_t end,
148802c24a82SJosef Bacik int datasync)
14891da177e4SLinus Torvalds {
14907ea80859SChristoph Hellwig struct inode *bmp_vi, *vi = filp->f_mapping->host;
14911da177e4SLinus Torvalds int err, ret;
14928331191eSAnton Altaparmakov ntfs_attr na;
14931da177e4SLinus Torvalds
14941da177e4SLinus Torvalds ntfs_debug("Entering for inode 0x%lx.", vi->i_ino);
149502c24a82SJosef Bacik
14963b49c9a1SJeff Layton err = file_write_and_wait_range(filp, start, end);
149702c24a82SJosef Bacik if (err)
149802c24a82SJosef Bacik return err;
14995955102cSAl Viro inode_lock(vi);
150002c24a82SJosef Bacik
15011da177e4SLinus Torvalds BUG_ON(!S_ISDIR(vi->i_mode));
15028331191eSAnton Altaparmakov /* If the bitmap attribute inode is in memory sync it, too. */
15038331191eSAnton Altaparmakov na.mft_no = vi->i_ino;
15048331191eSAnton Altaparmakov na.type = AT_BITMAP;
15058331191eSAnton Altaparmakov na.name = I30;
15068331191eSAnton Altaparmakov na.name_len = 4;
15071146f7e2SLuca Stefani bmp_vi = ilookup5(vi->i_sb, vi->i_ino, ntfs_test_inode, &na);
15088331191eSAnton Altaparmakov if (bmp_vi) {
15098331191eSAnton Altaparmakov write_inode_now(bmp_vi, !datasync);
15108331191eSAnton Altaparmakov iput(bmp_vi);
15118331191eSAnton Altaparmakov }
1512a9185b41SChristoph Hellwig ret = __ntfs_write_inode(vi, 1);
15131da177e4SLinus Torvalds write_inode_now(vi, !datasync);
15141da177e4SLinus Torvalds err = sync_blockdev(vi->i_sb->s_bdev);
15151da177e4SLinus Torvalds if (unlikely(err && !ret))
15161da177e4SLinus Torvalds ret = err;
15171da177e4SLinus Torvalds if (likely(!ret))
15181da177e4SLinus Torvalds ntfs_debug("Done.");
15191da177e4SLinus Torvalds else
15201da177e4SLinus Torvalds ntfs_warning(vi->i_sb, "Failed to f%ssync inode 0x%lx. Error "
15211da177e4SLinus Torvalds "%u.", datasync ? "data" : "", vi->i_ino, -ret);
15225955102cSAl Viro inode_unlock(vi);
15231da177e4SLinus Torvalds return ret;
15241da177e4SLinus Torvalds }
15251da177e4SLinus Torvalds
15261da177e4SLinus Torvalds #endif /* NTFS_RW */
15271da177e4SLinus Torvalds
1528*3e327154SLinus Torvalds WRAP_DIR_ITER(ntfs_readdir) // FIXME!
15294b6f5d20SArjan van de Ven const struct file_operations ntfs_dir_ops = {
15301da177e4SLinus Torvalds .llseek = generic_file_llseek, /* Seek inside directory. */
15311da177e4SLinus Torvalds .read = generic_read_dir, /* Return -EISDIR. */
1532*3e327154SLinus Torvalds .iterate_shared = shared_ntfs_readdir, /* Read directory contents. */
15331da177e4SLinus Torvalds #ifdef NTFS_RW
15341da177e4SLinus Torvalds .fsync = ntfs_dir_fsync, /* Sync a directory to disk. */
15351da177e4SLinus Torvalds #endif /* NTFS_RW */
15361da177e4SLinus Torvalds /*.ioctl = ,*/ /* Perform function on the
15371da177e4SLinus Torvalds mounted filesystem. */
15381da177e4SLinus Torvalds .open = ntfs_dir_open, /* Open directory. */
15391da177e4SLinus Torvalds };
1540