162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * dir.c - NTFS kernel directory operations. Part of the Linux-NTFS project.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (c) 2001-2007 Anton Altaparmakov
662306a36Sopenharmony_ci * Copyright (c) 2002 Richard Russon
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/buffer_head.h>
1062306a36Sopenharmony_ci#include <linux/slab.h>
1162306a36Sopenharmony_ci#include <linux/blkdev.h>
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#include "dir.h"
1462306a36Sopenharmony_ci#include "aops.h"
1562306a36Sopenharmony_ci#include "attrib.h"
1662306a36Sopenharmony_ci#include "mft.h"
1762306a36Sopenharmony_ci#include "debug.h"
1862306a36Sopenharmony_ci#include "ntfs.h"
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci/*
2162306a36Sopenharmony_ci * The little endian Unicode string $I30 as a global constant.
2262306a36Sopenharmony_ci */
2362306a36Sopenharmony_cintfschar I30[5] = { cpu_to_le16('$'), cpu_to_le16('I'),
2462306a36Sopenharmony_ci		cpu_to_le16('3'),	cpu_to_le16('0'), 0 };
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci/**
2762306a36Sopenharmony_ci * ntfs_lookup_inode_by_name - find an inode in a directory given its name
2862306a36Sopenharmony_ci * @dir_ni:	ntfs inode of the directory in which to search for the name
2962306a36Sopenharmony_ci * @uname:	Unicode name for which to search in the directory
3062306a36Sopenharmony_ci * @uname_len:	length of the name @uname in Unicode characters
3162306a36Sopenharmony_ci * @res:	return the found file name if necessary (see below)
3262306a36Sopenharmony_ci *
3362306a36Sopenharmony_ci * Look for an inode with name @uname in the directory with inode @dir_ni.
3462306a36Sopenharmony_ci * ntfs_lookup_inode_by_name() walks the contents of the directory looking for
3562306a36Sopenharmony_ci * the Unicode name. If the name is found in the directory, the corresponding
3662306a36Sopenharmony_ci * inode number (>= 0) is returned as a mft reference in cpu format, i.e. it
3762306a36Sopenharmony_ci * is a 64-bit number containing the sequence number.
3862306a36Sopenharmony_ci *
3962306a36Sopenharmony_ci * On error, a negative value is returned corresponding to the error code. In
4062306a36Sopenharmony_ci * particular if the inode is not found -ENOENT is returned. Note that you
4162306a36Sopenharmony_ci * can't just check the return value for being negative, you have to check the
4262306a36Sopenharmony_ci * inode number for being negative which you can extract using MREC(return
4362306a36Sopenharmony_ci * value).
4462306a36Sopenharmony_ci *
4562306a36Sopenharmony_ci * Note, @uname_len does not include the (optional) terminating NULL character.
4662306a36Sopenharmony_ci *
4762306a36Sopenharmony_ci * Note, we look for a case sensitive match first but we also look for a case
4862306a36Sopenharmony_ci * insensitive match at the same time. If we find a case insensitive match, we
4962306a36Sopenharmony_ci * save that for the case that we don't find an exact match, where we return
5062306a36Sopenharmony_ci * the case insensitive match and setup @res (which we allocate!) with the mft
5162306a36Sopenharmony_ci * reference, the file name type, length and with a copy of the little endian
5262306a36Sopenharmony_ci * Unicode file name itself. If we match a file name which is in the DOS name
5362306a36Sopenharmony_ci * space, we only return the mft reference and file name type in @res.
5462306a36Sopenharmony_ci * ntfs_lookup() then uses this to find the long file name in the inode itself.
5562306a36Sopenharmony_ci * This is to avoid polluting the dcache with short file names. We want them to
5662306a36Sopenharmony_ci * work but we don't care for how quickly one can access them. This also fixes
5762306a36Sopenharmony_ci * the dcache aliasing issues.
5862306a36Sopenharmony_ci *
5962306a36Sopenharmony_ci * Locking:  - Caller must hold i_mutex on the directory.
6062306a36Sopenharmony_ci *	     - Each page cache page in the index allocation mapping must be
6162306a36Sopenharmony_ci *	       locked whilst being accessed otherwise we may find a corrupt
6262306a36Sopenharmony_ci *	       page due to it being under ->writepage at the moment which
6362306a36Sopenharmony_ci *	       applies the mst protection fixups before writing out and then
6462306a36Sopenharmony_ci *	       removes them again after the write is complete after which it
6562306a36Sopenharmony_ci *	       unlocks the page.
6662306a36Sopenharmony_ci */
6762306a36Sopenharmony_ciMFT_REF ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const ntfschar *uname,
6862306a36Sopenharmony_ci		const int uname_len, ntfs_name **res)
6962306a36Sopenharmony_ci{
7062306a36Sopenharmony_ci	ntfs_volume *vol = dir_ni->vol;
7162306a36Sopenharmony_ci	struct super_block *sb = vol->sb;
7262306a36Sopenharmony_ci	MFT_RECORD *m;
7362306a36Sopenharmony_ci	INDEX_ROOT *ir;
7462306a36Sopenharmony_ci	INDEX_ENTRY *ie;
7562306a36Sopenharmony_ci	INDEX_ALLOCATION *ia;
7662306a36Sopenharmony_ci	u8 *index_end;
7762306a36Sopenharmony_ci	u64 mref;
7862306a36Sopenharmony_ci	ntfs_attr_search_ctx *ctx;
7962306a36Sopenharmony_ci	int err, rc;
8062306a36Sopenharmony_ci	VCN vcn, old_vcn;
8162306a36Sopenharmony_ci	struct address_space *ia_mapping;
8262306a36Sopenharmony_ci	struct page *page;
8362306a36Sopenharmony_ci	u8 *kaddr;
8462306a36Sopenharmony_ci	ntfs_name *name = NULL;
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	BUG_ON(!S_ISDIR(VFS_I(dir_ni)->i_mode));
8762306a36Sopenharmony_ci	BUG_ON(NInoAttr(dir_ni));
8862306a36Sopenharmony_ci	/* Get hold of the mft record for the directory. */
8962306a36Sopenharmony_ci	m = map_mft_record(dir_ni);
9062306a36Sopenharmony_ci	if (IS_ERR(m)) {
9162306a36Sopenharmony_ci		ntfs_error(sb, "map_mft_record() failed with error code %ld.",
9262306a36Sopenharmony_ci				-PTR_ERR(m));
9362306a36Sopenharmony_ci		return ERR_MREF(PTR_ERR(m));
9462306a36Sopenharmony_ci	}
9562306a36Sopenharmony_ci	ctx = ntfs_attr_get_search_ctx(dir_ni, m);
9662306a36Sopenharmony_ci	if (unlikely(!ctx)) {
9762306a36Sopenharmony_ci		err = -ENOMEM;
9862306a36Sopenharmony_ci		goto err_out;
9962306a36Sopenharmony_ci	}
10062306a36Sopenharmony_ci	/* Find the index root attribute in the mft record. */
10162306a36Sopenharmony_ci	err = ntfs_attr_lookup(AT_INDEX_ROOT, I30, 4, CASE_SENSITIVE, 0, NULL,
10262306a36Sopenharmony_ci			0, ctx);
10362306a36Sopenharmony_ci	if (unlikely(err)) {
10462306a36Sopenharmony_ci		if (err == -ENOENT) {
10562306a36Sopenharmony_ci			ntfs_error(sb, "Index root attribute missing in "
10662306a36Sopenharmony_ci					"directory inode 0x%lx.",
10762306a36Sopenharmony_ci					dir_ni->mft_no);
10862306a36Sopenharmony_ci			err = -EIO;
10962306a36Sopenharmony_ci		}
11062306a36Sopenharmony_ci		goto err_out;
11162306a36Sopenharmony_ci	}
11262306a36Sopenharmony_ci	/* Get to the index root value (it's been verified in read_inode). */
11362306a36Sopenharmony_ci	ir = (INDEX_ROOT*)((u8*)ctx->attr +
11462306a36Sopenharmony_ci			le16_to_cpu(ctx->attr->data.resident.value_offset));
11562306a36Sopenharmony_ci	index_end = (u8*)&ir->index + le32_to_cpu(ir->index.index_length);
11662306a36Sopenharmony_ci	/* The first index entry. */
11762306a36Sopenharmony_ci	ie = (INDEX_ENTRY*)((u8*)&ir->index +
11862306a36Sopenharmony_ci			le32_to_cpu(ir->index.entries_offset));
11962306a36Sopenharmony_ci	/*
12062306a36Sopenharmony_ci	 * Loop until we exceed valid memory (corruption case) or until we
12162306a36Sopenharmony_ci	 * reach the last entry.
12262306a36Sopenharmony_ci	 */
12362306a36Sopenharmony_ci	for (;; ie = (INDEX_ENTRY*)((u8*)ie + le16_to_cpu(ie->length))) {
12462306a36Sopenharmony_ci		/* Bounds checks. */
12562306a36Sopenharmony_ci		if ((u8*)ie < (u8*)ctx->mrec || (u8*)ie +
12662306a36Sopenharmony_ci				sizeof(INDEX_ENTRY_HEADER) > index_end ||
12762306a36Sopenharmony_ci				(u8*)ie + le16_to_cpu(ie->key_length) >
12862306a36Sopenharmony_ci				index_end)
12962306a36Sopenharmony_ci			goto dir_err_out;
13062306a36Sopenharmony_ci		/*
13162306a36Sopenharmony_ci		 * The last entry cannot contain a name. It can however contain
13262306a36Sopenharmony_ci		 * a pointer to a child node in the B+tree so we just break out.
13362306a36Sopenharmony_ci		 */
13462306a36Sopenharmony_ci		if (ie->flags & INDEX_ENTRY_END)
13562306a36Sopenharmony_ci			break;
13662306a36Sopenharmony_ci		/*
13762306a36Sopenharmony_ci		 * We perform a case sensitive comparison and if that matches
13862306a36Sopenharmony_ci		 * we are done and return the mft reference of the inode (i.e.
13962306a36Sopenharmony_ci		 * the inode number together with the sequence number for
14062306a36Sopenharmony_ci		 * consistency checking). We convert it to cpu format before
14162306a36Sopenharmony_ci		 * returning.
14262306a36Sopenharmony_ci		 */
14362306a36Sopenharmony_ci		if (ntfs_are_names_equal(uname, uname_len,
14462306a36Sopenharmony_ci				(ntfschar*)&ie->key.file_name.file_name,
14562306a36Sopenharmony_ci				ie->key.file_name.file_name_length,
14662306a36Sopenharmony_ci				CASE_SENSITIVE, vol->upcase, vol->upcase_len)) {
14762306a36Sopenharmony_cifound_it:
14862306a36Sopenharmony_ci			/*
14962306a36Sopenharmony_ci			 * We have a perfect match, so we don't need to care
15062306a36Sopenharmony_ci			 * about having matched imperfectly before, so we can
15162306a36Sopenharmony_ci			 * free name and set *res to NULL.
15262306a36Sopenharmony_ci			 * However, if the perfect match is a short file name,
15362306a36Sopenharmony_ci			 * we need to signal this through *res, so that
15462306a36Sopenharmony_ci			 * ntfs_lookup() can fix dcache aliasing issues.
15562306a36Sopenharmony_ci			 * As an optimization we just reuse an existing
15662306a36Sopenharmony_ci			 * allocation of *res.
15762306a36Sopenharmony_ci			 */
15862306a36Sopenharmony_ci			if (ie->key.file_name.file_name_type == FILE_NAME_DOS) {
15962306a36Sopenharmony_ci				if (!name) {
16062306a36Sopenharmony_ci					name = kmalloc(sizeof(ntfs_name),
16162306a36Sopenharmony_ci							GFP_NOFS);
16262306a36Sopenharmony_ci					if (!name) {
16362306a36Sopenharmony_ci						err = -ENOMEM;
16462306a36Sopenharmony_ci						goto err_out;
16562306a36Sopenharmony_ci					}
16662306a36Sopenharmony_ci				}
16762306a36Sopenharmony_ci				name->mref = le64_to_cpu(
16862306a36Sopenharmony_ci						ie->data.dir.indexed_file);
16962306a36Sopenharmony_ci				name->type = FILE_NAME_DOS;
17062306a36Sopenharmony_ci				name->len = 0;
17162306a36Sopenharmony_ci				*res = name;
17262306a36Sopenharmony_ci			} else {
17362306a36Sopenharmony_ci				kfree(name);
17462306a36Sopenharmony_ci				*res = NULL;
17562306a36Sopenharmony_ci			}
17662306a36Sopenharmony_ci			mref = le64_to_cpu(ie->data.dir.indexed_file);
17762306a36Sopenharmony_ci			ntfs_attr_put_search_ctx(ctx);
17862306a36Sopenharmony_ci			unmap_mft_record(dir_ni);
17962306a36Sopenharmony_ci			return mref;
18062306a36Sopenharmony_ci		}
18162306a36Sopenharmony_ci		/*
18262306a36Sopenharmony_ci		 * For a case insensitive mount, we also perform a case
18362306a36Sopenharmony_ci		 * insensitive comparison (provided the file name is not in the
18462306a36Sopenharmony_ci		 * POSIX namespace). If the comparison matches, and the name is
18562306a36Sopenharmony_ci		 * in the WIN32 namespace, we cache the filename in *res so
18662306a36Sopenharmony_ci		 * that the caller, ntfs_lookup(), can work on it. If the
18762306a36Sopenharmony_ci		 * comparison matches, and the name is in the DOS namespace, we
18862306a36Sopenharmony_ci		 * only cache the mft reference and the file name type (we set
18962306a36Sopenharmony_ci		 * the name length to zero for simplicity).
19062306a36Sopenharmony_ci		 */
19162306a36Sopenharmony_ci		if (!NVolCaseSensitive(vol) &&
19262306a36Sopenharmony_ci				ie->key.file_name.file_name_type &&
19362306a36Sopenharmony_ci				ntfs_are_names_equal(uname, uname_len,
19462306a36Sopenharmony_ci				(ntfschar*)&ie->key.file_name.file_name,
19562306a36Sopenharmony_ci				ie->key.file_name.file_name_length,
19662306a36Sopenharmony_ci				IGNORE_CASE, vol->upcase, vol->upcase_len)) {
19762306a36Sopenharmony_ci			int name_size = sizeof(ntfs_name);
19862306a36Sopenharmony_ci			u8 type = ie->key.file_name.file_name_type;
19962306a36Sopenharmony_ci			u8 len = ie->key.file_name.file_name_length;
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci			/* Only one case insensitive matching name allowed. */
20262306a36Sopenharmony_ci			if (name) {
20362306a36Sopenharmony_ci				ntfs_error(sb, "Found already allocated name "
20462306a36Sopenharmony_ci						"in phase 1. Please run chkdsk "
20562306a36Sopenharmony_ci						"and if that doesn't find any "
20662306a36Sopenharmony_ci						"errors please report you saw "
20762306a36Sopenharmony_ci						"this message to "
20862306a36Sopenharmony_ci						"linux-ntfs-dev@lists."
20962306a36Sopenharmony_ci						"sourceforge.net.");
21062306a36Sopenharmony_ci				goto dir_err_out;
21162306a36Sopenharmony_ci			}
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci			if (type != FILE_NAME_DOS)
21462306a36Sopenharmony_ci				name_size += len * sizeof(ntfschar);
21562306a36Sopenharmony_ci			name = kmalloc(name_size, GFP_NOFS);
21662306a36Sopenharmony_ci			if (!name) {
21762306a36Sopenharmony_ci				err = -ENOMEM;
21862306a36Sopenharmony_ci				goto err_out;
21962306a36Sopenharmony_ci			}
22062306a36Sopenharmony_ci			name->mref = le64_to_cpu(ie->data.dir.indexed_file);
22162306a36Sopenharmony_ci			name->type = type;
22262306a36Sopenharmony_ci			if (type != FILE_NAME_DOS) {
22362306a36Sopenharmony_ci				name->len = len;
22462306a36Sopenharmony_ci				memcpy(name->name, ie->key.file_name.file_name,
22562306a36Sopenharmony_ci						len * sizeof(ntfschar));
22662306a36Sopenharmony_ci			} else
22762306a36Sopenharmony_ci				name->len = 0;
22862306a36Sopenharmony_ci			*res = name;
22962306a36Sopenharmony_ci		}
23062306a36Sopenharmony_ci		/*
23162306a36Sopenharmony_ci		 * Not a perfect match, need to do full blown collation so we
23262306a36Sopenharmony_ci		 * know which way in the B+tree we have to go.
23362306a36Sopenharmony_ci		 */
23462306a36Sopenharmony_ci		rc = ntfs_collate_names(uname, uname_len,
23562306a36Sopenharmony_ci				(ntfschar*)&ie->key.file_name.file_name,
23662306a36Sopenharmony_ci				ie->key.file_name.file_name_length, 1,
23762306a36Sopenharmony_ci				IGNORE_CASE, vol->upcase, vol->upcase_len);
23862306a36Sopenharmony_ci		/*
23962306a36Sopenharmony_ci		 * If uname collates before the name of the current entry, there
24062306a36Sopenharmony_ci		 * is definitely no such name in this index but we might need to
24162306a36Sopenharmony_ci		 * descend into the B+tree so we just break out of the loop.
24262306a36Sopenharmony_ci		 */
24362306a36Sopenharmony_ci		if (rc == -1)
24462306a36Sopenharmony_ci			break;
24562306a36Sopenharmony_ci		/* The names are not equal, continue the search. */
24662306a36Sopenharmony_ci		if (rc)
24762306a36Sopenharmony_ci			continue;
24862306a36Sopenharmony_ci		/*
24962306a36Sopenharmony_ci		 * Names match with case insensitive comparison, now try the
25062306a36Sopenharmony_ci		 * case sensitive comparison, which is required for proper
25162306a36Sopenharmony_ci		 * collation.
25262306a36Sopenharmony_ci		 */
25362306a36Sopenharmony_ci		rc = ntfs_collate_names(uname, uname_len,
25462306a36Sopenharmony_ci				(ntfschar*)&ie->key.file_name.file_name,
25562306a36Sopenharmony_ci				ie->key.file_name.file_name_length, 1,
25662306a36Sopenharmony_ci				CASE_SENSITIVE, vol->upcase, vol->upcase_len);
25762306a36Sopenharmony_ci		if (rc == -1)
25862306a36Sopenharmony_ci			break;
25962306a36Sopenharmony_ci		if (rc)
26062306a36Sopenharmony_ci			continue;
26162306a36Sopenharmony_ci		/*
26262306a36Sopenharmony_ci		 * Perfect match, this will never happen as the
26362306a36Sopenharmony_ci		 * ntfs_are_names_equal() call will have gotten a match but we
26462306a36Sopenharmony_ci		 * still treat it correctly.
26562306a36Sopenharmony_ci		 */
26662306a36Sopenharmony_ci		goto found_it;
26762306a36Sopenharmony_ci	}
26862306a36Sopenharmony_ci	/*
26962306a36Sopenharmony_ci	 * We have finished with this index without success. Check for the
27062306a36Sopenharmony_ci	 * presence of a child node and if not present return -ENOENT, unless
27162306a36Sopenharmony_ci	 * we have got a matching name cached in name in which case return the
27262306a36Sopenharmony_ci	 * mft reference associated with it.
27362306a36Sopenharmony_ci	 */
27462306a36Sopenharmony_ci	if (!(ie->flags & INDEX_ENTRY_NODE)) {
27562306a36Sopenharmony_ci		if (name) {
27662306a36Sopenharmony_ci			ntfs_attr_put_search_ctx(ctx);
27762306a36Sopenharmony_ci			unmap_mft_record(dir_ni);
27862306a36Sopenharmony_ci			return name->mref;
27962306a36Sopenharmony_ci		}
28062306a36Sopenharmony_ci		ntfs_debug("Entry not found.");
28162306a36Sopenharmony_ci		err = -ENOENT;
28262306a36Sopenharmony_ci		goto err_out;
28362306a36Sopenharmony_ci	} /* Child node present, descend into it. */
28462306a36Sopenharmony_ci	/* Consistency check: Verify that an index allocation exists. */
28562306a36Sopenharmony_ci	if (!NInoIndexAllocPresent(dir_ni)) {
28662306a36Sopenharmony_ci		ntfs_error(sb, "No index allocation attribute but index entry "
28762306a36Sopenharmony_ci				"requires one. Directory inode 0x%lx is "
28862306a36Sopenharmony_ci				"corrupt or driver bug.", dir_ni->mft_no);
28962306a36Sopenharmony_ci		goto err_out;
29062306a36Sopenharmony_ci	}
29162306a36Sopenharmony_ci	/* Get the starting vcn of the index_block holding the child node. */
29262306a36Sopenharmony_ci	vcn = sle64_to_cpup((sle64*)((u8*)ie + le16_to_cpu(ie->length) - 8));
29362306a36Sopenharmony_ci	ia_mapping = VFS_I(dir_ni)->i_mapping;
29462306a36Sopenharmony_ci	/*
29562306a36Sopenharmony_ci	 * We are done with the index root and the mft record. Release them,
29662306a36Sopenharmony_ci	 * otherwise we deadlock with ntfs_map_page().
29762306a36Sopenharmony_ci	 */
29862306a36Sopenharmony_ci	ntfs_attr_put_search_ctx(ctx);
29962306a36Sopenharmony_ci	unmap_mft_record(dir_ni);
30062306a36Sopenharmony_ci	m = NULL;
30162306a36Sopenharmony_ci	ctx = NULL;
30262306a36Sopenharmony_cidescend_into_child_node:
30362306a36Sopenharmony_ci	/*
30462306a36Sopenharmony_ci	 * Convert vcn to index into the index allocation attribute in units
30562306a36Sopenharmony_ci	 * of PAGE_SIZE and map the page cache page, reading it from
30662306a36Sopenharmony_ci	 * disk if necessary.
30762306a36Sopenharmony_ci	 */
30862306a36Sopenharmony_ci	page = ntfs_map_page(ia_mapping, vcn <<
30962306a36Sopenharmony_ci			dir_ni->itype.index.vcn_size_bits >> PAGE_SHIFT);
31062306a36Sopenharmony_ci	if (IS_ERR(page)) {
31162306a36Sopenharmony_ci		ntfs_error(sb, "Failed to map directory index page, error %ld.",
31262306a36Sopenharmony_ci				-PTR_ERR(page));
31362306a36Sopenharmony_ci		err = PTR_ERR(page);
31462306a36Sopenharmony_ci		goto err_out;
31562306a36Sopenharmony_ci	}
31662306a36Sopenharmony_ci	lock_page(page);
31762306a36Sopenharmony_ci	kaddr = (u8*)page_address(page);
31862306a36Sopenharmony_cifast_descend_into_child_node:
31962306a36Sopenharmony_ci	/* Get to the index allocation block. */
32062306a36Sopenharmony_ci	ia = (INDEX_ALLOCATION*)(kaddr + ((vcn <<
32162306a36Sopenharmony_ci			dir_ni->itype.index.vcn_size_bits) & ~PAGE_MASK));
32262306a36Sopenharmony_ci	/* Bounds checks. */
32362306a36Sopenharmony_ci	if ((u8*)ia < kaddr || (u8*)ia > kaddr + PAGE_SIZE) {
32462306a36Sopenharmony_ci		ntfs_error(sb, "Out of bounds check failed. Corrupt directory "
32562306a36Sopenharmony_ci				"inode 0x%lx or driver bug.", dir_ni->mft_no);
32662306a36Sopenharmony_ci		goto unm_err_out;
32762306a36Sopenharmony_ci	}
32862306a36Sopenharmony_ci	/* Catch multi sector transfer fixup errors. */
32962306a36Sopenharmony_ci	if (unlikely(!ntfs_is_indx_record(ia->magic))) {
33062306a36Sopenharmony_ci		ntfs_error(sb, "Directory index record with vcn 0x%llx is "
33162306a36Sopenharmony_ci				"corrupt.  Corrupt inode 0x%lx.  Run chkdsk.",
33262306a36Sopenharmony_ci				(unsigned long long)vcn, dir_ni->mft_no);
33362306a36Sopenharmony_ci		goto unm_err_out;
33462306a36Sopenharmony_ci	}
33562306a36Sopenharmony_ci	if (sle64_to_cpu(ia->index_block_vcn) != vcn) {
33662306a36Sopenharmony_ci		ntfs_error(sb, "Actual VCN (0x%llx) of index buffer is "
33762306a36Sopenharmony_ci				"different from expected VCN (0x%llx). "
33862306a36Sopenharmony_ci				"Directory inode 0x%lx is corrupt or driver "
33962306a36Sopenharmony_ci				"bug.", (unsigned long long)
34062306a36Sopenharmony_ci				sle64_to_cpu(ia->index_block_vcn),
34162306a36Sopenharmony_ci				(unsigned long long)vcn, dir_ni->mft_no);
34262306a36Sopenharmony_ci		goto unm_err_out;
34362306a36Sopenharmony_ci	}
34462306a36Sopenharmony_ci	if (le32_to_cpu(ia->index.allocated_size) + 0x18 !=
34562306a36Sopenharmony_ci			dir_ni->itype.index.block_size) {
34662306a36Sopenharmony_ci		ntfs_error(sb, "Index buffer (VCN 0x%llx) of directory inode "
34762306a36Sopenharmony_ci				"0x%lx has a size (%u) differing from the "
34862306a36Sopenharmony_ci				"directory specified size (%u). Directory "
34962306a36Sopenharmony_ci				"inode is corrupt or driver bug.",
35062306a36Sopenharmony_ci				(unsigned long long)vcn, dir_ni->mft_no,
35162306a36Sopenharmony_ci				le32_to_cpu(ia->index.allocated_size) + 0x18,
35262306a36Sopenharmony_ci				dir_ni->itype.index.block_size);
35362306a36Sopenharmony_ci		goto unm_err_out;
35462306a36Sopenharmony_ci	}
35562306a36Sopenharmony_ci	index_end = (u8*)ia + dir_ni->itype.index.block_size;
35662306a36Sopenharmony_ci	if (index_end > kaddr + PAGE_SIZE) {
35762306a36Sopenharmony_ci		ntfs_error(sb, "Index buffer (VCN 0x%llx) of directory inode "
35862306a36Sopenharmony_ci				"0x%lx crosses page boundary. Impossible! "
35962306a36Sopenharmony_ci				"Cannot access! This is probably a bug in the "
36062306a36Sopenharmony_ci				"driver.", (unsigned long long)vcn,
36162306a36Sopenharmony_ci				dir_ni->mft_no);
36262306a36Sopenharmony_ci		goto unm_err_out;
36362306a36Sopenharmony_ci	}
36462306a36Sopenharmony_ci	index_end = (u8*)&ia->index + le32_to_cpu(ia->index.index_length);
36562306a36Sopenharmony_ci	if (index_end > (u8*)ia + dir_ni->itype.index.block_size) {
36662306a36Sopenharmony_ci		ntfs_error(sb, "Size of index buffer (VCN 0x%llx) of directory "
36762306a36Sopenharmony_ci				"inode 0x%lx exceeds maximum size.",
36862306a36Sopenharmony_ci				(unsigned long long)vcn, dir_ni->mft_no);
36962306a36Sopenharmony_ci		goto unm_err_out;
37062306a36Sopenharmony_ci	}
37162306a36Sopenharmony_ci	/* The first index entry. */
37262306a36Sopenharmony_ci	ie = (INDEX_ENTRY*)((u8*)&ia->index +
37362306a36Sopenharmony_ci			le32_to_cpu(ia->index.entries_offset));
37462306a36Sopenharmony_ci	/*
37562306a36Sopenharmony_ci	 * Iterate similar to above big loop but applied to index buffer, thus
37662306a36Sopenharmony_ci	 * loop until we exceed valid memory (corruption case) or until we
37762306a36Sopenharmony_ci	 * reach the last entry.
37862306a36Sopenharmony_ci	 */
37962306a36Sopenharmony_ci	for (;; ie = (INDEX_ENTRY*)((u8*)ie + le16_to_cpu(ie->length))) {
38062306a36Sopenharmony_ci		/* Bounds check. */
38162306a36Sopenharmony_ci		if ((u8*)ie < (u8*)ia || (u8*)ie +
38262306a36Sopenharmony_ci				sizeof(INDEX_ENTRY_HEADER) > index_end ||
38362306a36Sopenharmony_ci				(u8*)ie + le16_to_cpu(ie->key_length) >
38462306a36Sopenharmony_ci				index_end) {
38562306a36Sopenharmony_ci			ntfs_error(sb, "Index entry out of bounds in "
38662306a36Sopenharmony_ci					"directory inode 0x%lx.",
38762306a36Sopenharmony_ci					dir_ni->mft_no);
38862306a36Sopenharmony_ci			goto unm_err_out;
38962306a36Sopenharmony_ci		}
39062306a36Sopenharmony_ci		/*
39162306a36Sopenharmony_ci		 * The last entry cannot contain a name. It can however contain
39262306a36Sopenharmony_ci		 * a pointer to a child node in the B+tree so we just break out.
39362306a36Sopenharmony_ci		 */
39462306a36Sopenharmony_ci		if (ie->flags & INDEX_ENTRY_END)
39562306a36Sopenharmony_ci			break;
39662306a36Sopenharmony_ci		/*
39762306a36Sopenharmony_ci		 * We perform a case sensitive comparison and if that matches
39862306a36Sopenharmony_ci		 * we are done and return the mft reference of the inode (i.e.
39962306a36Sopenharmony_ci		 * the inode number together with the sequence number for
40062306a36Sopenharmony_ci		 * consistency checking). We convert it to cpu format before
40162306a36Sopenharmony_ci		 * returning.
40262306a36Sopenharmony_ci		 */
40362306a36Sopenharmony_ci		if (ntfs_are_names_equal(uname, uname_len,
40462306a36Sopenharmony_ci				(ntfschar*)&ie->key.file_name.file_name,
40562306a36Sopenharmony_ci				ie->key.file_name.file_name_length,
40662306a36Sopenharmony_ci				CASE_SENSITIVE, vol->upcase, vol->upcase_len)) {
40762306a36Sopenharmony_cifound_it2:
40862306a36Sopenharmony_ci			/*
40962306a36Sopenharmony_ci			 * We have a perfect match, so we don't need to care
41062306a36Sopenharmony_ci			 * about having matched imperfectly before, so we can
41162306a36Sopenharmony_ci			 * free name and set *res to NULL.
41262306a36Sopenharmony_ci			 * However, if the perfect match is a short file name,
41362306a36Sopenharmony_ci			 * we need to signal this through *res, so that
41462306a36Sopenharmony_ci			 * ntfs_lookup() can fix dcache aliasing issues.
41562306a36Sopenharmony_ci			 * As an optimization we just reuse an existing
41662306a36Sopenharmony_ci			 * allocation of *res.
41762306a36Sopenharmony_ci			 */
41862306a36Sopenharmony_ci			if (ie->key.file_name.file_name_type == FILE_NAME_DOS) {
41962306a36Sopenharmony_ci				if (!name) {
42062306a36Sopenharmony_ci					name = kmalloc(sizeof(ntfs_name),
42162306a36Sopenharmony_ci							GFP_NOFS);
42262306a36Sopenharmony_ci					if (!name) {
42362306a36Sopenharmony_ci						err = -ENOMEM;
42462306a36Sopenharmony_ci						goto unm_err_out;
42562306a36Sopenharmony_ci					}
42662306a36Sopenharmony_ci				}
42762306a36Sopenharmony_ci				name->mref = le64_to_cpu(
42862306a36Sopenharmony_ci						ie->data.dir.indexed_file);
42962306a36Sopenharmony_ci				name->type = FILE_NAME_DOS;
43062306a36Sopenharmony_ci				name->len = 0;
43162306a36Sopenharmony_ci				*res = name;
43262306a36Sopenharmony_ci			} else {
43362306a36Sopenharmony_ci				kfree(name);
43462306a36Sopenharmony_ci				*res = NULL;
43562306a36Sopenharmony_ci			}
43662306a36Sopenharmony_ci			mref = le64_to_cpu(ie->data.dir.indexed_file);
43762306a36Sopenharmony_ci			unlock_page(page);
43862306a36Sopenharmony_ci			ntfs_unmap_page(page);
43962306a36Sopenharmony_ci			return mref;
44062306a36Sopenharmony_ci		}
44162306a36Sopenharmony_ci		/*
44262306a36Sopenharmony_ci		 * For a case insensitive mount, we also perform a case
44362306a36Sopenharmony_ci		 * insensitive comparison (provided the file name is not in the
44462306a36Sopenharmony_ci		 * POSIX namespace). If the comparison matches, and the name is
44562306a36Sopenharmony_ci		 * in the WIN32 namespace, we cache the filename in *res so
44662306a36Sopenharmony_ci		 * that the caller, ntfs_lookup(), can work on it. If the
44762306a36Sopenharmony_ci		 * comparison matches, and the name is in the DOS namespace, we
44862306a36Sopenharmony_ci		 * only cache the mft reference and the file name type (we set
44962306a36Sopenharmony_ci		 * the name length to zero for simplicity).
45062306a36Sopenharmony_ci		 */
45162306a36Sopenharmony_ci		if (!NVolCaseSensitive(vol) &&
45262306a36Sopenharmony_ci				ie->key.file_name.file_name_type &&
45362306a36Sopenharmony_ci				ntfs_are_names_equal(uname, uname_len,
45462306a36Sopenharmony_ci				(ntfschar*)&ie->key.file_name.file_name,
45562306a36Sopenharmony_ci				ie->key.file_name.file_name_length,
45662306a36Sopenharmony_ci				IGNORE_CASE, vol->upcase, vol->upcase_len)) {
45762306a36Sopenharmony_ci			int name_size = sizeof(ntfs_name);
45862306a36Sopenharmony_ci			u8 type = ie->key.file_name.file_name_type;
45962306a36Sopenharmony_ci			u8 len = ie->key.file_name.file_name_length;
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci			/* Only one case insensitive matching name allowed. */
46262306a36Sopenharmony_ci			if (name) {
46362306a36Sopenharmony_ci				ntfs_error(sb, "Found already allocated name "
46462306a36Sopenharmony_ci						"in phase 2. Please run chkdsk "
46562306a36Sopenharmony_ci						"and if that doesn't find any "
46662306a36Sopenharmony_ci						"errors please report you saw "
46762306a36Sopenharmony_ci						"this message to "
46862306a36Sopenharmony_ci						"linux-ntfs-dev@lists."
46962306a36Sopenharmony_ci						"sourceforge.net.");
47062306a36Sopenharmony_ci				unlock_page(page);
47162306a36Sopenharmony_ci				ntfs_unmap_page(page);
47262306a36Sopenharmony_ci				goto dir_err_out;
47362306a36Sopenharmony_ci			}
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci			if (type != FILE_NAME_DOS)
47662306a36Sopenharmony_ci				name_size += len * sizeof(ntfschar);
47762306a36Sopenharmony_ci			name = kmalloc(name_size, GFP_NOFS);
47862306a36Sopenharmony_ci			if (!name) {
47962306a36Sopenharmony_ci				err = -ENOMEM;
48062306a36Sopenharmony_ci				goto unm_err_out;
48162306a36Sopenharmony_ci			}
48262306a36Sopenharmony_ci			name->mref = le64_to_cpu(ie->data.dir.indexed_file);
48362306a36Sopenharmony_ci			name->type = type;
48462306a36Sopenharmony_ci			if (type != FILE_NAME_DOS) {
48562306a36Sopenharmony_ci				name->len = len;
48662306a36Sopenharmony_ci				memcpy(name->name, ie->key.file_name.file_name,
48762306a36Sopenharmony_ci						len * sizeof(ntfschar));
48862306a36Sopenharmony_ci			} else
48962306a36Sopenharmony_ci				name->len = 0;
49062306a36Sopenharmony_ci			*res = name;
49162306a36Sopenharmony_ci		}
49262306a36Sopenharmony_ci		/*
49362306a36Sopenharmony_ci		 * Not a perfect match, need to do full blown collation so we
49462306a36Sopenharmony_ci		 * know which way in the B+tree we have to go.
49562306a36Sopenharmony_ci		 */
49662306a36Sopenharmony_ci		rc = ntfs_collate_names(uname, uname_len,
49762306a36Sopenharmony_ci				(ntfschar*)&ie->key.file_name.file_name,
49862306a36Sopenharmony_ci				ie->key.file_name.file_name_length, 1,
49962306a36Sopenharmony_ci				IGNORE_CASE, vol->upcase, vol->upcase_len);
50062306a36Sopenharmony_ci		/*
50162306a36Sopenharmony_ci		 * If uname collates before the name of the current entry, there
50262306a36Sopenharmony_ci		 * is definitely no such name in this index but we might need to
50362306a36Sopenharmony_ci		 * descend into the B+tree so we just break out of the loop.
50462306a36Sopenharmony_ci		 */
50562306a36Sopenharmony_ci		if (rc == -1)
50662306a36Sopenharmony_ci			break;
50762306a36Sopenharmony_ci		/* The names are not equal, continue the search. */
50862306a36Sopenharmony_ci		if (rc)
50962306a36Sopenharmony_ci			continue;
51062306a36Sopenharmony_ci		/*
51162306a36Sopenharmony_ci		 * Names match with case insensitive comparison, now try the
51262306a36Sopenharmony_ci		 * case sensitive comparison, which is required for proper
51362306a36Sopenharmony_ci		 * collation.
51462306a36Sopenharmony_ci		 */
51562306a36Sopenharmony_ci		rc = ntfs_collate_names(uname, uname_len,
51662306a36Sopenharmony_ci				(ntfschar*)&ie->key.file_name.file_name,
51762306a36Sopenharmony_ci				ie->key.file_name.file_name_length, 1,
51862306a36Sopenharmony_ci				CASE_SENSITIVE, vol->upcase, vol->upcase_len);
51962306a36Sopenharmony_ci		if (rc == -1)
52062306a36Sopenharmony_ci			break;
52162306a36Sopenharmony_ci		if (rc)
52262306a36Sopenharmony_ci			continue;
52362306a36Sopenharmony_ci		/*
52462306a36Sopenharmony_ci		 * Perfect match, this will never happen as the
52562306a36Sopenharmony_ci		 * ntfs_are_names_equal() call will have gotten a match but we
52662306a36Sopenharmony_ci		 * still treat it correctly.
52762306a36Sopenharmony_ci		 */
52862306a36Sopenharmony_ci		goto found_it2;
52962306a36Sopenharmony_ci	}
53062306a36Sopenharmony_ci	/*
53162306a36Sopenharmony_ci	 * We have finished with this index buffer without success. Check for
53262306a36Sopenharmony_ci	 * the presence of a child node.
53362306a36Sopenharmony_ci	 */
53462306a36Sopenharmony_ci	if (ie->flags & INDEX_ENTRY_NODE) {
53562306a36Sopenharmony_ci		if ((ia->index.flags & NODE_MASK) == LEAF_NODE) {
53662306a36Sopenharmony_ci			ntfs_error(sb, "Index entry with child node found in "
53762306a36Sopenharmony_ci					"a leaf node in directory inode 0x%lx.",
53862306a36Sopenharmony_ci					dir_ni->mft_no);
53962306a36Sopenharmony_ci			goto unm_err_out;
54062306a36Sopenharmony_ci		}
54162306a36Sopenharmony_ci		/* Child node present, descend into it. */
54262306a36Sopenharmony_ci		old_vcn = vcn;
54362306a36Sopenharmony_ci		vcn = sle64_to_cpup((sle64*)((u8*)ie +
54462306a36Sopenharmony_ci				le16_to_cpu(ie->length) - 8));
54562306a36Sopenharmony_ci		if (vcn >= 0) {
54662306a36Sopenharmony_ci			/* If vcn is in the same page cache page as old_vcn we
54762306a36Sopenharmony_ci			 * recycle the mapped page. */
54862306a36Sopenharmony_ci			if (old_vcn << vol->cluster_size_bits >>
54962306a36Sopenharmony_ci					PAGE_SHIFT == vcn <<
55062306a36Sopenharmony_ci					vol->cluster_size_bits >>
55162306a36Sopenharmony_ci					PAGE_SHIFT)
55262306a36Sopenharmony_ci				goto fast_descend_into_child_node;
55362306a36Sopenharmony_ci			unlock_page(page);
55462306a36Sopenharmony_ci			ntfs_unmap_page(page);
55562306a36Sopenharmony_ci			goto descend_into_child_node;
55662306a36Sopenharmony_ci		}
55762306a36Sopenharmony_ci		ntfs_error(sb, "Negative child node vcn in directory inode "
55862306a36Sopenharmony_ci				"0x%lx.", dir_ni->mft_no);
55962306a36Sopenharmony_ci		goto unm_err_out;
56062306a36Sopenharmony_ci	}
56162306a36Sopenharmony_ci	/*
56262306a36Sopenharmony_ci	 * No child node present, return -ENOENT, unless we have got a matching
56362306a36Sopenharmony_ci	 * name cached in name in which case return the mft reference
56462306a36Sopenharmony_ci	 * associated with it.
56562306a36Sopenharmony_ci	 */
56662306a36Sopenharmony_ci	if (name) {
56762306a36Sopenharmony_ci		unlock_page(page);
56862306a36Sopenharmony_ci		ntfs_unmap_page(page);
56962306a36Sopenharmony_ci		return name->mref;
57062306a36Sopenharmony_ci	}
57162306a36Sopenharmony_ci	ntfs_debug("Entry not found.");
57262306a36Sopenharmony_ci	err = -ENOENT;
57362306a36Sopenharmony_ciunm_err_out:
57462306a36Sopenharmony_ci	unlock_page(page);
57562306a36Sopenharmony_ci	ntfs_unmap_page(page);
57662306a36Sopenharmony_cierr_out:
57762306a36Sopenharmony_ci	if (!err)
57862306a36Sopenharmony_ci		err = -EIO;
57962306a36Sopenharmony_ci	if (ctx)
58062306a36Sopenharmony_ci		ntfs_attr_put_search_ctx(ctx);
58162306a36Sopenharmony_ci	if (m)
58262306a36Sopenharmony_ci		unmap_mft_record(dir_ni);
58362306a36Sopenharmony_ci	if (name) {
58462306a36Sopenharmony_ci		kfree(name);
58562306a36Sopenharmony_ci		*res = NULL;
58662306a36Sopenharmony_ci	}
58762306a36Sopenharmony_ci	return ERR_MREF(err);
58862306a36Sopenharmony_cidir_err_out:
58962306a36Sopenharmony_ci	ntfs_error(sb, "Corrupt directory.  Aborting lookup.");
59062306a36Sopenharmony_ci	goto err_out;
59162306a36Sopenharmony_ci}
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci#if 0
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci// TODO: (AIA)
59662306a36Sopenharmony_ci// The algorithm embedded in this code will be required for the time when we
59762306a36Sopenharmony_ci// want to support adding of entries to directories, where we require correct
59862306a36Sopenharmony_ci// collation of file names in order not to cause corruption of the filesystem.
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_ci/**
60162306a36Sopenharmony_ci * ntfs_lookup_inode_by_name - find an inode in a directory given its name
60262306a36Sopenharmony_ci * @dir_ni:	ntfs inode of the directory in which to search for the name
60362306a36Sopenharmony_ci * @uname:	Unicode name for which to search in the directory
60462306a36Sopenharmony_ci * @uname_len:	length of the name @uname in Unicode characters
60562306a36Sopenharmony_ci *
60662306a36Sopenharmony_ci * Look for an inode with name @uname in the directory with inode @dir_ni.
60762306a36Sopenharmony_ci * ntfs_lookup_inode_by_name() walks the contents of the directory looking for
60862306a36Sopenharmony_ci * the Unicode name. If the name is found in the directory, the corresponding
60962306a36Sopenharmony_ci * inode number (>= 0) is returned as a mft reference in cpu format, i.e. it
61062306a36Sopenharmony_ci * is a 64-bit number containing the sequence number.
61162306a36Sopenharmony_ci *
61262306a36Sopenharmony_ci * On error, a negative value is returned corresponding to the error code. In
61362306a36Sopenharmony_ci * particular if the inode is not found -ENOENT is returned. Note that you
61462306a36Sopenharmony_ci * can't just check the return value for being negative, you have to check the
61562306a36Sopenharmony_ci * inode number for being negative which you can extract using MREC(return
61662306a36Sopenharmony_ci * value).
61762306a36Sopenharmony_ci *
61862306a36Sopenharmony_ci * Note, @uname_len does not include the (optional) terminating NULL character.
61962306a36Sopenharmony_ci */
62062306a36Sopenharmony_ciu64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const ntfschar *uname,
62162306a36Sopenharmony_ci		const int uname_len)
62262306a36Sopenharmony_ci{
62362306a36Sopenharmony_ci	ntfs_volume *vol = dir_ni->vol;
62462306a36Sopenharmony_ci	struct super_block *sb = vol->sb;
62562306a36Sopenharmony_ci	MFT_RECORD *m;
62662306a36Sopenharmony_ci	INDEX_ROOT *ir;
62762306a36Sopenharmony_ci	INDEX_ENTRY *ie;
62862306a36Sopenharmony_ci	INDEX_ALLOCATION *ia;
62962306a36Sopenharmony_ci	u8 *index_end;
63062306a36Sopenharmony_ci	u64 mref;
63162306a36Sopenharmony_ci	ntfs_attr_search_ctx *ctx;
63262306a36Sopenharmony_ci	int err, rc;
63362306a36Sopenharmony_ci	IGNORE_CASE_BOOL ic;
63462306a36Sopenharmony_ci	VCN vcn, old_vcn;
63562306a36Sopenharmony_ci	struct address_space *ia_mapping;
63662306a36Sopenharmony_ci	struct page *page;
63762306a36Sopenharmony_ci	u8 *kaddr;
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_ci	/* Get hold of the mft record for the directory. */
64062306a36Sopenharmony_ci	m = map_mft_record(dir_ni);
64162306a36Sopenharmony_ci	if (IS_ERR(m)) {
64262306a36Sopenharmony_ci		ntfs_error(sb, "map_mft_record() failed with error code %ld.",
64362306a36Sopenharmony_ci				-PTR_ERR(m));
64462306a36Sopenharmony_ci		return ERR_MREF(PTR_ERR(m));
64562306a36Sopenharmony_ci	}
64662306a36Sopenharmony_ci	ctx = ntfs_attr_get_search_ctx(dir_ni, m);
64762306a36Sopenharmony_ci	if (!ctx) {
64862306a36Sopenharmony_ci		err = -ENOMEM;
64962306a36Sopenharmony_ci		goto err_out;
65062306a36Sopenharmony_ci	}
65162306a36Sopenharmony_ci	/* Find the index root attribute in the mft record. */
65262306a36Sopenharmony_ci	err = ntfs_attr_lookup(AT_INDEX_ROOT, I30, 4, CASE_SENSITIVE, 0, NULL,
65362306a36Sopenharmony_ci			0, ctx);
65462306a36Sopenharmony_ci	if (unlikely(err)) {
65562306a36Sopenharmony_ci		if (err == -ENOENT) {
65662306a36Sopenharmony_ci			ntfs_error(sb, "Index root attribute missing in "
65762306a36Sopenharmony_ci					"directory inode 0x%lx.",
65862306a36Sopenharmony_ci					dir_ni->mft_no);
65962306a36Sopenharmony_ci			err = -EIO;
66062306a36Sopenharmony_ci		}
66162306a36Sopenharmony_ci		goto err_out;
66262306a36Sopenharmony_ci	}
66362306a36Sopenharmony_ci	/* Get to the index root value (it's been verified in read_inode). */
66462306a36Sopenharmony_ci	ir = (INDEX_ROOT*)((u8*)ctx->attr +
66562306a36Sopenharmony_ci			le16_to_cpu(ctx->attr->data.resident.value_offset));
66662306a36Sopenharmony_ci	index_end = (u8*)&ir->index + le32_to_cpu(ir->index.index_length);
66762306a36Sopenharmony_ci	/* The first index entry. */
66862306a36Sopenharmony_ci	ie = (INDEX_ENTRY*)((u8*)&ir->index +
66962306a36Sopenharmony_ci			le32_to_cpu(ir->index.entries_offset));
67062306a36Sopenharmony_ci	/*
67162306a36Sopenharmony_ci	 * Loop until we exceed valid memory (corruption case) or until we
67262306a36Sopenharmony_ci	 * reach the last entry.
67362306a36Sopenharmony_ci	 */
67462306a36Sopenharmony_ci	for (;; ie = (INDEX_ENTRY*)((u8*)ie + le16_to_cpu(ie->length))) {
67562306a36Sopenharmony_ci		/* Bounds checks. */
67662306a36Sopenharmony_ci		if ((u8*)ie < (u8*)ctx->mrec || (u8*)ie +
67762306a36Sopenharmony_ci				sizeof(INDEX_ENTRY_HEADER) > index_end ||
67862306a36Sopenharmony_ci				(u8*)ie + le16_to_cpu(ie->key_length) >
67962306a36Sopenharmony_ci				index_end)
68062306a36Sopenharmony_ci			goto dir_err_out;
68162306a36Sopenharmony_ci		/*
68262306a36Sopenharmony_ci		 * The last entry cannot contain a name. It can however contain
68362306a36Sopenharmony_ci		 * a pointer to a child node in the B+tree so we just break out.
68462306a36Sopenharmony_ci		 */
68562306a36Sopenharmony_ci		if (ie->flags & INDEX_ENTRY_END)
68662306a36Sopenharmony_ci			break;
68762306a36Sopenharmony_ci		/*
68862306a36Sopenharmony_ci		 * If the current entry has a name type of POSIX, the name is
68962306a36Sopenharmony_ci		 * case sensitive and not otherwise. This has the effect of us
69062306a36Sopenharmony_ci		 * not being able to access any POSIX file names which collate
69162306a36Sopenharmony_ci		 * after the non-POSIX one when they only differ in case, but
69262306a36Sopenharmony_ci		 * anyone doing screwy stuff like that deserves to burn in
69362306a36Sopenharmony_ci		 * hell... Doing that kind of stuff on NT4 actually causes
69462306a36Sopenharmony_ci		 * corruption on the partition even when using SP6a and Linux
69562306a36Sopenharmony_ci		 * is not involved at all.
69662306a36Sopenharmony_ci		 */
69762306a36Sopenharmony_ci		ic = ie->key.file_name.file_name_type ? IGNORE_CASE :
69862306a36Sopenharmony_ci				CASE_SENSITIVE;
69962306a36Sopenharmony_ci		/*
70062306a36Sopenharmony_ci		 * If the names match perfectly, we are done and return the
70162306a36Sopenharmony_ci		 * mft reference of the inode (i.e. the inode number together
70262306a36Sopenharmony_ci		 * with the sequence number for consistency checking. We
70362306a36Sopenharmony_ci		 * convert it to cpu format before returning.
70462306a36Sopenharmony_ci		 */
70562306a36Sopenharmony_ci		if (ntfs_are_names_equal(uname, uname_len,
70662306a36Sopenharmony_ci				(ntfschar*)&ie->key.file_name.file_name,
70762306a36Sopenharmony_ci				ie->key.file_name.file_name_length, ic,
70862306a36Sopenharmony_ci				vol->upcase, vol->upcase_len)) {
70962306a36Sopenharmony_cifound_it:
71062306a36Sopenharmony_ci			mref = le64_to_cpu(ie->data.dir.indexed_file);
71162306a36Sopenharmony_ci			ntfs_attr_put_search_ctx(ctx);
71262306a36Sopenharmony_ci			unmap_mft_record(dir_ni);
71362306a36Sopenharmony_ci			return mref;
71462306a36Sopenharmony_ci		}
71562306a36Sopenharmony_ci		/*
71662306a36Sopenharmony_ci		 * Not a perfect match, need to do full blown collation so we
71762306a36Sopenharmony_ci		 * know which way in the B+tree we have to go.
71862306a36Sopenharmony_ci		 */
71962306a36Sopenharmony_ci		rc = ntfs_collate_names(uname, uname_len,
72062306a36Sopenharmony_ci				(ntfschar*)&ie->key.file_name.file_name,
72162306a36Sopenharmony_ci				ie->key.file_name.file_name_length, 1,
72262306a36Sopenharmony_ci				IGNORE_CASE, vol->upcase, vol->upcase_len);
72362306a36Sopenharmony_ci		/*
72462306a36Sopenharmony_ci		 * If uname collates before the name of the current entry, there
72562306a36Sopenharmony_ci		 * is definitely no such name in this index but we might need to
72662306a36Sopenharmony_ci		 * descend into the B+tree so we just break out of the loop.
72762306a36Sopenharmony_ci		 */
72862306a36Sopenharmony_ci		if (rc == -1)
72962306a36Sopenharmony_ci			break;
73062306a36Sopenharmony_ci		/* The names are not equal, continue the search. */
73162306a36Sopenharmony_ci		if (rc)
73262306a36Sopenharmony_ci			continue;
73362306a36Sopenharmony_ci		/*
73462306a36Sopenharmony_ci		 * Names match with case insensitive comparison, now try the
73562306a36Sopenharmony_ci		 * case sensitive comparison, which is required for proper
73662306a36Sopenharmony_ci		 * collation.
73762306a36Sopenharmony_ci		 */
73862306a36Sopenharmony_ci		rc = ntfs_collate_names(uname, uname_len,
73962306a36Sopenharmony_ci				(ntfschar*)&ie->key.file_name.file_name,
74062306a36Sopenharmony_ci				ie->key.file_name.file_name_length, 1,
74162306a36Sopenharmony_ci				CASE_SENSITIVE, vol->upcase, vol->upcase_len);
74262306a36Sopenharmony_ci		if (rc == -1)
74362306a36Sopenharmony_ci			break;
74462306a36Sopenharmony_ci		if (rc)
74562306a36Sopenharmony_ci			continue;
74662306a36Sopenharmony_ci		/*
74762306a36Sopenharmony_ci		 * Perfect match, this will never happen as the
74862306a36Sopenharmony_ci		 * ntfs_are_names_equal() call will have gotten a match but we
74962306a36Sopenharmony_ci		 * still treat it correctly.
75062306a36Sopenharmony_ci		 */
75162306a36Sopenharmony_ci		goto found_it;
75262306a36Sopenharmony_ci	}
75362306a36Sopenharmony_ci	/*
75462306a36Sopenharmony_ci	 * We have finished with this index without success. Check for the
75562306a36Sopenharmony_ci	 * presence of a child node.
75662306a36Sopenharmony_ci	 */
75762306a36Sopenharmony_ci	if (!(ie->flags & INDEX_ENTRY_NODE)) {
75862306a36Sopenharmony_ci		/* No child node, return -ENOENT. */
75962306a36Sopenharmony_ci		err = -ENOENT;
76062306a36Sopenharmony_ci		goto err_out;
76162306a36Sopenharmony_ci	} /* Child node present, descend into it. */
76262306a36Sopenharmony_ci	/* Consistency check: Verify that an index allocation exists. */
76362306a36Sopenharmony_ci	if (!NInoIndexAllocPresent(dir_ni)) {
76462306a36Sopenharmony_ci		ntfs_error(sb, "No index allocation attribute but index entry "
76562306a36Sopenharmony_ci				"requires one. Directory inode 0x%lx is "
76662306a36Sopenharmony_ci				"corrupt or driver bug.", dir_ni->mft_no);
76762306a36Sopenharmony_ci		goto err_out;
76862306a36Sopenharmony_ci	}
76962306a36Sopenharmony_ci	/* Get the starting vcn of the index_block holding the child node. */
77062306a36Sopenharmony_ci	vcn = sle64_to_cpup((u8*)ie + le16_to_cpu(ie->length) - 8);
77162306a36Sopenharmony_ci	ia_mapping = VFS_I(dir_ni)->i_mapping;
77262306a36Sopenharmony_ci	/*
77362306a36Sopenharmony_ci	 * We are done with the index root and the mft record. Release them,
77462306a36Sopenharmony_ci	 * otherwise we deadlock with ntfs_map_page().
77562306a36Sopenharmony_ci	 */
77662306a36Sopenharmony_ci	ntfs_attr_put_search_ctx(ctx);
77762306a36Sopenharmony_ci	unmap_mft_record(dir_ni);
77862306a36Sopenharmony_ci	m = NULL;
77962306a36Sopenharmony_ci	ctx = NULL;
78062306a36Sopenharmony_cidescend_into_child_node:
78162306a36Sopenharmony_ci	/*
78262306a36Sopenharmony_ci	 * Convert vcn to index into the index allocation attribute in units
78362306a36Sopenharmony_ci	 * of PAGE_SIZE and map the page cache page, reading it from
78462306a36Sopenharmony_ci	 * disk if necessary.
78562306a36Sopenharmony_ci	 */
78662306a36Sopenharmony_ci	page = ntfs_map_page(ia_mapping, vcn <<
78762306a36Sopenharmony_ci			dir_ni->itype.index.vcn_size_bits >> PAGE_SHIFT);
78862306a36Sopenharmony_ci	if (IS_ERR(page)) {
78962306a36Sopenharmony_ci		ntfs_error(sb, "Failed to map directory index page, error %ld.",
79062306a36Sopenharmony_ci				-PTR_ERR(page));
79162306a36Sopenharmony_ci		err = PTR_ERR(page);
79262306a36Sopenharmony_ci		goto err_out;
79362306a36Sopenharmony_ci	}
79462306a36Sopenharmony_ci	lock_page(page);
79562306a36Sopenharmony_ci	kaddr = (u8*)page_address(page);
79662306a36Sopenharmony_cifast_descend_into_child_node:
79762306a36Sopenharmony_ci	/* Get to the index allocation block. */
79862306a36Sopenharmony_ci	ia = (INDEX_ALLOCATION*)(kaddr + ((vcn <<
79962306a36Sopenharmony_ci			dir_ni->itype.index.vcn_size_bits) & ~PAGE_MASK));
80062306a36Sopenharmony_ci	/* Bounds checks. */
80162306a36Sopenharmony_ci	if ((u8*)ia < kaddr || (u8*)ia > kaddr + PAGE_SIZE) {
80262306a36Sopenharmony_ci		ntfs_error(sb, "Out of bounds check failed. Corrupt directory "
80362306a36Sopenharmony_ci				"inode 0x%lx or driver bug.", dir_ni->mft_no);
80462306a36Sopenharmony_ci		goto unm_err_out;
80562306a36Sopenharmony_ci	}
80662306a36Sopenharmony_ci	/* Catch multi sector transfer fixup errors. */
80762306a36Sopenharmony_ci	if (unlikely(!ntfs_is_indx_record(ia->magic))) {
80862306a36Sopenharmony_ci		ntfs_error(sb, "Directory index record with vcn 0x%llx is "
80962306a36Sopenharmony_ci				"corrupt.  Corrupt inode 0x%lx.  Run chkdsk.",
81062306a36Sopenharmony_ci				(unsigned long long)vcn, dir_ni->mft_no);
81162306a36Sopenharmony_ci		goto unm_err_out;
81262306a36Sopenharmony_ci	}
81362306a36Sopenharmony_ci	if (sle64_to_cpu(ia->index_block_vcn) != vcn) {
81462306a36Sopenharmony_ci		ntfs_error(sb, "Actual VCN (0x%llx) of index buffer is "
81562306a36Sopenharmony_ci				"different from expected VCN (0x%llx). "
81662306a36Sopenharmony_ci				"Directory inode 0x%lx is corrupt or driver "
81762306a36Sopenharmony_ci				"bug.", (unsigned long long)
81862306a36Sopenharmony_ci				sle64_to_cpu(ia->index_block_vcn),
81962306a36Sopenharmony_ci				(unsigned long long)vcn, dir_ni->mft_no);
82062306a36Sopenharmony_ci		goto unm_err_out;
82162306a36Sopenharmony_ci	}
82262306a36Sopenharmony_ci	if (le32_to_cpu(ia->index.allocated_size) + 0x18 !=
82362306a36Sopenharmony_ci			dir_ni->itype.index.block_size) {
82462306a36Sopenharmony_ci		ntfs_error(sb, "Index buffer (VCN 0x%llx) of directory inode "
82562306a36Sopenharmony_ci				"0x%lx has a size (%u) differing from the "
82662306a36Sopenharmony_ci				"directory specified size (%u). Directory "
82762306a36Sopenharmony_ci				"inode is corrupt or driver bug.",
82862306a36Sopenharmony_ci				(unsigned long long)vcn, dir_ni->mft_no,
82962306a36Sopenharmony_ci				le32_to_cpu(ia->index.allocated_size) + 0x18,
83062306a36Sopenharmony_ci				dir_ni->itype.index.block_size);
83162306a36Sopenharmony_ci		goto unm_err_out;
83262306a36Sopenharmony_ci	}
83362306a36Sopenharmony_ci	index_end = (u8*)ia + dir_ni->itype.index.block_size;
83462306a36Sopenharmony_ci	if (index_end > kaddr + PAGE_SIZE) {
83562306a36Sopenharmony_ci		ntfs_error(sb, "Index buffer (VCN 0x%llx) of directory inode "
83662306a36Sopenharmony_ci				"0x%lx crosses page boundary. Impossible! "
83762306a36Sopenharmony_ci				"Cannot access! This is probably a bug in the "
83862306a36Sopenharmony_ci				"driver.", (unsigned long long)vcn,
83962306a36Sopenharmony_ci				dir_ni->mft_no);
84062306a36Sopenharmony_ci		goto unm_err_out;
84162306a36Sopenharmony_ci	}
84262306a36Sopenharmony_ci	index_end = (u8*)&ia->index + le32_to_cpu(ia->index.index_length);
84362306a36Sopenharmony_ci	if (index_end > (u8*)ia + dir_ni->itype.index.block_size) {
84462306a36Sopenharmony_ci		ntfs_error(sb, "Size of index buffer (VCN 0x%llx) of directory "
84562306a36Sopenharmony_ci				"inode 0x%lx exceeds maximum size.",
84662306a36Sopenharmony_ci				(unsigned long long)vcn, dir_ni->mft_no);
84762306a36Sopenharmony_ci		goto unm_err_out;
84862306a36Sopenharmony_ci	}
84962306a36Sopenharmony_ci	/* The first index entry. */
85062306a36Sopenharmony_ci	ie = (INDEX_ENTRY*)((u8*)&ia->index +
85162306a36Sopenharmony_ci			le32_to_cpu(ia->index.entries_offset));
85262306a36Sopenharmony_ci	/*
85362306a36Sopenharmony_ci	 * Iterate similar to above big loop but applied to index buffer, thus
85462306a36Sopenharmony_ci	 * loop until we exceed valid memory (corruption case) or until we
85562306a36Sopenharmony_ci	 * reach the last entry.
85662306a36Sopenharmony_ci	 */
85762306a36Sopenharmony_ci	for (;; ie = (INDEX_ENTRY*)((u8*)ie + le16_to_cpu(ie->length))) {
85862306a36Sopenharmony_ci		/* Bounds check. */
85962306a36Sopenharmony_ci		if ((u8*)ie < (u8*)ia || (u8*)ie +
86062306a36Sopenharmony_ci				sizeof(INDEX_ENTRY_HEADER) > index_end ||
86162306a36Sopenharmony_ci				(u8*)ie + le16_to_cpu(ie->key_length) >
86262306a36Sopenharmony_ci				index_end) {
86362306a36Sopenharmony_ci			ntfs_error(sb, "Index entry out of bounds in "
86462306a36Sopenharmony_ci					"directory inode 0x%lx.",
86562306a36Sopenharmony_ci					dir_ni->mft_no);
86662306a36Sopenharmony_ci			goto unm_err_out;
86762306a36Sopenharmony_ci		}
86862306a36Sopenharmony_ci		/*
86962306a36Sopenharmony_ci		 * The last entry cannot contain a name. It can however contain
87062306a36Sopenharmony_ci		 * a pointer to a child node in the B+tree so we just break out.
87162306a36Sopenharmony_ci		 */
87262306a36Sopenharmony_ci		if (ie->flags & INDEX_ENTRY_END)
87362306a36Sopenharmony_ci			break;
87462306a36Sopenharmony_ci		/*
87562306a36Sopenharmony_ci		 * If the current entry has a name type of POSIX, the name is
87662306a36Sopenharmony_ci		 * case sensitive and not otherwise. This has the effect of us
87762306a36Sopenharmony_ci		 * not being able to access any POSIX file names which collate
87862306a36Sopenharmony_ci		 * after the non-POSIX one when they only differ in case, but
87962306a36Sopenharmony_ci		 * anyone doing screwy stuff like that deserves to burn in
88062306a36Sopenharmony_ci		 * hell... Doing that kind of stuff on NT4 actually causes
88162306a36Sopenharmony_ci		 * corruption on the partition even when using SP6a and Linux
88262306a36Sopenharmony_ci		 * is not involved at all.
88362306a36Sopenharmony_ci		 */
88462306a36Sopenharmony_ci		ic = ie->key.file_name.file_name_type ? IGNORE_CASE :
88562306a36Sopenharmony_ci				CASE_SENSITIVE;
88662306a36Sopenharmony_ci		/*
88762306a36Sopenharmony_ci		 * If the names match perfectly, we are done and return the
88862306a36Sopenharmony_ci		 * mft reference of the inode (i.e. the inode number together
88962306a36Sopenharmony_ci		 * with the sequence number for consistency checking. We
89062306a36Sopenharmony_ci		 * convert it to cpu format before returning.
89162306a36Sopenharmony_ci		 */
89262306a36Sopenharmony_ci		if (ntfs_are_names_equal(uname, uname_len,
89362306a36Sopenharmony_ci				(ntfschar*)&ie->key.file_name.file_name,
89462306a36Sopenharmony_ci				ie->key.file_name.file_name_length, ic,
89562306a36Sopenharmony_ci				vol->upcase, vol->upcase_len)) {
89662306a36Sopenharmony_cifound_it2:
89762306a36Sopenharmony_ci			mref = le64_to_cpu(ie->data.dir.indexed_file);
89862306a36Sopenharmony_ci			unlock_page(page);
89962306a36Sopenharmony_ci			ntfs_unmap_page(page);
90062306a36Sopenharmony_ci			return mref;
90162306a36Sopenharmony_ci		}
90262306a36Sopenharmony_ci		/*
90362306a36Sopenharmony_ci		 * Not a perfect match, need to do full blown collation so we
90462306a36Sopenharmony_ci		 * know which way in the B+tree we have to go.
90562306a36Sopenharmony_ci		 */
90662306a36Sopenharmony_ci		rc = ntfs_collate_names(uname, uname_len,
90762306a36Sopenharmony_ci				(ntfschar*)&ie->key.file_name.file_name,
90862306a36Sopenharmony_ci				ie->key.file_name.file_name_length, 1,
90962306a36Sopenharmony_ci				IGNORE_CASE, vol->upcase, vol->upcase_len);
91062306a36Sopenharmony_ci		/*
91162306a36Sopenharmony_ci		 * If uname collates before the name of the current entry, there
91262306a36Sopenharmony_ci		 * is definitely no such name in this index but we might need to
91362306a36Sopenharmony_ci		 * descend into the B+tree so we just break out of the loop.
91462306a36Sopenharmony_ci		 */
91562306a36Sopenharmony_ci		if (rc == -1)
91662306a36Sopenharmony_ci			break;
91762306a36Sopenharmony_ci		/* The names are not equal, continue the search. */
91862306a36Sopenharmony_ci		if (rc)
91962306a36Sopenharmony_ci			continue;
92062306a36Sopenharmony_ci		/*
92162306a36Sopenharmony_ci		 * Names match with case insensitive comparison, now try the
92262306a36Sopenharmony_ci		 * case sensitive comparison, which is required for proper
92362306a36Sopenharmony_ci		 * collation.
92462306a36Sopenharmony_ci		 */
92562306a36Sopenharmony_ci		rc = ntfs_collate_names(uname, uname_len,
92662306a36Sopenharmony_ci				(ntfschar*)&ie->key.file_name.file_name,
92762306a36Sopenharmony_ci				ie->key.file_name.file_name_length, 1,
92862306a36Sopenharmony_ci				CASE_SENSITIVE, vol->upcase, vol->upcase_len);
92962306a36Sopenharmony_ci		if (rc == -1)
93062306a36Sopenharmony_ci			break;
93162306a36Sopenharmony_ci		if (rc)
93262306a36Sopenharmony_ci			continue;
93362306a36Sopenharmony_ci		/*
93462306a36Sopenharmony_ci		 * Perfect match, this will never happen as the
93562306a36Sopenharmony_ci		 * ntfs_are_names_equal() call will have gotten a match but we
93662306a36Sopenharmony_ci		 * still treat it correctly.
93762306a36Sopenharmony_ci		 */
93862306a36Sopenharmony_ci		goto found_it2;
93962306a36Sopenharmony_ci	}
94062306a36Sopenharmony_ci	/*
94162306a36Sopenharmony_ci	 * We have finished with this index buffer without success. Check for
94262306a36Sopenharmony_ci	 * the presence of a child node.
94362306a36Sopenharmony_ci	 */
94462306a36Sopenharmony_ci	if (ie->flags & INDEX_ENTRY_NODE) {
94562306a36Sopenharmony_ci		if ((ia->index.flags & NODE_MASK) == LEAF_NODE) {
94662306a36Sopenharmony_ci			ntfs_error(sb, "Index entry with child node found in "
94762306a36Sopenharmony_ci					"a leaf node in directory inode 0x%lx.",
94862306a36Sopenharmony_ci					dir_ni->mft_no);
94962306a36Sopenharmony_ci			goto unm_err_out;
95062306a36Sopenharmony_ci		}
95162306a36Sopenharmony_ci		/* Child node present, descend into it. */
95262306a36Sopenharmony_ci		old_vcn = vcn;
95362306a36Sopenharmony_ci		vcn = sle64_to_cpup((u8*)ie + le16_to_cpu(ie->length) - 8);
95462306a36Sopenharmony_ci		if (vcn >= 0) {
95562306a36Sopenharmony_ci			/* If vcn is in the same page cache page as old_vcn we
95662306a36Sopenharmony_ci			 * recycle the mapped page. */
95762306a36Sopenharmony_ci			if (old_vcn << vol->cluster_size_bits >>
95862306a36Sopenharmony_ci					PAGE_SHIFT == vcn <<
95962306a36Sopenharmony_ci					vol->cluster_size_bits >>
96062306a36Sopenharmony_ci					PAGE_SHIFT)
96162306a36Sopenharmony_ci				goto fast_descend_into_child_node;
96262306a36Sopenharmony_ci			unlock_page(page);
96362306a36Sopenharmony_ci			ntfs_unmap_page(page);
96462306a36Sopenharmony_ci			goto descend_into_child_node;
96562306a36Sopenharmony_ci		}
96662306a36Sopenharmony_ci		ntfs_error(sb, "Negative child node vcn in directory inode "
96762306a36Sopenharmony_ci				"0x%lx.", dir_ni->mft_no);
96862306a36Sopenharmony_ci		goto unm_err_out;
96962306a36Sopenharmony_ci	}
97062306a36Sopenharmony_ci	/* No child node, return -ENOENT. */
97162306a36Sopenharmony_ci	ntfs_debug("Entry not found.");
97262306a36Sopenharmony_ci	err = -ENOENT;
97362306a36Sopenharmony_ciunm_err_out:
97462306a36Sopenharmony_ci	unlock_page(page);
97562306a36Sopenharmony_ci	ntfs_unmap_page(page);
97662306a36Sopenharmony_cierr_out:
97762306a36Sopenharmony_ci	if (!err)
97862306a36Sopenharmony_ci		err = -EIO;
97962306a36Sopenharmony_ci	if (ctx)
98062306a36Sopenharmony_ci		ntfs_attr_put_search_ctx(ctx);
98162306a36Sopenharmony_ci	if (m)
98262306a36Sopenharmony_ci		unmap_mft_record(dir_ni);
98362306a36Sopenharmony_ci	return ERR_MREF(err);
98462306a36Sopenharmony_cidir_err_out:
98562306a36Sopenharmony_ci	ntfs_error(sb, "Corrupt directory. Aborting lookup.");
98662306a36Sopenharmony_ci	goto err_out;
98762306a36Sopenharmony_ci}
98862306a36Sopenharmony_ci
98962306a36Sopenharmony_ci#endif
99062306a36Sopenharmony_ci
99162306a36Sopenharmony_ci/**
99262306a36Sopenharmony_ci * ntfs_filldir - ntfs specific filldir method
99362306a36Sopenharmony_ci * @vol:	current ntfs volume
99462306a36Sopenharmony_ci * @ndir:	ntfs inode of current directory
99562306a36Sopenharmony_ci * @ia_page:	page in which the index allocation buffer @ie is in resides
99662306a36Sopenharmony_ci * @ie:		current index entry
99762306a36Sopenharmony_ci * @name:	buffer to use for the converted name
99862306a36Sopenharmony_ci * @actor:	what to feed the entries to
99962306a36Sopenharmony_ci *
100062306a36Sopenharmony_ci * Convert the Unicode @name to the loaded NLS and pass it to the @filldir
100162306a36Sopenharmony_ci * callback.
100262306a36Sopenharmony_ci *
100362306a36Sopenharmony_ci * If @ia_page is not NULL it is the locked page containing the index
100462306a36Sopenharmony_ci * allocation block containing the index entry @ie.
100562306a36Sopenharmony_ci *
100662306a36Sopenharmony_ci * Note, we drop (and then reacquire) the page lock on @ia_page across the
100762306a36Sopenharmony_ci * @filldir() call otherwise we would deadlock with NFSd when it calls ->lookup
100862306a36Sopenharmony_ci * since ntfs_lookup() will lock the same page.  As an optimization, we do not
100962306a36Sopenharmony_ci * retake the lock if we are returning a non-zero value as ntfs_readdir()
101062306a36Sopenharmony_ci * would need to drop the lock immediately anyway.
101162306a36Sopenharmony_ci */
101262306a36Sopenharmony_cistatic inline int ntfs_filldir(ntfs_volume *vol,
101362306a36Sopenharmony_ci		ntfs_inode *ndir, struct page *ia_page, INDEX_ENTRY *ie,
101462306a36Sopenharmony_ci		u8 *name, struct dir_context *actor)
101562306a36Sopenharmony_ci{
101662306a36Sopenharmony_ci	unsigned long mref;
101762306a36Sopenharmony_ci	int name_len;
101862306a36Sopenharmony_ci	unsigned dt_type;
101962306a36Sopenharmony_ci	FILE_NAME_TYPE_FLAGS name_type;
102062306a36Sopenharmony_ci
102162306a36Sopenharmony_ci	name_type = ie->key.file_name.file_name_type;
102262306a36Sopenharmony_ci	if (name_type == FILE_NAME_DOS) {
102362306a36Sopenharmony_ci		ntfs_debug("Skipping DOS name space entry.");
102462306a36Sopenharmony_ci		return 0;
102562306a36Sopenharmony_ci	}
102662306a36Sopenharmony_ci	if (MREF_LE(ie->data.dir.indexed_file) == FILE_root) {
102762306a36Sopenharmony_ci		ntfs_debug("Skipping root directory self reference entry.");
102862306a36Sopenharmony_ci		return 0;
102962306a36Sopenharmony_ci	}
103062306a36Sopenharmony_ci	if (MREF_LE(ie->data.dir.indexed_file) < FILE_first_user &&
103162306a36Sopenharmony_ci			!NVolShowSystemFiles(vol)) {
103262306a36Sopenharmony_ci		ntfs_debug("Skipping system file.");
103362306a36Sopenharmony_ci		return 0;
103462306a36Sopenharmony_ci	}
103562306a36Sopenharmony_ci	name_len = ntfs_ucstonls(vol, (ntfschar*)&ie->key.file_name.file_name,
103662306a36Sopenharmony_ci			ie->key.file_name.file_name_length, &name,
103762306a36Sopenharmony_ci			NTFS_MAX_NAME_LEN * NLS_MAX_CHARSET_SIZE + 1);
103862306a36Sopenharmony_ci	if (name_len <= 0) {
103962306a36Sopenharmony_ci		ntfs_warning(vol->sb, "Skipping unrepresentable inode 0x%llx.",
104062306a36Sopenharmony_ci				(long long)MREF_LE(ie->data.dir.indexed_file));
104162306a36Sopenharmony_ci		return 0;
104262306a36Sopenharmony_ci	}
104362306a36Sopenharmony_ci	if (ie->key.file_name.file_attributes &
104462306a36Sopenharmony_ci			FILE_ATTR_DUP_FILE_NAME_INDEX_PRESENT)
104562306a36Sopenharmony_ci		dt_type = DT_DIR;
104662306a36Sopenharmony_ci	else
104762306a36Sopenharmony_ci		dt_type = DT_REG;
104862306a36Sopenharmony_ci	mref = MREF_LE(ie->data.dir.indexed_file);
104962306a36Sopenharmony_ci	/*
105062306a36Sopenharmony_ci	 * Drop the page lock otherwise we deadlock with NFS when it calls
105162306a36Sopenharmony_ci	 * ->lookup since ntfs_lookup() will lock the same page.
105262306a36Sopenharmony_ci	 */
105362306a36Sopenharmony_ci	if (ia_page)
105462306a36Sopenharmony_ci		unlock_page(ia_page);
105562306a36Sopenharmony_ci	ntfs_debug("Calling filldir for %s with len %i, fpos 0x%llx, inode "
105662306a36Sopenharmony_ci			"0x%lx, DT_%s.", name, name_len, actor->pos, mref,
105762306a36Sopenharmony_ci			dt_type == DT_DIR ? "DIR" : "REG");
105862306a36Sopenharmony_ci	if (!dir_emit(actor, name, name_len, mref, dt_type))
105962306a36Sopenharmony_ci		return 1;
106062306a36Sopenharmony_ci	/* Relock the page but not if we are aborting ->readdir. */
106162306a36Sopenharmony_ci	if (ia_page)
106262306a36Sopenharmony_ci		lock_page(ia_page);
106362306a36Sopenharmony_ci	return 0;
106462306a36Sopenharmony_ci}
106562306a36Sopenharmony_ci
106662306a36Sopenharmony_ci/*
106762306a36Sopenharmony_ci * We use the same basic approach as the old NTFS driver, i.e. we parse the
106862306a36Sopenharmony_ci * index root entries and then the index allocation entries that are marked
106962306a36Sopenharmony_ci * as in use in the index bitmap.
107062306a36Sopenharmony_ci *
107162306a36Sopenharmony_ci * While this will return the names in random order this doesn't matter for
107262306a36Sopenharmony_ci * ->readdir but OTOH results in a faster ->readdir.
107362306a36Sopenharmony_ci *
107462306a36Sopenharmony_ci * VFS calls ->readdir without BKL but with i_mutex held. This protects the VFS
107562306a36Sopenharmony_ci * parts (e.g. ->f_pos and ->i_size, and it also protects against directory
107662306a36Sopenharmony_ci * modifications).
107762306a36Sopenharmony_ci *
107862306a36Sopenharmony_ci * Locking:  - Caller must hold i_mutex on the directory.
107962306a36Sopenharmony_ci *	     - Each page cache page in the index allocation mapping must be
108062306a36Sopenharmony_ci *	       locked whilst being accessed otherwise we may find a corrupt
108162306a36Sopenharmony_ci *	       page due to it being under ->writepage at the moment which
108262306a36Sopenharmony_ci *	       applies the mst protection fixups before writing out and then
108362306a36Sopenharmony_ci *	       removes them again after the write is complete after which it
108462306a36Sopenharmony_ci *	       unlocks the page.
108562306a36Sopenharmony_ci */
108662306a36Sopenharmony_cistatic int ntfs_readdir(struct file *file, struct dir_context *actor)
108762306a36Sopenharmony_ci{
108862306a36Sopenharmony_ci	s64 ia_pos, ia_start, prev_ia_pos, bmp_pos;
108962306a36Sopenharmony_ci	loff_t i_size;
109062306a36Sopenharmony_ci	struct inode *bmp_vi, *vdir = file_inode(file);
109162306a36Sopenharmony_ci	struct super_block *sb = vdir->i_sb;
109262306a36Sopenharmony_ci	ntfs_inode *ndir = NTFS_I(vdir);
109362306a36Sopenharmony_ci	ntfs_volume *vol = NTFS_SB(sb);
109462306a36Sopenharmony_ci	MFT_RECORD *m;
109562306a36Sopenharmony_ci	INDEX_ROOT *ir = NULL;
109662306a36Sopenharmony_ci	INDEX_ENTRY *ie;
109762306a36Sopenharmony_ci	INDEX_ALLOCATION *ia;
109862306a36Sopenharmony_ci	u8 *name = NULL;
109962306a36Sopenharmony_ci	int rc, err, ir_pos, cur_bmp_pos;
110062306a36Sopenharmony_ci	struct address_space *ia_mapping, *bmp_mapping;
110162306a36Sopenharmony_ci	struct page *bmp_page = NULL, *ia_page = NULL;
110262306a36Sopenharmony_ci	u8 *kaddr, *bmp, *index_end;
110362306a36Sopenharmony_ci	ntfs_attr_search_ctx *ctx;
110462306a36Sopenharmony_ci
110562306a36Sopenharmony_ci	ntfs_debug("Entering for inode 0x%lx, fpos 0x%llx.",
110662306a36Sopenharmony_ci			vdir->i_ino, actor->pos);
110762306a36Sopenharmony_ci	rc = err = 0;
110862306a36Sopenharmony_ci	/* Are we at end of dir yet? */
110962306a36Sopenharmony_ci	i_size = i_size_read(vdir);
111062306a36Sopenharmony_ci	if (actor->pos >= i_size + vol->mft_record_size)
111162306a36Sopenharmony_ci		return 0;
111262306a36Sopenharmony_ci	/* Emulate . and .. for all directories. */
111362306a36Sopenharmony_ci	if (!dir_emit_dots(file, actor))
111462306a36Sopenharmony_ci		return 0;
111562306a36Sopenharmony_ci	m = NULL;
111662306a36Sopenharmony_ci	ctx = NULL;
111762306a36Sopenharmony_ci	/*
111862306a36Sopenharmony_ci	 * Allocate a buffer to store the current name being processed
111962306a36Sopenharmony_ci	 * converted to format determined by current NLS.
112062306a36Sopenharmony_ci	 */
112162306a36Sopenharmony_ci	name = kmalloc(NTFS_MAX_NAME_LEN * NLS_MAX_CHARSET_SIZE + 1, GFP_NOFS);
112262306a36Sopenharmony_ci	if (unlikely(!name)) {
112362306a36Sopenharmony_ci		err = -ENOMEM;
112462306a36Sopenharmony_ci		goto err_out;
112562306a36Sopenharmony_ci	}
112662306a36Sopenharmony_ci	/* Are we jumping straight into the index allocation attribute? */
112762306a36Sopenharmony_ci	if (actor->pos >= vol->mft_record_size)
112862306a36Sopenharmony_ci		goto skip_index_root;
112962306a36Sopenharmony_ci	/* Get hold of the mft record for the directory. */
113062306a36Sopenharmony_ci	m = map_mft_record(ndir);
113162306a36Sopenharmony_ci	if (IS_ERR(m)) {
113262306a36Sopenharmony_ci		err = PTR_ERR(m);
113362306a36Sopenharmony_ci		m = NULL;
113462306a36Sopenharmony_ci		goto err_out;
113562306a36Sopenharmony_ci	}
113662306a36Sopenharmony_ci	ctx = ntfs_attr_get_search_ctx(ndir, m);
113762306a36Sopenharmony_ci	if (unlikely(!ctx)) {
113862306a36Sopenharmony_ci		err = -ENOMEM;
113962306a36Sopenharmony_ci		goto err_out;
114062306a36Sopenharmony_ci	}
114162306a36Sopenharmony_ci	/* Get the offset into the index root attribute. */
114262306a36Sopenharmony_ci	ir_pos = (s64)actor->pos;
114362306a36Sopenharmony_ci	/* Find the index root attribute in the mft record. */
114462306a36Sopenharmony_ci	err = ntfs_attr_lookup(AT_INDEX_ROOT, I30, 4, CASE_SENSITIVE, 0, NULL,
114562306a36Sopenharmony_ci			0, ctx);
114662306a36Sopenharmony_ci	if (unlikely(err)) {
114762306a36Sopenharmony_ci		ntfs_error(sb, "Index root attribute missing in directory "
114862306a36Sopenharmony_ci				"inode 0x%lx.", vdir->i_ino);
114962306a36Sopenharmony_ci		goto err_out;
115062306a36Sopenharmony_ci	}
115162306a36Sopenharmony_ci	/*
115262306a36Sopenharmony_ci	 * Copy the index root attribute value to a buffer so that we can put
115362306a36Sopenharmony_ci	 * the search context and unmap the mft record before calling the
115462306a36Sopenharmony_ci	 * filldir() callback.  We need to do this because of NFSd which calls
115562306a36Sopenharmony_ci	 * ->lookup() from its filldir callback() and this causes NTFS to
115662306a36Sopenharmony_ci	 * deadlock as ntfs_lookup() maps the mft record of the directory and
115762306a36Sopenharmony_ci	 * we have got it mapped here already.  The only solution is for us to
115862306a36Sopenharmony_ci	 * unmap the mft record here so that a call to ntfs_lookup() is able to
115962306a36Sopenharmony_ci	 * map the mft record without deadlocking.
116062306a36Sopenharmony_ci	 */
116162306a36Sopenharmony_ci	rc = le32_to_cpu(ctx->attr->data.resident.value_length);
116262306a36Sopenharmony_ci	ir = kmalloc(rc, GFP_NOFS);
116362306a36Sopenharmony_ci	if (unlikely(!ir)) {
116462306a36Sopenharmony_ci		err = -ENOMEM;
116562306a36Sopenharmony_ci		goto err_out;
116662306a36Sopenharmony_ci	}
116762306a36Sopenharmony_ci	/* Copy the index root value (it has been verified in read_inode). */
116862306a36Sopenharmony_ci	memcpy(ir, (u8*)ctx->attr +
116962306a36Sopenharmony_ci			le16_to_cpu(ctx->attr->data.resident.value_offset), rc);
117062306a36Sopenharmony_ci	ntfs_attr_put_search_ctx(ctx);
117162306a36Sopenharmony_ci	unmap_mft_record(ndir);
117262306a36Sopenharmony_ci	ctx = NULL;
117362306a36Sopenharmony_ci	m = NULL;
117462306a36Sopenharmony_ci	index_end = (u8*)&ir->index + le32_to_cpu(ir->index.index_length);
117562306a36Sopenharmony_ci	/* The first index entry. */
117662306a36Sopenharmony_ci	ie = (INDEX_ENTRY*)((u8*)&ir->index +
117762306a36Sopenharmony_ci			le32_to_cpu(ir->index.entries_offset));
117862306a36Sopenharmony_ci	/*
117962306a36Sopenharmony_ci	 * Loop until we exceed valid memory (corruption case) or until we
118062306a36Sopenharmony_ci	 * reach the last entry or until filldir tells us it has had enough
118162306a36Sopenharmony_ci	 * or signals an error (both covered by the rc test).
118262306a36Sopenharmony_ci	 */
118362306a36Sopenharmony_ci	for (;; ie = (INDEX_ENTRY*)((u8*)ie + le16_to_cpu(ie->length))) {
118462306a36Sopenharmony_ci		ntfs_debug("In index root, offset 0x%zx.", (u8*)ie - (u8*)ir);
118562306a36Sopenharmony_ci		/* Bounds checks. */
118662306a36Sopenharmony_ci		if (unlikely((u8*)ie < (u8*)ir || (u8*)ie +
118762306a36Sopenharmony_ci				sizeof(INDEX_ENTRY_HEADER) > index_end ||
118862306a36Sopenharmony_ci				(u8*)ie + le16_to_cpu(ie->key_length) >
118962306a36Sopenharmony_ci				index_end))
119062306a36Sopenharmony_ci			goto err_out;
119162306a36Sopenharmony_ci		/* The last entry cannot contain a name. */
119262306a36Sopenharmony_ci		if (ie->flags & INDEX_ENTRY_END)
119362306a36Sopenharmony_ci			break;
119462306a36Sopenharmony_ci		/* Skip index root entry if continuing previous readdir. */
119562306a36Sopenharmony_ci		if (ir_pos > (u8*)ie - (u8*)ir)
119662306a36Sopenharmony_ci			continue;
119762306a36Sopenharmony_ci		/* Advance the position even if going to skip the entry. */
119862306a36Sopenharmony_ci		actor->pos = (u8*)ie - (u8*)ir;
119962306a36Sopenharmony_ci		/* Submit the name to the filldir callback. */
120062306a36Sopenharmony_ci		rc = ntfs_filldir(vol, ndir, NULL, ie, name, actor);
120162306a36Sopenharmony_ci		if (rc) {
120262306a36Sopenharmony_ci			kfree(ir);
120362306a36Sopenharmony_ci			goto abort;
120462306a36Sopenharmony_ci		}
120562306a36Sopenharmony_ci	}
120662306a36Sopenharmony_ci	/* We are done with the index root and can free the buffer. */
120762306a36Sopenharmony_ci	kfree(ir);
120862306a36Sopenharmony_ci	ir = NULL;
120962306a36Sopenharmony_ci	/* If there is no index allocation attribute we are finished. */
121062306a36Sopenharmony_ci	if (!NInoIndexAllocPresent(ndir))
121162306a36Sopenharmony_ci		goto EOD;
121262306a36Sopenharmony_ci	/* Advance fpos to the beginning of the index allocation. */
121362306a36Sopenharmony_ci	actor->pos = vol->mft_record_size;
121462306a36Sopenharmony_ciskip_index_root:
121562306a36Sopenharmony_ci	kaddr = NULL;
121662306a36Sopenharmony_ci	prev_ia_pos = -1LL;
121762306a36Sopenharmony_ci	/* Get the offset into the index allocation attribute. */
121862306a36Sopenharmony_ci	ia_pos = (s64)actor->pos - vol->mft_record_size;
121962306a36Sopenharmony_ci	ia_mapping = vdir->i_mapping;
122062306a36Sopenharmony_ci	ntfs_debug("Inode 0x%lx, getting index bitmap.", vdir->i_ino);
122162306a36Sopenharmony_ci	bmp_vi = ntfs_attr_iget(vdir, AT_BITMAP, I30, 4);
122262306a36Sopenharmony_ci	if (IS_ERR(bmp_vi)) {
122362306a36Sopenharmony_ci		ntfs_error(sb, "Failed to get bitmap attribute.");
122462306a36Sopenharmony_ci		err = PTR_ERR(bmp_vi);
122562306a36Sopenharmony_ci		goto err_out;
122662306a36Sopenharmony_ci	}
122762306a36Sopenharmony_ci	bmp_mapping = bmp_vi->i_mapping;
122862306a36Sopenharmony_ci	/* Get the starting bitmap bit position and sanity check it. */
122962306a36Sopenharmony_ci	bmp_pos = ia_pos >> ndir->itype.index.block_size_bits;
123062306a36Sopenharmony_ci	if (unlikely(bmp_pos >> 3 >= i_size_read(bmp_vi))) {
123162306a36Sopenharmony_ci		ntfs_error(sb, "Current index allocation position exceeds "
123262306a36Sopenharmony_ci				"index bitmap size.");
123362306a36Sopenharmony_ci		goto iput_err_out;
123462306a36Sopenharmony_ci	}
123562306a36Sopenharmony_ci	/* Get the starting bit position in the current bitmap page. */
123662306a36Sopenharmony_ci	cur_bmp_pos = bmp_pos & ((PAGE_SIZE * 8) - 1);
123762306a36Sopenharmony_ci	bmp_pos &= ~(u64)((PAGE_SIZE * 8) - 1);
123862306a36Sopenharmony_ciget_next_bmp_page:
123962306a36Sopenharmony_ci	ntfs_debug("Reading bitmap with page index 0x%llx, bit ofs 0x%llx",
124062306a36Sopenharmony_ci			(unsigned long long)bmp_pos >> (3 + PAGE_SHIFT),
124162306a36Sopenharmony_ci			(unsigned long long)bmp_pos &
124262306a36Sopenharmony_ci			(unsigned long long)((PAGE_SIZE * 8) - 1));
124362306a36Sopenharmony_ci	bmp_page = ntfs_map_page(bmp_mapping,
124462306a36Sopenharmony_ci			bmp_pos >> (3 + PAGE_SHIFT));
124562306a36Sopenharmony_ci	if (IS_ERR(bmp_page)) {
124662306a36Sopenharmony_ci		ntfs_error(sb, "Reading index bitmap failed.");
124762306a36Sopenharmony_ci		err = PTR_ERR(bmp_page);
124862306a36Sopenharmony_ci		bmp_page = NULL;
124962306a36Sopenharmony_ci		goto iput_err_out;
125062306a36Sopenharmony_ci	}
125162306a36Sopenharmony_ci	bmp = (u8*)page_address(bmp_page);
125262306a36Sopenharmony_ci	/* Find next index block in use. */
125362306a36Sopenharmony_ci	while (!(bmp[cur_bmp_pos >> 3] & (1 << (cur_bmp_pos & 7)))) {
125462306a36Sopenharmony_cifind_next_index_buffer:
125562306a36Sopenharmony_ci		cur_bmp_pos++;
125662306a36Sopenharmony_ci		/*
125762306a36Sopenharmony_ci		 * If we have reached the end of the bitmap page, get the next
125862306a36Sopenharmony_ci		 * page, and put away the old one.
125962306a36Sopenharmony_ci		 */
126062306a36Sopenharmony_ci		if (unlikely((cur_bmp_pos >> 3) >= PAGE_SIZE)) {
126162306a36Sopenharmony_ci			ntfs_unmap_page(bmp_page);
126262306a36Sopenharmony_ci			bmp_pos += PAGE_SIZE * 8;
126362306a36Sopenharmony_ci			cur_bmp_pos = 0;
126462306a36Sopenharmony_ci			goto get_next_bmp_page;
126562306a36Sopenharmony_ci		}
126662306a36Sopenharmony_ci		/* If we have reached the end of the bitmap, we are done. */
126762306a36Sopenharmony_ci		if (unlikely(((bmp_pos + cur_bmp_pos) >> 3) >= i_size))
126862306a36Sopenharmony_ci			goto unm_EOD;
126962306a36Sopenharmony_ci		ia_pos = (bmp_pos + cur_bmp_pos) <<
127062306a36Sopenharmony_ci				ndir->itype.index.block_size_bits;
127162306a36Sopenharmony_ci	}
127262306a36Sopenharmony_ci	ntfs_debug("Handling index buffer 0x%llx.",
127362306a36Sopenharmony_ci			(unsigned long long)bmp_pos + cur_bmp_pos);
127462306a36Sopenharmony_ci	/* If the current index buffer is in the same page we reuse the page. */
127562306a36Sopenharmony_ci	if ((prev_ia_pos & (s64)PAGE_MASK) !=
127662306a36Sopenharmony_ci			(ia_pos & (s64)PAGE_MASK)) {
127762306a36Sopenharmony_ci		prev_ia_pos = ia_pos;
127862306a36Sopenharmony_ci		if (likely(ia_page != NULL)) {
127962306a36Sopenharmony_ci			unlock_page(ia_page);
128062306a36Sopenharmony_ci			ntfs_unmap_page(ia_page);
128162306a36Sopenharmony_ci		}
128262306a36Sopenharmony_ci		/*
128362306a36Sopenharmony_ci		 * Map the page cache page containing the current ia_pos,
128462306a36Sopenharmony_ci		 * reading it from disk if necessary.
128562306a36Sopenharmony_ci		 */
128662306a36Sopenharmony_ci		ia_page = ntfs_map_page(ia_mapping, ia_pos >> PAGE_SHIFT);
128762306a36Sopenharmony_ci		if (IS_ERR(ia_page)) {
128862306a36Sopenharmony_ci			ntfs_error(sb, "Reading index allocation data failed.");
128962306a36Sopenharmony_ci			err = PTR_ERR(ia_page);
129062306a36Sopenharmony_ci			ia_page = NULL;
129162306a36Sopenharmony_ci			goto err_out;
129262306a36Sopenharmony_ci		}
129362306a36Sopenharmony_ci		lock_page(ia_page);
129462306a36Sopenharmony_ci		kaddr = (u8*)page_address(ia_page);
129562306a36Sopenharmony_ci	}
129662306a36Sopenharmony_ci	/* Get the current index buffer. */
129762306a36Sopenharmony_ci	ia = (INDEX_ALLOCATION*)(kaddr + (ia_pos & ~PAGE_MASK &
129862306a36Sopenharmony_ci					  ~(s64)(ndir->itype.index.block_size - 1)));
129962306a36Sopenharmony_ci	/* Bounds checks. */
130062306a36Sopenharmony_ci	if (unlikely((u8*)ia < kaddr || (u8*)ia > kaddr + PAGE_SIZE)) {
130162306a36Sopenharmony_ci		ntfs_error(sb, "Out of bounds check failed. Corrupt directory "
130262306a36Sopenharmony_ci				"inode 0x%lx or driver bug.", vdir->i_ino);
130362306a36Sopenharmony_ci		goto err_out;
130462306a36Sopenharmony_ci	}
130562306a36Sopenharmony_ci	/* Catch multi sector transfer fixup errors. */
130662306a36Sopenharmony_ci	if (unlikely(!ntfs_is_indx_record(ia->magic))) {
130762306a36Sopenharmony_ci		ntfs_error(sb, "Directory index record with vcn 0x%llx is "
130862306a36Sopenharmony_ci				"corrupt.  Corrupt inode 0x%lx.  Run chkdsk.",
130962306a36Sopenharmony_ci				(unsigned long long)ia_pos >>
131062306a36Sopenharmony_ci				ndir->itype.index.vcn_size_bits, vdir->i_ino);
131162306a36Sopenharmony_ci		goto err_out;
131262306a36Sopenharmony_ci	}
131362306a36Sopenharmony_ci	if (unlikely(sle64_to_cpu(ia->index_block_vcn) != (ia_pos &
131462306a36Sopenharmony_ci			~(s64)(ndir->itype.index.block_size - 1)) >>
131562306a36Sopenharmony_ci			ndir->itype.index.vcn_size_bits)) {
131662306a36Sopenharmony_ci		ntfs_error(sb, "Actual VCN (0x%llx) of index buffer is "
131762306a36Sopenharmony_ci				"different from expected VCN (0x%llx). "
131862306a36Sopenharmony_ci				"Directory inode 0x%lx is corrupt or driver "
131962306a36Sopenharmony_ci				"bug. ", (unsigned long long)
132062306a36Sopenharmony_ci				sle64_to_cpu(ia->index_block_vcn),
132162306a36Sopenharmony_ci				(unsigned long long)ia_pos >>
132262306a36Sopenharmony_ci				ndir->itype.index.vcn_size_bits, vdir->i_ino);
132362306a36Sopenharmony_ci		goto err_out;
132462306a36Sopenharmony_ci	}
132562306a36Sopenharmony_ci	if (unlikely(le32_to_cpu(ia->index.allocated_size) + 0x18 !=
132662306a36Sopenharmony_ci			ndir->itype.index.block_size)) {
132762306a36Sopenharmony_ci		ntfs_error(sb, "Index buffer (VCN 0x%llx) of directory inode "
132862306a36Sopenharmony_ci				"0x%lx has a size (%u) differing from the "
132962306a36Sopenharmony_ci				"directory specified size (%u). Directory "
133062306a36Sopenharmony_ci				"inode is corrupt or driver bug.",
133162306a36Sopenharmony_ci				(unsigned long long)ia_pos >>
133262306a36Sopenharmony_ci				ndir->itype.index.vcn_size_bits, vdir->i_ino,
133362306a36Sopenharmony_ci				le32_to_cpu(ia->index.allocated_size) + 0x18,
133462306a36Sopenharmony_ci				ndir->itype.index.block_size);
133562306a36Sopenharmony_ci		goto err_out;
133662306a36Sopenharmony_ci	}
133762306a36Sopenharmony_ci	index_end = (u8*)ia + ndir->itype.index.block_size;
133862306a36Sopenharmony_ci	if (unlikely(index_end > kaddr + PAGE_SIZE)) {
133962306a36Sopenharmony_ci		ntfs_error(sb, "Index buffer (VCN 0x%llx) of directory inode "
134062306a36Sopenharmony_ci				"0x%lx crosses page boundary. Impossible! "
134162306a36Sopenharmony_ci				"Cannot access! This is probably a bug in the "
134262306a36Sopenharmony_ci				"driver.", (unsigned long long)ia_pos >>
134362306a36Sopenharmony_ci				ndir->itype.index.vcn_size_bits, vdir->i_ino);
134462306a36Sopenharmony_ci		goto err_out;
134562306a36Sopenharmony_ci	}
134662306a36Sopenharmony_ci	ia_start = ia_pos & ~(s64)(ndir->itype.index.block_size - 1);
134762306a36Sopenharmony_ci	index_end = (u8*)&ia->index + le32_to_cpu(ia->index.index_length);
134862306a36Sopenharmony_ci	if (unlikely(index_end > (u8*)ia + ndir->itype.index.block_size)) {
134962306a36Sopenharmony_ci		ntfs_error(sb, "Size of index buffer (VCN 0x%llx) of directory "
135062306a36Sopenharmony_ci				"inode 0x%lx exceeds maximum size.",
135162306a36Sopenharmony_ci				(unsigned long long)ia_pos >>
135262306a36Sopenharmony_ci				ndir->itype.index.vcn_size_bits, vdir->i_ino);
135362306a36Sopenharmony_ci		goto err_out;
135462306a36Sopenharmony_ci	}
135562306a36Sopenharmony_ci	/* The first index entry in this index buffer. */
135662306a36Sopenharmony_ci	ie = (INDEX_ENTRY*)((u8*)&ia->index +
135762306a36Sopenharmony_ci			le32_to_cpu(ia->index.entries_offset));
135862306a36Sopenharmony_ci	/*
135962306a36Sopenharmony_ci	 * Loop until we exceed valid memory (corruption case) or until we
136062306a36Sopenharmony_ci	 * reach the last entry or until filldir tells us it has had enough
136162306a36Sopenharmony_ci	 * or signals an error (both covered by the rc test).
136262306a36Sopenharmony_ci	 */
136362306a36Sopenharmony_ci	for (;; ie = (INDEX_ENTRY*)((u8*)ie + le16_to_cpu(ie->length))) {
136462306a36Sopenharmony_ci		ntfs_debug("In index allocation, offset 0x%llx.",
136562306a36Sopenharmony_ci				(unsigned long long)ia_start +
136662306a36Sopenharmony_ci				(unsigned long long)((u8*)ie - (u8*)ia));
136762306a36Sopenharmony_ci		/* Bounds checks. */
136862306a36Sopenharmony_ci		if (unlikely((u8*)ie < (u8*)ia || (u8*)ie +
136962306a36Sopenharmony_ci				sizeof(INDEX_ENTRY_HEADER) > index_end ||
137062306a36Sopenharmony_ci				(u8*)ie + le16_to_cpu(ie->key_length) >
137162306a36Sopenharmony_ci				index_end))
137262306a36Sopenharmony_ci			goto err_out;
137362306a36Sopenharmony_ci		/* The last entry cannot contain a name. */
137462306a36Sopenharmony_ci		if (ie->flags & INDEX_ENTRY_END)
137562306a36Sopenharmony_ci			break;
137662306a36Sopenharmony_ci		/* Skip index block entry if continuing previous readdir. */
137762306a36Sopenharmony_ci		if (ia_pos - ia_start > (u8*)ie - (u8*)ia)
137862306a36Sopenharmony_ci			continue;
137962306a36Sopenharmony_ci		/* Advance the position even if going to skip the entry. */
138062306a36Sopenharmony_ci		actor->pos = (u8*)ie - (u8*)ia +
138162306a36Sopenharmony_ci				(sle64_to_cpu(ia->index_block_vcn) <<
138262306a36Sopenharmony_ci				ndir->itype.index.vcn_size_bits) +
138362306a36Sopenharmony_ci				vol->mft_record_size;
138462306a36Sopenharmony_ci		/*
138562306a36Sopenharmony_ci		 * Submit the name to the @filldir callback.  Note,
138662306a36Sopenharmony_ci		 * ntfs_filldir() drops the lock on @ia_page but it retakes it
138762306a36Sopenharmony_ci		 * before returning, unless a non-zero value is returned in
138862306a36Sopenharmony_ci		 * which case the page is left unlocked.
138962306a36Sopenharmony_ci		 */
139062306a36Sopenharmony_ci		rc = ntfs_filldir(vol, ndir, ia_page, ie, name, actor);
139162306a36Sopenharmony_ci		if (rc) {
139262306a36Sopenharmony_ci			/* @ia_page is already unlocked in this case. */
139362306a36Sopenharmony_ci			ntfs_unmap_page(ia_page);
139462306a36Sopenharmony_ci			ntfs_unmap_page(bmp_page);
139562306a36Sopenharmony_ci			iput(bmp_vi);
139662306a36Sopenharmony_ci			goto abort;
139762306a36Sopenharmony_ci		}
139862306a36Sopenharmony_ci	}
139962306a36Sopenharmony_ci	goto find_next_index_buffer;
140062306a36Sopenharmony_ciunm_EOD:
140162306a36Sopenharmony_ci	if (ia_page) {
140262306a36Sopenharmony_ci		unlock_page(ia_page);
140362306a36Sopenharmony_ci		ntfs_unmap_page(ia_page);
140462306a36Sopenharmony_ci	}
140562306a36Sopenharmony_ci	ntfs_unmap_page(bmp_page);
140662306a36Sopenharmony_ci	iput(bmp_vi);
140762306a36Sopenharmony_ciEOD:
140862306a36Sopenharmony_ci	/* We are finished, set fpos to EOD. */
140962306a36Sopenharmony_ci	actor->pos = i_size + vol->mft_record_size;
141062306a36Sopenharmony_ciabort:
141162306a36Sopenharmony_ci	kfree(name);
141262306a36Sopenharmony_ci	return 0;
141362306a36Sopenharmony_cierr_out:
141462306a36Sopenharmony_ci	if (bmp_page) {
141562306a36Sopenharmony_ci		ntfs_unmap_page(bmp_page);
141662306a36Sopenharmony_ciiput_err_out:
141762306a36Sopenharmony_ci		iput(bmp_vi);
141862306a36Sopenharmony_ci	}
141962306a36Sopenharmony_ci	if (ia_page) {
142062306a36Sopenharmony_ci		unlock_page(ia_page);
142162306a36Sopenharmony_ci		ntfs_unmap_page(ia_page);
142262306a36Sopenharmony_ci	}
142362306a36Sopenharmony_ci	kfree(ir);
142462306a36Sopenharmony_ci	kfree(name);
142562306a36Sopenharmony_ci	if (ctx)
142662306a36Sopenharmony_ci		ntfs_attr_put_search_ctx(ctx);
142762306a36Sopenharmony_ci	if (m)
142862306a36Sopenharmony_ci		unmap_mft_record(ndir);
142962306a36Sopenharmony_ci	if (!err)
143062306a36Sopenharmony_ci		err = -EIO;
143162306a36Sopenharmony_ci	ntfs_debug("Failed. Returning error code %i.", -err);
143262306a36Sopenharmony_ci	return err;
143362306a36Sopenharmony_ci}
143462306a36Sopenharmony_ci
143562306a36Sopenharmony_ci/**
143662306a36Sopenharmony_ci * ntfs_dir_open - called when an inode is about to be opened
143762306a36Sopenharmony_ci * @vi:		inode to be opened
143862306a36Sopenharmony_ci * @filp:	file structure describing the inode
143962306a36Sopenharmony_ci *
144062306a36Sopenharmony_ci * Limit directory size to the page cache limit on architectures where unsigned
144162306a36Sopenharmony_ci * long is 32-bits. This is the most we can do for now without overflowing the
144262306a36Sopenharmony_ci * page cache page index. Doing it this way means we don't run into problems
144362306a36Sopenharmony_ci * because of existing too large directories. It would be better to allow the
144462306a36Sopenharmony_ci * user to read the accessible part of the directory but I doubt very much
144562306a36Sopenharmony_ci * anyone is going to hit this check on a 32-bit architecture, so there is no
144662306a36Sopenharmony_ci * point in adding the extra complexity required to support this.
144762306a36Sopenharmony_ci *
144862306a36Sopenharmony_ci * On 64-bit architectures, the check is hopefully optimized away by the
144962306a36Sopenharmony_ci * compiler.
145062306a36Sopenharmony_ci */
145162306a36Sopenharmony_cistatic int ntfs_dir_open(struct inode *vi, struct file *filp)
145262306a36Sopenharmony_ci{
145362306a36Sopenharmony_ci	if (sizeof(unsigned long) < 8) {
145462306a36Sopenharmony_ci		if (i_size_read(vi) > MAX_LFS_FILESIZE)
145562306a36Sopenharmony_ci			return -EFBIG;
145662306a36Sopenharmony_ci	}
145762306a36Sopenharmony_ci	return 0;
145862306a36Sopenharmony_ci}
145962306a36Sopenharmony_ci
146062306a36Sopenharmony_ci#ifdef NTFS_RW
146162306a36Sopenharmony_ci
146262306a36Sopenharmony_ci/**
146362306a36Sopenharmony_ci * ntfs_dir_fsync - sync a directory to disk
146462306a36Sopenharmony_ci * @filp:	directory to be synced
146562306a36Sopenharmony_ci * @dentry:	dentry describing the directory to sync
146662306a36Sopenharmony_ci * @datasync:	if non-zero only flush user data and not metadata
146762306a36Sopenharmony_ci *
146862306a36Sopenharmony_ci * Data integrity sync of a directory to disk.  Used for fsync, fdatasync, and
146962306a36Sopenharmony_ci * msync system calls.  This function is based on file.c::ntfs_file_fsync().
147062306a36Sopenharmony_ci *
147162306a36Sopenharmony_ci * Write the mft record and all associated extent mft records as well as the
147262306a36Sopenharmony_ci * $INDEX_ALLOCATION and $BITMAP attributes and then sync the block device.
147362306a36Sopenharmony_ci *
147462306a36Sopenharmony_ci * If @datasync is true, we do not wait on the inode(s) to be written out
147562306a36Sopenharmony_ci * but we always wait on the page cache pages to be written out.
147662306a36Sopenharmony_ci *
147762306a36Sopenharmony_ci * Note: In the past @filp could be NULL so we ignore it as we don't need it
147862306a36Sopenharmony_ci * anyway.
147962306a36Sopenharmony_ci *
148062306a36Sopenharmony_ci * Locking: Caller must hold i_mutex on the inode.
148162306a36Sopenharmony_ci *
148262306a36Sopenharmony_ci * TODO: We should probably also write all attribute/index inodes associated
148362306a36Sopenharmony_ci * with this inode but since we have no simple way of getting to them we ignore
148462306a36Sopenharmony_ci * this problem for now.  We do write the $BITMAP attribute if it is present
148562306a36Sopenharmony_ci * which is the important one for a directory so things are not too bad.
148662306a36Sopenharmony_ci */
148762306a36Sopenharmony_cistatic int ntfs_dir_fsync(struct file *filp, loff_t start, loff_t end,
148862306a36Sopenharmony_ci			  int datasync)
148962306a36Sopenharmony_ci{
149062306a36Sopenharmony_ci	struct inode *bmp_vi, *vi = filp->f_mapping->host;
149162306a36Sopenharmony_ci	int err, ret;
149262306a36Sopenharmony_ci	ntfs_attr na;
149362306a36Sopenharmony_ci
149462306a36Sopenharmony_ci	ntfs_debug("Entering for inode 0x%lx.", vi->i_ino);
149562306a36Sopenharmony_ci
149662306a36Sopenharmony_ci	err = file_write_and_wait_range(filp, start, end);
149762306a36Sopenharmony_ci	if (err)
149862306a36Sopenharmony_ci		return err;
149962306a36Sopenharmony_ci	inode_lock(vi);
150062306a36Sopenharmony_ci
150162306a36Sopenharmony_ci	BUG_ON(!S_ISDIR(vi->i_mode));
150262306a36Sopenharmony_ci	/* If the bitmap attribute inode is in memory sync it, too. */
150362306a36Sopenharmony_ci	na.mft_no = vi->i_ino;
150462306a36Sopenharmony_ci	na.type = AT_BITMAP;
150562306a36Sopenharmony_ci	na.name = I30;
150662306a36Sopenharmony_ci	na.name_len = 4;
150762306a36Sopenharmony_ci	bmp_vi = ilookup5(vi->i_sb, vi->i_ino, ntfs_test_inode, &na);
150862306a36Sopenharmony_ci	if (bmp_vi) {
150962306a36Sopenharmony_ci 		write_inode_now(bmp_vi, !datasync);
151062306a36Sopenharmony_ci		iput(bmp_vi);
151162306a36Sopenharmony_ci	}
151262306a36Sopenharmony_ci	ret = __ntfs_write_inode(vi, 1);
151362306a36Sopenharmony_ci	write_inode_now(vi, !datasync);
151462306a36Sopenharmony_ci	err = sync_blockdev(vi->i_sb->s_bdev);
151562306a36Sopenharmony_ci	if (unlikely(err && !ret))
151662306a36Sopenharmony_ci		ret = err;
151762306a36Sopenharmony_ci	if (likely(!ret))
151862306a36Sopenharmony_ci		ntfs_debug("Done.");
151962306a36Sopenharmony_ci	else
152062306a36Sopenharmony_ci		ntfs_warning(vi->i_sb, "Failed to f%ssync inode 0x%lx.  Error "
152162306a36Sopenharmony_ci				"%u.", datasync ? "data" : "", vi->i_ino, -ret);
152262306a36Sopenharmony_ci	inode_unlock(vi);
152362306a36Sopenharmony_ci	return ret;
152462306a36Sopenharmony_ci}
152562306a36Sopenharmony_ci
152662306a36Sopenharmony_ci#endif /* NTFS_RW */
152762306a36Sopenharmony_ci
152862306a36Sopenharmony_ciWRAP_DIR_ITER(ntfs_readdir) // FIXME!
152962306a36Sopenharmony_ciconst struct file_operations ntfs_dir_ops = {
153062306a36Sopenharmony_ci	.llseek		= generic_file_llseek,	/* Seek inside directory. */
153162306a36Sopenharmony_ci	.read		= generic_read_dir,	/* Return -EISDIR. */
153262306a36Sopenharmony_ci	.iterate_shared	= shared_ntfs_readdir,	/* Read directory contents. */
153362306a36Sopenharmony_ci#ifdef NTFS_RW
153462306a36Sopenharmony_ci	.fsync		= ntfs_dir_fsync,	/* Sync a directory to disk. */
153562306a36Sopenharmony_ci#endif /* NTFS_RW */
153662306a36Sopenharmony_ci	/*.ioctl	= ,*/			/* Perform function on the
153762306a36Sopenharmony_ci						   mounted filesystem. */
153862306a36Sopenharmony_ci	.open		= ntfs_dir_open,	/* Open directory. */
153962306a36Sopenharmony_ci};
1540