18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/**
38c2ecf20Sopenharmony_ci * attrib.c - NTFS attribute operations.  Part of the Linux-NTFS project.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (c) 2001-2012 Anton Altaparmakov and Tuxera Inc.
68c2ecf20Sopenharmony_ci * Copyright (c) 2002 Richard Russon
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <linux/buffer_head.h>
108c2ecf20Sopenharmony_ci#include <linux/sched.h>
118c2ecf20Sopenharmony_ci#include <linux/slab.h>
128c2ecf20Sopenharmony_ci#include <linux/swap.h>
138c2ecf20Sopenharmony_ci#include <linux/writeback.h>
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#include "attrib.h"
168c2ecf20Sopenharmony_ci#include "debug.h"
178c2ecf20Sopenharmony_ci#include "layout.h"
188c2ecf20Sopenharmony_ci#include "lcnalloc.h"
198c2ecf20Sopenharmony_ci#include "malloc.h"
208c2ecf20Sopenharmony_ci#include "mft.h"
218c2ecf20Sopenharmony_ci#include "ntfs.h"
228c2ecf20Sopenharmony_ci#include "types.h"
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci/**
258c2ecf20Sopenharmony_ci * ntfs_map_runlist_nolock - map (a part of) a runlist of an ntfs inode
268c2ecf20Sopenharmony_ci * @ni:		ntfs inode for which to map (part of) a runlist
278c2ecf20Sopenharmony_ci * @vcn:	map runlist part containing this vcn
288c2ecf20Sopenharmony_ci * @ctx:	active attribute search context if present or NULL if not
298c2ecf20Sopenharmony_ci *
308c2ecf20Sopenharmony_ci * Map the part of a runlist containing the @vcn of the ntfs inode @ni.
318c2ecf20Sopenharmony_ci *
328c2ecf20Sopenharmony_ci * If @ctx is specified, it is an active search context of @ni and its base mft
338c2ecf20Sopenharmony_ci * record.  This is needed when ntfs_map_runlist_nolock() encounters unmapped
348c2ecf20Sopenharmony_ci * runlist fragments and allows their mapping.  If you do not have the mft
358c2ecf20Sopenharmony_ci * record mapped, you can specify @ctx as NULL and ntfs_map_runlist_nolock()
368c2ecf20Sopenharmony_ci * will perform the necessary mapping and unmapping.
378c2ecf20Sopenharmony_ci *
388c2ecf20Sopenharmony_ci * Note, ntfs_map_runlist_nolock() saves the state of @ctx on entry and
398c2ecf20Sopenharmony_ci * restores it before returning.  Thus, @ctx will be left pointing to the same
408c2ecf20Sopenharmony_ci * attribute on return as on entry.  However, the actual pointers in @ctx may
418c2ecf20Sopenharmony_ci * point to different memory locations on return, so you must remember to reset
428c2ecf20Sopenharmony_ci * any cached pointers from the @ctx, i.e. after the call to
438c2ecf20Sopenharmony_ci * ntfs_map_runlist_nolock(), you will probably want to do:
448c2ecf20Sopenharmony_ci *	m = ctx->mrec;
458c2ecf20Sopenharmony_ci *	a = ctx->attr;
468c2ecf20Sopenharmony_ci * Assuming you cache ctx->attr in a variable @a of type ATTR_RECORD * and that
478c2ecf20Sopenharmony_ci * you cache ctx->mrec in a variable @m of type MFT_RECORD *.
488c2ecf20Sopenharmony_ci *
498c2ecf20Sopenharmony_ci * Return 0 on success and -errno on error.  There is one special error code
508c2ecf20Sopenharmony_ci * which is not an error as such.  This is -ENOENT.  It means that @vcn is out
518c2ecf20Sopenharmony_ci * of bounds of the runlist.
528c2ecf20Sopenharmony_ci *
538c2ecf20Sopenharmony_ci * Note the runlist can be NULL after this function returns if @vcn is zero and
548c2ecf20Sopenharmony_ci * the attribute has zero allocated size, i.e. there simply is no runlist.
558c2ecf20Sopenharmony_ci *
568c2ecf20Sopenharmony_ci * WARNING: If @ctx is supplied, regardless of whether success or failure is
578c2ecf20Sopenharmony_ci *	    returned, you need to check IS_ERR(@ctx->mrec) and if 'true' the @ctx
588c2ecf20Sopenharmony_ci *	    is no longer valid, i.e. you need to either call
598c2ecf20Sopenharmony_ci *	    ntfs_attr_reinit_search_ctx() or ntfs_attr_put_search_ctx() on it.
608c2ecf20Sopenharmony_ci *	    In that case PTR_ERR(@ctx->mrec) will give you the error code for
618c2ecf20Sopenharmony_ci *	    why the mapping of the old inode failed.
628c2ecf20Sopenharmony_ci *
638c2ecf20Sopenharmony_ci * Locking: - The runlist described by @ni must be locked for writing on entry
648c2ecf20Sopenharmony_ci *	      and is locked on return.  Note the runlist will be modified.
658c2ecf20Sopenharmony_ci *	    - If @ctx is NULL, the base mft record of @ni must not be mapped on
668c2ecf20Sopenharmony_ci *	      entry and it will be left unmapped on return.
678c2ecf20Sopenharmony_ci *	    - If @ctx is not NULL, the base mft record must be mapped on entry
688c2ecf20Sopenharmony_ci *	      and it will be left mapped on return.
698c2ecf20Sopenharmony_ci */
708c2ecf20Sopenharmony_ciint ntfs_map_runlist_nolock(ntfs_inode *ni, VCN vcn, ntfs_attr_search_ctx *ctx)
718c2ecf20Sopenharmony_ci{
728c2ecf20Sopenharmony_ci	VCN end_vcn;
738c2ecf20Sopenharmony_ci	unsigned long flags;
748c2ecf20Sopenharmony_ci	ntfs_inode *base_ni;
758c2ecf20Sopenharmony_ci	MFT_RECORD *m;
768c2ecf20Sopenharmony_ci	ATTR_RECORD *a;
778c2ecf20Sopenharmony_ci	runlist_element *rl;
788c2ecf20Sopenharmony_ci	struct page *put_this_page = NULL;
798c2ecf20Sopenharmony_ci	int err = 0;
808c2ecf20Sopenharmony_ci	bool ctx_is_temporary, ctx_needs_reset;
818c2ecf20Sopenharmony_ci	ntfs_attr_search_ctx old_ctx = { NULL, };
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	ntfs_debug("Mapping runlist part containing vcn 0x%llx.",
848c2ecf20Sopenharmony_ci			(unsigned long long)vcn);
858c2ecf20Sopenharmony_ci	if (!NInoAttr(ni))
868c2ecf20Sopenharmony_ci		base_ni = ni;
878c2ecf20Sopenharmony_ci	else
888c2ecf20Sopenharmony_ci		base_ni = ni->ext.base_ntfs_ino;
898c2ecf20Sopenharmony_ci	if (!ctx) {
908c2ecf20Sopenharmony_ci		ctx_is_temporary = ctx_needs_reset = true;
918c2ecf20Sopenharmony_ci		m = map_mft_record(base_ni);
928c2ecf20Sopenharmony_ci		if (IS_ERR(m))
938c2ecf20Sopenharmony_ci			return PTR_ERR(m);
948c2ecf20Sopenharmony_ci		ctx = ntfs_attr_get_search_ctx(base_ni, m);
958c2ecf20Sopenharmony_ci		if (unlikely(!ctx)) {
968c2ecf20Sopenharmony_ci			err = -ENOMEM;
978c2ecf20Sopenharmony_ci			goto err_out;
988c2ecf20Sopenharmony_ci		}
998c2ecf20Sopenharmony_ci	} else {
1008c2ecf20Sopenharmony_ci		VCN allocated_size_vcn;
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci		BUG_ON(IS_ERR(ctx->mrec));
1038c2ecf20Sopenharmony_ci		a = ctx->attr;
1048c2ecf20Sopenharmony_ci		BUG_ON(!a->non_resident);
1058c2ecf20Sopenharmony_ci		ctx_is_temporary = false;
1068c2ecf20Sopenharmony_ci		end_vcn = sle64_to_cpu(a->data.non_resident.highest_vcn);
1078c2ecf20Sopenharmony_ci		read_lock_irqsave(&ni->size_lock, flags);
1088c2ecf20Sopenharmony_ci		allocated_size_vcn = ni->allocated_size >>
1098c2ecf20Sopenharmony_ci				ni->vol->cluster_size_bits;
1108c2ecf20Sopenharmony_ci		read_unlock_irqrestore(&ni->size_lock, flags);
1118c2ecf20Sopenharmony_ci		if (!a->data.non_resident.lowest_vcn && end_vcn <= 0)
1128c2ecf20Sopenharmony_ci			end_vcn = allocated_size_vcn - 1;
1138c2ecf20Sopenharmony_ci		/*
1148c2ecf20Sopenharmony_ci		 * If we already have the attribute extent containing @vcn in
1158c2ecf20Sopenharmony_ci		 * @ctx, no need to look it up again.  We slightly cheat in
1168c2ecf20Sopenharmony_ci		 * that if vcn exceeds the allocated size, we will refuse to
1178c2ecf20Sopenharmony_ci		 * map the runlist below, so there is definitely no need to get
1188c2ecf20Sopenharmony_ci		 * the right attribute extent.
1198c2ecf20Sopenharmony_ci		 */
1208c2ecf20Sopenharmony_ci		if (vcn >= allocated_size_vcn || (a->type == ni->type &&
1218c2ecf20Sopenharmony_ci				a->name_length == ni->name_len &&
1228c2ecf20Sopenharmony_ci				!memcmp((u8*)a + le16_to_cpu(a->name_offset),
1238c2ecf20Sopenharmony_ci				ni->name, ni->name_len) &&
1248c2ecf20Sopenharmony_ci				sle64_to_cpu(a->data.non_resident.lowest_vcn)
1258c2ecf20Sopenharmony_ci				<= vcn && end_vcn >= vcn))
1268c2ecf20Sopenharmony_ci			ctx_needs_reset = false;
1278c2ecf20Sopenharmony_ci		else {
1288c2ecf20Sopenharmony_ci			/* Save the old search context. */
1298c2ecf20Sopenharmony_ci			old_ctx = *ctx;
1308c2ecf20Sopenharmony_ci			/*
1318c2ecf20Sopenharmony_ci			 * If the currently mapped (extent) inode is not the
1328c2ecf20Sopenharmony_ci			 * base inode we will unmap it when we reinitialize the
1338c2ecf20Sopenharmony_ci			 * search context which means we need to get a
1348c2ecf20Sopenharmony_ci			 * reference to the page containing the mapped mft
1358c2ecf20Sopenharmony_ci			 * record so we do not accidentally drop changes to the
1368c2ecf20Sopenharmony_ci			 * mft record when it has not been marked dirty yet.
1378c2ecf20Sopenharmony_ci			 */
1388c2ecf20Sopenharmony_ci			if (old_ctx.base_ntfs_ino && old_ctx.ntfs_ino !=
1398c2ecf20Sopenharmony_ci					old_ctx.base_ntfs_ino) {
1408c2ecf20Sopenharmony_ci				put_this_page = old_ctx.ntfs_ino->page;
1418c2ecf20Sopenharmony_ci				get_page(put_this_page);
1428c2ecf20Sopenharmony_ci			}
1438c2ecf20Sopenharmony_ci			/*
1448c2ecf20Sopenharmony_ci			 * Reinitialize the search context so we can lookup the
1458c2ecf20Sopenharmony_ci			 * needed attribute extent.
1468c2ecf20Sopenharmony_ci			 */
1478c2ecf20Sopenharmony_ci			ntfs_attr_reinit_search_ctx(ctx);
1488c2ecf20Sopenharmony_ci			ctx_needs_reset = true;
1498c2ecf20Sopenharmony_ci		}
1508c2ecf20Sopenharmony_ci	}
1518c2ecf20Sopenharmony_ci	if (ctx_needs_reset) {
1528c2ecf20Sopenharmony_ci		err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len,
1538c2ecf20Sopenharmony_ci				CASE_SENSITIVE, vcn, NULL, 0, ctx);
1548c2ecf20Sopenharmony_ci		if (unlikely(err)) {
1558c2ecf20Sopenharmony_ci			if (err == -ENOENT)
1568c2ecf20Sopenharmony_ci				err = -EIO;
1578c2ecf20Sopenharmony_ci			goto err_out;
1588c2ecf20Sopenharmony_ci		}
1598c2ecf20Sopenharmony_ci		BUG_ON(!ctx->attr->non_resident);
1608c2ecf20Sopenharmony_ci	}
1618c2ecf20Sopenharmony_ci	a = ctx->attr;
1628c2ecf20Sopenharmony_ci	/*
1638c2ecf20Sopenharmony_ci	 * Only decompress the mapping pairs if @vcn is inside it.  Otherwise
1648c2ecf20Sopenharmony_ci	 * we get into problems when we try to map an out of bounds vcn because
1658c2ecf20Sopenharmony_ci	 * we then try to map the already mapped runlist fragment and
1668c2ecf20Sopenharmony_ci	 * ntfs_mapping_pairs_decompress() fails.
1678c2ecf20Sopenharmony_ci	 */
1688c2ecf20Sopenharmony_ci	end_vcn = sle64_to_cpu(a->data.non_resident.highest_vcn) + 1;
1698c2ecf20Sopenharmony_ci	if (unlikely(vcn && vcn >= end_vcn)) {
1708c2ecf20Sopenharmony_ci		err = -ENOENT;
1718c2ecf20Sopenharmony_ci		goto err_out;
1728c2ecf20Sopenharmony_ci	}
1738c2ecf20Sopenharmony_ci	rl = ntfs_mapping_pairs_decompress(ni->vol, a, ni->runlist.rl);
1748c2ecf20Sopenharmony_ci	if (IS_ERR(rl))
1758c2ecf20Sopenharmony_ci		err = PTR_ERR(rl);
1768c2ecf20Sopenharmony_ci	else
1778c2ecf20Sopenharmony_ci		ni->runlist.rl = rl;
1788c2ecf20Sopenharmony_cierr_out:
1798c2ecf20Sopenharmony_ci	if (ctx_is_temporary) {
1808c2ecf20Sopenharmony_ci		if (likely(ctx))
1818c2ecf20Sopenharmony_ci			ntfs_attr_put_search_ctx(ctx);
1828c2ecf20Sopenharmony_ci		unmap_mft_record(base_ni);
1838c2ecf20Sopenharmony_ci	} else if (ctx_needs_reset) {
1848c2ecf20Sopenharmony_ci		/*
1858c2ecf20Sopenharmony_ci		 * If there is no attribute list, restoring the search context
1868c2ecf20Sopenharmony_ci		 * is accomplished simply by copying the saved context back over
1878c2ecf20Sopenharmony_ci		 * the caller supplied context.  If there is an attribute list,
1888c2ecf20Sopenharmony_ci		 * things are more complicated as we need to deal with mapping
1898c2ecf20Sopenharmony_ci		 * of mft records and resulting potential changes in pointers.
1908c2ecf20Sopenharmony_ci		 */
1918c2ecf20Sopenharmony_ci		if (NInoAttrList(base_ni)) {
1928c2ecf20Sopenharmony_ci			/*
1938c2ecf20Sopenharmony_ci			 * If the currently mapped (extent) inode is not the
1948c2ecf20Sopenharmony_ci			 * one we had before, we need to unmap it and map the
1958c2ecf20Sopenharmony_ci			 * old one.
1968c2ecf20Sopenharmony_ci			 */
1978c2ecf20Sopenharmony_ci			if (ctx->ntfs_ino != old_ctx.ntfs_ino) {
1988c2ecf20Sopenharmony_ci				/*
1998c2ecf20Sopenharmony_ci				 * If the currently mapped inode is not the
2008c2ecf20Sopenharmony_ci				 * base inode, unmap it.
2018c2ecf20Sopenharmony_ci				 */
2028c2ecf20Sopenharmony_ci				if (ctx->base_ntfs_ino && ctx->ntfs_ino !=
2038c2ecf20Sopenharmony_ci						ctx->base_ntfs_ino) {
2048c2ecf20Sopenharmony_ci					unmap_extent_mft_record(ctx->ntfs_ino);
2058c2ecf20Sopenharmony_ci					ctx->mrec = ctx->base_mrec;
2068c2ecf20Sopenharmony_ci					BUG_ON(!ctx->mrec);
2078c2ecf20Sopenharmony_ci				}
2088c2ecf20Sopenharmony_ci				/*
2098c2ecf20Sopenharmony_ci				 * If the old mapped inode is not the base
2108c2ecf20Sopenharmony_ci				 * inode, map it.
2118c2ecf20Sopenharmony_ci				 */
2128c2ecf20Sopenharmony_ci				if (old_ctx.base_ntfs_ino &&
2138c2ecf20Sopenharmony_ci						old_ctx.ntfs_ino !=
2148c2ecf20Sopenharmony_ci						old_ctx.base_ntfs_ino) {
2158c2ecf20Sopenharmony_ciretry_map:
2168c2ecf20Sopenharmony_ci					ctx->mrec = map_mft_record(
2178c2ecf20Sopenharmony_ci							old_ctx.ntfs_ino);
2188c2ecf20Sopenharmony_ci					/*
2198c2ecf20Sopenharmony_ci					 * Something bad has happened.  If out
2208c2ecf20Sopenharmony_ci					 * of memory retry till it succeeds.
2218c2ecf20Sopenharmony_ci					 * Any other errors are fatal and we
2228c2ecf20Sopenharmony_ci					 * return the error code in ctx->mrec.
2238c2ecf20Sopenharmony_ci					 * Let the caller deal with it...  We
2248c2ecf20Sopenharmony_ci					 * just need to fudge things so the
2258c2ecf20Sopenharmony_ci					 * caller can reinit and/or put the
2268c2ecf20Sopenharmony_ci					 * search context safely.
2278c2ecf20Sopenharmony_ci					 */
2288c2ecf20Sopenharmony_ci					if (IS_ERR(ctx->mrec)) {
2298c2ecf20Sopenharmony_ci						if (PTR_ERR(ctx->mrec) ==
2308c2ecf20Sopenharmony_ci								-ENOMEM) {
2318c2ecf20Sopenharmony_ci							schedule();
2328c2ecf20Sopenharmony_ci							goto retry_map;
2338c2ecf20Sopenharmony_ci						} else
2348c2ecf20Sopenharmony_ci							old_ctx.ntfs_ino =
2358c2ecf20Sopenharmony_ci								old_ctx.
2368c2ecf20Sopenharmony_ci								base_ntfs_ino;
2378c2ecf20Sopenharmony_ci					}
2388c2ecf20Sopenharmony_ci				}
2398c2ecf20Sopenharmony_ci			}
2408c2ecf20Sopenharmony_ci			/* Update the changed pointers in the saved context. */
2418c2ecf20Sopenharmony_ci			if (ctx->mrec != old_ctx.mrec) {
2428c2ecf20Sopenharmony_ci				if (!IS_ERR(ctx->mrec))
2438c2ecf20Sopenharmony_ci					old_ctx.attr = (ATTR_RECORD*)(
2448c2ecf20Sopenharmony_ci							(u8*)ctx->mrec +
2458c2ecf20Sopenharmony_ci							((u8*)old_ctx.attr -
2468c2ecf20Sopenharmony_ci							(u8*)old_ctx.mrec));
2478c2ecf20Sopenharmony_ci				old_ctx.mrec = ctx->mrec;
2488c2ecf20Sopenharmony_ci			}
2498c2ecf20Sopenharmony_ci		}
2508c2ecf20Sopenharmony_ci		/* Restore the search context to the saved one. */
2518c2ecf20Sopenharmony_ci		*ctx = old_ctx;
2528c2ecf20Sopenharmony_ci		/*
2538c2ecf20Sopenharmony_ci		 * We drop the reference on the page we took earlier.  In the
2548c2ecf20Sopenharmony_ci		 * case that IS_ERR(ctx->mrec) is true this means we might lose
2558c2ecf20Sopenharmony_ci		 * some changes to the mft record that had been made between
2568c2ecf20Sopenharmony_ci		 * the last time it was marked dirty/written out and now.  This
2578c2ecf20Sopenharmony_ci		 * at this stage is not a problem as the mapping error is fatal
2588c2ecf20Sopenharmony_ci		 * enough that the mft record cannot be written out anyway and
2598c2ecf20Sopenharmony_ci		 * the caller is very likely to shutdown the whole inode
2608c2ecf20Sopenharmony_ci		 * immediately and mark the volume dirty for chkdsk to pick up
2618c2ecf20Sopenharmony_ci		 * the pieces anyway.
2628c2ecf20Sopenharmony_ci		 */
2638c2ecf20Sopenharmony_ci		if (put_this_page)
2648c2ecf20Sopenharmony_ci			put_page(put_this_page);
2658c2ecf20Sopenharmony_ci	}
2668c2ecf20Sopenharmony_ci	return err;
2678c2ecf20Sopenharmony_ci}
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci/**
2708c2ecf20Sopenharmony_ci * ntfs_map_runlist - map (a part of) a runlist of an ntfs inode
2718c2ecf20Sopenharmony_ci * @ni:		ntfs inode for which to map (part of) a runlist
2728c2ecf20Sopenharmony_ci * @vcn:	map runlist part containing this vcn
2738c2ecf20Sopenharmony_ci *
2748c2ecf20Sopenharmony_ci * Map the part of a runlist containing the @vcn of the ntfs inode @ni.
2758c2ecf20Sopenharmony_ci *
2768c2ecf20Sopenharmony_ci * Return 0 on success and -errno on error.  There is one special error code
2778c2ecf20Sopenharmony_ci * which is not an error as such.  This is -ENOENT.  It means that @vcn is out
2788c2ecf20Sopenharmony_ci * of bounds of the runlist.
2798c2ecf20Sopenharmony_ci *
2808c2ecf20Sopenharmony_ci * Locking: - The runlist must be unlocked on entry and is unlocked on return.
2818c2ecf20Sopenharmony_ci *	    - This function takes the runlist lock for writing and may modify
2828c2ecf20Sopenharmony_ci *	      the runlist.
2838c2ecf20Sopenharmony_ci */
2848c2ecf20Sopenharmony_ciint ntfs_map_runlist(ntfs_inode *ni, VCN vcn)
2858c2ecf20Sopenharmony_ci{
2868c2ecf20Sopenharmony_ci	int err = 0;
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci	down_write(&ni->runlist.lock);
2898c2ecf20Sopenharmony_ci	/* Make sure someone else didn't do the work while we were sleeping. */
2908c2ecf20Sopenharmony_ci	if (likely(ntfs_rl_vcn_to_lcn(ni->runlist.rl, vcn) <=
2918c2ecf20Sopenharmony_ci			LCN_RL_NOT_MAPPED))
2928c2ecf20Sopenharmony_ci		err = ntfs_map_runlist_nolock(ni, vcn, NULL);
2938c2ecf20Sopenharmony_ci	up_write(&ni->runlist.lock);
2948c2ecf20Sopenharmony_ci	return err;
2958c2ecf20Sopenharmony_ci}
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci/**
2988c2ecf20Sopenharmony_ci * ntfs_attr_vcn_to_lcn_nolock - convert a vcn into a lcn given an ntfs inode
2998c2ecf20Sopenharmony_ci * @ni:			ntfs inode of the attribute whose runlist to search
3008c2ecf20Sopenharmony_ci * @vcn:		vcn to convert
3018c2ecf20Sopenharmony_ci * @write_locked:	true if the runlist is locked for writing
3028c2ecf20Sopenharmony_ci *
3038c2ecf20Sopenharmony_ci * Find the virtual cluster number @vcn in the runlist of the ntfs attribute
3048c2ecf20Sopenharmony_ci * described by the ntfs inode @ni and return the corresponding logical cluster
3058c2ecf20Sopenharmony_ci * number (lcn).
3068c2ecf20Sopenharmony_ci *
3078c2ecf20Sopenharmony_ci * If the @vcn is not mapped yet, the attempt is made to map the attribute
3088c2ecf20Sopenharmony_ci * extent containing the @vcn and the vcn to lcn conversion is retried.
3098c2ecf20Sopenharmony_ci *
3108c2ecf20Sopenharmony_ci * If @write_locked is true the caller has locked the runlist for writing and
3118c2ecf20Sopenharmony_ci * if false for reading.
3128c2ecf20Sopenharmony_ci *
3138c2ecf20Sopenharmony_ci * Since lcns must be >= 0, we use negative return codes with special meaning:
3148c2ecf20Sopenharmony_ci *
3158c2ecf20Sopenharmony_ci * Return code	Meaning / Description
3168c2ecf20Sopenharmony_ci * ==========================================
3178c2ecf20Sopenharmony_ci *  LCN_HOLE	Hole / not allocated on disk.
3188c2ecf20Sopenharmony_ci *  LCN_ENOENT	There is no such vcn in the runlist, i.e. @vcn is out of bounds.
3198c2ecf20Sopenharmony_ci *  LCN_ENOMEM	Not enough memory to map runlist.
3208c2ecf20Sopenharmony_ci *  LCN_EIO	Critical error (runlist/file is corrupt, i/o error, etc).
3218c2ecf20Sopenharmony_ci *
3228c2ecf20Sopenharmony_ci * Locking: - The runlist must be locked on entry and is left locked on return.
3238c2ecf20Sopenharmony_ci *	    - If @write_locked is 'false', i.e. the runlist is locked for reading,
3248c2ecf20Sopenharmony_ci *	      the lock may be dropped inside the function so you cannot rely on
3258c2ecf20Sopenharmony_ci *	      the runlist still being the same when this function returns.
3268c2ecf20Sopenharmony_ci */
3278c2ecf20Sopenharmony_ciLCN ntfs_attr_vcn_to_lcn_nolock(ntfs_inode *ni, const VCN vcn,
3288c2ecf20Sopenharmony_ci		const bool write_locked)
3298c2ecf20Sopenharmony_ci{
3308c2ecf20Sopenharmony_ci	LCN lcn;
3318c2ecf20Sopenharmony_ci	unsigned long flags;
3328c2ecf20Sopenharmony_ci	bool is_retry = false;
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	BUG_ON(!ni);
3358c2ecf20Sopenharmony_ci	ntfs_debug("Entering for i_ino 0x%lx, vcn 0x%llx, %s_locked.",
3368c2ecf20Sopenharmony_ci			ni->mft_no, (unsigned long long)vcn,
3378c2ecf20Sopenharmony_ci			write_locked ? "write" : "read");
3388c2ecf20Sopenharmony_ci	BUG_ON(!NInoNonResident(ni));
3398c2ecf20Sopenharmony_ci	BUG_ON(vcn < 0);
3408c2ecf20Sopenharmony_ci	if (!ni->runlist.rl) {
3418c2ecf20Sopenharmony_ci		read_lock_irqsave(&ni->size_lock, flags);
3428c2ecf20Sopenharmony_ci		if (!ni->allocated_size) {
3438c2ecf20Sopenharmony_ci			read_unlock_irqrestore(&ni->size_lock, flags);
3448c2ecf20Sopenharmony_ci			return LCN_ENOENT;
3458c2ecf20Sopenharmony_ci		}
3468c2ecf20Sopenharmony_ci		read_unlock_irqrestore(&ni->size_lock, flags);
3478c2ecf20Sopenharmony_ci	}
3488c2ecf20Sopenharmony_ciretry_remap:
3498c2ecf20Sopenharmony_ci	/* Convert vcn to lcn.  If that fails map the runlist and retry once. */
3508c2ecf20Sopenharmony_ci	lcn = ntfs_rl_vcn_to_lcn(ni->runlist.rl, vcn);
3518c2ecf20Sopenharmony_ci	if (likely(lcn >= LCN_HOLE)) {
3528c2ecf20Sopenharmony_ci		ntfs_debug("Done, lcn 0x%llx.", (long long)lcn);
3538c2ecf20Sopenharmony_ci		return lcn;
3548c2ecf20Sopenharmony_ci	}
3558c2ecf20Sopenharmony_ci	if (lcn != LCN_RL_NOT_MAPPED) {
3568c2ecf20Sopenharmony_ci		if (lcn != LCN_ENOENT)
3578c2ecf20Sopenharmony_ci			lcn = LCN_EIO;
3588c2ecf20Sopenharmony_ci	} else if (!is_retry) {
3598c2ecf20Sopenharmony_ci		int err;
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_ci		if (!write_locked) {
3628c2ecf20Sopenharmony_ci			up_read(&ni->runlist.lock);
3638c2ecf20Sopenharmony_ci			down_write(&ni->runlist.lock);
3648c2ecf20Sopenharmony_ci			if (unlikely(ntfs_rl_vcn_to_lcn(ni->runlist.rl, vcn) !=
3658c2ecf20Sopenharmony_ci					LCN_RL_NOT_MAPPED)) {
3668c2ecf20Sopenharmony_ci				up_write(&ni->runlist.lock);
3678c2ecf20Sopenharmony_ci				down_read(&ni->runlist.lock);
3688c2ecf20Sopenharmony_ci				goto retry_remap;
3698c2ecf20Sopenharmony_ci			}
3708c2ecf20Sopenharmony_ci		}
3718c2ecf20Sopenharmony_ci		err = ntfs_map_runlist_nolock(ni, vcn, NULL);
3728c2ecf20Sopenharmony_ci		if (!write_locked) {
3738c2ecf20Sopenharmony_ci			up_write(&ni->runlist.lock);
3748c2ecf20Sopenharmony_ci			down_read(&ni->runlist.lock);
3758c2ecf20Sopenharmony_ci		}
3768c2ecf20Sopenharmony_ci		if (likely(!err)) {
3778c2ecf20Sopenharmony_ci			is_retry = true;
3788c2ecf20Sopenharmony_ci			goto retry_remap;
3798c2ecf20Sopenharmony_ci		}
3808c2ecf20Sopenharmony_ci		if (err == -ENOENT)
3818c2ecf20Sopenharmony_ci			lcn = LCN_ENOENT;
3828c2ecf20Sopenharmony_ci		else if (err == -ENOMEM)
3838c2ecf20Sopenharmony_ci			lcn = LCN_ENOMEM;
3848c2ecf20Sopenharmony_ci		else
3858c2ecf20Sopenharmony_ci			lcn = LCN_EIO;
3868c2ecf20Sopenharmony_ci	}
3878c2ecf20Sopenharmony_ci	if (lcn != LCN_ENOENT)
3888c2ecf20Sopenharmony_ci		ntfs_error(ni->vol->sb, "Failed with error code %lli.",
3898c2ecf20Sopenharmony_ci				(long long)lcn);
3908c2ecf20Sopenharmony_ci	return lcn;
3918c2ecf20Sopenharmony_ci}
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci/**
3948c2ecf20Sopenharmony_ci * ntfs_attr_find_vcn_nolock - find a vcn in the runlist of an ntfs inode
3958c2ecf20Sopenharmony_ci * @ni:		ntfs inode describing the runlist to search
3968c2ecf20Sopenharmony_ci * @vcn:	vcn to find
3978c2ecf20Sopenharmony_ci * @ctx:	active attribute search context if present or NULL if not
3988c2ecf20Sopenharmony_ci *
3998c2ecf20Sopenharmony_ci * Find the virtual cluster number @vcn in the runlist described by the ntfs
4008c2ecf20Sopenharmony_ci * inode @ni and return the address of the runlist element containing the @vcn.
4018c2ecf20Sopenharmony_ci *
4028c2ecf20Sopenharmony_ci * If the @vcn is not mapped yet, the attempt is made to map the attribute
4038c2ecf20Sopenharmony_ci * extent containing the @vcn and the vcn to lcn conversion is retried.
4048c2ecf20Sopenharmony_ci *
4058c2ecf20Sopenharmony_ci * If @ctx is specified, it is an active search context of @ni and its base mft
4068c2ecf20Sopenharmony_ci * record.  This is needed when ntfs_attr_find_vcn_nolock() encounters unmapped
4078c2ecf20Sopenharmony_ci * runlist fragments and allows their mapping.  If you do not have the mft
4088c2ecf20Sopenharmony_ci * record mapped, you can specify @ctx as NULL and ntfs_attr_find_vcn_nolock()
4098c2ecf20Sopenharmony_ci * will perform the necessary mapping and unmapping.
4108c2ecf20Sopenharmony_ci *
4118c2ecf20Sopenharmony_ci * Note, ntfs_attr_find_vcn_nolock() saves the state of @ctx on entry and
4128c2ecf20Sopenharmony_ci * restores it before returning.  Thus, @ctx will be left pointing to the same
4138c2ecf20Sopenharmony_ci * attribute on return as on entry.  However, the actual pointers in @ctx may
4148c2ecf20Sopenharmony_ci * point to different memory locations on return, so you must remember to reset
4158c2ecf20Sopenharmony_ci * any cached pointers from the @ctx, i.e. after the call to
4168c2ecf20Sopenharmony_ci * ntfs_attr_find_vcn_nolock(), you will probably want to do:
4178c2ecf20Sopenharmony_ci *	m = ctx->mrec;
4188c2ecf20Sopenharmony_ci *	a = ctx->attr;
4198c2ecf20Sopenharmony_ci * Assuming you cache ctx->attr in a variable @a of type ATTR_RECORD * and that
4208c2ecf20Sopenharmony_ci * you cache ctx->mrec in a variable @m of type MFT_RECORD *.
4218c2ecf20Sopenharmony_ci * Note you need to distinguish between the lcn of the returned runlist element
4228c2ecf20Sopenharmony_ci * being >= 0 and LCN_HOLE.  In the later case you have to return zeroes on
4238c2ecf20Sopenharmony_ci * read and allocate clusters on write.
4248c2ecf20Sopenharmony_ci *
4258c2ecf20Sopenharmony_ci * Return the runlist element containing the @vcn on success and
4268c2ecf20Sopenharmony_ci * ERR_PTR(-errno) on error.  You need to test the return value with IS_ERR()
4278c2ecf20Sopenharmony_ci * to decide if the return is success or failure and PTR_ERR() to get to the
4288c2ecf20Sopenharmony_ci * error code if IS_ERR() is true.
4298c2ecf20Sopenharmony_ci *
4308c2ecf20Sopenharmony_ci * The possible error return codes are:
4318c2ecf20Sopenharmony_ci *	-ENOENT - No such vcn in the runlist, i.e. @vcn is out of bounds.
4328c2ecf20Sopenharmony_ci *	-ENOMEM - Not enough memory to map runlist.
4338c2ecf20Sopenharmony_ci *	-EIO	- Critical error (runlist/file is corrupt, i/o error, etc).
4348c2ecf20Sopenharmony_ci *
4358c2ecf20Sopenharmony_ci * WARNING: If @ctx is supplied, regardless of whether success or failure is
4368c2ecf20Sopenharmony_ci *	    returned, you need to check IS_ERR(@ctx->mrec) and if 'true' the @ctx
4378c2ecf20Sopenharmony_ci *	    is no longer valid, i.e. you need to either call
4388c2ecf20Sopenharmony_ci *	    ntfs_attr_reinit_search_ctx() or ntfs_attr_put_search_ctx() on it.
4398c2ecf20Sopenharmony_ci *	    In that case PTR_ERR(@ctx->mrec) will give you the error code for
4408c2ecf20Sopenharmony_ci *	    why the mapping of the old inode failed.
4418c2ecf20Sopenharmony_ci *
4428c2ecf20Sopenharmony_ci * Locking: - The runlist described by @ni must be locked for writing on entry
4438c2ecf20Sopenharmony_ci *	      and is locked on return.  Note the runlist may be modified when
4448c2ecf20Sopenharmony_ci *	      needed runlist fragments need to be mapped.
4458c2ecf20Sopenharmony_ci *	    - If @ctx is NULL, the base mft record of @ni must not be mapped on
4468c2ecf20Sopenharmony_ci *	      entry and it will be left unmapped on return.
4478c2ecf20Sopenharmony_ci *	    - If @ctx is not NULL, the base mft record must be mapped on entry
4488c2ecf20Sopenharmony_ci *	      and it will be left mapped on return.
4498c2ecf20Sopenharmony_ci */
4508c2ecf20Sopenharmony_cirunlist_element *ntfs_attr_find_vcn_nolock(ntfs_inode *ni, const VCN vcn,
4518c2ecf20Sopenharmony_ci		ntfs_attr_search_ctx *ctx)
4528c2ecf20Sopenharmony_ci{
4538c2ecf20Sopenharmony_ci	unsigned long flags;
4548c2ecf20Sopenharmony_ci	runlist_element *rl;
4558c2ecf20Sopenharmony_ci	int err = 0;
4568c2ecf20Sopenharmony_ci	bool is_retry = false;
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_ci	BUG_ON(!ni);
4598c2ecf20Sopenharmony_ci	ntfs_debug("Entering for i_ino 0x%lx, vcn 0x%llx, with%s ctx.",
4608c2ecf20Sopenharmony_ci			ni->mft_no, (unsigned long long)vcn, ctx ? "" : "out");
4618c2ecf20Sopenharmony_ci	BUG_ON(!NInoNonResident(ni));
4628c2ecf20Sopenharmony_ci	BUG_ON(vcn < 0);
4638c2ecf20Sopenharmony_ci	if (!ni->runlist.rl) {
4648c2ecf20Sopenharmony_ci		read_lock_irqsave(&ni->size_lock, flags);
4658c2ecf20Sopenharmony_ci		if (!ni->allocated_size) {
4668c2ecf20Sopenharmony_ci			read_unlock_irqrestore(&ni->size_lock, flags);
4678c2ecf20Sopenharmony_ci			return ERR_PTR(-ENOENT);
4688c2ecf20Sopenharmony_ci		}
4698c2ecf20Sopenharmony_ci		read_unlock_irqrestore(&ni->size_lock, flags);
4708c2ecf20Sopenharmony_ci	}
4718c2ecf20Sopenharmony_ciretry_remap:
4728c2ecf20Sopenharmony_ci	rl = ni->runlist.rl;
4738c2ecf20Sopenharmony_ci	if (likely(rl && vcn >= rl[0].vcn)) {
4748c2ecf20Sopenharmony_ci		while (likely(rl->length)) {
4758c2ecf20Sopenharmony_ci			if (unlikely(vcn < rl[1].vcn)) {
4768c2ecf20Sopenharmony_ci				if (likely(rl->lcn >= LCN_HOLE)) {
4778c2ecf20Sopenharmony_ci					ntfs_debug("Done.");
4788c2ecf20Sopenharmony_ci					return rl;
4798c2ecf20Sopenharmony_ci				}
4808c2ecf20Sopenharmony_ci				break;
4818c2ecf20Sopenharmony_ci			}
4828c2ecf20Sopenharmony_ci			rl++;
4838c2ecf20Sopenharmony_ci		}
4848c2ecf20Sopenharmony_ci		if (likely(rl->lcn != LCN_RL_NOT_MAPPED)) {
4858c2ecf20Sopenharmony_ci			if (likely(rl->lcn == LCN_ENOENT))
4868c2ecf20Sopenharmony_ci				err = -ENOENT;
4878c2ecf20Sopenharmony_ci			else
4888c2ecf20Sopenharmony_ci				err = -EIO;
4898c2ecf20Sopenharmony_ci		}
4908c2ecf20Sopenharmony_ci	}
4918c2ecf20Sopenharmony_ci	if (!err && !is_retry) {
4928c2ecf20Sopenharmony_ci		/*
4938c2ecf20Sopenharmony_ci		 * If the search context is invalid we cannot map the unmapped
4948c2ecf20Sopenharmony_ci		 * region.
4958c2ecf20Sopenharmony_ci		 */
4968c2ecf20Sopenharmony_ci		if (IS_ERR(ctx->mrec))
4978c2ecf20Sopenharmony_ci			err = PTR_ERR(ctx->mrec);
4988c2ecf20Sopenharmony_ci		else {
4998c2ecf20Sopenharmony_ci			/*
5008c2ecf20Sopenharmony_ci			 * The @vcn is in an unmapped region, map the runlist
5018c2ecf20Sopenharmony_ci			 * and retry.
5028c2ecf20Sopenharmony_ci			 */
5038c2ecf20Sopenharmony_ci			err = ntfs_map_runlist_nolock(ni, vcn, ctx);
5048c2ecf20Sopenharmony_ci			if (likely(!err)) {
5058c2ecf20Sopenharmony_ci				is_retry = true;
5068c2ecf20Sopenharmony_ci				goto retry_remap;
5078c2ecf20Sopenharmony_ci			}
5088c2ecf20Sopenharmony_ci		}
5098c2ecf20Sopenharmony_ci		if (err == -EINVAL)
5108c2ecf20Sopenharmony_ci			err = -EIO;
5118c2ecf20Sopenharmony_ci	} else if (!err)
5128c2ecf20Sopenharmony_ci		err = -EIO;
5138c2ecf20Sopenharmony_ci	if (err != -ENOENT)
5148c2ecf20Sopenharmony_ci		ntfs_error(ni->vol->sb, "Failed with error code %i.", err);
5158c2ecf20Sopenharmony_ci	return ERR_PTR(err);
5168c2ecf20Sopenharmony_ci}
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_ci/**
5198c2ecf20Sopenharmony_ci * ntfs_attr_find - find (next) attribute in mft record
5208c2ecf20Sopenharmony_ci * @type:	attribute type to find
5218c2ecf20Sopenharmony_ci * @name:	attribute name to find (optional, i.e. NULL means don't care)
5228c2ecf20Sopenharmony_ci * @name_len:	attribute name length (only needed if @name present)
5238c2ecf20Sopenharmony_ci * @ic:		IGNORE_CASE or CASE_SENSITIVE (ignored if @name not present)
5248c2ecf20Sopenharmony_ci * @val:	attribute value to find (optional, resident attributes only)
5258c2ecf20Sopenharmony_ci * @val_len:	attribute value length
5268c2ecf20Sopenharmony_ci * @ctx:	search context with mft record and attribute to search from
5278c2ecf20Sopenharmony_ci *
5288c2ecf20Sopenharmony_ci * You should not need to call this function directly.  Use ntfs_attr_lookup()
5298c2ecf20Sopenharmony_ci * instead.
5308c2ecf20Sopenharmony_ci *
5318c2ecf20Sopenharmony_ci * ntfs_attr_find() takes a search context @ctx as parameter and searches the
5328c2ecf20Sopenharmony_ci * mft record specified by @ctx->mrec, beginning at @ctx->attr, for an
5338c2ecf20Sopenharmony_ci * attribute of @type, optionally @name and @val.
5348c2ecf20Sopenharmony_ci *
5358c2ecf20Sopenharmony_ci * If the attribute is found, ntfs_attr_find() returns 0 and @ctx->attr will
5368c2ecf20Sopenharmony_ci * point to the found attribute.
5378c2ecf20Sopenharmony_ci *
5388c2ecf20Sopenharmony_ci * If the attribute is not found, ntfs_attr_find() returns -ENOENT and
5398c2ecf20Sopenharmony_ci * @ctx->attr will point to the attribute before which the attribute being
5408c2ecf20Sopenharmony_ci * searched for would need to be inserted if such an action were to be desired.
5418c2ecf20Sopenharmony_ci *
5428c2ecf20Sopenharmony_ci * On actual error, ntfs_attr_find() returns -EIO.  In this case @ctx->attr is
5438c2ecf20Sopenharmony_ci * undefined and in particular do not rely on it not changing.
5448c2ecf20Sopenharmony_ci *
5458c2ecf20Sopenharmony_ci * If @ctx->is_first is 'true', the search begins with @ctx->attr itself.  If it
5468c2ecf20Sopenharmony_ci * is 'false', the search begins after @ctx->attr.
5478c2ecf20Sopenharmony_ci *
5488c2ecf20Sopenharmony_ci * If @ic is IGNORE_CASE, the @name comparisson is not case sensitive and
5498c2ecf20Sopenharmony_ci * @ctx->ntfs_ino must be set to the ntfs inode to which the mft record
5508c2ecf20Sopenharmony_ci * @ctx->mrec belongs.  This is so we can get at the ntfs volume and hence at
5518c2ecf20Sopenharmony_ci * the upcase table.  If @ic is CASE_SENSITIVE, the comparison is case
5528c2ecf20Sopenharmony_ci * sensitive.  When @name is present, @name_len is the @name length in Unicode
5538c2ecf20Sopenharmony_ci * characters.
5548c2ecf20Sopenharmony_ci *
5558c2ecf20Sopenharmony_ci * If @name is not present (NULL), we assume that the unnamed attribute is
5568c2ecf20Sopenharmony_ci * being searched for.
5578c2ecf20Sopenharmony_ci *
5588c2ecf20Sopenharmony_ci * Finally, the resident attribute value @val is looked for, if present.  If
5598c2ecf20Sopenharmony_ci * @val is not present (NULL), @val_len is ignored.
5608c2ecf20Sopenharmony_ci *
5618c2ecf20Sopenharmony_ci * ntfs_attr_find() only searches the specified mft record and it ignores the
5628c2ecf20Sopenharmony_ci * presence of an attribute list attribute (unless it is the one being searched
5638c2ecf20Sopenharmony_ci * for, obviously).  If you need to take attribute lists into consideration,
5648c2ecf20Sopenharmony_ci * use ntfs_attr_lookup() instead (see below).  This also means that you cannot
5658c2ecf20Sopenharmony_ci * use ntfs_attr_find() to search for extent records of non-resident
5668c2ecf20Sopenharmony_ci * attributes, as extents with lowest_vcn != 0 are usually described by the
5678c2ecf20Sopenharmony_ci * attribute list attribute only. - Note that it is possible that the first
5688c2ecf20Sopenharmony_ci * extent is only in the attribute list while the last extent is in the base
5698c2ecf20Sopenharmony_ci * mft record, so do not rely on being able to find the first extent in the
5708c2ecf20Sopenharmony_ci * base mft record.
5718c2ecf20Sopenharmony_ci *
5728c2ecf20Sopenharmony_ci * Warning: Never use @val when looking for attribute types which can be
5738c2ecf20Sopenharmony_ci *	    non-resident as this most likely will result in a crash!
5748c2ecf20Sopenharmony_ci */
5758c2ecf20Sopenharmony_cistatic int ntfs_attr_find(const ATTR_TYPE type, const ntfschar *name,
5768c2ecf20Sopenharmony_ci		const u32 name_len, const IGNORE_CASE_BOOL ic,
5778c2ecf20Sopenharmony_ci		const u8 *val, const u32 val_len, ntfs_attr_search_ctx *ctx)
5788c2ecf20Sopenharmony_ci{
5798c2ecf20Sopenharmony_ci	ATTR_RECORD *a;
5808c2ecf20Sopenharmony_ci	ntfs_volume *vol = ctx->ntfs_ino->vol;
5818c2ecf20Sopenharmony_ci	ntfschar *upcase = vol->upcase;
5828c2ecf20Sopenharmony_ci	u32 upcase_len = vol->upcase_len;
5838c2ecf20Sopenharmony_ci
5848c2ecf20Sopenharmony_ci	/*
5858c2ecf20Sopenharmony_ci	 * Iterate over attributes in mft record starting at @ctx->attr, or the
5868c2ecf20Sopenharmony_ci	 * attribute following that, if @ctx->is_first is 'true'.
5878c2ecf20Sopenharmony_ci	 */
5888c2ecf20Sopenharmony_ci	if (ctx->is_first) {
5898c2ecf20Sopenharmony_ci		a = ctx->attr;
5908c2ecf20Sopenharmony_ci		ctx->is_first = false;
5918c2ecf20Sopenharmony_ci	} else
5928c2ecf20Sopenharmony_ci		a = (ATTR_RECORD*)((u8*)ctx->attr +
5938c2ecf20Sopenharmony_ci				le32_to_cpu(ctx->attr->length));
5948c2ecf20Sopenharmony_ci	for (;;	a = (ATTR_RECORD*)((u8*)a + le32_to_cpu(a->length))) {
5958c2ecf20Sopenharmony_ci		u8 *mrec_end = (u8 *)ctx->mrec +
5968c2ecf20Sopenharmony_ci		               le32_to_cpu(ctx->mrec->bytes_allocated);
5978c2ecf20Sopenharmony_ci		u8 *name_end;
5988c2ecf20Sopenharmony_ci
5998c2ecf20Sopenharmony_ci		/* check whether ATTR_RECORD wrap */
6008c2ecf20Sopenharmony_ci		if ((u8 *)a < (u8 *)ctx->mrec)
6018c2ecf20Sopenharmony_ci			break;
6028c2ecf20Sopenharmony_ci
6038c2ecf20Sopenharmony_ci		/* check whether Attribute Record Header is within bounds */
6048c2ecf20Sopenharmony_ci		if ((u8 *)a > mrec_end ||
6058c2ecf20Sopenharmony_ci		    (u8 *)a + sizeof(ATTR_RECORD) > mrec_end)
6068c2ecf20Sopenharmony_ci			break;
6078c2ecf20Sopenharmony_ci
6088c2ecf20Sopenharmony_ci		/* check whether ATTR_RECORD's name is within bounds */
6098c2ecf20Sopenharmony_ci		name_end = (u8 *)a + le16_to_cpu(a->name_offset) +
6108c2ecf20Sopenharmony_ci			   a->name_length * sizeof(ntfschar);
6118c2ecf20Sopenharmony_ci		if (name_end > mrec_end)
6128c2ecf20Sopenharmony_ci			break;
6138c2ecf20Sopenharmony_ci
6148c2ecf20Sopenharmony_ci		ctx->attr = a;
6158c2ecf20Sopenharmony_ci		if (unlikely(le32_to_cpu(a->type) > le32_to_cpu(type) ||
6168c2ecf20Sopenharmony_ci				a->type == AT_END))
6178c2ecf20Sopenharmony_ci			return -ENOENT;
6188c2ecf20Sopenharmony_ci		if (unlikely(!a->length))
6198c2ecf20Sopenharmony_ci			break;
6208c2ecf20Sopenharmony_ci
6218c2ecf20Sopenharmony_ci		/* check whether ATTR_RECORD's length wrap */
6228c2ecf20Sopenharmony_ci		if ((u8 *)a + le32_to_cpu(a->length) < (u8 *)a)
6238c2ecf20Sopenharmony_ci			break;
6248c2ecf20Sopenharmony_ci		/* check whether ATTR_RECORD's length is within bounds */
6258c2ecf20Sopenharmony_ci		if ((u8 *)a + le32_to_cpu(a->length) > mrec_end)
6268c2ecf20Sopenharmony_ci			break;
6278c2ecf20Sopenharmony_ci
6288c2ecf20Sopenharmony_ci		if (a->type != type)
6298c2ecf20Sopenharmony_ci			continue;
6308c2ecf20Sopenharmony_ci		/*
6318c2ecf20Sopenharmony_ci		 * If @name is present, compare the two names.  If @name is
6328c2ecf20Sopenharmony_ci		 * missing, assume we want an unnamed attribute.
6338c2ecf20Sopenharmony_ci		 */
6348c2ecf20Sopenharmony_ci		if (!name) {
6358c2ecf20Sopenharmony_ci			/* The search failed if the found attribute is named. */
6368c2ecf20Sopenharmony_ci			if (a->name_length)
6378c2ecf20Sopenharmony_ci				return -ENOENT;
6388c2ecf20Sopenharmony_ci		} else if (!ntfs_are_names_equal(name, name_len,
6398c2ecf20Sopenharmony_ci			    (ntfschar*)((u8*)a + le16_to_cpu(a->name_offset)),
6408c2ecf20Sopenharmony_ci			    a->name_length, ic, upcase, upcase_len)) {
6418c2ecf20Sopenharmony_ci			register int rc;
6428c2ecf20Sopenharmony_ci
6438c2ecf20Sopenharmony_ci			rc = ntfs_collate_names(name, name_len,
6448c2ecf20Sopenharmony_ci					(ntfschar*)((u8*)a +
6458c2ecf20Sopenharmony_ci					le16_to_cpu(a->name_offset)),
6468c2ecf20Sopenharmony_ci					a->name_length, 1, IGNORE_CASE,
6478c2ecf20Sopenharmony_ci					upcase, upcase_len);
6488c2ecf20Sopenharmony_ci			/*
6498c2ecf20Sopenharmony_ci			 * If @name collates before a->name, there is no
6508c2ecf20Sopenharmony_ci			 * matching attribute.
6518c2ecf20Sopenharmony_ci			 */
6528c2ecf20Sopenharmony_ci			if (rc == -1)
6538c2ecf20Sopenharmony_ci				return -ENOENT;
6548c2ecf20Sopenharmony_ci			/* If the strings are not equal, continue search. */
6558c2ecf20Sopenharmony_ci			if (rc)
6568c2ecf20Sopenharmony_ci				continue;
6578c2ecf20Sopenharmony_ci			rc = ntfs_collate_names(name, name_len,
6588c2ecf20Sopenharmony_ci					(ntfschar*)((u8*)a +
6598c2ecf20Sopenharmony_ci					le16_to_cpu(a->name_offset)),
6608c2ecf20Sopenharmony_ci					a->name_length, 1, CASE_SENSITIVE,
6618c2ecf20Sopenharmony_ci					upcase, upcase_len);
6628c2ecf20Sopenharmony_ci			if (rc == -1)
6638c2ecf20Sopenharmony_ci				return -ENOENT;
6648c2ecf20Sopenharmony_ci			if (rc)
6658c2ecf20Sopenharmony_ci				continue;
6668c2ecf20Sopenharmony_ci		}
6678c2ecf20Sopenharmony_ci		/*
6688c2ecf20Sopenharmony_ci		 * The names match or @name not present and attribute is
6698c2ecf20Sopenharmony_ci		 * unnamed.  If no @val specified, we have found the attribute
6708c2ecf20Sopenharmony_ci		 * and are done.
6718c2ecf20Sopenharmony_ci		 */
6728c2ecf20Sopenharmony_ci		if (!val)
6738c2ecf20Sopenharmony_ci			return 0;
6748c2ecf20Sopenharmony_ci		/* @val is present; compare values. */
6758c2ecf20Sopenharmony_ci		else {
6768c2ecf20Sopenharmony_ci			register int rc;
6778c2ecf20Sopenharmony_ci
6788c2ecf20Sopenharmony_ci			rc = memcmp(val, (u8*)a + le16_to_cpu(
6798c2ecf20Sopenharmony_ci					a->data.resident.value_offset),
6808c2ecf20Sopenharmony_ci					min_t(u32, val_len, le32_to_cpu(
6818c2ecf20Sopenharmony_ci					a->data.resident.value_length)));
6828c2ecf20Sopenharmony_ci			/*
6838c2ecf20Sopenharmony_ci			 * If @val collates before the current attribute's
6848c2ecf20Sopenharmony_ci			 * value, there is no matching attribute.
6858c2ecf20Sopenharmony_ci			 */
6868c2ecf20Sopenharmony_ci			if (!rc) {
6878c2ecf20Sopenharmony_ci				register u32 avl;
6888c2ecf20Sopenharmony_ci
6898c2ecf20Sopenharmony_ci				avl = le32_to_cpu(
6908c2ecf20Sopenharmony_ci						a->data.resident.value_length);
6918c2ecf20Sopenharmony_ci				if (val_len == avl)
6928c2ecf20Sopenharmony_ci					return 0;
6938c2ecf20Sopenharmony_ci				if (val_len < avl)
6948c2ecf20Sopenharmony_ci					return -ENOENT;
6958c2ecf20Sopenharmony_ci			} else if (rc < 0)
6968c2ecf20Sopenharmony_ci				return -ENOENT;
6978c2ecf20Sopenharmony_ci		}
6988c2ecf20Sopenharmony_ci	}
6998c2ecf20Sopenharmony_ci	ntfs_error(vol->sb, "Inode is corrupt.  Run chkdsk.");
7008c2ecf20Sopenharmony_ci	NVolSetErrors(vol);
7018c2ecf20Sopenharmony_ci	return -EIO;
7028c2ecf20Sopenharmony_ci}
7038c2ecf20Sopenharmony_ci
7048c2ecf20Sopenharmony_ci/**
7058c2ecf20Sopenharmony_ci * load_attribute_list - load an attribute list into memory
7068c2ecf20Sopenharmony_ci * @vol:		ntfs volume from which to read
7078c2ecf20Sopenharmony_ci * @runlist:		runlist of the attribute list
7088c2ecf20Sopenharmony_ci * @al_start:		destination buffer
7098c2ecf20Sopenharmony_ci * @size:		size of the destination buffer in bytes
7108c2ecf20Sopenharmony_ci * @initialized_size:	initialized size of the attribute list
7118c2ecf20Sopenharmony_ci *
7128c2ecf20Sopenharmony_ci * Walk the runlist @runlist and load all clusters from it copying them into
7138c2ecf20Sopenharmony_ci * the linear buffer @al. The maximum number of bytes copied to @al is @size
7148c2ecf20Sopenharmony_ci * bytes. Note, @size does not need to be a multiple of the cluster size. If
7158c2ecf20Sopenharmony_ci * @initialized_size is less than @size, the region in @al between
7168c2ecf20Sopenharmony_ci * @initialized_size and @size will be zeroed and not read from disk.
7178c2ecf20Sopenharmony_ci *
7188c2ecf20Sopenharmony_ci * Return 0 on success or -errno on error.
7198c2ecf20Sopenharmony_ci */
7208c2ecf20Sopenharmony_ciint load_attribute_list(ntfs_volume *vol, runlist *runlist, u8 *al_start,
7218c2ecf20Sopenharmony_ci		const s64 size, const s64 initialized_size)
7228c2ecf20Sopenharmony_ci{
7238c2ecf20Sopenharmony_ci	LCN lcn;
7248c2ecf20Sopenharmony_ci	u8 *al = al_start;
7258c2ecf20Sopenharmony_ci	u8 *al_end = al + initialized_size;
7268c2ecf20Sopenharmony_ci	runlist_element *rl;
7278c2ecf20Sopenharmony_ci	struct buffer_head *bh;
7288c2ecf20Sopenharmony_ci	struct super_block *sb;
7298c2ecf20Sopenharmony_ci	unsigned long block_size;
7308c2ecf20Sopenharmony_ci	unsigned long block, max_block;
7318c2ecf20Sopenharmony_ci	int err = 0;
7328c2ecf20Sopenharmony_ci	unsigned char block_size_bits;
7338c2ecf20Sopenharmony_ci
7348c2ecf20Sopenharmony_ci	ntfs_debug("Entering.");
7358c2ecf20Sopenharmony_ci	if (!vol || !runlist || !al || size <= 0 || initialized_size < 0 ||
7368c2ecf20Sopenharmony_ci			initialized_size > size)
7378c2ecf20Sopenharmony_ci		return -EINVAL;
7388c2ecf20Sopenharmony_ci	if (!initialized_size) {
7398c2ecf20Sopenharmony_ci		memset(al, 0, size);
7408c2ecf20Sopenharmony_ci		return 0;
7418c2ecf20Sopenharmony_ci	}
7428c2ecf20Sopenharmony_ci	sb = vol->sb;
7438c2ecf20Sopenharmony_ci	block_size = sb->s_blocksize;
7448c2ecf20Sopenharmony_ci	block_size_bits = sb->s_blocksize_bits;
7458c2ecf20Sopenharmony_ci	down_read(&runlist->lock);
7468c2ecf20Sopenharmony_ci	rl = runlist->rl;
7478c2ecf20Sopenharmony_ci	if (!rl) {
7488c2ecf20Sopenharmony_ci		ntfs_error(sb, "Cannot read attribute list since runlist is "
7498c2ecf20Sopenharmony_ci				"missing.");
7508c2ecf20Sopenharmony_ci		goto err_out;
7518c2ecf20Sopenharmony_ci	}
7528c2ecf20Sopenharmony_ci	/* Read all clusters specified by the runlist one run at a time. */
7538c2ecf20Sopenharmony_ci	while (rl->length) {
7548c2ecf20Sopenharmony_ci		lcn = ntfs_rl_vcn_to_lcn(rl, rl->vcn);
7558c2ecf20Sopenharmony_ci		ntfs_debug("Reading vcn = 0x%llx, lcn = 0x%llx.",
7568c2ecf20Sopenharmony_ci				(unsigned long long)rl->vcn,
7578c2ecf20Sopenharmony_ci				(unsigned long long)lcn);
7588c2ecf20Sopenharmony_ci		/* The attribute list cannot be sparse. */
7598c2ecf20Sopenharmony_ci		if (lcn < 0) {
7608c2ecf20Sopenharmony_ci			ntfs_error(sb, "ntfs_rl_vcn_to_lcn() failed.  Cannot "
7618c2ecf20Sopenharmony_ci					"read attribute list.");
7628c2ecf20Sopenharmony_ci			goto err_out;
7638c2ecf20Sopenharmony_ci		}
7648c2ecf20Sopenharmony_ci		block = lcn << vol->cluster_size_bits >> block_size_bits;
7658c2ecf20Sopenharmony_ci		/* Read the run from device in chunks of block_size bytes. */
7668c2ecf20Sopenharmony_ci		max_block = block + (rl->length << vol->cluster_size_bits >>
7678c2ecf20Sopenharmony_ci				block_size_bits);
7688c2ecf20Sopenharmony_ci		ntfs_debug("max_block = 0x%lx.", max_block);
7698c2ecf20Sopenharmony_ci		do {
7708c2ecf20Sopenharmony_ci			ntfs_debug("Reading block = 0x%lx.", block);
7718c2ecf20Sopenharmony_ci			bh = sb_bread(sb, block);
7728c2ecf20Sopenharmony_ci			if (!bh) {
7738c2ecf20Sopenharmony_ci				ntfs_error(sb, "sb_bread() failed. Cannot "
7748c2ecf20Sopenharmony_ci						"read attribute list.");
7758c2ecf20Sopenharmony_ci				goto err_out;
7768c2ecf20Sopenharmony_ci			}
7778c2ecf20Sopenharmony_ci			if (al + block_size >= al_end)
7788c2ecf20Sopenharmony_ci				goto do_final;
7798c2ecf20Sopenharmony_ci			memcpy(al, bh->b_data, block_size);
7808c2ecf20Sopenharmony_ci			brelse(bh);
7818c2ecf20Sopenharmony_ci			al += block_size;
7828c2ecf20Sopenharmony_ci		} while (++block < max_block);
7838c2ecf20Sopenharmony_ci		rl++;
7848c2ecf20Sopenharmony_ci	}
7858c2ecf20Sopenharmony_ci	if (initialized_size < size) {
7868c2ecf20Sopenharmony_ciinitialize:
7878c2ecf20Sopenharmony_ci		memset(al_start + initialized_size, 0, size - initialized_size);
7888c2ecf20Sopenharmony_ci	}
7898c2ecf20Sopenharmony_cidone:
7908c2ecf20Sopenharmony_ci	up_read(&runlist->lock);
7918c2ecf20Sopenharmony_ci	return err;
7928c2ecf20Sopenharmony_cido_final:
7938c2ecf20Sopenharmony_ci	if (al < al_end) {
7948c2ecf20Sopenharmony_ci		/*
7958c2ecf20Sopenharmony_ci		 * Partial block.
7968c2ecf20Sopenharmony_ci		 *
7978c2ecf20Sopenharmony_ci		 * Note: The attribute list can be smaller than its allocation
7988c2ecf20Sopenharmony_ci		 * by multiple clusters.  This has been encountered by at least
7998c2ecf20Sopenharmony_ci		 * two people running Windows XP, thus we cannot do any
8008c2ecf20Sopenharmony_ci		 * truncation sanity checking here. (AIA)
8018c2ecf20Sopenharmony_ci		 */
8028c2ecf20Sopenharmony_ci		memcpy(al, bh->b_data, al_end - al);
8038c2ecf20Sopenharmony_ci		brelse(bh);
8048c2ecf20Sopenharmony_ci		if (initialized_size < size)
8058c2ecf20Sopenharmony_ci			goto initialize;
8068c2ecf20Sopenharmony_ci		goto done;
8078c2ecf20Sopenharmony_ci	}
8088c2ecf20Sopenharmony_ci	brelse(bh);
8098c2ecf20Sopenharmony_ci	/* Real overflow! */
8108c2ecf20Sopenharmony_ci	ntfs_error(sb, "Attribute list buffer overflow. Read attribute list "
8118c2ecf20Sopenharmony_ci			"is truncated.");
8128c2ecf20Sopenharmony_cierr_out:
8138c2ecf20Sopenharmony_ci	err = -EIO;
8148c2ecf20Sopenharmony_ci	goto done;
8158c2ecf20Sopenharmony_ci}
8168c2ecf20Sopenharmony_ci
8178c2ecf20Sopenharmony_ci/**
8188c2ecf20Sopenharmony_ci * ntfs_external_attr_find - find an attribute in the attribute list of an inode
8198c2ecf20Sopenharmony_ci * @type:	attribute type to find
8208c2ecf20Sopenharmony_ci * @name:	attribute name to find (optional, i.e. NULL means don't care)
8218c2ecf20Sopenharmony_ci * @name_len:	attribute name length (only needed if @name present)
8228c2ecf20Sopenharmony_ci * @ic:		IGNORE_CASE or CASE_SENSITIVE (ignored if @name not present)
8238c2ecf20Sopenharmony_ci * @lowest_vcn:	lowest vcn to find (optional, non-resident attributes only)
8248c2ecf20Sopenharmony_ci * @val:	attribute value to find (optional, resident attributes only)
8258c2ecf20Sopenharmony_ci * @val_len:	attribute value length
8268c2ecf20Sopenharmony_ci * @ctx:	search context with mft record and attribute to search from
8278c2ecf20Sopenharmony_ci *
8288c2ecf20Sopenharmony_ci * You should not need to call this function directly.  Use ntfs_attr_lookup()
8298c2ecf20Sopenharmony_ci * instead.
8308c2ecf20Sopenharmony_ci *
8318c2ecf20Sopenharmony_ci * Find an attribute by searching the attribute list for the corresponding
8328c2ecf20Sopenharmony_ci * attribute list entry.  Having found the entry, map the mft record if the
8338c2ecf20Sopenharmony_ci * attribute is in a different mft record/inode, ntfs_attr_find() the attribute
8348c2ecf20Sopenharmony_ci * in there and return it.
8358c2ecf20Sopenharmony_ci *
8368c2ecf20Sopenharmony_ci * On first search @ctx->ntfs_ino must be the base mft record and @ctx must
8378c2ecf20Sopenharmony_ci * have been obtained from a call to ntfs_attr_get_search_ctx().  On subsequent
8388c2ecf20Sopenharmony_ci * calls @ctx->ntfs_ino can be any extent inode, too (@ctx->base_ntfs_ino is
8398c2ecf20Sopenharmony_ci * then the base inode).
8408c2ecf20Sopenharmony_ci *
8418c2ecf20Sopenharmony_ci * After finishing with the attribute/mft record you need to call
8428c2ecf20Sopenharmony_ci * ntfs_attr_put_search_ctx() to cleanup the search context (unmapping any
8438c2ecf20Sopenharmony_ci * mapped inodes, etc).
8448c2ecf20Sopenharmony_ci *
8458c2ecf20Sopenharmony_ci * If the attribute is found, ntfs_external_attr_find() returns 0 and
8468c2ecf20Sopenharmony_ci * @ctx->attr will point to the found attribute.  @ctx->mrec will point to the
8478c2ecf20Sopenharmony_ci * mft record in which @ctx->attr is located and @ctx->al_entry will point to
8488c2ecf20Sopenharmony_ci * the attribute list entry for the attribute.
8498c2ecf20Sopenharmony_ci *
8508c2ecf20Sopenharmony_ci * If the attribute is not found, ntfs_external_attr_find() returns -ENOENT and
8518c2ecf20Sopenharmony_ci * @ctx->attr will point to the attribute in the base mft record before which
8528c2ecf20Sopenharmony_ci * the attribute being searched for would need to be inserted if such an action
8538c2ecf20Sopenharmony_ci * were to be desired.  @ctx->mrec will point to the mft record in which
8548c2ecf20Sopenharmony_ci * @ctx->attr is located and @ctx->al_entry will point to the attribute list
8558c2ecf20Sopenharmony_ci * entry of the attribute before which the attribute being searched for would
8568c2ecf20Sopenharmony_ci * need to be inserted if such an action were to be desired.
8578c2ecf20Sopenharmony_ci *
8588c2ecf20Sopenharmony_ci * Thus to insert the not found attribute, one wants to add the attribute to
8598c2ecf20Sopenharmony_ci * @ctx->mrec (the base mft record) and if there is not enough space, the
8608c2ecf20Sopenharmony_ci * attribute should be placed in a newly allocated extent mft record.  The
8618c2ecf20Sopenharmony_ci * attribute list entry for the inserted attribute should be inserted in the
8628c2ecf20Sopenharmony_ci * attribute list attribute at @ctx->al_entry.
8638c2ecf20Sopenharmony_ci *
8648c2ecf20Sopenharmony_ci * On actual error, ntfs_external_attr_find() returns -EIO.  In this case
8658c2ecf20Sopenharmony_ci * @ctx->attr is undefined and in particular do not rely on it not changing.
8668c2ecf20Sopenharmony_ci */
8678c2ecf20Sopenharmony_cistatic int ntfs_external_attr_find(const ATTR_TYPE type,
8688c2ecf20Sopenharmony_ci		const ntfschar *name, const u32 name_len,
8698c2ecf20Sopenharmony_ci		const IGNORE_CASE_BOOL ic, const VCN lowest_vcn,
8708c2ecf20Sopenharmony_ci		const u8 *val, const u32 val_len, ntfs_attr_search_ctx *ctx)
8718c2ecf20Sopenharmony_ci{
8728c2ecf20Sopenharmony_ci	ntfs_inode *base_ni, *ni;
8738c2ecf20Sopenharmony_ci	ntfs_volume *vol;
8748c2ecf20Sopenharmony_ci	ATTR_LIST_ENTRY *al_entry, *next_al_entry;
8758c2ecf20Sopenharmony_ci	u8 *al_start, *al_end;
8768c2ecf20Sopenharmony_ci	ATTR_RECORD *a;
8778c2ecf20Sopenharmony_ci	ntfschar *al_name;
8788c2ecf20Sopenharmony_ci	u32 al_name_len;
8798c2ecf20Sopenharmony_ci	int err = 0;
8808c2ecf20Sopenharmony_ci	static const char *es = " Unmount and run chkdsk.";
8818c2ecf20Sopenharmony_ci
8828c2ecf20Sopenharmony_ci	ni = ctx->ntfs_ino;
8838c2ecf20Sopenharmony_ci	base_ni = ctx->base_ntfs_ino;
8848c2ecf20Sopenharmony_ci	ntfs_debug("Entering for inode 0x%lx, type 0x%x.", ni->mft_no, type);
8858c2ecf20Sopenharmony_ci	if (!base_ni) {
8868c2ecf20Sopenharmony_ci		/* First call happens with the base mft record. */
8878c2ecf20Sopenharmony_ci		base_ni = ctx->base_ntfs_ino = ctx->ntfs_ino;
8888c2ecf20Sopenharmony_ci		ctx->base_mrec = ctx->mrec;
8898c2ecf20Sopenharmony_ci	}
8908c2ecf20Sopenharmony_ci	if (ni == base_ni)
8918c2ecf20Sopenharmony_ci		ctx->base_attr = ctx->attr;
8928c2ecf20Sopenharmony_ci	if (type == AT_END)
8938c2ecf20Sopenharmony_ci		goto not_found;
8948c2ecf20Sopenharmony_ci	vol = base_ni->vol;
8958c2ecf20Sopenharmony_ci	al_start = base_ni->attr_list;
8968c2ecf20Sopenharmony_ci	al_end = al_start + base_ni->attr_list_size;
8978c2ecf20Sopenharmony_ci	if (!ctx->al_entry)
8988c2ecf20Sopenharmony_ci		ctx->al_entry = (ATTR_LIST_ENTRY*)al_start;
8998c2ecf20Sopenharmony_ci	/*
9008c2ecf20Sopenharmony_ci	 * Iterate over entries in attribute list starting at @ctx->al_entry,
9018c2ecf20Sopenharmony_ci	 * or the entry following that, if @ctx->is_first is 'true'.
9028c2ecf20Sopenharmony_ci	 */
9038c2ecf20Sopenharmony_ci	if (ctx->is_first) {
9048c2ecf20Sopenharmony_ci		al_entry = ctx->al_entry;
9058c2ecf20Sopenharmony_ci		ctx->is_first = false;
9068c2ecf20Sopenharmony_ci	} else
9078c2ecf20Sopenharmony_ci		al_entry = (ATTR_LIST_ENTRY*)((u8*)ctx->al_entry +
9088c2ecf20Sopenharmony_ci				le16_to_cpu(ctx->al_entry->length));
9098c2ecf20Sopenharmony_ci	for (;; al_entry = next_al_entry) {
9108c2ecf20Sopenharmony_ci		/* Out of bounds check. */
9118c2ecf20Sopenharmony_ci		if ((u8*)al_entry < base_ni->attr_list ||
9128c2ecf20Sopenharmony_ci				(u8*)al_entry > al_end)
9138c2ecf20Sopenharmony_ci			break;	/* Inode is corrupt. */
9148c2ecf20Sopenharmony_ci		ctx->al_entry = al_entry;
9158c2ecf20Sopenharmony_ci		/* Catch the end of the attribute list. */
9168c2ecf20Sopenharmony_ci		if ((u8*)al_entry == al_end)
9178c2ecf20Sopenharmony_ci			goto not_found;
9188c2ecf20Sopenharmony_ci		if (!al_entry->length)
9198c2ecf20Sopenharmony_ci			break;
9208c2ecf20Sopenharmony_ci		if ((u8*)al_entry + 6 > al_end || (u8*)al_entry +
9218c2ecf20Sopenharmony_ci				le16_to_cpu(al_entry->length) > al_end)
9228c2ecf20Sopenharmony_ci			break;
9238c2ecf20Sopenharmony_ci		next_al_entry = (ATTR_LIST_ENTRY*)((u8*)al_entry +
9248c2ecf20Sopenharmony_ci				le16_to_cpu(al_entry->length));
9258c2ecf20Sopenharmony_ci		if (le32_to_cpu(al_entry->type) > le32_to_cpu(type))
9268c2ecf20Sopenharmony_ci			goto not_found;
9278c2ecf20Sopenharmony_ci		if (type != al_entry->type)
9288c2ecf20Sopenharmony_ci			continue;
9298c2ecf20Sopenharmony_ci		/*
9308c2ecf20Sopenharmony_ci		 * If @name is present, compare the two names.  If @name is
9318c2ecf20Sopenharmony_ci		 * missing, assume we want an unnamed attribute.
9328c2ecf20Sopenharmony_ci		 */
9338c2ecf20Sopenharmony_ci		al_name_len = al_entry->name_length;
9348c2ecf20Sopenharmony_ci		al_name = (ntfschar*)((u8*)al_entry + al_entry->name_offset);
9358c2ecf20Sopenharmony_ci		if (!name) {
9368c2ecf20Sopenharmony_ci			if (al_name_len)
9378c2ecf20Sopenharmony_ci				goto not_found;
9388c2ecf20Sopenharmony_ci		} else if (!ntfs_are_names_equal(al_name, al_name_len, name,
9398c2ecf20Sopenharmony_ci				name_len, ic, vol->upcase, vol->upcase_len)) {
9408c2ecf20Sopenharmony_ci			register int rc;
9418c2ecf20Sopenharmony_ci
9428c2ecf20Sopenharmony_ci			rc = ntfs_collate_names(name, name_len, al_name,
9438c2ecf20Sopenharmony_ci					al_name_len, 1, IGNORE_CASE,
9448c2ecf20Sopenharmony_ci					vol->upcase, vol->upcase_len);
9458c2ecf20Sopenharmony_ci			/*
9468c2ecf20Sopenharmony_ci			 * If @name collates before al_name, there is no
9478c2ecf20Sopenharmony_ci			 * matching attribute.
9488c2ecf20Sopenharmony_ci			 */
9498c2ecf20Sopenharmony_ci			if (rc == -1)
9508c2ecf20Sopenharmony_ci				goto not_found;
9518c2ecf20Sopenharmony_ci			/* If the strings are not equal, continue search. */
9528c2ecf20Sopenharmony_ci			if (rc)
9538c2ecf20Sopenharmony_ci				continue;
9548c2ecf20Sopenharmony_ci			/*
9558c2ecf20Sopenharmony_ci			 * FIXME: Reverse engineering showed 0, IGNORE_CASE but
9568c2ecf20Sopenharmony_ci			 * that is inconsistent with ntfs_attr_find().  The
9578c2ecf20Sopenharmony_ci			 * subsequent rc checks were also different.  Perhaps I
9588c2ecf20Sopenharmony_ci			 * made a mistake in one of the two.  Need to recheck
9598c2ecf20Sopenharmony_ci			 * which is correct or at least see what is going on...
9608c2ecf20Sopenharmony_ci			 * (AIA)
9618c2ecf20Sopenharmony_ci			 */
9628c2ecf20Sopenharmony_ci			rc = ntfs_collate_names(name, name_len, al_name,
9638c2ecf20Sopenharmony_ci					al_name_len, 1, CASE_SENSITIVE,
9648c2ecf20Sopenharmony_ci					vol->upcase, vol->upcase_len);
9658c2ecf20Sopenharmony_ci			if (rc == -1)
9668c2ecf20Sopenharmony_ci				goto not_found;
9678c2ecf20Sopenharmony_ci			if (rc)
9688c2ecf20Sopenharmony_ci				continue;
9698c2ecf20Sopenharmony_ci		}
9708c2ecf20Sopenharmony_ci		/*
9718c2ecf20Sopenharmony_ci		 * The names match or @name not present and attribute is
9728c2ecf20Sopenharmony_ci		 * unnamed.  Now check @lowest_vcn.  Continue search if the
9738c2ecf20Sopenharmony_ci		 * next attribute list entry still fits @lowest_vcn.  Otherwise
9748c2ecf20Sopenharmony_ci		 * we have reached the right one or the search has failed.
9758c2ecf20Sopenharmony_ci		 */
9768c2ecf20Sopenharmony_ci		if (lowest_vcn && (u8*)next_al_entry >= al_start	    &&
9778c2ecf20Sopenharmony_ci				(u8*)next_al_entry + 6 < al_end		    &&
9788c2ecf20Sopenharmony_ci				(u8*)next_al_entry + le16_to_cpu(
9798c2ecf20Sopenharmony_ci					next_al_entry->length) <= al_end    &&
9808c2ecf20Sopenharmony_ci				sle64_to_cpu(next_al_entry->lowest_vcn) <=
9818c2ecf20Sopenharmony_ci					lowest_vcn			    &&
9828c2ecf20Sopenharmony_ci				next_al_entry->type == al_entry->type	    &&
9838c2ecf20Sopenharmony_ci				next_al_entry->name_length == al_name_len   &&
9848c2ecf20Sopenharmony_ci				ntfs_are_names_equal((ntfschar*)((u8*)
9858c2ecf20Sopenharmony_ci					next_al_entry +
9868c2ecf20Sopenharmony_ci					next_al_entry->name_offset),
9878c2ecf20Sopenharmony_ci					next_al_entry->name_length,
9888c2ecf20Sopenharmony_ci					al_name, al_name_len, CASE_SENSITIVE,
9898c2ecf20Sopenharmony_ci					vol->upcase, vol->upcase_len))
9908c2ecf20Sopenharmony_ci			continue;
9918c2ecf20Sopenharmony_ci		if (MREF_LE(al_entry->mft_reference) == ni->mft_no) {
9928c2ecf20Sopenharmony_ci			if (MSEQNO_LE(al_entry->mft_reference) != ni->seq_no) {
9938c2ecf20Sopenharmony_ci				ntfs_error(vol->sb, "Found stale mft "
9948c2ecf20Sopenharmony_ci						"reference in attribute list "
9958c2ecf20Sopenharmony_ci						"of base inode 0x%lx.%s",
9968c2ecf20Sopenharmony_ci						base_ni->mft_no, es);
9978c2ecf20Sopenharmony_ci				err = -EIO;
9988c2ecf20Sopenharmony_ci				break;
9998c2ecf20Sopenharmony_ci			}
10008c2ecf20Sopenharmony_ci		} else { /* Mft references do not match. */
10018c2ecf20Sopenharmony_ci			/* If there is a mapped record unmap it first. */
10028c2ecf20Sopenharmony_ci			if (ni != base_ni)
10038c2ecf20Sopenharmony_ci				unmap_extent_mft_record(ni);
10048c2ecf20Sopenharmony_ci			/* Do we want the base record back? */
10058c2ecf20Sopenharmony_ci			if (MREF_LE(al_entry->mft_reference) ==
10068c2ecf20Sopenharmony_ci					base_ni->mft_no) {
10078c2ecf20Sopenharmony_ci				ni = ctx->ntfs_ino = base_ni;
10088c2ecf20Sopenharmony_ci				ctx->mrec = ctx->base_mrec;
10098c2ecf20Sopenharmony_ci			} else {
10108c2ecf20Sopenharmony_ci				/* We want an extent record. */
10118c2ecf20Sopenharmony_ci				ctx->mrec = map_extent_mft_record(base_ni,
10128c2ecf20Sopenharmony_ci						le64_to_cpu(
10138c2ecf20Sopenharmony_ci						al_entry->mft_reference), &ni);
10148c2ecf20Sopenharmony_ci				if (IS_ERR(ctx->mrec)) {
10158c2ecf20Sopenharmony_ci					ntfs_error(vol->sb, "Failed to map "
10168c2ecf20Sopenharmony_ci							"extent mft record "
10178c2ecf20Sopenharmony_ci							"0x%lx of base inode "
10188c2ecf20Sopenharmony_ci							"0x%lx.%s",
10198c2ecf20Sopenharmony_ci							MREF_LE(al_entry->
10208c2ecf20Sopenharmony_ci							mft_reference),
10218c2ecf20Sopenharmony_ci							base_ni->mft_no, es);
10228c2ecf20Sopenharmony_ci					err = PTR_ERR(ctx->mrec);
10238c2ecf20Sopenharmony_ci					if (err == -ENOENT)
10248c2ecf20Sopenharmony_ci						err = -EIO;
10258c2ecf20Sopenharmony_ci					/* Cause @ctx to be sanitized below. */
10268c2ecf20Sopenharmony_ci					ni = NULL;
10278c2ecf20Sopenharmony_ci					break;
10288c2ecf20Sopenharmony_ci				}
10298c2ecf20Sopenharmony_ci				ctx->ntfs_ino = ni;
10308c2ecf20Sopenharmony_ci			}
10318c2ecf20Sopenharmony_ci			ctx->attr = (ATTR_RECORD*)((u8*)ctx->mrec +
10328c2ecf20Sopenharmony_ci					le16_to_cpu(ctx->mrec->attrs_offset));
10338c2ecf20Sopenharmony_ci		}
10348c2ecf20Sopenharmony_ci		/*
10358c2ecf20Sopenharmony_ci		 * ctx->vfs_ino, ctx->mrec, and ctx->attr now point to the
10368c2ecf20Sopenharmony_ci		 * mft record containing the attribute represented by the
10378c2ecf20Sopenharmony_ci		 * current al_entry.
10388c2ecf20Sopenharmony_ci		 */
10398c2ecf20Sopenharmony_ci		/*
10408c2ecf20Sopenharmony_ci		 * We could call into ntfs_attr_find() to find the right
10418c2ecf20Sopenharmony_ci		 * attribute in this mft record but this would be less
10428c2ecf20Sopenharmony_ci		 * efficient and not quite accurate as ntfs_attr_find() ignores
10438c2ecf20Sopenharmony_ci		 * the attribute instance numbers for example which become
10448c2ecf20Sopenharmony_ci		 * important when one plays with attribute lists.  Also,
10458c2ecf20Sopenharmony_ci		 * because a proper match has been found in the attribute list
10468c2ecf20Sopenharmony_ci		 * entry above, the comparison can now be optimized.  So it is
10478c2ecf20Sopenharmony_ci		 * worth re-implementing a simplified ntfs_attr_find() here.
10488c2ecf20Sopenharmony_ci		 */
10498c2ecf20Sopenharmony_ci		a = ctx->attr;
10508c2ecf20Sopenharmony_ci		/*
10518c2ecf20Sopenharmony_ci		 * Use a manual loop so we can still use break and continue
10528c2ecf20Sopenharmony_ci		 * with the same meanings as above.
10538c2ecf20Sopenharmony_ci		 */
10548c2ecf20Sopenharmony_cido_next_attr_loop:
10558c2ecf20Sopenharmony_ci		if ((u8*)a < (u8*)ctx->mrec || (u8*)a > (u8*)ctx->mrec +
10568c2ecf20Sopenharmony_ci				le32_to_cpu(ctx->mrec->bytes_allocated))
10578c2ecf20Sopenharmony_ci			break;
10588c2ecf20Sopenharmony_ci		if (a->type == AT_END)
10598c2ecf20Sopenharmony_ci			break;
10608c2ecf20Sopenharmony_ci		if (!a->length)
10618c2ecf20Sopenharmony_ci			break;
10628c2ecf20Sopenharmony_ci		if (al_entry->instance != a->instance)
10638c2ecf20Sopenharmony_ci			goto do_next_attr;
10648c2ecf20Sopenharmony_ci		/*
10658c2ecf20Sopenharmony_ci		 * If the type and/or the name are mismatched between the
10668c2ecf20Sopenharmony_ci		 * attribute list entry and the attribute record, there is
10678c2ecf20Sopenharmony_ci		 * corruption so we break and return error EIO.
10688c2ecf20Sopenharmony_ci		 */
10698c2ecf20Sopenharmony_ci		if (al_entry->type != a->type)
10708c2ecf20Sopenharmony_ci			break;
10718c2ecf20Sopenharmony_ci		if (!ntfs_are_names_equal((ntfschar*)((u8*)a +
10728c2ecf20Sopenharmony_ci				le16_to_cpu(a->name_offset)), a->name_length,
10738c2ecf20Sopenharmony_ci				al_name, al_name_len, CASE_SENSITIVE,
10748c2ecf20Sopenharmony_ci				vol->upcase, vol->upcase_len))
10758c2ecf20Sopenharmony_ci			break;
10768c2ecf20Sopenharmony_ci		ctx->attr = a;
10778c2ecf20Sopenharmony_ci		/*
10788c2ecf20Sopenharmony_ci		 * If no @val specified or @val specified and it matches, we
10798c2ecf20Sopenharmony_ci		 * have found it!
10808c2ecf20Sopenharmony_ci		 */
10818c2ecf20Sopenharmony_ci		if (!val || (!a->non_resident && le32_to_cpu(
10828c2ecf20Sopenharmony_ci				a->data.resident.value_length) == val_len &&
10838c2ecf20Sopenharmony_ci				!memcmp((u8*)a +
10848c2ecf20Sopenharmony_ci				le16_to_cpu(a->data.resident.value_offset),
10858c2ecf20Sopenharmony_ci				val, val_len))) {
10868c2ecf20Sopenharmony_ci			ntfs_debug("Done, found.");
10878c2ecf20Sopenharmony_ci			return 0;
10888c2ecf20Sopenharmony_ci		}
10898c2ecf20Sopenharmony_cido_next_attr:
10908c2ecf20Sopenharmony_ci		/* Proceed to the next attribute in the current mft record. */
10918c2ecf20Sopenharmony_ci		a = (ATTR_RECORD*)((u8*)a + le32_to_cpu(a->length));
10928c2ecf20Sopenharmony_ci		goto do_next_attr_loop;
10938c2ecf20Sopenharmony_ci	}
10948c2ecf20Sopenharmony_ci	if (!err) {
10958c2ecf20Sopenharmony_ci		ntfs_error(vol->sb, "Base inode 0x%lx contains corrupt "
10968c2ecf20Sopenharmony_ci				"attribute list attribute.%s", base_ni->mft_no,
10978c2ecf20Sopenharmony_ci				es);
10988c2ecf20Sopenharmony_ci		err = -EIO;
10998c2ecf20Sopenharmony_ci	}
11008c2ecf20Sopenharmony_ci	if (ni != base_ni) {
11018c2ecf20Sopenharmony_ci		if (ni)
11028c2ecf20Sopenharmony_ci			unmap_extent_mft_record(ni);
11038c2ecf20Sopenharmony_ci		ctx->ntfs_ino = base_ni;
11048c2ecf20Sopenharmony_ci		ctx->mrec = ctx->base_mrec;
11058c2ecf20Sopenharmony_ci		ctx->attr = ctx->base_attr;
11068c2ecf20Sopenharmony_ci	}
11078c2ecf20Sopenharmony_ci	if (err != -ENOMEM)
11088c2ecf20Sopenharmony_ci		NVolSetErrors(vol);
11098c2ecf20Sopenharmony_ci	return err;
11108c2ecf20Sopenharmony_cinot_found:
11118c2ecf20Sopenharmony_ci	/*
11128c2ecf20Sopenharmony_ci	 * If we were looking for AT_END, we reset the search context @ctx and
11138c2ecf20Sopenharmony_ci	 * use ntfs_attr_find() to seek to the end of the base mft record.
11148c2ecf20Sopenharmony_ci	 */
11158c2ecf20Sopenharmony_ci	if (type == AT_END) {
11168c2ecf20Sopenharmony_ci		ntfs_attr_reinit_search_ctx(ctx);
11178c2ecf20Sopenharmony_ci		return ntfs_attr_find(AT_END, name, name_len, ic, val, val_len,
11188c2ecf20Sopenharmony_ci				ctx);
11198c2ecf20Sopenharmony_ci	}
11208c2ecf20Sopenharmony_ci	/*
11218c2ecf20Sopenharmony_ci	 * The attribute was not found.  Before we return, we want to ensure
11228c2ecf20Sopenharmony_ci	 * @ctx->mrec and @ctx->attr indicate the position at which the
11238c2ecf20Sopenharmony_ci	 * attribute should be inserted in the base mft record.  Since we also
11248c2ecf20Sopenharmony_ci	 * want to preserve @ctx->al_entry we cannot reinitialize the search
11258c2ecf20Sopenharmony_ci	 * context using ntfs_attr_reinit_search_ctx() as this would set
11268c2ecf20Sopenharmony_ci	 * @ctx->al_entry to NULL.  Thus we do the necessary bits manually (see
11278c2ecf20Sopenharmony_ci	 * ntfs_attr_init_search_ctx() below).  Note, we _only_ preserve
11288c2ecf20Sopenharmony_ci	 * @ctx->al_entry as the remaining fields (base_*) are identical to
11298c2ecf20Sopenharmony_ci	 * their non base_ counterparts and we cannot set @ctx->base_attr
11308c2ecf20Sopenharmony_ci	 * correctly yet as we do not know what @ctx->attr will be set to by
11318c2ecf20Sopenharmony_ci	 * the call to ntfs_attr_find() below.
11328c2ecf20Sopenharmony_ci	 */
11338c2ecf20Sopenharmony_ci	if (ni != base_ni)
11348c2ecf20Sopenharmony_ci		unmap_extent_mft_record(ni);
11358c2ecf20Sopenharmony_ci	ctx->mrec = ctx->base_mrec;
11368c2ecf20Sopenharmony_ci	ctx->attr = (ATTR_RECORD*)((u8*)ctx->mrec +
11378c2ecf20Sopenharmony_ci			le16_to_cpu(ctx->mrec->attrs_offset));
11388c2ecf20Sopenharmony_ci	ctx->is_first = true;
11398c2ecf20Sopenharmony_ci	ctx->ntfs_ino = base_ni;
11408c2ecf20Sopenharmony_ci	ctx->base_ntfs_ino = NULL;
11418c2ecf20Sopenharmony_ci	ctx->base_mrec = NULL;
11428c2ecf20Sopenharmony_ci	ctx->base_attr = NULL;
11438c2ecf20Sopenharmony_ci	/*
11448c2ecf20Sopenharmony_ci	 * In case there are multiple matches in the base mft record, need to
11458c2ecf20Sopenharmony_ci	 * keep enumerating until we get an attribute not found response (or
11468c2ecf20Sopenharmony_ci	 * another error), otherwise we would keep returning the same attribute
11478c2ecf20Sopenharmony_ci	 * over and over again and all programs using us for enumeration would
11488c2ecf20Sopenharmony_ci	 * lock up in a tight loop.
11498c2ecf20Sopenharmony_ci	 */
11508c2ecf20Sopenharmony_ci	do {
11518c2ecf20Sopenharmony_ci		err = ntfs_attr_find(type, name, name_len, ic, val, val_len,
11528c2ecf20Sopenharmony_ci				ctx);
11538c2ecf20Sopenharmony_ci	} while (!err);
11548c2ecf20Sopenharmony_ci	ntfs_debug("Done, not found.");
11558c2ecf20Sopenharmony_ci	return err;
11568c2ecf20Sopenharmony_ci}
11578c2ecf20Sopenharmony_ci
11588c2ecf20Sopenharmony_ci/**
11598c2ecf20Sopenharmony_ci * ntfs_attr_lookup - find an attribute in an ntfs inode
11608c2ecf20Sopenharmony_ci * @type:	attribute type to find
11618c2ecf20Sopenharmony_ci * @name:	attribute name to find (optional, i.e. NULL means don't care)
11628c2ecf20Sopenharmony_ci * @name_len:	attribute name length (only needed if @name present)
11638c2ecf20Sopenharmony_ci * @ic:		IGNORE_CASE or CASE_SENSITIVE (ignored if @name not present)
11648c2ecf20Sopenharmony_ci * @lowest_vcn:	lowest vcn to find (optional, non-resident attributes only)
11658c2ecf20Sopenharmony_ci * @val:	attribute value to find (optional, resident attributes only)
11668c2ecf20Sopenharmony_ci * @val_len:	attribute value length
11678c2ecf20Sopenharmony_ci * @ctx:	search context with mft record and attribute to search from
11688c2ecf20Sopenharmony_ci *
11698c2ecf20Sopenharmony_ci * Find an attribute in an ntfs inode.  On first search @ctx->ntfs_ino must
11708c2ecf20Sopenharmony_ci * be the base mft record and @ctx must have been obtained from a call to
11718c2ecf20Sopenharmony_ci * ntfs_attr_get_search_ctx().
11728c2ecf20Sopenharmony_ci *
11738c2ecf20Sopenharmony_ci * This function transparently handles attribute lists and @ctx is used to
11748c2ecf20Sopenharmony_ci * continue searches where they were left off at.
11758c2ecf20Sopenharmony_ci *
11768c2ecf20Sopenharmony_ci * After finishing with the attribute/mft record you need to call
11778c2ecf20Sopenharmony_ci * ntfs_attr_put_search_ctx() to cleanup the search context (unmapping any
11788c2ecf20Sopenharmony_ci * mapped inodes, etc).
11798c2ecf20Sopenharmony_ci *
11808c2ecf20Sopenharmony_ci * Return 0 if the search was successful and -errno if not.
11818c2ecf20Sopenharmony_ci *
11828c2ecf20Sopenharmony_ci * When 0, @ctx->attr is the found attribute and it is in mft record
11838c2ecf20Sopenharmony_ci * @ctx->mrec.  If an attribute list attribute is present, @ctx->al_entry is
11848c2ecf20Sopenharmony_ci * the attribute list entry of the found attribute.
11858c2ecf20Sopenharmony_ci *
11868c2ecf20Sopenharmony_ci * When -ENOENT, @ctx->attr is the attribute which collates just after the
11878c2ecf20Sopenharmony_ci * attribute being searched for, i.e. if one wants to add the attribute to the
11888c2ecf20Sopenharmony_ci * mft record this is the correct place to insert it into.  If an attribute
11898c2ecf20Sopenharmony_ci * list attribute is present, @ctx->al_entry is the attribute list entry which
11908c2ecf20Sopenharmony_ci * collates just after the attribute list entry of the attribute being searched
11918c2ecf20Sopenharmony_ci * for, i.e. if one wants to add the attribute to the mft record this is the
11928c2ecf20Sopenharmony_ci * correct place to insert its attribute list entry into.
11938c2ecf20Sopenharmony_ci *
11948c2ecf20Sopenharmony_ci * When -errno != -ENOENT, an error occurred during the lookup.  @ctx->attr is
11958c2ecf20Sopenharmony_ci * then undefined and in particular you should not rely on it not changing.
11968c2ecf20Sopenharmony_ci */
11978c2ecf20Sopenharmony_ciint ntfs_attr_lookup(const ATTR_TYPE type, const ntfschar *name,
11988c2ecf20Sopenharmony_ci		const u32 name_len, const IGNORE_CASE_BOOL ic,
11998c2ecf20Sopenharmony_ci		const VCN lowest_vcn, const u8 *val, const u32 val_len,
12008c2ecf20Sopenharmony_ci		ntfs_attr_search_ctx *ctx)
12018c2ecf20Sopenharmony_ci{
12028c2ecf20Sopenharmony_ci	ntfs_inode *base_ni;
12038c2ecf20Sopenharmony_ci
12048c2ecf20Sopenharmony_ci	ntfs_debug("Entering.");
12058c2ecf20Sopenharmony_ci	BUG_ON(IS_ERR(ctx->mrec));
12068c2ecf20Sopenharmony_ci	if (ctx->base_ntfs_ino)
12078c2ecf20Sopenharmony_ci		base_ni = ctx->base_ntfs_ino;
12088c2ecf20Sopenharmony_ci	else
12098c2ecf20Sopenharmony_ci		base_ni = ctx->ntfs_ino;
12108c2ecf20Sopenharmony_ci	/* Sanity check, just for debugging really. */
12118c2ecf20Sopenharmony_ci	BUG_ON(!base_ni);
12128c2ecf20Sopenharmony_ci	if (!NInoAttrList(base_ni) || type == AT_ATTRIBUTE_LIST)
12138c2ecf20Sopenharmony_ci		return ntfs_attr_find(type, name, name_len, ic, val, val_len,
12148c2ecf20Sopenharmony_ci				ctx);
12158c2ecf20Sopenharmony_ci	return ntfs_external_attr_find(type, name, name_len, ic, lowest_vcn,
12168c2ecf20Sopenharmony_ci			val, val_len, ctx);
12178c2ecf20Sopenharmony_ci}
12188c2ecf20Sopenharmony_ci
12198c2ecf20Sopenharmony_ci/**
12208c2ecf20Sopenharmony_ci * ntfs_attr_init_search_ctx - initialize an attribute search context
12218c2ecf20Sopenharmony_ci * @ctx:	attribute search context to initialize
12228c2ecf20Sopenharmony_ci * @ni:		ntfs inode with which to initialize the search context
12238c2ecf20Sopenharmony_ci * @mrec:	mft record with which to initialize the search context
12248c2ecf20Sopenharmony_ci *
12258c2ecf20Sopenharmony_ci * Initialize the attribute search context @ctx with @ni and @mrec.
12268c2ecf20Sopenharmony_ci */
12278c2ecf20Sopenharmony_cistatic inline void ntfs_attr_init_search_ctx(ntfs_attr_search_ctx *ctx,
12288c2ecf20Sopenharmony_ci		ntfs_inode *ni, MFT_RECORD *mrec)
12298c2ecf20Sopenharmony_ci{
12308c2ecf20Sopenharmony_ci	*ctx = (ntfs_attr_search_ctx) {
12318c2ecf20Sopenharmony_ci		.mrec = mrec,
12328c2ecf20Sopenharmony_ci		/* Sanity checks are performed elsewhere. */
12338c2ecf20Sopenharmony_ci		.attr = (ATTR_RECORD*)((u8*)mrec +
12348c2ecf20Sopenharmony_ci				le16_to_cpu(mrec->attrs_offset)),
12358c2ecf20Sopenharmony_ci		.is_first = true,
12368c2ecf20Sopenharmony_ci		.ntfs_ino = ni,
12378c2ecf20Sopenharmony_ci	};
12388c2ecf20Sopenharmony_ci}
12398c2ecf20Sopenharmony_ci
12408c2ecf20Sopenharmony_ci/**
12418c2ecf20Sopenharmony_ci * ntfs_attr_reinit_search_ctx - reinitialize an attribute search context
12428c2ecf20Sopenharmony_ci * @ctx:	attribute search context to reinitialize
12438c2ecf20Sopenharmony_ci *
12448c2ecf20Sopenharmony_ci * Reinitialize the attribute search context @ctx, unmapping an associated
12458c2ecf20Sopenharmony_ci * extent mft record if present, and initialize the search context again.
12468c2ecf20Sopenharmony_ci *
12478c2ecf20Sopenharmony_ci * This is used when a search for a new attribute is being started to reset
12488c2ecf20Sopenharmony_ci * the search context to the beginning.
12498c2ecf20Sopenharmony_ci */
12508c2ecf20Sopenharmony_civoid ntfs_attr_reinit_search_ctx(ntfs_attr_search_ctx *ctx)
12518c2ecf20Sopenharmony_ci{
12528c2ecf20Sopenharmony_ci	if (likely(!ctx->base_ntfs_ino)) {
12538c2ecf20Sopenharmony_ci		/* No attribute list. */
12548c2ecf20Sopenharmony_ci		ctx->is_first = true;
12558c2ecf20Sopenharmony_ci		/* Sanity checks are performed elsewhere. */
12568c2ecf20Sopenharmony_ci		ctx->attr = (ATTR_RECORD*)((u8*)ctx->mrec +
12578c2ecf20Sopenharmony_ci				le16_to_cpu(ctx->mrec->attrs_offset));
12588c2ecf20Sopenharmony_ci		/*
12598c2ecf20Sopenharmony_ci		 * This needs resetting due to ntfs_external_attr_find() which
12608c2ecf20Sopenharmony_ci		 * can leave it set despite having zeroed ctx->base_ntfs_ino.
12618c2ecf20Sopenharmony_ci		 */
12628c2ecf20Sopenharmony_ci		ctx->al_entry = NULL;
12638c2ecf20Sopenharmony_ci		return;
12648c2ecf20Sopenharmony_ci	} /* Attribute list. */
12658c2ecf20Sopenharmony_ci	if (ctx->ntfs_ino != ctx->base_ntfs_ino)
12668c2ecf20Sopenharmony_ci		unmap_extent_mft_record(ctx->ntfs_ino);
12678c2ecf20Sopenharmony_ci	ntfs_attr_init_search_ctx(ctx, ctx->base_ntfs_ino, ctx->base_mrec);
12688c2ecf20Sopenharmony_ci	return;
12698c2ecf20Sopenharmony_ci}
12708c2ecf20Sopenharmony_ci
12718c2ecf20Sopenharmony_ci/**
12728c2ecf20Sopenharmony_ci * ntfs_attr_get_search_ctx - allocate/initialize a new attribute search context
12738c2ecf20Sopenharmony_ci * @ni:		ntfs inode with which to initialize the search context
12748c2ecf20Sopenharmony_ci * @mrec:	mft record with which to initialize the search context
12758c2ecf20Sopenharmony_ci *
12768c2ecf20Sopenharmony_ci * Allocate a new attribute search context, initialize it with @ni and @mrec,
12778c2ecf20Sopenharmony_ci * and return it. Return NULL if allocation failed.
12788c2ecf20Sopenharmony_ci */
12798c2ecf20Sopenharmony_cintfs_attr_search_ctx *ntfs_attr_get_search_ctx(ntfs_inode *ni, MFT_RECORD *mrec)
12808c2ecf20Sopenharmony_ci{
12818c2ecf20Sopenharmony_ci	ntfs_attr_search_ctx *ctx;
12828c2ecf20Sopenharmony_ci
12838c2ecf20Sopenharmony_ci	ctx = kmem_cache_alloc(ntfs_attr_ctx_cache, GFP_NOFS);
12848c2ecf20Sopenharmony_ci	if (ctx)
12858c2ecf20Sopenharmony_ci		ntfs_attr_init_search_ctx(ctx, ni, mrec);
12868c2ecf20Sopenharmony_ci	return ctx;
12878c2ecf20Sopenharmony_ci}
12888c2ecf20Sopenharmony_ci
12898c2ecf20Sopenharmony_ci/**
12908c2ecf20Sopenharmony_ci * ntfs_attr_put_search_ctx - release an attribute search context
12918c2ecf20Sopenharmony_ci * @ctx:	attribute search context to free
12928c2ecf20Sopenharmony_ci *
12938c2ecf20Sopenharmony_ci * Release the attribute search context @ctx, unmapping an associated extent
12948c2ecf20Sopenharmony_ci * mft record if present.
12958c2ecf20Sopenharmony_ci */
12968c2ecf20Sopenharmony_civoid ntfs_attr_put_search_ctx(ntfs_attr_search_ctx *ctx)
12978c2ecf20Sopenharmony_ci{
12988c2ecf20Sopenharmony_ci	if (ctx->base_ntfs_ino && ctx->ntfs_ino != ctx->base_ntfs_ino)
12998c2ecf20Sopenharmony_ci		unmap_extent_mft_record(ctx->ntfs_ino);
13008c2ecf20Sopenharmony_ci	kmem_cache_free(ntfs_attr_ctx_cache, ctx);
13018c2ecf20Sopenharmony_ci	return;
13028c2ecf20Sopenharmony_ci}
13038c2ecf20Sopenharmony_ci
13048c2ecf20Sopenharmony_ci#ifdef NTFS_RW
13058c2ecf20Sopenharmony_ci
13068c2ecf20Sopenharmony_ci/**
13078c2ecf20Sopenharmony_ci * ntfs_attr_find_in_attrdef - find an attribute in the $AttrDef system file
13088c2ecf20Sopenharmony_ci * @vol:	ntfs volume to which the attribute belongs
13098c2ecf20Sopenharmony_ci * @type:	attribute type which to find
13108c2ecf20Sopenharmony_ci *
13118c2ecf20Sopenharmony_ci * Search for the attribute definition record corresponding to the attribute
13128c2ecf20Sopenharmony_ci * @type in the $AttrDef system file.
13138c2ecf20Sopenharmony_ci *
13148c2ecf20Sopenharmony_ci * Return the attribute type definition record if found and NULL if not found.
13158c2ecf20Sopenharmony_ci */
13168c2ecf20Sopenharmony_cistatic ATTR_DEF *ntfs_attr_find_in_attrdef(const ntfs_volume *vol,
13178c2ecf20Sopenharmony_ci		const ATTR_TYPE type)
13188c2ecf20Sopenharmony_ci{
13198c2ecf20Sopenharmony_ci	ATTR_DEF *ad;
13208c2ecf20Sopenharmony_ci
13218c2ecf20Sopenharmony_ci	BUG_ON(!vol->attrdef);
13228c2ecf20Sopenharmony_ci	BUG_ON(!type);
13238c2ecf20Sopenharmony_ci	for (ad = vol->attrdef; (u8*)ad - (u8*)vol->attrdef <
13248c2ecf20Sopenharmony_ci			vol->attrdef_size && ad->type; ++ad) {
13258c2ecf20Sopenharmony_ci		/* We have not found it yet, carry on searching. */
13268c2ecf20Sopenharmony_ci		if (likely(le32_to_cpu(ad->type) < le32_to_cpu(type)))
13278c2ecf20Sopenharmony_ci			continue;
13288c2ecf20Sopenharmony_ci		/* We found the attribute; return it. */
13298c2ecf20Sopenharmony_ci		if (likely(ad->type == type))
13308c2ecf20Sopenharmony_ci			return ad;
13318c2ecf20Sopenharmony_ci		/* We have gone too far already.  No point in continuing. */
13328c2ecf20Sopenharmony_ci		break;
13338c2ecf20Sopenharmony_ci	}
13348c2ecf20Sopenharmony_ci	/* Attribute not found. */
13358c2ecf20Sopenharmony_ci	ntfs_debug("Attribute type 0x%x not found in $AttrDef.",
13368c2ecf20Sopenharmony_ci			le32_to_cpu(type));
13378c2ecf20Sopenharmony_ci	return NULL;
13388c2ecf20Sopenharmony_ci}
13398c2ecf20Sopenharmony_ci
13408c2ecf20Sopenharmony_ci/**
13418c2ecf20Sopenharmony_ci * ntfs_attr_size_bounds_check - check a size of an attribute type for validity
13428c2ecf20Sopenharmony_ci * @vol:	ntfs volume to which the attribute belongs
13438c2ecf20Sopenharmony_ci * @type:	attribute type which to check
13448c2ecf20Sopenharmony_ci * @size:	size which to check
13458c2ecf20Sopenharmony_ci *
13468c2ecf20Sopenharmony_ci * Check whether the @size in bytes is valid for an attribute of @type on the
13478c2ecf20Sopenharmony_ci * ntfs volume @vol.  This information is obtained from $AttrDef system file.
13488c2ecf20Sopenharmony_ci *
13498c2ecf20Sopenharmony_ci * Return 0 if valid, -ERANGE if not valid, or -ENOENT if the attribute is not
13508c2ecf20Sopenharmony_ci * listed in $AttrDef.
13518c2ecf20Sopenharmony_ci */
13528c2ecf20Sopenharmony_ciint ntfs_attr_size_bounds_check(const ntfs_volume *vol, const ATTR_TYPE type,
13538c2ecf20Sopenharmony_ci		const s64 size)
13548c2ecf20Sopenharmony_ci{
13558c2ecf20Sopenharmony_ci	ATTR_DEF *ad;
13568c2ecf20Sopenharmony_ci
13578c2ecf20Sopenharmony_ci	BUG_ON(size < 0);
13588c2ecf20Sopenharmony_ci	/*
13598c2ecf20Sopenharmony_ci	 * $ATTRIBUTE_LIST has a maximum size of 256kiB, but this is not
13608c2ecf20Sopenharmony_ci	 * listed in $AttrDef.
13618c2ecf20Sopenharmony_ci	 */
13628c2ecf20Sopenharmony_ci	if (unlikely(type == AT_ATTRIBUTE_LIST && size > 256 * 1024))
13638c2ecf20Sopenharmony_ci		return -ERANGE;
13648c2ecf20Sopenharmony_ci	/* Get the $AttrDef entry for the attribute @type. */
13658c2ecf20Sopenharmony_ci	ad = ntfs_attr_find_in_attrdef(vol, type);
13668c2ecf20Sopenharmony_ci	if (unlikely(!ad))
13678c2ecf20Sopenharmony_ci		return -ENOENT;
13688c2ecf20Sopenharmony_ci	/* Do the bounds check. */
13698c2ecf20Sopenharmony_ci	if (((sle64_to_cpu(ad->min_size) > 0) &&
13708c2ecf20Sopenharmony_ci			size < sle64_to_cpu(ad->min_size)) ||
13718c2ecf20Sopenharmony_ci			((sle64_to_cpu(ad->max_size) > 0) && size >
13728c2ecf20Sopenharmony_ci			sle64_to_cpu(ad->max_size)))
13738c2ecf20Sopenharmony_ci		return -ERANGE;
13748c2ecf20Sopenharmony_ci	return 0;
13758c2ecf20Sopenharmony_ci}
13768c2ecf20Sopenharmony_ci
13778c2ecf20Sopenharmony_ci/**
13788c2ecf20Sopenharmony_ci * ntfs_attr_can_be_non_resident - check if an attribute can be non-resident
13798c2ecf20Sopenharmony_ci * @vol:	ntfs volume to which the attribute belongs
13808c2ecf20Sopenharmony_ci * @type:	attribute type which to check
13818c2ecf20Sopenharmony_ci *
13828c2ecf20Sopenharmony_ci * Check whether the attribute of @type on the ntfs volume @vol is allowed to
13838c2ecf20Sopenharmony_ci * be non-resident.  This information is obtained from $AttrDef system file.
13848c2ecf20Sopenharmony_ci *
13858c2ecf20Sopenharmony_ci * Return 0 if the attribute is allowed to be non-resident, -EPERM if not, and
13868c2ecf20Sopenharmony_ci * -ENOENT if the attribute is not listed in $AttrDef.
13878c2ecf20Sopenharmony_ci */
13888c2ecf20Sopenharmony_ciint ntfs_attr_can_be_non_resident(const ntfs_volume *vol, const ATTR_TYPE type)
13898c2ecf20Sopenharmony_ci{
13908c2ecf20Sopenharmony_ci	ATTR_DEF *ad;
13918c2ecf20Sopenharmony_ci
13928c2ecf20Sopenharmony_ci	/* Find the attribute definition record in $AttrDef. */
13938c2ecf20Sopenharmony_ci	ad = ntfs_attr_find_in_attrdef(vol, type);
13948c2ecf20Sopenharmony_ci	if (unlikely(!ad))
13958c2ecf20Sopenharmony_ci		return -ENOENT;
13968c2ecf20Sopenharmony_ci	/* Check the flags and return the result. */
13978c2ecf20Sopenharmony_ci	if (ad->flags & ATTR_DEF_RESIDENT)
13988c2ecf20Sopenharmony_ci		return -EPERM;
13998c2ecf20Sopenharmony_ci	return 0;
14008c2ecf20Sopenharmony_ci}
14018c2ecf20Sopenharmony_ci
14028c2ecf20Sopenharmony_ci/**
14038c2ecf20Sopenharmony_ci * ntfs_attr_can_be_resident - check if an attribute can be resident
14048c2ecf20Sopenharmony_ci * @vol:	ntfs volume to which the attribute belongs
14058c2ecf20Sopenharmony_ci * @type:	attribute type which to check
14068c2ecf20Sopenharmony_ci *
14078c2ecf20Sopenharmony_ci * Check whether the attribute of @type on the ntfs volume @vol is allowed to
14088c2ecf20Sopenharmony_ci * be resident.  This information is derived from our ntfs knowledge and may
14098c2ecf20Sopenharmony_ci * not be completely accurate, especially when user defined attributes are
14108c2ecf20Sopenharmony_ci * present.  Basically we allow everything to be resident except for index
14118c2ecf20Sopenharmony_ci * allocation and $EA attributes.
14128c2ecf20Sopenharmony_ci *
14138c2ecf20Sopenharmony_ci * Return 0 if the attribute is allowed to be non-resident and -EPERM if not.
14148c2ecf20Sopenharmony_ci *
14158c2ecf20Sopenharmony_ci * Warning: In the system file $MFT the attribute $Bitmap must be non-resident
14168c2ecf20Sopenharmony_ci *	    otherwise windows will not boot (blue screen of death)!  We cannot
14178c2ecf20Sopenharmony_ci *	    check for this here as we do not know which inode's $Bitmap is
14188c2ecf20Sopenharmony_ci *	    being asked about so the caller needs to special case this.
14198c2ecf20Sopenharmony_ci */
14208c2ecf20Sopenharmony_ciint ntfs_attr_can_be_resident(const ntfs_volume *vol, const ATTR_TYPE type)
14218c2ecf20Sopenharmony_ci{
14228c2ecf20Sopenharmony_ci	if (type == AT_INDEX_ALLOCATION)
14238c2ecf20Sopenharmony_ci		return -EPERM;
14248c2ecf20Sopenharmony_ci	return 0;
14258c2ecf20Sopenharmony_ci}
14268c2ecf20Sopenharmony_ci
14278c2ecf20Sopenharmony_ci/**
14288c2ecf20Sopenharmony_ci * ntfs_attr_record_resize - resize an attribute record
14298c2ecf20Sopenharmony_ci * @m:		mft record containing attribute record
14308c2ecf20Sopenharmony_ci * @a:		attribute record to resize
14318c2ecf20Sopenharmony_ci * @new_size:	new size in bytes to which to resize the attribute record @a
14328c2ecf20Sopenharmony_ci *
14338c2ecf20Sopenharmony_ci * Resize the attribute record @a, i.e. the resident part of the attribute, in
14348c2ecf20Sopenharmony_ci * the mft record @m to @new_size bytes.
14358c2ecf20Sopenharmony_ci *
14368c2ecf20Sopenharmony_ci * Return 0 on success and -errno on error.  The following error codes are
14378c2ecf20Sopenharmony_ci * defined:
14388c2ecf20Sopenharmony_ci *	-ENOSPC	- Not enough space in the mft record @m to perform the resize.
14398c2ecf20Sopenharmony_ci *
14408c2ecf20Sopenharmony_ci * Note: On error, no modifications have been performed whatsoever.
14418c2ecf20Sopenharmony_ci *
14428c2ecf20Sopenharmony_ci * Warning: If you make a record smaller without having copied all the data you
14438c2ecf20Sopenharmony_ci *	    are interested in the data may be overwritten.
14448c2ecf20Sopenharmony_ci */
14458c2ecf20Sopenharmony_ciint ntfs_attr_record_resize(MFT_RECORD *m, ATTR_RECORD *a, u32 new_size)
14468c2ecf20Sopenharmony_ci{
14478c2ecf20Sopenharmony_ci	ntfs_debug("Entering for new_size %u.", new_size);
14488c2ecf20Sopenharmony_ci	/* Align to 8 bytes if it is not already done. */
14498c2ecf20Sopenharmony_ci	if (new_size & 7)
14508c2ecf20Sopenharmony_ci		new_size = (new_size + 7) & ~7;
14518c2ecf20Sopenharmony_ci	/* If the actual attribute length has changed, move things around. */
14528c2ecf20Sopenharmony_ci	if (new_size != le32_to_cpu(a->length)) {
14538c2ecf20Sopenharmony_ci		u32 new_muse = le32_to_cpu(m->bytes_in_use) -
14548c2ecf20Sopenharmony_ci				le32_to_cpu(a->length) + new_size;
14558c2ecf20Sopenharmony_ci		/* Not enough space in this mft record. */
14568c2ecf20Sopenharmony_ci		if (new_muse > le32_to_cpu(m->bytes_allocated))
14578c2ecf20Sopenharmony_ci			return -ENOSPC;
14588c2ecf20Sopenharmony_ci		/* Move attributes following @a to their new location. */
14598c2ecf20Sopenharmony_ci		memmove((u8*)a + new_size, (u8*)a + le32_to_cpu(a->length),
14608c2ecf20Sopenharmony_ci				le32_to_cpu(m->bytes_in_use) - ((u8*)a -
14618c2ecf20Sopenharmony_ci				(u8*)m) - le32_to_cpu(a->length));
14628c2ecf20Sopenharmony_ci		/* Adjust @m to reflect the change in used space. */
14638c2ecf20Sopenharmony_ci		m->bytes_in_use = cpu_to_le32(new_muse);
14648c2ecf20Sopenharmony_ci		/* Adjust @a to reflect the new size. */
14658c2ecf20Sopenharmony_ci		if (new_size >= offsetof(ATTR_REC, length) + sizeof(a->length))
14668c2ecf20Sopenharmony_ci			a->length = cpu_to_le32(new_size);
14678c2ecf20Sopenharmony_ci	}
14688c2ecf20Sopenharmony_ci	return 0;
14698c2ecf20Sopenharmony_ci}
14708c2ecf20Sopenharmony_ci
14718c2ecf20Sopenharmony_ci/**
14728c2ecf20Sopenharmony_ci * ntfs_resident_attr_value_resize - resize the value of a resident attribute
14738c2ecf20Sopenharmony_ci * @m:		mft record containing attribute record
14748c2ecf20Sopenharmony_ci * @a:		attribute record whose value to resize
14758c2ecf20Sopenharmony_ci * @new_size:	new size in bytes to which to resize the attribute value of @a
14768c2ecf20Sopenharmony_ci *
14778c2ecf20Sopenharmony_ci * Resize the value of the attribute @a in the mft record @m to @new_size bytes.
14788c2ecf20Sopenharmony_ci * If the value is made bigger, the newly allocated space is cleared.
14798c2ecf20Sopenharmony_ci *
14808c2ecf20Sopenharmony_ci * Return 0 on success and -errno on error.  The following error codes are
14818c2ecf20Sopenharmony_ci * defined:
14828c2ecf20Sopenharmony_ci *	-ENOSPC	- Not enough space in the mft record @m to perform the resize.
14838c2ecf20Sopenharmony_ci *
14848c2ecf20Sopenharmony_ci * Note: On error, no modifications have been performed whatsoever.
14858c2ecf20Sopenharmony_ci *
14868c2ecf20Sopenharmony_ci * Warning: If you make a record smaller without having copied all the data you
14878c2ecf20Sopenharmony_ci *	    are interested in the data may be overwritten.
14888c2ecf20Sopenharmony_ci */
14898c2ecf20Sopenharmony_ciint ntfs_resident_attr_value_resize(MFT_RECORD *m, ATTR_RECORD *a,
14908c2ecf20Sopenharmony_ci		const u32 new_size)
14918c2ecf20Sopenharmony_ci{
14928c2ecf20Sopenharmony_ci	u32 old_size;
14938c2ecf20Sopenharmony_ci
14948c2ecf20Sopenharmony_ci	/* Resize the resident part of the attribute record. */
14958c2ecf20Sopenharmony_ci	if (ntfs_attr_record_resize(m, a,
14968c2ecf20Sopenharmony_ci			le16_to_cpu(a->data.resident.value_offset) + new_size))
14978c2ecf20Sopenharmony_ci		return -ENOSPC;
14988c2ecf20Sopenharmony_ci	/*
14998c2ecf20Sopenharmony_ci	 * The resize succeeded!  If we made the attribute value bigger, clear
15008c2ecf20Sopenharmony_ci	 * the area between the old size and @new_size.
15018c2ecf20Sopenharmony_ci	 */
15028c2ecf20Sopenharmony_ci	old_size = le32_to_cpu(a->data.resident.value_length);
15038c2ecf20Sopenharmony_ci	if (new_size > old_size)
15048c2ecf20Sopenharmony_ci		memset((u8*)a + le16_to_cpu(a->data.resident.value_offset) +
15058c2ecf20Sopenharmony_ci				old_size, 0, new_size - old_size);
15068c2ecf20Sopenharmony_ci	/* Finally update the length of the attribute value. */
15078c2ecf20Sopenharmony_ci	a->data.resident.value_length = cpu_to_le32(new_size);
15088c2ecf20Sopenharmony_ci	return 0;
15098c2ecf20Sopenharmony_ci}
15108c2ecf20Sopenharmony_ci
15118c2ecf20Sopenharmony_ci/**
15128c2ecf20Sopenharmony_ci * ntfs_attr_make_non_resident - convert a resident to a non-resident attribute
15138c2ecf20Sopenharmony_ci * @ni:		ntfs inode describing the attribute to convert
15148c2ecf20Sopenharmony_ci * @data_size:	size of the resident data to copy to the non-resident attribute
15158c2ecf20Sopenharmony_ci *
15168c2ecf20Sopenharmony_ci * Convert the resident ntfs attribute described by the ntfs inode @ni to a
15178c2ecf20Sopenharmony_ci * non-resident one.
15188c2ecf20Sopenharmony_ci *
15198c2ecf20Sopenharmony_ci * @data_size must be equal to the attribute value size.  This is needed since
15208c2ecf20Sopenharmony_ci * we need to know the size before we can map the mft record and our callers
15218c2ecf20Sopenharmony_ci * always know it.  The reason we cannot simply read the size from the vfs
15228c2ecf20Sopenharmony_ci * inode i_size is that this is not necessarily uptodate.  This happens when
15238c2ecf20Sopenharmony_ci * ntfs_attr_make_non_resident() is called in the ->truncate call path(s).
15248c2ecf20Sopenharmony_ci *
15258c2ecf20Sopenharmony_ci * Return 0 on success and -errno on error.  The following error return codes
15268c2ecf20Sopenharmony_ci * are defined:
15278c2ecf20Sopenharmony_ci *	-EPERM	- The attribute is not allowed to be non-resident.
15288c2ecf20Sopenharmony_ci *	-ENOMEM	- Not enough memory.
15298c2ecf20Sopenharmony_ci *	-ENOSPC	- Not enough disk space.
15308c2ecf20Sopenharmony_ci *	-EINVAL	- Attribute not defined on the volume.
15318c2ecf20Sopenharmony_ci *	-EIO	- I/o error or other error.
15328c2ecf20Sopenharmony_ci * Note that -ENOSPC is also returned in the case that there is not enough
15338c2ecf20Sopenharmony_ci * space in the mft record to do the conversion.  This can happen when the mft
15348c2ecf20Sopenharmony_ci * record is already very full.  The caller is responsible for trying to make
15358c2ecf20Sopenharmony_ci * space in the mft record and trying again.  FIXME: Do we need a separate
15368c2ecf20Sopenharmony_ci * error return code for this kind of -ENOSPC or is it always worth trying
15378c2ecf20Sopenharmony_ci * again in case the attribute may then fit in a resident state so no need to
15388c2ecf20Sopenharmony_ci * make it non-resident at all?  Ho-hum...  (AIA)
15398c2ecf20Sopenharmony_ci *
15408c2ecf20Sopenharmony_ci * NOTE to self: No changes in the attribute list are required to move from
15418c2ecf20Sopenharmony_ci *		 a resident to a non-resident attribute.
15428c2ecf20Sopenharmony_ci *
15438c2ecf20Sopenharmony_ci * Locking: - The caller must hold i_mutex on the inode.
15448c2ecf20Sopenharmony_ci */
15458c2ecf20Sopenharmony_ciint ntfs_attr_make_non_resident(ntfs_inode *ni, const u32 data_size)
15468c2ecf20Sopenharmony_ci{
15478c2ecf20Sopenharmony_ci	s64 new_size;
15488c2ecf20Sopenharmony_ci	struct inode *vi = VFS_I(ni);
15498c2ecf20Sopenharmony_ci	ntfs_volume *vol = ni->vol;
15508c2ecf20Sopenharmony_ci	ntfs_inode *base_ni;
15518c2ecf20Sopenharmony_ci	MFT_RECORD *m;
15528c2ecf20Sopenharmony_ci	ATTR_RECORD *a;
15538c2ecf20Sopenharmony_ci	ntfs_attr_search_ctx *ctx;
15548c2ecf20Sopenharmony_ci	struct page *page;
15558c2ecf20Sopenharmony_ci	runlist_element *rl;
15568c2ecf20Sopenharmony_ci	u8 *kaddr;
15578c2ecf20Sopenharmony_ci	unsigned long flags;
15588c2ecf20Sopenharmony_ci	int mp_size, mp_ofs, name_ofs, arec_size, err, err2;
15598c2ecf20Sopenharmony_ci	u32 attr_size;
15608c2ecf20Sopenharmony_ci	u8 old_res_attr_flags;
15618c2ecf20Sopenharmony_ci
15628c2ecf20Sopenharmony_ci	/* Check that the attribute is allowed to be non-resident. */
15638c2ecf20Sopenharmony_ci	err = ntfs_attr_can_be_non_resident(vol, ni->type);
15648c2ecf20Sopenharmony_ci	if (unlikely(err)) {
15658c2ecf20Sopenharmony_ci		if (err == -EPERM)
15668c2ecf20Sopenharmony_ci			ntfs_debug("Attribute is not allowed to be "
15678c2ecf20Sopenharmony_ci					"non-resident.");
15688c2ecf20Sopenharmony_ci		else
15698c2ecf20Sopenharmony_ci			ntfs_debug("Attribute not defined on the NTFS "
15708c2ecf20Sopenharmony_ci					"volume!");
15718c2ecf20Sopenharmony_ci		return err;
15728c2ecf20Sopenharmony_ci	}
15738c2ecf20Sopenharmony_ci	/*
15748c2ecf20Sopenharmony_ci	 * FIXME: Compressed and encrypted attributes are not supported when
15758c2ecf20Sopenharmony_ci	 * writing and we should never have gotten here for them.
15768c2ecf20Sopenharmony_ci	 */
15778c2ecf20Sopenharmony_ci	BUG_ON(NInoCompressed(ni));
15788c2ecf20Sopenharmony_ci	BUG_ON(NInoEncrypted(ni));
15798c2ecf20Sopenharmony_ci	/*
15808c2ecf20Sopenharmony_ci	 * The size needs to be aligned to a cluster boundary for allocation
15818c2ecf20Sopenharmony_ci	 * purposes.
15828c2ecf20Sopenharmony_ci	 */
15838c2ecf20Sopenharmony_ci	new_size = (data_size + vol->cluster_size - 1) &
15848c2ecf20Sopenharmony_ci			~(vol->cluster_size - 1);
15858c2ecf20Sopenharmony_ci	if (new_size > 0) {
15868c2ecf20Sopenharmony_ci		/*
15878c2ecf20Sopenharmony_ci		 * Will need the page later and since the page lock nests
15888c2ecf20Sopenharmony_ci		 * outside all ntfs locks, we need to get the page now.
15898c2ecf20Sopenharmony_ci		 */
15908c2ecf20Sopenharmony_ci		page = find_or_create_page(vi->i_mapping, 0,
15918c2ecf20Sopenharmony_ci				mapping_gfp_mask(vi->i_mapping));
15928c2ecf20Sopenharmony_ci		if (unlikely(!page))
15938c2ecf20Sopenharmony_ci			return -ENOMEM;
15948c2ecf20Sopenharmony_ci		/* Start by allocating clusters to hold the attribute value. */
15958c2ecf20Sopenharmony_ci		rl = ntfs_cluster_alloc(vol, 0, new_size >>
15968c2ecf20Sopenharmony_ci				vol->cluster_size_bits, -1, DATA_ZONE, true);
15978c2ecf20Sopenharmony_ci		if (IS_ERR(rl)) {
15988c2ecf20Sopenharmony_ci			err = PTR_ERR(rl);
15998c2ecf20Sopenharmony_ci			ntfs_debug("Failed to allocate cluster%s, error code "
16008c2ecf20Sopenharmony_ci					"%i.", (new_size >>
16018c2ecf20Sopenharmony_ci					vol->cluster_size_bits) > 1 ? "s" : "",
16028c2ecf20Sopenharmony_ci					err);
16038c2ecf20Sopenharmony_ci			goto page_err_out;
16048c2ecf20Sopenharmony_ci		}
16058c2ecf20Sopenharmony_ci	} else {
16068c2ecf20Sopenharmony_ci		rl = NULL;
16078c2ecf20Sopenharmony_ci		page = NULL;
16088c2ecf20Sopenharmony_ci	}
16098c2ecf20Sopenharmony_ci	/* Determine the size of the mapping pairs array. */
16108c2ecf20Sopenharmony_ci	mp_size = ntfs_get_size_for_mapping_pairs(vol, rl, 0, -1);
16118c2ecf20Sopenharmony_ci	if (unlikely(mp_size < 0)) {
16128c2ecf20Sopenharmony_ci		err = mp_size;
16138c2ecf20Sopenharmony_ci		ntfs_debug("Failed to get size for mapping pairs array, error "
16148c2ecf20Sopenharmony_ci				"code %i.", err);
16158c2ecf20Sopenharmony_ci		goto rl_err_out;
16168c2ecf20Sopenharmony_ci	}
16178c2ecf20Sopenharmony_ci	down_write(&ni->runlist.lock);
16188c2ecf20Sopenharmony_ci	if (!NInoAttr(ni))
16198c2ecf20Sopenharmony_ci		base_ni = ni;
16208c2ecf20Sopenharmony_ci	else
16218c2ecf20Sopenharmony_ci		base_ni = ni->ext.base_ntfs_ino;
16228c2ecf20Sopenharmony_ci	m = map_mft_record(base_ni);
16238c2ecf20Sopenharmony_ci	if (IS_ERR(m)) {
16248c2ecf20Sopenharmony_ci		err = PTR_ERR(m);
16258c2ecf20Sopenharmony_ci		m = NULL;
16268c2ecf20Sopenharmony_ci		ctx = NULL;
16278c2ecf20Sopenharmony_ci		goto err_out;
16288c2ecf20Sopenharmony_ci	}
16298c2ecf20Sopenharmony_ci	ctx = ntfs_attr_get_search_ctx(base_ni, m);
16308c2ecf20Sopenharmony_ci	if (unlikely(!ctx)) {
16318c2ecf20Sopenharmony_ci		err = -ENOMEM;
16328c2ecf20Sopenharmony_ci		goto err_out;
16338c2ecf20Sopenharmony_ci	}
16348c2ecf20Sopenharmony_ci	err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len,
16358c2ecf20Sopenharmony_ci			CASE_SENSITIVE, 0, NULL, 0, ctx);
16368c2ecf20Sopenharmony_ci	if (unlikely(err)) {
16378c2ecf20Sopenharmony_ci		if (err == -ENOENT)
16388c2ecf20Sopenharmony_ci			err = -EIO;
16398c2ecf20Sopenharmony_ci		goto err_out;
16408c2ecf20Sopenharmony_ci	}
16418c2ecf20Sopenharmony_ci	m = ctx->mrec;
16428c2ecf20Sopenharmony_ci	a = ctx->attr;
16438c2ecf20Sopenharmony_ci	BUG_ON(NInoNonResident(ni));
16448c2ecf20Sopenharmony_ci	BUG_ON(a->non_resident);
16458c2ecf20Sopenharmony_ci	/*
16468c2ecf20Sopenharmony_ci	 * Calculate new offsets for the name and the mapping pairs array.
16478c2ecf20Sopenharmony_ci	 */
16488c2ecf20Sopenharmony_ci	if (NInoSparse(ni) || NInoCompressed(ni))
16498c2ecf20Sopenharmony_ci		name_ofs = (offsetof(ATTR_REC,
16508c2ecf20Sopenharmony_ci				data.non_resident.compressed_size) +
16518c2ecf20Sopenharmony_ci				sizeof(a->data.non_resident.compressed_size) +
16528c2ecf20Sopenharmony_ci				7) & ~7;
16538c2ecf20Sopenharmony_ci	else
16548c2ecf20Sopenharmony_ci		name_ofs = (offsetof(ATTR_REC,
16558c2ecf20Sopenharmony_ci				data.non_resident.compressed_size) + 7) & ~7;
16568c2ecf20Sopenharmony_ci	mp_ofs = (name_ofs + a->name_length * sizeof(ntfschar) + 7) & ~7;
16578c2ecf20Sopenharmony_ci	/*
16588c2ecf20Sopenharmony_ci	 * Determine the size of the resident part of the now non-resident
16598c2ecf20Sopenharmony_ci	 * attribute record.
16608c2ecf20Sopenharmony_ci	 */
16618c2ecf20Sopenharmony_ci	arec_size = (mp_ofs + mp_size + 7) & ~7;
16628c2ecf20Sopenharmony_ci	/*
16638c2ecf20Sopenharmony_ci	 * If the page is not uptodate bring it uptodate by copying from the
16648c2ecf20Sopenharmony_ci	 * attribute value.
16658c2ecf20Sopenharmony_ci	 */
16668c2ecf20Sopenharmony_ci	attr_size = le32_to_cpu(a->data.resident.value_length);
16678c2ecf20Sopenharmony_ci	BUG_ON(attr_size != data_size);
16688c2ecf20Sopenharmony_ci	if (page && !PageUptodate(page)) {
16698c2ecf20Sopenharmony_ci		kaddr = kmap_atomic(page);
16708c2ecf20Sopenharmony_ci		memcpy(kaddr, (u8*)a +
16718c2ecf20Sopenharmony_ci				le16_to_cpu(a->data.resident.value_offset),
16728c2ecf20Sopenharmony_ci				attr_size);
16738c2ecf20Sopenharmony_ci		memset(kaddr + attr_size, 0, PAGE_SIZE - attr_size);
16748c2ecf20Sopenharmony_ci		kunmap_atomic(kaddr);
16758c2ecf20Sopenharmony_ci		flush_dcache_page(page);
16768c2ecf20Sopenharmony_ci		SetPageUptodate(page);
16778c2ecf20Sopenharmony_ci	}
16788c2ecf20Sopenharmony_ci	/* Backup the attribute flag. */
16798c2ecf20Sopenharmony_ci	old_res_attr_flags = a->data.resident.flags;
16808c2ecf20Sopenharmony_ci	/* Resize the resident part of the attribute record. */
16818c2ecf20Sopenharmony_ci	err = ntfs_attr_record_resize(m, a, arec_size);
16828c2ecf20Sopenharmony_ci	if (unlikely(err))
16838c2ecf20Sopenharmony_ci		goto err_out;
16848c2ecf20Sopenharmony_ci	/*
16858c2ecf20Sopenharmony_ci	 * Convert the resident part of the attribute record to describe a
16868c2ecf20Sopenharmony_ci	 * non-resident attribute.
16878c2ecf20Sopenharmony_ci	 */
16888c2ecf20Sopenharmony_ci	a->non_resident = 1;
16898c2ecf20Sopenharmony_ci	/* Move the attribute name if it exists and update the offset. */
16908c2ecf20Sopenharmony_ci	if (a->name_length)
16918c2ecf20Sopenharmony_ci		memmove((u8*)a + name_ofs, (u8*)a + le16_to_cpu(a->name_offset),
16928c2ecf20Sopenharmony_ci				a->name_length * sizeof(ntfschar));
16938c2ecf20Sopenharmony_ci	a->name_offset = cpu_to_le16(name_ofs);
16948c2ecf20Sopenharmony_ci	/* Setup the fields specific to non-resident attributes. */
16958c2ecf20Sopenharmony_ci	a->data.non_resident.lowest_vcn = 0;
16968c2ecf20Sopenharmony_ci	a->data.non_resident.highest_vcn = cpu_to_sle64((new_size - 1) >>
16978c2ecf20Sopenharmony_ci			vol->cluster_size_bits);
16988c2ecf20Sopenharmony_ci	a->data.non_resident.mapping_pairs_offset = cpu_to_le16(mp_ofs);
16998c2ecf20Sopenharmony_ci	memset(&a->data.non_resident.reserved, 0,
17008c2ecf20Sopenharmony_ci			sizeof(a->data.non_resident.reserved));
17018c2ecf20Sopenharmony_ci	a->data.non_resident.allocated_size = cpu_to_sle64(new_size);
17028c2ecf20Sopenharmony_ci	a->data.non_resident.data_size =
17038c2ecf20Sopenharmony_ci			a->data.non_resident.initialized_size =
17048c2ecf20Sopenharmony_ci			cpu_to_sle64(attr_size);
17058c2ecf20Sopenharmony_ci	if (NInoSparse(ni) || NInoCompressed(ni)) {
17068c2ecf20Sopenharmony_ci		a->data.non_resident.compression_unit = 0;
17078c2ecf20Sopenharmony_ci		if (NInoCompressed(ni) || vol->major_ver < 3)
17088c2ecf20Sopenharmony_ci			a->data.non_resident.compression_unit = 4;
17098c2ecf20Sopenharmony_ci		a->data.non_resident.compressed_size =
17108c2ecf20Sopenharmony_ci				a->data.non_resident.allocated_size;
17118c2ecf20Sopenharmony_ci	} else
17128c2ecf20Sopenharmony_ci		a->data.non_resident.compression_unit = 0;
17138c2ecf20Sopenharmony_ci	/* Generate the mapping pairs array into the attribute record. */
17148c2ecf20Sopenharmony_ci	err = ntfs_mapping_pairs_build(vol, (u8*)a + mp_ofs,
17158c2ecf20Sopenharmony_ci			arec_size - mp_ofs, rl, 0, -1, NULL);
17168c2ecf20Sopenharmony_ci	if (unlikely(err)) {
17178c2ecf20Sopenharmony_ci		ntfs_debug("Failed to build mapping pairs, error code %i.",
17188c2ecf20Sopenharmony_ci				err);
17198c2ecf20Sopenharmony_ci		goto undo_err_out;
17208c2ecf20Sopenharmony_ci	}
17218c2ecf20Sopenharmony_ci	/* Setup the in-memory attribute structure to be non-resident. */
17228c2ecf20Sopenharmony_ci	ni->runlist.rl = rl;
17238c2ecf20Sopenharmony_ci	write_lock_irqsave(&ni->size_lock, flags);
17248c2ecf20Sopenharmony_ci	ni->allocated_size = new_size;
17258c2ecf20Sopenharmony_ci	if (NInoSparse(ni) || NInoCompressed(ni)) {
17268c2ecf20Sopenharmony_ci		ni->itype.compressed.size = ni->allocated_size;
17278c2ecf20Sopenharmony_ci		if (a->data.non_resident.compression_unit) {
17288c2ecf20Sopenharmony_ci			ni->itype.compressed.block_size = 1U << (a->data.
17298c2ecf20Sopenharmony_ci					non_resident.compression_unit +
17308c2ecf20Sopenharmony_ci					vol->cluster_size_bits);
17318c2ecf20Sopenharmony_ci			ni->itype.compressed.block_size_bits =
17328c2ecf20Sopenharmony_ci					ffs(ni->itype.compressed.block_size) -
17338c2ecf20Sopenharmony_ci					1;
17348c2ecf20Sopenharmony_ci			ni->itype.compressed.block_clusters = 1U <<
17358c2ecf20Sopenharmony_ci					a->data.non_resident.compression_unit;
17368c2ecf20Sopenharmony_ci		} else {
17378c2ecf20Sopenharmony_ci			ni->itype.compressed.block_size = 0;
17388c2ecf20Sopenharmony_ci			ni->itype.compressed.block_size_bits = 0;
17398c2ecf20Sopenharmony_ci			ni->itype.compressed.block_clusters = 0;
17408c2ecf20Sopenharmony_ci		}
17418c2ecf20Sopenharmony_ci		vi->i_blocks = ni->itype.compressed.size >> 9;
17428c2ecf20Sopenharmony_ci	} else
17438c2ecf20Sopenharmony_ci		vi->i_blocks = ni->allocated_size >> 9;
17448c2ecf20Sopenharmony_ci	write_unlock_irqrestore(&ni->size_lock, flags);
17458c2ecf20Sopenharmony_ci	/*
17468c2ecf20Sopenharmony_ci	 * This needs to be last since the address space operations ->readpage
17478c2ecf20Sopenharmony_ci	 * and ->writepage can run concurrently with us as they are not
17488c2ecf20Sopenharmony_ci	 * serialized on i_mutex.  Note, we are not allowed to fail once we flip
17498c2ecf20Sopenharmony_ci	 * this switch, which is another reason to do this last.
17508c2ecf20Sopenharmony_ci	 */
17518c2ecf20Sopenharmony_ci	NInoSetNonResident(ni);
17528c2ecf20Sopenharmony_ci	/* Mark the mft record dirty, so it gets written back. */
17538c2ecf20Sopenharmony_ci	flush_dcache_mft_record_page(ctx->ntfs_ino);
17548c2ecf20Sopenharmony_ci	mark_mft_record_dirty(ctx->ntfs_ino);
17558c2ecf20Sopenharmony_ci	ntfs_attr_put_search_ctx(ctx);
17568c2ecf20Sopenharmony_ci	unmap_mft_record(base_ni);
17578c2ecf20Sopenharmony_ci	up_write(&ni->runlist.lock);
17588c2ecf20Sopenharmony_ci	if (page) {
17598c2ecf20Sopenharmony_ci		set_page_dirty(page);
17608c2ecf20Sopenharmony_ci		unlock_page(page);
17618c2ecf20Sopenharmony_ci		put_page(page);
17628c2ecf20Sopenharmony_ci	}
17638c2ecf20Sopenharmony_ci	ntfs_debug("Done.");
17648c2ecf20Sopenharmony_ci	return 0;
17658c2ecf20Sopenharmony_ciundo_err_out:
17668c2ecf20Sopenharmony_ci	/* Convert the attribute back into a resident attribute. */
17678c2ecf20Sopenharmony_ci	a->non_resident = 0;
17688c2ecf20Sopenharmony_ci	/* Move the attribute name if it exists and update the offset. */
17698c2ecf20Sopenharmony_ci	name_ofs = (offsetof(ATTR_RECORD, data.resident.reserved) +
17708c2ecf20Sopenharmony_ci			sizeof(a->data.resident.reserved) + 7) & ~7;
17718c2ecf20Sopenharmony_ci	if (a->name_length)
17728c2ecf20Sopenharmony_ci		memmove((u8*)a + name_ofs, (u8*)a + le16_to_cpu(a->name_offset),
17738c2ecf20Sopenharmony_ci				a->name_length * sizeof(ntfschar));
17748c2ecf20Sopenharmony_ci	mp_ofs = (name_ofs + a->name_length * sizeof(ntfschar) + 7) & ~7;
17758c2ecf20Sopenharmony_ci	a->name_offset = cpu_to_le16(name_ofs);
17768c2ecf20Sopenharmony_ci	arec_size = (mp_ofs + attr_size + 7) & ~7;
17778c2ecf20Sopenharmony_ci	/* Resize the resident part of the attribute record. */
17788c2ecf20Sopenharmony_ci	err2 = ntfs_attr_record_resize(m, a, arec_size);
17798c2ecf20Sopenharmony_ci	if (unlikely(err2)) {
17808c2ecf20Sopenharmony_ci		/*
17818c2ecf20Sopenharmony_ci		 * This cannot happen (well if memory corruption is at work it
17828c2ecf20Sopenharmony_ci		 * could happen in theory), but deal with it as well as we can.
17838c2ecf20Sopenharmony_ci		 * If the old size is too small, truncate the attribute,
17848c2ecf20Sopenharmony_ci		 * otherwise simply give it a larger allocated size.
17858c2ecf20Sopenharmony_ci		 * FIXME: Should check whether chkdsk complains when the
17868c2ecf20Sopenharmony_ci		 * allocated size is much bigger than the resident value size.
17878c2ecf20Sopenharmony_ci		 */
17888c2ecf20Sopenharmony_ci		arec_size = le32_to_cpu(a->length);
17898c2ecf20Sopenharmony_ci		if ((mp_ofs + attr_size) > arec_size) {
17908c2ecf20Sopenharmony_ci			err2 = attr_size;
17918c2ecf20Sopenharmony_ci			attr_size = arec_size - mp_ofs;
17928c2ecf20Sopenharmony_ci			ntfs_error(vol->sb, "Failed to undo partial resident "
17938c2ecf20Sopenharmony_ci					"to non-resident attribute "
17948c2ecf20Sopenharmony_ci					"conversion.  Truncating inode 0x%lx, "
17958c2ecf20Sopenharmony_ci					"attribute type 0x%x from %i bytes to "
17968c2ecf20Sopenharmony_ci					"%i bytes to maintain metadata "
17978c2ecf20Sopenharmony_ci					"consistency.  THIS MEANS YOU ARE "
17988c2ecf20Sopenharmony_ci					"LOSING %i BYTES DATA FROM THIS %s.",
17998c2ecf20Sopenharmony_ci					vi->i_ino,
18008c2ecf20Sopenharmony_ci					(unsigned)le32_to_cpu(ni->type),
18018c2ecf20Sopenharmony_ci					err2, attr_size, err2 - attr_size,
18028c2ecf20Sopenharmony_ci					((ni->type == AT_DATA) &&
18038c2ecf20Sopenharmony_ci					!ni->name_len) ? "FILE": "ATTRIBUTE");
18048c2ecf20Sopenharmony_ci			write_lock_irqsave(&ni->size_lock, flags);
18058c2ecf20Sopenharmony_ci			ni->initialized_size = attr_size;
18068c2ecf20Sopenharmony_ci			i_size_write(vi, attr_size);
18078c2ecf20Sopenharmony_ci			write_unlock_irqrestore(&ni->size_lock, flags);
18088c2ecf20Sopenharmony_ci		}
18098c2ecf20Sopenharmony_ci	}
18108c2ecf20Sopenharmony_ci	/* Setup the fields specific to resident attributes. */
18118c2ecf20Sopenharmony_ci	a->data.resident.value_length = cpu_to_le32(attr_size);
18128c2ecf20Sopenharmony_ci	a->data.resident.value_offset = cpu_to_le16(mp_ofs);
18138c2ecf20Sopenharmony_ci	a->data.resident.flags = old_res_attr_flags;
18148c2ecf20Sopenharmony_ci	memset(&a->data.resident.reserved, 0,
18158c2ecf20Sopenharmony_ci			sizeof(a->data.resident.reserved));
18168c2ecf20Sopenharmony_ci	/* Copy the data from the page back to the attribute value. */
18178c2ecf20Sopenharmony_ci	if (page) {
18188c2ecf20Sopenharmony_ci		kaddr = kmap_atomic(page);
18198c2ecf20Sopenharmony_ci		memcpy((u8*)a + mp_ofs, kaddr, attr_size);
18208c2ecf20Sopenharmony_ci		kunmap_atomic(kaddr);
18218c2ecf20Sopenharmony_ci	}
18228c2ecf20Sopenharmony_ci	/* Setup the allocated size in the ntfs inode in case it changed. */
18238c2ecf20Sopenharmony_ci	write_lock_irqsave(&ni->size_lock, flags);
18248c2ecf20Sopenharmony_ci	ni->allocated_size = arec_size - mp_ofs;
18258c2ecf20Sopenharmony_ci	write_unlock_irqrestore(&ni->size_lock, flags);
18268c2ecf20Sopenharmony_ci	/* Mark the mft record dirty, so it gets written back. */
18278c2ecf20Sopenharmony_ci	flush_dcache_mft_record_page(ctx->ntfs_ino);
18288c2ecf20Sopenharmony_ci	mark_mft_record_dirty(ctx->ntfs_ino);
18298c2ecf20Sopenharmony_cierr_out:
18308c2ecf20Sopenharmony_ci	if (ctx)
18318c2ecf20Sopenharmony_ci		ntfs_attr_put_search_ctx(ctx);
18328c2ecf20Sopenharmony_ci	if (m)
18338c2ecf20Sopenharmony_ci		unmap_mft_record(base_ni);
18348c2ecf20Sopenharmony_ci	ni->runlist.rl = NULL;
18358c2ecf20Sopenharmony_ci	up_write(&ni->runlist.lock);
18368c2ecf20Sopenharmony_cirl_err_out:
18378c2ecf20Sopenharmony_ci	if (rl) {
18388c2ecf20Sopenharmony_ci		if (ntfs_cluster_free_from_rl(vol, rl) < 0) {
18398c2ecf20Sopenharmony_ci			ntfs_error(vol->sb, "Failed to release allocated "
18408c2ecf20Sopenharmony_ci					"cluster(s) in error code path.  Run "
18418c2ecf20Sopenharmony_ci					"chkdsk to recover the lost "
18428c2ecf20Sopenharmony_ci					"cluster(s).");
18438c2ecf20Sopenharmony_ci			NVolSetErrors(vol);
18448c2ecf20Sopenharmony_ci		}
18458c2ecf20Sopenharmony_ci		ntfs_free(rl);
18468c2ecf20Sopenharmony_cipage_err_out:
18478c2ecf20Sopenharmony_ci		unlock_page(page);
18488c2ecf20Sopenharmony_ci		put_page(page);
18498c2ecf20Sopenharmony_ci	}
18508c2ecf20Sopenharmony_ci	if (err == -EINVAL)
18518c2ecf20Sopenharmony_ci		err = -EIO;
18528c2ecf20Sopenharmony_ci	return err;
18538c2ecf20Sopenharmony_ci}
18548c2ecf20Sopenharmony_ci
18558c2ecf20Sopenharmony_ci/**
18568c2ecf20Sopenharmony_ci * ntfs_attr_extend_allocation - extend the allocated space of an attribute
18578c2ecf20Sopenharmony_ci * @ni:			ntfs inode of the attribute whose allocation to extend
18588c2ecf20Sopenharmony_ci * @new_alloc_size:	new size in bytes to which to extend the allocation to
18598c2ecf20Sopenharmony_ci * @new_data_size:	new size in bytes to which to extend the data to
18608c2ecf20Sopenharmony_ci * @data_start:		beginning of region which is required to be non-sparse
18618c2ecf20Sopenharmony_ci *
18628c2ecf20Sopenharmony_ci * Extend the allocated space of an attribute described by the ntfs inode @ni
18638c2ecf20Sopenharmony_ci * to @new_alloc_size bytes.  If @data_start is -1, the whole extension may be
18648c2ecf20Sopenharmony_ci * implemented as a hole in the file (as long as both the volume and the ntfs
18658c2ecf20Sopenharmony_ci * inode @ni have sparse support enabled).  If @data_start is >= 0, then the
18668c2ecf20Sopenharmony_ci * region between the old allocated size and @data_start - 1 may be made sparse
18678c2ecf20Sopenharmony_ci * but the regions between @data_start and @new_alloc_size must be backed by
18688c2ecf20Sopenharmony_ci * actual clusters.
18698c2ecf20Sopenharmony_ci *
18708c2ecf20Sopenharmony_ci * If @new_data_size is -1, it is ignored.  If it is >= 0, then the data size
18718c2ecf20Sopenharmony_ci * of the attribute is extended to @new_data_size.  Note that the i_size of the
18728c2ecf20Sopenharmony_ci * vfs inode is not updated.  Only the data size in the base attribute record
18738c2ecf20Sopenharmony_ci * is updated.  The caller has to update i_size separately if this is required.
18748c2ecf20Sopenharmony_ci * WARNING: It is a BUG() for @new_data_size to be smaller than the old data
18758c2ecf20Sopenharmony_ci * size as well as for @new_data_size to be greater than @new_alloc_size.
18768c2ecf20Sopenharmony_ci *
18778c2ecf20Sopenharmony_ci * For resident attributes this involves resizing the attribute record and if
18788c2ecf20Sopenharmony_ci * necessary moving it and/or other attributes into extent mft records and/or
18798c2ecf20Sopenharmony_ci * converting the attribute to a non-resident attribute which in turn involves
18808c2ecf20Sopenharmony_ci * extending the allocation of a non-resident attribute as described below.
18818c2ecf20Sopenharmony_ci *
18828c2ecf20Sopenharmony_ci * For non-resident attributes this involves allocating clusters in the data
18838c2ecf20Sopenharmony_ci * zone on the volume (except for regions that are being made sparse) and
18848c2ecf20Sopenharmony_ci * extending the run list to describe the allocated clusters as well as
18858c2ecf20Sopenharmony_ci * updating the mapping pairs array of the attribute.  This in turn involves
18868c2ecf20Sopenharmony_ci * resizing the attribute record and if necessary moving it and/or other
18878c2ecf20Sopenharmony_ci * attributes into extent mft records and/or splitting the attribute record
18888c2ecf20Sopenharmony_ci * into multiple extent attribute records.
18898c2ecf20Sopenharmony_ci *
18908c2ecf20Sopenharmony_ci * Also, the attribute list attribute is updated if present and in some of the
18918c2ecf20Sopenharmony_ci * above cases (the ones where extent mft records/attributes come into play),
18928c2ecf20Sopenharmony_ci * an attribute list attribute is created if not already present.
18938c2ecf20Sopenharmony_ci *
18948c2ecf20Sopenharmony_ci * Return the new allocated size on success and -errno on error.  In the case
18958c2ecf20Sopenharmony_ci * that an error is encountered but a partial extension at least up to
18968c2ecf20Sopenharmony_ci * @data_start (if present) is possible, the allocation is partially extended
18978c2ecf20Sopenharmony_ci * and this is returned.  This means the caller must check the returned size to
18988c2ecf20Sopenharmony_ci * determine if the extension was partial.  If @data_start is -1 then partial
18998c2ecf20Sopenharmony_ci * allocations are not performed.
19008c2ecf20Sopenharmony_ci *
19018c2ecf20Sopenharmony_ci * WARNING: Do not call ntfs_attr_extend_allocation() for $MFT/$DATA.
19028c2ecf20Sopenharmony_ci *
19038c2ecf20Sopenharmony_ci * Locking: This function takes the runlist lock of @ni for writing as well as
19048c2ecf20Sopenharmony_ci * locking the mft record of the base ntfs inode.  These locks are maintained
19058c2ecf20Sopenharmony_ci * throughout execution of the function.  These locks are required so that the
19068c2ecf20Sopenharmony_ci * attribute can be resized safely and so that it can for example be converted
19078c2ecf20Sopenharmony_ci * from resident to non-resident safely.
19088c2ecf20Sopenharmony_ci *
19098c2ecf20Sopenharmony_ci * TODO: At present attribute list attribute handling is not implemented.
19108c2ecf20Sopenharmony_ci *
19118c2ecf20Sopenharmony_ci * TODO: At present it is not safe to call this function for anything other
19128c2ecf20Sopenharmony_ci * than the $DATA attribute(s) of an uncompressed and unencrypted file.
19138c2ecf20Sopenharmony_ci */
19148c2ecf20Sopenharmony_cis64 ntfs_attr_extend_allocation(ntfs_inode *ni, s64 new_alloc_size,
19158c2ecf20Sopenharmony_ci		const s64 new_data_size, const s64 data_start)
19168c2ecf20Sopenharmony_ci{
19178c2ecf20Sopenharmony_ci	VCN vcn;
19188c2ecf20Sopenharmony_ci	s64 ll, allocated_size, start = data_start;
19198c2ecf20Sopenharmony_ci	struct inode *vi = VFS_I(ni);
19208c2ecf20Sopenharmony_ci	ntfs_volume *vol = ni->vol;
19218c2ecf20Sopenharmony_ci	ntfs_inode *base_ni;
19228c2ecf20Sopenharmony_ci	MFT_RECORD *m;
19238c2ecf20Sopenharmony_ci	ATTR_RECORD *a;
19248c2ecf20Sopenharmony_ci	ntfs_attr_search_ctx *ctx;
19258c2ecf20Sopenharmony_ci	runlist_element *rl, *rl2;
19268c2ecf20Sopenharmony_ci	unsigned long flags;
19278c2ecf20Sopenharmony_ci	int err, mp_size;
19288c2ecf20Sopenharmony_ci	u32 attr_len = 0; /* Silence stupid gcc warning. */
19298c2ecf20Sopenharmony_ci	bool mp_rebuilt;
19308c2ecf20Sopenharmony_ci
19318c2ecf20Sopenharmony_ci#ifdef DEBUG
19328c2ecf20Sopenharmony_ci	read_lock_irqsave(&ni->size_lock, flags);
19338c2ecf20Sopenharmony_ci	allocated_size = ni->allocated_size;
19348c2ecf20Sopenharmony_ci	read_unlock_irqrestore(&ni->size_lock, flags);
19358c2ecf20Sopenharmony_ci	ntfs_debug("Entering for i_ino 0x%lx, attribute type 0x%x, "
19368c2ecf20Sopenharmony_ci			"old_allocated_size 0x%llx, "
19378c2ecf20Sopenharmony_ci			"new_allocated_size 0x%llx, new_data_size 0x%llx, "
19388c2ecf20Sopenharmony_ci			"data_start 0x%llx.", vi->i_ino,
19398c2ecf20Sopenharmony_ci			(unsigned)le32_to_cpu(ni->type),
19408c2ecf20Sopenharmony_ci			(unsigned long long)allocated_size,
19418c2ecf20Sopenharmony_ci			(unsigned long long)new_alloc_size,
19428c2ecf20Sopenharmony_ci			(unsigned long long)new_data_size,
19438c2ecf20Sopenharmony_ci			(unsigned long long)start);
19448c2ecf20Sopenharmony_ci#endif
19458c2ecf20Sopenharmony_ciretry_extend:
19468c2ecf20Sopenharmony_ci	/*
19478c2ecf20Sopenharmony_ci	 * For non-resident attributes, @start and @new_size need to be aligned
19488c2ecf20Sopenharmony_ci	 * to cluster boundaries for allocation purposes.
19498c2ecf20Sopenharmony_ci	 */
19508c2ecf20Sopenharmony_ci	if (NInoNonResident(ni)) {
19518c2ecf20Sopenharmony_ci		if (start > 0)
19528c2ecf20Sopenharmony_ci			start &= ~(s64)vol->cluster_size_mask;
19538c2ecf20Sopenharmony_ci		new_alloc_size = (new_alloc_size + vol->cluster_size - 1) &
19548c2ecf20Sopenharmony_ci				~(s64)vol->cluster_size_mask;
19558c2ecf20Sopenharmony_ci	}
19568c2ecf20Sopenharmony_ci	BUG_ON(new_data_size >= 0 && new_data_size > new_alloc_size);
19578c2ecf20Sopenharmony_ci	/* Check if new size is allowed in $AttrDef. */
19588c2ecf20Sopenharmony_ci	err = ntfs_attr_size_bounds_check(vol, ni->type, new_alloc_size);
19598c2ecf20Sopenharmony_ci	if (unlikely(err)) {
19608c2ecf20Sopenharmony_ci		/* Only emit errors when the write will fail completely. */
19618c2ecf20Sopenharmony_ci		read_lock_irqsave(&ni->size_lock, flags);
19628c2ecf20Sopenharmony_ci		allocated_size = ni->allocated_size;
19638c2ecf20Sopenharmony_ci		read_unlock_irqrestore(&ni->size_lock, flags);
19648c2ecf20Sopenharmony_ci		if (start < 0 || start >= allocated_size) {
19658c2ecf20Sopenharmony_ci			if (err == -ERANGE) {
19668c2ecf20Sopenharmony_ci				ntfs_error(vol->sb, "Cannot extend allocation "
19678c2ecf20Sopenharmony_ci						"of inode 0x%lx, attribute "
19688c2ecf20Sopenharmony_ci						"type 0x%x, because the new "
19698c2ecf20Sopenharmony_ci						"allocation would exceed the "
19708c2ecf20Sopenharmony_ci						"maximum allowed size for "
19718c2ecf20Sopenharmony_ci						"this attribute type.",
19728c2ecf20Sopenharmony_ci						vi->i_ino, (unsigned)
19738c2ecf20Sopenharmony_ci						le32_to_cpu(ni->type));
19748c2ecf20Sopenharmony_ci			} else {
19758c2ecf20Sopenharmony_ci				ntfs_error(vol->sb, "Cannot extend allocation "
19768c2ecf20Sopenharmony_ci						"of inode 0x%lx, attribute "
19778c2ecf20Sopenharmony_ci						"type 0x%x, because this "
19788c2ecf20Sopenharmony_ci						"attribute type is not "
19798c2ecf20Sopenharmony_ci						"defined on the NTFS volume.  "
19808c2ecf20Sopenharmony_ci						"Possible corruption!  You "
19818c2ecf20Sopenharmony_ci						"should run chkdsk!",
19828c2ecf20Sopenharmony_ci						vi->i_ino, (unsigned)
19838c2ecf20Sopenharmony_ci						le32_to_cpu(ni->type));
19848c2ecf20Sopenharmony_ci			}
19858c2ecf20Sopenharmony_ci		}
19868c2ecf20Sopenharmony_ci		/* Translate error code to be POSIX conformant for write(2). */
19878c2ecf20Sopenharmony_ci		if (err == -ERANGE)
19888c2ecf20Sopenharmony_ci			err = -EFBIG;
19898c2ecf20Sopenharmony_ci		else
19908c2ecf20Sopenharmony_ci			err = -EIO;
19918c2ecf20Sopenharmony_ci		return err;
19928c2ecf20Sopenharmony_ci	}
19938c2ecf20Sopenharmony_ci	if (!NInoAttr(ni))
19948c2ecf20Sopenharmony_ci		base_ni = ni;
19958c2ecf20Sopenharmony_ci	else
19968c2ecf20Sopenharmony_ci		base_ni = ni->ext.base_ntfs_ino;
19978c2ecf20Sopenharmony_ci	/*
19988c2ecf20Sopenharmony_ci	 * We will be modifying both the runlist (if non-resident) and the mft
19998c2ecf20Sopenharmony_ci	 * record so lock them both down.
20008c2ecf20Sopenharmony_ci	 */
20018c2ecf20Sopenharmony_ci	down_write(&ni->runlist.lock);
20028c2ecf20Sopenharmony_ci	m = map_mft_record(base_ni);
20038c2ecf20Sopenharmony_ci	if (IS_ERR(m)) {
20048c2ecf20Sopenharmony_ci		err = PTR_ERR(m);
20058c2ecf20Sopenharmony_ci		m = NULL;
20068c2ecf20Sopenharmony_ci		ctx = NULL;
20078c2ecf20Sopenharmony_ci		goto err_out;
20088c2ecf20Sopenharmony_ci	}
20098c2ecf20Sopenharmony_ci	ctx = ntfs_attr_get_search_ctx(base_ni, m);
20108c2ecf20Sopenharmony_ci	if (unlikely(!ctx)) {
20118c2ecf20Sopenharmony_ci		err = -ENOMEM;
20128c2ecf20Sopenharmony_ci		goto err_out;
20138c2ecf20Sopenharmony_ci	}
20148c2ecf20Sopenharmony_ci	read_lock_irqsave(&ni->size_lock, flags);
20158c2ecf20Sopenharmony_ci	allocated_size = ni->allocated_size;
20168c2ecf20Sopenharmony_ci	read_unlock_irqrestore(&ni->size_lock, flags);
20178c2ecf20Sopenharmony_ci	/*
20188c2ecf20Sopenharmony_ci	 * If non-resident, seek to the last extent.  If resident, there is
20198c2ecf20Sopenharmony_ci	 * only one extent, so seek to that.
20208c2ecf20Sopenharmony_ci	 */
20218c2ecf20Sopenharmony_ci	vcn = NInoNonResident(ni) ? allocated_size >> vol->cluster_size_bits :
20228c2ecf20Sopenharmony_ci			0;
20238c2ecf20Sopenharmony_ci	/*
20248c2ecf20Sopenharmony_ci	 * Abort if someone did the work whilst we waited for the locks.  If we
20258c2ecf20Sopenharmony_ci	 * just converted the attribute from resident to non-resident it is
20268c2ecf20Sopenharmony_ci	 * likely that exactly this has happened already.  We cannot quite
20278c2ecf20Sopenharmony_ci	 * abort if we need to update the data size.
20288c2ecf20Sopenharmony_ci	 */
20298c2ecf20Sopenharmony_ci	if (unlikely(new_alloc_size <= allocated_size)) {
20308c2ecf20Sopenharmony_ci		ntfs_debug("Allocated size already exceeds requested size.");
20318c2ecf20Sopenharmony_ci		new_alloc_size = allocated_size;
20328c2ecf20Sopenharmony_ci		if (new_data_size < 0)
20338c2ecf20Sopenharmony_ci			goto done;
20348c2ecf20Sopenharmony_ci		/*
20358c2ecf20Sopenharmony_ci		 * We want the first attribute extent so that we can update the
20368c2ecf20Sopenharmony_ci		 * data size.
20378c2ecf20Sopenharmony_ci		 */
20388c2ecf20Sopenharmony_ci		vcn = 0;
20398c2ecf20Sopenharmony_ci	}
20408c2ecf20Sopenharmony_ci	err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len,
20418c2ecf20Sopenharmony_ci			CASE_SENSITIVE, vcn, NULL, 0, ctx);
20428c2ecf20Sopenharmony_ci	if (unlikely(err)) {
20438c2ecf20Sopenharmony_ci		if (err == -ENOENT)
20448c2ecf20Sopenharmony_ci			err = -EIO;
20458c2ecf20Sopenharmony_ci		goto err_out;
20468c2ecf20Sopenharmony_ci	}
20478c2ecf20Sopenharmony_ci	m = ctx->mrec;
20488c2ecf20Sopenharmony_ci	a = ctx->attr;
20498c2ecf20Sopenharmony_ci	/* Use goto to reduce indentation. */
20508c2ecf20Sopenharmony_ci	if (a->non_resident)
20518c2ecf20Sopenharmony_ci		goto do_non_resident_extend;
20528c2ecf20Sopenharmony_ci	BUG_ON(NInoNonResident(ni));
20538c2ecf20Sopenharmony_ci	/* The total length of the attribute value. */
20548c2ecf20Sopenharmony_ci	attr_len = le32_to_cpu(a->data.resident.value_length);
20558c2ecf20Sopenharmony_ci	/*
20568c2ecf20Sopenharmony_ci	 * Extend the attribute record to be able to store the new attribute
20578c2ecf20Sopenharmony_ci	 * size.  ntfs_attr_record_resize() will not do anything if the size is
20588c2ecf20Sopenharmony_ci	 * not changing.
20598c2ecf20Sopenharmony_ci	 */
20608c2ecf20Sopenharmony_ci	if (new_alloc_size < vol->mft_record_size &&
20618c2ecf20Sopenharmony_ci			!ntfs_attr_record_resize(m, a,
20628c2ecf20Sopenharmony_ci			le16_to_cpu(a->data.resident.value_offset) +
20638c2ecf20Sopenharmony_ci			new_alloc_size)) {
20648c2ecf20Sopenharmony_ci		/* The resize succeeded! */
20658c2ecf20Sopenharmony_ci		write_lock_irqsave(&ni->size_lock, flags);
20668c2ecf20Sopenharmony_ci		ni->allocated_size = le32_to_cpu(a->length) -
20678c2ecf20Sopenharmony_ci				le16_to_cpu(a->data.resident.value_offset);
20688c2ecf20Sopenharmony_ci		write_unlock_irqrestore(&ni->size_lock, flags);
20698c2ecf20Sopenharmony_ci		if (new_data_size >= 0) {
20708c2ecf20Sopenharmony_ci			BUG_ON(new_data_size < attr_len);
20718c2ecf20Sopenharmony_ci			a->data.resident.value_length =
20728c2ecf20Sopenharmony_ci					cpu_to_le32((u32)new_data_size);
20738c2ecf20Sopenharmony_ci		}
20748c2ecf20Sopenharmony_ci		goto flush_done;
20758c2ecf20Sopenharmony_ci	}
20768c2ecf20Sopenharmony_ci	/*
20778c2ecf20Sopenharmony_ci	 * We have to drop all the locks so we can call
20788c2ecf20Sopenharmony_ci	 * ntfs_attr_make_non_resident().  This could be optimised by try-
20798c2ecf20Sopenharmony_ci	 * locking the first page cache page and only if that fails dropping
20808c2ecf20Sopenharmony_ci	 * the locks, locking the page, and redoing all the locking and
20818c2ecf20Sopenharmony_ci	 * lookups.  While this would be a huge optimisation, it is not worth
20828c2ecf20Sopenharmony_ci	 * it as this is definitely a slow code path.
20838c2ecf20Sopenharmony_ci	 */
20848c2ecf20Sopenharmony_ci	ntfs_attr_put_search_ctx(ctx);
20858c2ecf20Sopenharmony_ci	unmap_mft_record(base_ni);
20868c2ecf20Sopenharmony_ci	up_write(&ni->runlist.lock);
20878c2ecf20Sopenharmony_ci	/*
20888c2ecf20Sopenharmony_ci	 * Not enough space in the mft record, try to make the attribute
20898c2ecf20Sopenharmony_ci	 * non-resident and if successful restart the extension process.
20908c2ecf20Sopenharmony_ci	 */
20918c2ecf20Sopenharmony_ci	err = ntfs_attr_make_non_resident(ni, attr_len);
20928c2ecf20Sopenharmony_ci	if (likely(!err))
20938c2ecf20Sopenharmony_ci		goto retry_extend;
20948c2ecf20Sopenharmony_ci	/*
20958c2ecf20Sopenharmony_ci	 * Could not make non-resident.  If this is due to this not being
20968c2ecf20Sopenharmony_ci	 * permitted for this attribute type or there not being enough space,
20978c2ecf20Sopenharmony_ci	 * try to make other attributes non-resident.  Otherwise fail.
20988c2ecf20Sopenharmony_ci	 */
20998c2ecf20Sopenharmony_ci	if (unlikely(err != -EPERM && err != -ENOSPC)) {
21008c2ecf20Sopenharmony_ci		/* Only emit errors when the write will fail completely. */
21018c2ecf20Sopenharmony_ci		read_lock_irqsave(&ni->size_lock, flags);
21028c2ecf20Sopenharmony_ci		allocated_size = ni->allocated_size;
21038c2ecf20Sopenharmony_ci		read_unlock_irqrestore(&ni->size_lock, flags);
21048c2ecf20Sopenharmony_ci		if (start < 0 || start >= allocated_size)
21058c2ecf20Sopenharmony_ci			ntfs_error(vol->sb, "Cannot extend allocation of "
21068c2ecf20Sopenharmony_ci					"inode 0x%lx, attribute type 0x%x, "
21078c2ecf20Sopenharmony_ci					"because the conversion from resident "
21088c2ecf20Sopenharmony_ci					"to non-resident attribute failed "
21098c2ecf20Sopenharmony_ci					"with error code %i.", vi->i_ino,
21108c2ecf20Sopenharmony_ci					(unsigned)le32_to_cpu(ni->type), err);
21118c2ecf20Sopenharmony_ci		if (err != -ENOMEM)
21128c2ecf20Sopenharmony_ci			err = -EIO;
21138c2ecf20Sopenharmony_ci		goto conv_err_out;
21148c2ecf20Sopenharmony_ci	}
21158c2ecf20Sopenharmony_ci	/* TODO: Not implemented from here, abort. */
21168c2ecf20Sopenharmony_ci	read_lock_irqsave(&ni->size_lock, flags);
21178c2ecf20Sopenharmony_ci	allocated_size = ni->allocated_size;
21188c2ecf20Sopenharmony_ci	read_unlock_irqrestore(&ni->size_lock, flags);
21198c2ecf20Sopenharmony_ci	if (start < 0 || start >= allocated_size) {
21208c2ecf20Sopenharmony_ci		if (err == -ENOSPC)
21218c2ecf20Sopenharmony_ci			ntfs_error(vol->sb, "Not enough space in the mft "
21228c2ecf20Sopenharmony_ci					"record/on disk for the non-resident "
21238c2ecf20Sopenharmony_ci					"attribute value.  This case is not "
21248c2ecf20Sopenharmony_ci					"implemented yet.");
21258c2ecf20Sopenharmony_ci		else /* if (err == -EPERM) */
21268c2ecf20Sopenharmony_ci			ntfs_error(vol->sb, "This attribute type may not be "
21278c2ecf20Sopenharmony_ci					"non-resident.  This case is not "
21288c2ecf20Sopenharmony_ci					"implemented yet.");
21298c2ecf20Sopenharmony_ci	}
21308c2ecf20Sopenharmony_ci	err = -EOPNOTSUPP;
21318c2ecf20Sopenharmony_ci	goto conv_err_out;
21328c2ecf20Sopenharmony_ci#if 0
21338c2ecf20Sopenharmony_ci	// TODO: Attempt to make other attributes non-resident.
21348c2ecf20Sopenharmony_ci	if (!err)
21358c2ecf20Sopenharmony_ci		goto do_resident_extend;
21368c2ecf20Sopenharmony_ci	/*
21378c2ecf20Sopenharmony_ci	 * Both the attribute list attribute and the standard information
21388c2ecf20Sopenharmony_ci	 * attribute must remain in the base inode.  Thus, if this is one of
21398c2ecf20Sopenharmony_ci	 * these attributes, we have to try to move other attributes out into
21408c2ecf20Sopenharmony_ci	 * extent mft records instead.
21418c2ecf20Sopenharmony_ci	 */
21428c2ecf20Sopenharmony_ci	if (ni->type == AT_ATTRIBUTE_LIST ||
21438c2ecf20Sopenharmony_ci			ni->type == AT_STANDARD_INFORMATION) {
21448c2ecf20Sopenharmony_ci		// TODO: Attempt to move other attributes into extent mft
21458c2ecf20Sopenharmony_ci		// records.
21468c2ecf20Sopenharmony_ci		err = -EOPNOTSUPP;
21478c2ecf20Sopenharmony_ci		if (!err)
21488c2ecf20Sopenharmony_ci			goto do_resident_extend;
21498c2ecf20Sopenharmony_ci		goto err_out;
21508c2ecf20Sopenharmony_ci	}
21518c2ecf20Sopenharmony_ci	// TODO: Attempt to move this attribute to an extent mft record, but
21528c2ecf20Sopenharmony_ci	// only if it is not already the only attribute in an mft record in
21538c2ecf20Sopenharmony_ci	// which case there would be nothing to gain.
21548c2ecf20Sopenharmony_ci	err = -EOPNOTSUPP;
21558c2ecf20Sopenharmony_ci	if (!err)
21568c2ecf20Sopenharmony_ci		goto do_resident_extend;
21578c2ecf20Sopenharmony_ci	/* There is nothing we can do to make enough space. )-: */
21588c2ecf20Sopenharmony_ci	goto err_out;
21598c2ecf20Sopenharmony_ci#endif
21608c2ecf20Sopenharmony_cido_non_resident_extend:
21618c2ecf20Sopenharmony_ci	BUG_ON(!NInoNonResident(ni));
21628c2ecf20Sopenharmony_ci	if (new_alloc_size == allocated_size) {
21638c2ecf20Sopenharmony_ci		BUG_ON(vcn);
21648c2ecf20Sopenharmony_ci		goto alloc_done;
21658c2ecf20Sopenharmony_ci	}
21668c2ecf20Sopenharmony_ci	/*
21678c2ecf20Sopenharmony_ci	 * If the data starts after the end of the old allocation, this is a
21688c2ecf20Sopenharmony_ci	 * $DATA attribute and sparse attributes are enabled on the volume and
21698c2ecf20Sopenharmony_ci	 * for this inode, then create a sparse region between the old
21708c2ecf20Sopenharmony_ci	 * allocated size and the start of the data.  Otherwise simply proceed
21718c2ecf20Sopenharmony_ci	 * with filling the whole space between the old allocated size and the
21728c2ecf20Sopenharmony_ci	 * new allocated size with clusters.
21738c2ecf20Sopenharmony_ci	 */
21748c2ecf20Sopenharmony_ci	if ((start >= 0 && start <= allocated_size) || ni->type != AT_DATA ||
21758c2ecf20Sopenharmony_ci			!NVolSparseEnabled(vol) || NInoSparseDisabled(ni))
21768c2ecf20Sopenharmony_ci		goto skip_sparse;
21778c2ecf20Sopenharmony_ci	// TODO: This is not implemented yet.  We just fill in with real
21788c2ecf20Sopenharmony_ci	// clusters for now...
21798c2ecf20Sopenharmony_ci	ntfs_debug("Inserting holes is not-implemented yet.  Falling back to "
21808c2ecf20Sopenharmony_ci			"allocating real clusters instead.");
21818c2ecf20Sopenharmony_ciskip_sparse:
21828c2ecf20Sopenharmony_ci	rl = ni->runlist.rl;
21838c2ecf20Sopenharmony_ci	if (likely(rl)) {
21848c2ecf20Sopenharmony_ci		/* Seek to the end of the runlist. */
21858c2ecf20Sopenharmony_ci		while (rl->length)
21868c2ecf20Sopenharmony_ci			rl++;
21878c2ecf20Sopenharmony_ci	}
21888c2ecf20Sopenharmony_ci	/* If this attribute extent is not mapped, map it now. */
21898c2ecf20Sopenharmony_ci	if (unlikely(!rl || rl->lcn == LCN_RL_NOT_MAPPED ||
21908c2ecf20Sopenharmony_ci			(rl->lcn == LCN_ENOENT && rl > ni->runlist.rl &&
21918c2ecf20Sopenharmony_ci			(rl-1)->lcn == LCN_RL_NOT_MAPPED))) {
21928c2ecf20Sopenharmony_ci		if (!rl && !allocated_size)
21938c2ecf20Sopenharmony_ci			goto first_alloc;
21948c2ecf20Sopenharmony_ci		rl = ntfs_mapping_pairs_decompress(vol, a, ni->runlist.rl);
21958c2ecf20Sopenharmony_ci		if (IS_ERR(rl)) {
21968c2ecf20Sopenharmony_ci			err = PTR_ERR(rl);
21978c2ecf20Sopenharmony_ci			if (start < 0 || start >= allocated_size)
21988c2ecf20Sopenharmony_ci				ntfs_error(vol->sb, "Cannot extend allocation "
21998c2ecf20Sopenharmony_ci						"of inode 0x%lx, attribute "
22008c2ecf20Sopenharmony_ci						"type 0x%x, because the "
22018c2ecf20Sopenharmony_ci						"mapping of a runlist "
22028c2ecf20Sopenharmony_ci						"fragment failed with error "
22038c2ecf20Sopenharmony_ci						"code %i.", vi->i_ino,
22048c2ecf20Sopenharmony_ci						(unsigned)le32_to_cpu(ni->type),
22058c2ecf20Sopenharmony_ci						err);
22068c2ecf20Sopenharmony_ci			if (err != -ENOMEM)
22078c2ecf20Sopenharmony_ci				err = -EIO;
22088c2ecf20Sopenharmony_ci			goto err_out;
22098c2ecf20Sopenharmony_ci		}
22108c2ecf20Sopenharmony_ci		ni->runlist.rl = rl;
22118c2ecf20Sopenharmony_ci		/* Seek to the end of the runlist. */
22128c2ecf20Sopenharmony_ci		while (rl->length)
22138c2ecf20Sopenharmony_ci			rl++;
22148c2ecf20Sopenharmony_ci	}
22158c2ecf20Sopenharmony_ci	/*
22168c2ecf20Sopenharmony_ci	 * We now know the runlist of the last extent is mapped and @rl is at
22178c2ecf20Sopenharmony_ci	 * the end of the runlist.  We want to begin allocating clusters
22188c2ecf20Sopenharmony_ci	 * starting at the last allocated cluster to reduce fragmentation.  If
22198c2ecf20Sopenharmony_ci	 * there are no valid LCNs in the attribute we let the cluster
22208c2ecf20Sopenharmony_ci	 * allocator choose the starting cluster.
22218c2ecf20Sopenharmony_ci	 */
22228c2ecf20Sopenharmony_ci	/* If the last LCN is a hole or simillar seek back to last real LCN. */
22238c2ecf20Sopenharmony_ci	while (rl->lcn < 0 && rl > ni->runlist.rl)
22248c2ecf20Sopenharmony_ci		rl--;
22258c2ecf20Sopenharmony_cifirst_alloc:
22268c2ecf20Sopenharmony_ci	// FIXME: Need to implement partial allocations so at least part of the
22278c2ecf20Sopenharmony_ci	// write can be performed when start >= 0.  (Needed for POSIX write(2)
22288c2ecf20Sopenharmony_ci	// conformance.)
22298c2ecf20Sopenharmony_ci	rl2 = ntfs_cluster_alloc(vol, allocated_size >> vol->cluster_size_bits,
22308c2ecf20Sopenharmony_ci			(new_alloc_size - allocated_size) >>
22318c2ecf20Sopenharmony_ci			vol->cluster_size_bits, (rl && (rl->lcn >= 0)) ?
22328c2ecf20Sopenharmony_ci			rl->lcn + rl->length : -1, DATA_ZONE, true);
22338c2ecf20Sopenharmony_ci	if (IS_ERR(rl2)) {
22348c2ecf20Sopenharmony_ci		err = PTR_ERR(rl2);
22358c2ecf20Sopenharmony_ci		if (start < 0 || start >= allocated_size)
22368c2ecf20Sopenharmony_ci			ntfs_error(vol->sb, "Cannot extend allocation of "
22378c2ecf20Sopenharmony_ci					"inode 0x%lx, attribute type 0x%x, "
22388c2ecf20Sopenharmony_ci					"because the allocation of clusters "
22398c2ecf20Sopenharmony_ci					"failed with error code %i.", vi->i_ino,
22408c2ecf20Sopenharmony_ci					(unsigned)le32_to_cpu(ni->type), err);
22418c2ecf20Sopenharmony_ci		if (err != -ENOMEM && err != -ENOSPC)
22428c2ecf20Sopenharmony_ci			err = -EIO;
22438c2ecf20Sopenharmony_ci		goto err_out;
22448c2ecf20Sopenharmony_ci	}
22458c2ecf20Sopenharmony_ci	rl = ntfs_runlists_merge(ni->runlist.rl, rl2);
22468c2ecf20Sopenharmony_ci	if (IS_ERR(rl)) {
22478c2ecf20Sopenharmony_ci		err = PTR_ERR(rl);
22488c2ecf20Sopenharmony_ci		if (start < 0 || start >= allocated_size)
22498c2ecf20Sopenharmony_ci			ntfs_error(vol->sb, "Cannot extend allocation of "
22508c2ecf20Sopenharmony_ci					"inode 0x%lx, attribute type 0x%x, "
22518c2ecf20Sopenharmony_ci					"because the runlist merge failed "
22528c2ecf20Sopenharmony_ci					"with error code %i.", vi->i_ino,
22538c2ecf20Sopenharmony_ci					(unsigned)le32_to_cpu(ni->type), err);
22548c2ecf20Sopenharmony_ci		if (err != -ENOMEM)
22558c2ecf20Sopenharmony_ci			err = -EIO;
22568c2ecf20Sopenharmony_ci		if (ntfs_cluster_free_from_rl(vol, rl2)) {
22578c2ecf20Sopenharmony_ci			ntfs_error(vol->sb, "Failed to release allocated "
22588c2ecf20Sopenharmony_ci					"cluster(s) in error code path.  Run "
22598c2ecf20Sopenharmony_ci					"chkdsk to recover the lost "
22608c2ecf20Sopenharmony_ci					"cluster(s).");
22618c2ecf20Sopenharmony_ci			NVolSetErrors(vol);
22628c2ecf20Sopenharmony_ci		}
22638c2ecf20Sopenharmony_ci		ntfs_free(rl2);
22648c2ecf20Sopenharmony_ci		goto err_out;
22658c2ecf20Sopenharmony_ci	}
22668c2ecf20Sopenharmony_ci	ni->runlist.rl = rl;
22678c2ecf20Sopenharmony_ci	ntfs_debug("Allocated 0x%llx clusters.", (long long)(new_alloc_size -
22688c2ecf20Sopenharmony_ci			allocated_size) >> vol->cluster_size_bits);
22698c2ecf20Sopenharmony_ci	/* Find the runlist element with which the attribute extent starts. */
22708c2ecf20Sopenharmony_ci	ll = sle64_to_cpu(a->data.non_resident.lowest_vcn);
22718c2ecf20Sopenharmony_ci	rl2 = ntfs_rl_find_vcn_nolock(rl, ll);
22728c2ecf20Sopenharmony_ci	BUG_ON(!rl2);
22738c2ecf20Sopenharmony_ci	BUG_ON(!rl2->length);
22748c2ecf20Sopenharmony_ci	BUG_ON(rl2->lcn < LCN_HOLE);
22758c2ecf20Sopenharmony_ci	mp_rebuilt = false;
22768c2ecf20Sopenharmony_ci	/* Get the size for the new mapping pairs array for this extent. */
22778c2ecf20Sopenharmony_ci	mp_size = ntfs_get_size_for_mapping_pairs(vol, rl2, ll, -1);
22788c2ecf20Sopenharmony_ci	if (unlikely(mp_size <= 0)) {
22798c2ecf20Sopenharmony_ci		err = mp_size;
22808c2ecf20Sopenharmony_ci		if (start < 0 || start >= allocated_size)
22818c2ecf20Sopenharmony_ci			ntfs_error(vol->sb, "Cannot extend allocation of "
22828c2ecf20Sopenharmony_ci					"inode 0x%lx, attribute type 0x%x, "
22838c2ecf20Sopenharmony_ci					"because determining the size for the "
22848c2ecf20Sopenharmony_ci					"mapping pairs failed with error code "
22858c2ecf20Sopenharmony_ci					"%i.", vi->i_ino,
22868c2ecf20Sopenharmony_ci					(unsigned)le32_to_cpu(ni->type), err);
22878c2ecf20Sopenharmony_ci		err = -EIO;
22888c2ecf20Sopenharmony_ci		goto undo_alloc;
22898c2ecf20Sopenharmony_ci	}
22908c2ecf20Sopenharmony_ci	/* Extend the attribute record to fit the bigger mapping pairs array. */
22918c2ecf20Sopenharmony_ci	attr_len = le32_to_cpu(a->length);
22928c2ecf20Sopenharmony_ci	err = ntfs_attr_record_resize(m, a, mp_size +
22938c2ecf20Sopenharmony_ci			le16_to_cpu(a->data.non_resident.mapping_pairs_offset));
22948c2ecf20Sopenharmony_ci	if (unlikely(err)) {
22958c2ecf20Sopenharmony_ci		BUG_ON(err != -ENOSPC);
22968c2ecf20Sopenharmony_ci		// TODO: Deal with this by moving this extent to a new mft
22978c2ecf20Sopenharmony_ci		// record or by starting a new extent in a new mft record,
22988c2ecf20Sopenharmony_ci		// possibly by extending this extent partially and filling it
22998c2ecf20Sopenharmony_ci		// and creating a new extent for the remainder, or by making
23008c2ecf20Sopenharmony_ci		// other attributes non-resident and/or by moving other
23018c2ecf20Sopenharmony_ci		// attributes out of this mft record.
23028c2ecf20Sopenharmony_ci		if (start < 0 || start >= allocated_size)
23038c2ecf20Sopenharmony_ci			ntfs_error(vol->sb, "Not enough space in the mft "
23048c2ecf20Sopenharmony_ci					"record for the extended attribute "
23058c2ecf20Sopenharmony_ci					"record.  This case is not "
23068c2ecf20Sopenharmony_ci					"implemented yet.");
23078c2ecf20Sopenharmony_ci		err = -EOPNOTSUPP;
23088c2ecf20Sopenharmony_ci		goto undo_alloc;
23098c2ecf20Sopenharmony_ci	}
23108c2ecf20Sopenharmony_ci	mp_rebuilt = true;
23118c2ecf20Sopenharmony_ci	/* Generate the mapping pairs array directly into the attr record. */
23128c2ecf20Sopenharmony_ci	err = ntfs_mapping_pairs_build(vol, (u8*)a +
23138c2ecf20Sopenharmony_ci			le16_to_cpu(a->data.non_resident.mapping_pairs_offset),
23148c2ecf20Sopenharmony_ci			mp_size, rl2, ll, -1, NULL);
23158c2ecf20Sopenharmony_ci	if (unlikely(err)) {
23168c2ecf20Sopenharmony_ci		if (start < 0 || start >= allocated_size)
23178c2ecf20Sopenharmony_ci			ntfs_error(vol->sb, "Cannot extend allocation of "
23188c2ecf20Sopenharmony_ci					"inode 0x%lx, attribute type 0x%x, "
23198c2ecf20Sopenharmony_ci					"because building the mapping pairs "
23208c2ecf20Sopenharmony_ci					"failed with error code %i.", vi->i_ino,
23218c2ecf20Sopenharmony_ci					(unsigned)le32_to_cpu(ni->type), err);
23228c2ecf20Sopenharmony_ci		err = -EIO;
23238c2ecf20Sopenharmony_ci		goto undo_alloc;
23248c2ecf20Sopenharmony_ci	}
23258c2ecf20Sopenharmony_ci	/* Update the highest_vcn. */
23268c2ecf20Sopenharmony_ci	a->data.non_resident.highest_vcn = cpu_to_sle64((new_alloc_size >>
23278c2ecf20Sopenharmony_ci			vol->cluster_size_bits) - 1);
23288c2ecf20Sopenharmony_ci	/*
23298c2ecf20Sopenharmony_ci	 * We now have extended the allocated size of the attribute.  Reflect
23308c2ecf20Sopenharmony_ci	 * this in the ntfs_inode structure and the attribute record.
23318c2ecf20Sopenharmony_ci	 */
23328c2ecf20Sopenharmony_ci	if (a->data.non_resident.lowest_vcn) {
23338c2ecf20Sopenharmony_ci		/*
23348c2ecf20Sopenharmony_ci		 * We are not in the first attribute extent, switch to it, but
23358c2ecf20Sopenharmony_ci		 * first ensure the changes will make it to disk later.
23368c2ecf20Sopenharmony_ci		 */
23378c2ecf20Sopenharmony_ci		flush_dcache_mft_record_page(ctx->ntfs_ino);
23388c2ecf20Sopenharmony_ci		mark_mft_record_dirty(ctx->ntfs_ino);
23398c2ecf20Sopenharmony_ci		ntfs_attr_reinit_search_ctx(ctx);
23408c2ecf20Sopenharmony_ci		err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len,
23418c2ecf20Sopenharmony_ci				CASE_SENSITIVE, 0, NULL, 0, ctx);
23428c2ecf20Sopenharmony_ci		if (unlikely(err))
23438c2ecf20Sopenharmony_ci			goto restore_undo_alloc;
23448c2ecf20Sopenharmony_ci		/* @m is not used any more so no need to set it. */
23458c2ecf20Sopenharmony_ci		a = ctx->attr;
23468c2ecf20Sopenharmony_ci	}
23478c2ecf20Sopenharmony_ci	write_lock_irqsave(&ni->size_lock, flags);
23488c2ecf20Sopenharmony_ci	ni->allocated_size = new_alloc_size;
23498c2ecf20Sopenharmony_ci	a->data.non_resident.allocated_size = cpu_to_sle64(new_alloc_size);
23508c2ecf20Sopenharmony_ci	/*
23518c2ecf20Sopenharmony_ci	 * FIXME: This would fail if @ni is a directory, $MFT, or an index,
23528c2ecf20Sopenharmony_ci	 * since those can have sparse/compressed set.  For example can be
23538c2ecf20Sopenharmony_ci	 * set compressed even though it is not compressed itself and in that
23548c2ecf20Sopenharmony_ci	 * case the bit means that files are to be created compressed in the
23558c2ecf20Sopenharmony_ci	 * directory...  At present this is ok as this code is only called for
23568c2ecf20Sopenharmony_ci	 * regular files, and only for their $DATA attribute(s).
23578c2ecf20Sopenharmony_ci	 * FIXME: The calculation is wrong if we created a hole above.  For now
23588c2ecf20Sopenharmony_ci	 * it does not matter as we never create holes.
23598c2ecf20Sopenharmony_ci	 */
23608c2ecf20Sopenharmony_ci	if (NInoSparse(ni) || NInoCompressed(ni)) {
23618c2ecf20Sopenharmony_ci		ni->itype.compressed.size += new_alloc_size - allocated_size;
23628c2ecf20Sopenharmony_ci		a->data.non_resident.compressed_size =
23638c2ecf20Sopenharmony_ci				cpu_to_sle64(ni->itype.compressed.size);
23648c2ecf20Sopenharmony_ci		vi->i_blocks = ni->itype.compressed.size >> 9;
23658c2ecf20Sopenharmony_ci	} else
23668c2ecf20Sopenharmony_ci		vi->i_blocks = new_alloc_size >> 9;
23678c2ecf20Sopenharmony_ci	write_unlock_irqrestore(&ni->size_lock, flags);
23688c2ecf20Sopenharmony_cialloc_done:
23698c2ecf20Sopenharmony_ci	if (new_data_size >= 0) {
23708c2ecf20Sopenharmony_ci		BUG_ON(new_data_size <
23718c2ecf20Sopenharmony_ci				sle64_to_cpu(a->data.non_resident.data_size));
23728c2ecf20Sopenharmony_ci		a->data.non_resident.data_size = cpu_to_sle64(new_data_size);
23738c2ecf20Sopenharmony_ci	}
23748c2ecf20Sopenharmony_ciflush_done:
23758c2ecf20Sopenharmony_ci	/* Ensure the changes make it to disk. */
23768c2ecf20Sopenharmony_ci	flush_dcache_mft_record_page(ctx->ntfs_ino);
23778c2ecf20Sopenharmony_ci	mark_mft_record_dirty(ctx->ntfs_ino);
23788c2ecf20Sopenharmony_cidone:
23798c2ecf20Sopenharmony_ci	ntfs_attr_put_search_ctx(ctx);
23808c2ecf20Sopenharmony_ci	unmap_mft_record(base_ni);
23818c2ecf20Sopenharmony_ci	up_write(&ni->runlist.lock);
23828c2ecf20Sopenharmony_ci	ntfs_debug("Done, new_allocated_size 0x%llx.",
23838c2ecf20Sopenharmony_ci			(unsigned long long)new_alloc_size);
23848c2ecf20Sopenharmony_ci	return new_alloc_size;
23858c2ecf20Sopenharmony_cirestore_undo_alloc:
23868c2ecf20Sopenharmony_ci	if (start < 0 || start >= allocated_size)
23878c2ecf20Sopenharmony_ci		ntfs_error(vol->sb, "Cannot complete extension of allocation "
23888c2ecf20Sopenharmony_ci				"of inode 0x%lx, attribute type 0x%x, because "
23898c2ecf20Sopenharmony_ci				"lookup of first attribute extent failed with "
23908c2ecf20Sopenharmony_ci				"error code %i.", vi->i_ino,
23918c2ecf20Sopenharmony_ci				(unsigned)le32_to_cpu(ni->type), err);
23928c2ecf20Sopenharmony_ci	if (err == -ENOENT)
23938c2ecf20Sopenharmony_ci		err = -EIO;
23948c2ecf20Sopenharmony_ci	ntfs_attr_reinit_search_ctx(ctx);
23958c2ecf20Sopenharmony_ci	if (ntfs_attr_lookup(ni->type, ni->name, ni->name_len, CASE_SENSITIVE,
23968c2ecf20Sopenharmony_ci			allocated_size >> vol->cluster_size_bits, NULL, 0,
23978c2ecf20Sopenharmony_ci			ctx)) {
23988c2ecf20Sopenharmony_ci		ntfs_error(vol->sb, "Failed to find last attribute extent of "
23998c2ecf20Sopenharmony_ci				"attribute in error code path.  Run chkdsk to "
24008c2ecf20Sopenharmony_ci				"recover.");
24018c2ecf20Sopenharmony_ci		write_lock_irqsave(&ni->size_lock, flags);
24028c2ecf20Sopenharmony_ci		ni->allocated_size = new_alloc_size;
24038c2ecf20Sopenharmony_ci		/*
24048c2ecf20Sopenharmony_ci		 * FIXME: This would fail if @ni is a directory...  See above.
24058c2ecf20Sopenharmony_ci		 * FIXME: The calculation is wrong if we created a hole above.
24068c2ecf20Sopenharmony_ci		 * For now it does not matter as we never create holes.
24078c2ecf20Sopenharmony_ci		 */
24088c2ecf20Sopenharmony_ci		if (NInoSparse(ni) || NInoCompressed(ni)) {
24098c2ecf20Sopenharmony_ci			ni->itype.compressed.size += new_alloc_size -
24108c2ecf20Sopenharmony_ci					allocated_size;
24118c2ecf20Sopenharmony_ci			vi->i_blocks = ni->itype.compressed.size >> 9;
24128c2ecf20Sopenharmony_ci		} else
24138c2ecf20Sopenharmony_ci			vi->i_blocks = new_alloc_size >> 9;
24148c2ecf20Sopenharmony_ci		write_unlock_irqrestore(&ni->size_lock, flags);
24158c2ecf20Sopenharmony_ci		ntfs_attr_put_search_ctx(ctx);
24168c2ecf20Sopenharmony_ci		unmap_mft_record(base_ni);
24178c2ecf20Sopenharmony_ci		up_write(&ni->runlist.lock);
24188c2ecf20Sopenharmony_ci		/*
24198c2ecf20Sopenharmony_ci		 * The only thing that is now wrong is the allocated size of the
24208c2ecf20Sopenharmony_ci		 * base attribute extent which chkdsk should be able to fix.
24218c2ecf20Sopenharmony_ci		 */
24228c2ecf20Sopenharmony_ci		NVolSetErrors(vol);
24238c2ecf20Sopenharmony_ci		return err;
24248c2ecf20Sopenharmony_ci	}
24258c2ecf20Sopenharmony_ci	ctx->attr->data.non_resident.highest_vcn = cpu_to_sle64(
24268c2ecf20Sopenharmony_ci			(allocated_size >> vol->cluster_size_bits) - 1);
24278c2ecf20Sopenharmony_ciundo_alloc:
24288c2ecf20Sopenharmony_ci	ll = allocated_size >> vol->cluster_size_bits;
24298c2ecf20Sopenharmony_ci	if (ntfs_cluster_free(ni, ll, -1, ctx) < 0) {
24308c2ecf20Sopenharmony_ci		ntfs_error(vol->sb, "Failed to release allocated cluster(s) "
24318c2ecf20Sopenharmony_ci				"in error code path.  Run chkdsk to recover "
24328c2ecf20Sopenharmony_ci				"the lost cluster(s).");
24338c2ecf20Sopenharmony_ci		NVolSetErrors(vol);
24348c2ecf20Sopenharmony_ci	}
24358c2ecf20Sopenharmony_ci	m = ctx->mrec;
24368c2ecf20Sopenharmony_ci	a = ctx->attr;
24378c2ecf20Sopenharmony_ci	/*
24388c2ecf20Sopenharmony_ci	 * If the runlist truncation fails and/or the search context is no
24398c2ecf20Sopenharmony_ci	 * longer valid, we cannot resize the attribute record or build the
24408c2ecf20Sopenharmony_ci	 * mapping pairs array thus we mark the inode bad so that no access to
24418c2ecf20Sopenharmony_ci	 * the freed clusters can happen.
24428c2ecf20Sopenharmony_ci	 */
24438c2ecf20Sopenharmony_ci	if (ntfs_rl_truncate_nolock(vol, &ni->runlist, ll) || IS_ERR(m)) {
24448c2ecf20Sopenharmony_ci		ntfs_error(vol->sb, "Failed to %s in error code path.  Run "
24458c2ecf20Sopenharmony_ci				"chkdsk to recover.", IS_ERR(m) ?
24468c2ecf20Sopenharmony_ci				"restore attribute search context" :
24478c2ecf20Sopenharmony_ci				"truncate attribute runlist");
24488c2ecf20Sopenharmony_ci		NVolSetErrors(vol);
24498c2ecf20Sopenharmony_ci	} else if (mp_rebuilt) {
24508c2ecf20Sopenharmony_ci		if (ntfs_attr_record_resize(m, a, attr_len)) {
24518c2ecf20Sopenharmony_ci			ntfs_error(vol->sb, "Failed to restore attribute "
24528c2ecf20Sopenharmony_ci					"record in error code path.  Run "
24538c2ecf20Sopenharmony_ci					"chkdsk to recover.");
24548c2ecf20Sopenharmony_ci			NVolSetErrors(vol);
24558c2ecf20Sopenharmony_ci		} else /* if (success) */ {
24568c2ecf20Sopenharmony_ci			if (ntfs_mapping_pairs_build(vol, (u8*)a + le16_to_cpu(
24578c2ecf20Sopenharmony_ci					a->data.non_resident.
24588c2ecf20Sopenharmony_ci					mapping_pairs_offset), attr_len -
24598c2ecf20Sopenharmony_ci					le16_to_cpu(a->data.non_resident.
24608c2ecf20Sopenharmony_ci					mapping_pairs_offset), rl2, ll, -1,
24618c2ecf20Sopenharmony_ci					NULL)) {
24628c2ecf20Sopenharmony_ci				ntfs_error(vol->sb, "Failed to restore "
24638c2ecf20Sopenharmony_ci						"mapping pairs array in error "
24648c2ecf20Sopenharmony_ci						"code path.  Run chkdsk to "
24658c2ecf20Sopenharmony_ci						"recover.");
24668c2ecf20Sopenharmony_ci				NVolSetErrors(vol);
24678c2ecf20Sopenharmony_ci			}
24688c2ecf20Sopenharmony_ci			flush_dcache_mft_record_page(ctx->ntfs_ino);
24698c2ecf20Sopenharmony_ci			mark_mft_record_dirty(ctx->ntfs_ino);
24708c2ecf20Sopenharmony_ci		}
24718c2ecf20Sopenharmony_ci	}
24728c2ecf20Sopenharmony_cierr_out:
24738c2ecf20Sopenharmony_ci	if (ctx)
24748c2ecf20Sopenharmony_ci		ntfs_attr_put_search_ctx(ctx);
24758c2ecf20Sopenharmony_ci	if (m)
24768c2ecf20Sopenharmony_ci		unmap_mft_record(base_ni);
24778c2ecf20Sopenharmony_ci	up_write(&ni->runlist.lock);
24788c2ecf20Sopenharmony_ciconv_err_out:
24798c2ecf20Sopenharmony_ci	ntfs_debug("Failed.  Returning error code %i.", err);
24808c2ecf20Sopenharmony_ci	return err;
24818c2ecf20Sopenharmony_ci}
24828c2ecf20Sopenharmony_ci
24838c2ecf20Sopenharmony_ci/**
24848c2ecf20Sopenharmony_ci * ntfs_attr_set - fill (a part of) an attribute with a byte
24858c2ecf20Sopenharmony_ci * @ni:		ntfs inode describing the attribute to fill
24868c2ecf20Sopenharmony_ci * @ofs:	offset inside the attribute at which to start to fill
24878c2ecf20Sopenharmony_ci * @cnt:	number of bytes to fill
24888c2ecf20Sopenharmony_ci * @val:	the unsigned 8-bit value with which to fill the attribute
24898c2ecf20Sopenharmony_ci *
24908c2ecf20Sopenharmony_ci * Fill @cnt bytes of the attribute described by the ntfs inode @ni starting at
24918c2ecf20Sopenharmony_ci * byte offset @ofs inside the attribute with the constant byte @val.
24928c2ecf20Sopenharmony_ci *
24938c2ecf20Sopenharmony_ci * This function is effectively like memset() applied to an ntfs attribute.
24948c2ecf20Sopenharmony_ci * Note thie function actually only operates on the page cache pages belonging
24958c2ecf20Sopenharmony_ci * to the ntfs attribute and it marks them dirty after doing the memset().
24968c2ecf20Sopenharmony_ci * Thus it relies on the vm dirty page write code paths to cause the modified
24978c2ecf20Sopenharmony_ci * pages to be written to the mft record/disk.
24988c2ecf20Sopenharmony_ci *
24998c2ecf20Sopenharmony_ci * Return 0 on success and -errno on error.  An error code of -ESPIPE means
25008c2ecf20Sopenharmony_ci * that @ofs + @cnt were outside the end of the attribute and no write was
25018c2ecf20Sopenharmony_ci * performed.
25028c2ecf20Sopenharmony_ci */
25038c2ecf20Sopenharmony_ciint ntfs_attr_set(ntfs_inode *ni, const s64 ofs, const s64 cnt, const u8 val)
25048c2ecf20Sopenharmony_ci{
25058c2ecf20Sopenharmony_ci	ntfs_volume *vol = ni->vol;
25068c2ecf20Sopenharmony_ci	struct address_space *mapping;
25078c2ecf20Sopenharmony_ci	struct page *page;
25088c2ecf20Sopenharmony_ci	u8 *kaddr;
25098c2ecf20Sopenharmony_ci	pgoff_t idx, end;
25108c2ecf20Sopenharmony_ci	unsigned start_ofs, end_ofs, size;
25118c2ecf20Sopenharmony_ci
25128c2ecf20Sopenharmony_ci	ntfs_debug("Entering for ofs 0x%llx, cnt 0x%llx, val 0x%hx.",
25138c2ecf20Sopenharmony_ci			(long long)ofs, (long long)cnt, val);
25148c2ecf20Sopenharmony_ci	BUG_ON(ofs < 0);
25158c2ecf20Sopenharmony_ci	BUG_ON(cnt < 0);
25168c2ecf20Sopenharmony_ci	if (!cnt)
25178c2ecf20Sopenharmony_ci		goto done;
25188c2ecf20Sopenharmony_ci	/*
25198c2ecf20Sopenharmony_ci	 * FIXME: Compressed and encrypted attributes are not supported when
25208c2ecf20Sopenharmony_ci	 * writing and we should never have gotten here for them.
25218c2ecf20Sopenharmony_ci	 */
25228c2ecf20Sopenharmony_ci	BUG_ON(NInoCompressed(ni));
25238c2ecf20Sopenharmony_ci	BUG_ON(NInoEncrypted(ni));
25248c2ecf20Sopenharmony_ci	mapping = VFS_I(ni)->i_mapping;
25258c2ecf20Sopenharmony_ci	/* Work out the starting index and page offset. */
25268c2ecf20Sopenharmony_ci	idx = ofs >> PAGE_SHIFT;
25278c2ecf20Sopenharmony_ci	start_ofs = ofs & ~PAGE_MASK;
25288c2ecf20Sopenharmony_ci	/* Work out the ending index and page offset. */
25298c2ecf20Sopenharmony_ci	end = ofs + cnt;
25308c2ecf20Sopenharmony_ci	end_ofs = end & ~PAGE_MASK;
25318c2ecf20Sopenharmony_ci	/* If the end is outside the inode size return -ESPIPE. */
25328c2ecf20Sopenharmony_ci	if (unlikely(end > i_size_read(VFS_I(ni)))) {
25338c2ecf20Sopenharmony_ci		ntfs_error(vol->sb, "Request exceeds end of attribute.");
25348c2ecf20Sopenharmony_ci		return -ESPIPE;
25358c2ecf20Sopenharmony_ci	}
25368c2ecf20Sopenharmony_ci	end >>= PAGE_SHIFT;
25378c2ecf20Sopenharmony_ci	/* If there is a first partial page, need to do it the slow way. */
25388c2ecf20Sopenharmony_ci	if (start_ofs) {
25398c2ecf20Sopenharmony_ci		page = read_mapping_page(mapping, idx, NULL);
25408c2ecf20Sopenharmony_ci		if (IS_ERR(page)) {
25418c2ecf20Sopenharmony_ci			ntfs_error(vol->sb, "Failed to read first partial "
25428c2ecf20Sopenharmony_ci					"page (error, index 0x%lx).", idx);
25438c2ecf20Sopenharmony_ci			return PTR_ERR(page);
25448c2ecf20Sopenharmony_ci		}
25458c2ecf20Sopenharmony_ci		/*
25468c2ecf20Sopenharmony_ci		 * If the last page is the same as the first page, need to
25478c2ecf20Sopenharmony_ci		 * limit the write to the end offset.
25488c2ecf20Sopenharmony_ci		 */
25498c2ecf20Sopenharmony_ci		size = PAGE_SIZE;
25508c2ecf20Sopenharmony_ci		if (idx == end)
25518c2ecf20Sopenharmony_ci			size = end_ofs;
25528c2ecf20Sopenharmony_ci		kaddr = kmap_atomic(page);
25538c2ecf20Sopenharmony_ci		memset(kaddr + start_ofs, val, size - start_ofs);
25548c2ecf20Sopenharmony_ci		flush_dcache_page(page);
25558c2ecf20Sopenharmony_ci		kunmap_atomic(kaddr);
25568c2ecf20Sopenharmony_ci		set_page_dirty(page);
25578c2ecf20Sopenharmony_ci		put_page(page);
25588c2ecf20Sopenharmony_ci		balance_dirty_pages_ratelimited(mapping);
25598c2ecf20Sopenharmony_ci		cond_resched();
25608c2ecf20Sopenharmony_ci		if (idx == end)
25618c2ecf20Sopenharmony_ci			goto done;
25628c2ecf20Sopenharmony_ci		idx++;
25638c2ecf20Sopenharmony_ci	}
25648c2ecf20Sopenharmony_ci	/* Do the whole pages the fast way. */
25658c2ecf20Sopenharmony_ci	for (; idx < end; idx++) {
25668c2ecf20Sopenharmony_ci		/* Find or create the current page.  (The page is locked.) */
25678c2ecf20Sopenharmony_ci		page = grab_cache_page(mapping, idx);
25688c2ecf20Sopenharmony_ci		if (unlikely(!page)) {
25698c2ecf20Sopenharmony_ci			ntfs_error(vol->sb, "Insufficient memory to grab "
25708c2ecf20Sopenharmony_ci					"page (index 0x%lx).", idx);
25718c2ecf20Sopenharmony_ci			return -ENOMEM;
25728c2ecf20Sopenharmony_ci		}
25738c2ecf20Sopenharmony_ci		kaddr = kmap_atomic(page);
25748c2ecf20Sopenharmony_ci		memset(kaddr, val, PAGE_SIZE);
25758c2ecf20Sopenharmony_ci		flush_dcache_page(page);
25768c2ecf20Sopenharmony_ci		kunmap_atomic(kaddr);
25778c2ecf20Sopenharmony_ci		/*
25788c2ecf20Sopenharmony_ci		 * If the page has buffers, mark them uptodate since buffer
25798c2ecf20Sopenharmony_ci		 * state and not page state is definitive in 2.6 kernels.
25808c2ecf20Sopenharmony_ci		 */
25818c2ecf20Sopenharmony_ci		if (page_has_buffers(page)) {
25828c2ecf20Sopenharmony_ci			struct buffer_head *bh, *head;
25838c2ecf20Sopenharmony_ci
25848c2ecf20Sopenharmony_ci			bh = head = page_buffers(page);
25858c2ecf20Sopenharmony_ci			do {
25868c2ecf20Sopenharmony_ci				set_buffer_uptodate(bh);
25878c2ecf20Sopenharmony_ci			} while ((bh = bh->b_this_page) != head);
25888c2ecf20Sopenharmony_ci		}
25898c2ecf20Sopenharmony_ci		/* Now that buffers are uptodate, set the page uptodate, too. */
25908c2ecf20Sopenharmony_ci		SetPageUptodate(page);
25918c2ecf20Sopenharmony_ci		/*
25928c2ecf20Sopenharmony_ci		 * Set the page and all its buffers dirty and mark the inode
25938c2ecf20Sopenharmony_ci		 * dirty, too.  The VM will write the page later on.
25948c2ecf20Sopenharmony_ci		 */
25958c2ecf20Sopenharmony_ci		set_page_dirty(page);
25968c2ecf20Sopenharmony_ci		/* Finally unlock and release the page. */
25978c2ecf20Sopenharmony_ci		unlock_page(page);
25988c2ecf20Sopenharmony_ci		put_page(page);
25998c2ecf20Sopenharmony_ci		balance_dirty_pages_ratelimited(mapping);
26008c2ecf20Sopenharmony_ci		cond_resched();
26018c2ecf20Sopenharmony_ci	}
26028c2ecf20Sopenharmony_ci	/* If there is a last partial page, need to do it the slow way. */
26038c2ecf20Sopenharmony_ci	if (end_ofs) {
26048c2ecf20Sopenharmony_ci		page = read_mapping_page(mapping, idx, NULL);
26058c2ecf20Sopenharmony_ci		if (IS_ERR(page)) {
26068c2ecf20Sopenharmony_ci			ntfs_error(vol->sb, "Failed to read last partial page "
26078c2ecf20Sopenharmony_ci					"(error, index 0x%lx).", idx);
26088c2ecf20Sopenharmony_ci			return PTR_ERR(page);
26098c2ecf20Sopenharmony_ci		}
26108c2ecf20Sopenharmony_ci		kaddr = kmap_atomic(page);
26118c2ecf20Sopenharmony_ci		memset(kaddr, val, end_ofs);
26128c2ecf20Sopenharmony_ci		flush_dcache_page(page);
26138c2ecf20Sopenharmony_ci		kunmap_atomic(kaddr);
26148c2ecf20Sopenharmony_ci		set_page_dirty(page);
26158c2ecf20Sopenharmony_ci		put_page(page);
26168c2ecf20Sopenharmony_ci		balance_dirty_pages_ratelimited(mapping);
26178c2ecf20Sopenharmony_ci		cond_resched();
26188c2ecf20Sopenharmony_ci	}
26198c2ecf20Sopenharmony_cidone:
26208c2ecf20Sopenharmony_ci	ntfs_debug("Done.");
26218c2ecf20Sopenharmony_ci	return 0;
26228c2ecf20Sopenharmony_ci}
26238c2ecf20Sopenharmony_ci
26248c2ecf20Sopenharmony_ci#endif /* NTFS_RW */
2625