xref: /openbmc/linux/fs/ntfs/dir.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
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