1987da915Sopenharmony_ci/**
2987da915Sopenharmony_ci * attrib.c - Attribute handling code. Originated from the Linux-NTFS project.
3987da915Sopenharmony_ci *
4987da915Sopenharmony_ci * Copyright (c) 2000-2010 Anton Altaparmakov
5987da915Sopenharmony_ci * Copyright (c) 2002-2005 Richard Russon
6987da915Sopenharmony_ci * Copyright (c) 2002-2008 Szabolcs Szakacsits
7987da915Sopenharmony_ci * Copyright (c) 2004-2007 Yura Pakhuchiy
8987da915Sopenharmony_ci * Copyright (c) 2007-2021 Jean-Pierre Andre
9987da915Sopenharmony_ci * Copyright (c) 2010      Erik Larsson
10987da915Sopenharmony_ci *
11987da915Sopenharmony_ci * This program/include file is free software; you can redistribute it and/or
12987da915Sopenharmony_ci * modify it under the terms of the GNU General Public License as published
13987da915Sopenharmony_ci * by the Free Software Foundation; either version 2 of the License, or
14987da915Sopenharmony_ci * (at your option) any later version.
15987da915Sopenharmony_ci *
16987da915Sopenharmony_ci * This program/include file is distributed in the hope that it will be
17987da915Sopenharmony_ci * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
18987da915Sopenharmony_ci * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19987da915Sopenharmony_ci * GNU General Public License for more details.
20987da915Sopenharmony_ci *
21987da915Sopenharmony_ci * You should have received a copy of the GNU General Public License
22987da915Sopenharmony_ci * along with this program (in the main directory of the NTFS-3G
23987da915Sopenharmony_ci * distribution in the file COPYING); if not, write to the Free Software
24987da915Sopenharmony_ci * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
25987da915Sopenharmony_ci */
26987da915Sopenharmony_ci
27987da915Sopenharmony_ci#ifdef HAVE_CONFIG_H
28987da915Sopenharmony_ci#include "config.h"
29987da915Sopenharmony_ci#endif
30987da915Sopenharmony_ci
31987da915Sopenharmony_ci#ifdef HAVE_STDIO_H
32987da915Sopenharmony_ci#include <stdio.h>
33987da915Sopenharmony_ci#endif
34987da915Sopenharmony_ci#ifdef HAVE_STRING_H
35987da915Sopenharmony_ci#include <string.h>
36987da915Sopenharmony_ci#endif
37987da915Sopenharmony_ci#ifdef HAVE_STDLIB_H
38987da915Sopenharmony_ci#include <stdlib.h>
39987da915Sopenharmony_ci#endif
40987da915Sopenharmony_ci#ifdef HAVE_ERRNO_H
41987da915Sopenharmony_ci#include <errno.h>
42987da915Sopenharmony_ci#endif
43987da915Sopenharmony_ci#ifdef HAVE_LIMITS_H
44987da915Sopenharmony_ci#include <limits.h>
45987da915Sopenharmony_ci#endif
46987da915Sopenharmony_ci
47987da915Sopenharmony_ci#include "param.h"
48987da915Sopenharmony_ci#include "compat.h"
49987da915Sopenharmony_ci#include "attrib.h"
50987da915Sopenharmony_ci#include "attrlist.h"
51987da915Sopenharmony_ci#include "device.h"
52987da915Sopenharmony_ci#include "mft.h"
53987da915Sopenharmony_ci#include "debug.h"
54987da915Sopenharmony_ci#include "mst.h"
55987da915Sopenharmony_ci#include "volume.h"
56987da915Sopenharmony_ci#include "types.h"
57987da915Sopenharmony_ci#include "layout.h"
58987da915Sopenharmony_ci#include "inode.h"
59987da915Sopenharmony_ci#include "runlist.h"
60987da915Sopenharmony_ci#include "lcnalloc.h"
61987da915Sopenharmony_ci#include "dir.h"
62987da915Sopenharmony_ci#include "compress.h"
63987da915Sopenharmony_ci#include "bitmap.h"
64987da915Sopenharmony_ci#include "logging.h"
65987da915Sopenharmony_ci#include "misc.h"
66987da915Sopenharmony_ci#include "efs.h"
67987da915Sopenharmony_ci
68987da915Sopenharmony_cintfschar AT_UNNAMED[] = { const_cpu_to_le16('\0') };
69987da915Sopenharmony_cintfschar STREAM_SDS[] = { const_cpu_to_le16('$'),
70987da915Sopenharmony_ci			const_cpu_to_le16('S'),
71987da915Sopenharmony_ci			const_cpu_to_le16('D'),
72987da915Sopenharmony_ci			const_cpu_to_le16('S'),
73987da915Sopenharmony_ci			const_cpu_to_le16('\0') };
74987da915Sopenharmony_ci
75987da915Sopenharmony_cintfschar TXF_DATA[] = { const_cpu_to_le16('$'),
76987da915Sopenharmony_ci			const_cpu_to_le16('T'),
77987da915Sopenharmony_ci			const_cpu_to_le16('X'),
78987da915Sopenharmony_ci			const_cpu_to_le16('F'),
79987da915Sopenharmony_ci			const_cpu_to_le16('_'),
80987da915Sopenharmony_ci			const_cpu_to_le16('D'),
81987da915Sopenharmony_ci			const_cpu_to_le16('A'),
82987da915Sopenharmony_ci			const_cpu_to_le16('T'),
83987da915Sopenharmony_ci			const_cpu_to_le16('A'),
84987da915Sopenharmony_ci			const_cpu_to_le16('\0') };
85987da915Sopenharmony_ci
86987da915Sopenharmony_cistatic int NAttrFlag(ntfs_attr *na, FILE_ATTR_FLAGS flag)
87987da915Sopenharmony_ci{
88987da915Sopenharmony_ci	if (na->type == AT_DATA && na->name == AT_UNNAMED)
89987da915Sopenharmony_ci		return (na->ni->flags & flag);
90987da915Sopenharmony_ci	return 0;
91987da915Sopenharmony_ci}
92987da915Sopenharmony_ci
93987da915Sopenharmony_cistatic void NAttrSetFlag(ntfs_attr *na, FILE_ATTR_FLAGS flag)
94987da915Sopenharmony_ci{
95987da915Sopenharmony_ci	if (na->type == AT_DATA && na->name == AT_UNNAMED)
96987da915Sopenharmony_ci		na->ni->flags |= flag;
97987da915Sopenharmony_ci	else
98987da915Sopenharmony_ci		ntfs_log_trace("Denied setting flag %d for not unnamed data "
99987da915Sopenharmony_ci			       "attribute\n", le32_to_cpu(flag));
100987da915Sopenharmony_ci}
101987da915Sopenharmony_ci
102987da915Sopenharmony_cistatic void NAttrClearFlag(ntfs_attr *na, FILE_ATTR_FLAGS flag)
103987da915Sopenharmony_ci{
104987da915Sopenharmony_ci	if (na->type == AT_DATA && na->name == AT_UNNAMED)
105987da915Sopenharmony_ci		na->ni->flags &= ~flag;
106987da915Sopenharmony_ci}
107987da915Sopenharmony_ci
108987da915Sopenharmony_ci#define GenNAttrIno(func_name, flag)					\
109987da915Sopenharmony_ciint NAttr##func_name(ntfs_attr *na) { return NAttrFlag   (na, flag); } 	\
110987da915Sopenharmony_civoid NAttrSet##func_name(ntfs_attr *na)	 { NAttrSetFlag  (na, flag); }	\
111987da915Sopenharmony_civoid NAttrClear##func_name(ntfs_attr *na){ NAttrClearFlag(na, flag); }
112987da915Sopenharmony_ci
113987da915Sopenharmony_ciGenNAttrIno(Compressed, FILE_ATTR_COMPRESSED)
114987da915Sopenharmony_ciGenNAttrIno(Encrypted, 	FILE_ATTR_ENCRYPTED)
115987da915Sopenharmony_ciGenNAttrIno(Sparse, 	FILE_ATTR_SPARSE_FILE)
116987da915Sopenharmony_ci
117987da915Sopenharmony_ci/**
118987da915Sopenharmony_ci * ntfs_get_attribute_value_length - Find the length of an attribute
119987da915Sopenharmony_ci * @a:
120987da915Sopenharmony_ci *
121987da915Sopenharmony_ci * Description...
122987da915Sopenharmony_ci *
123987da915Sopenharmony_ci * Returns:
124987da915Sopenharmony_ci */
125987da915Sopenharmony_cis64 ntfs_get_attribute_value_length(const ATTR_RECORD *a)
126987da915Sopenharmony_ci{
127987da915Sopenharmony_ci	if (!a) {
128987da915Sopenharmony_ci		errno = EINVAL;
129987da915Sopenharmony_ci		return 0;
130987da915Sopenharmony_ci	}
131987da915Sopenharmony_ci	errno = 0;
132987da915Sopenharmony_ci	if (a->non_resident)
133987da915Sopenharmony_ci		return sle64_to_cpu(a->data_size);
134987da915Sopenharmony_ci
135987da915Sopenharmony_ci	return (s64)le32_to_cpu(a->value_length);
136987da915Sopenharmony_ci}
137987da915Sopenharmony_ci
138987da915Sopenharmony_ci/**
139987da915Sopenharmony_ci * ntfs_get_attribute_value - Get a copy of an attribute
140987da915Sopenharmony_ci * @vol:
141987da915Sopenharmony_ci * @a:
142987da915Sopenharmony_ci * @b:
143987da915Sopenharmony_ci *
144987da915Sopenharmony_ci * Description...
145987da915Sopenharmony_ci *
146987da915Sopenharmony_ci * Returns:
147987da915Sopenharmony_ci */
148987da915Sopenharmony_cis64 ntfs_get_attribute_value(const ntfs_volume *vol,
149987da915Sopenharmony_ci		const ATTR_RECORD *a, u8 *b)
150987da915Sopenharmony_ci{
151987da915Sopenharmony_ci	runlist *rl;
152987da915Sopenharmony_ci	s64 total, r;
153987da915Sopenharmony_ci	int i;
154987da915Sopenharmony_ci
155987da915Sopenharmony_ci	/* Sanity checks. */
156987da915Sopenharmony_ci	if (!vol || !a || !b) {
157987da915Sopenharmony_ci		errno = EINVAL;
158987da915Sopenharmony_ci		return 0;
159987da915Sopenharmony_ci	}
160987da915Sopenharmony_ci	/* Complex attribute? */
161987da915Sopenharmony_ci	/*
162987da915Sopenharmony_ci	 * Ignore the flags in case they are not zero for an attribute list
163987da915Sopenharmony_ci	 * attribute.  Windows does not complain about invalid flags and chkdsk
164987da915Sopenharmony_ci	 * does not detect or fix them so we need to cope with it, too.
165987da915Sopenharmony_ci	 */
166987da915Sopenharmony_ci	if (a->type != AT_ATTRIBUTE_LIST && a->flags) {
167987da915Sopenharmony_ci		ntfs_log_error("Non-zero (%04x) attribute flags. Cannot handle "
168987da915Sopenharmony_ci			       "this yet.\n", le16_to_cpu(a->flags));
169987da915Sopenharmony_ci		errno = EOPNOTSUPP;
170987da915Sopenharmony_ci		return 0;
171987da915Sopenharmony_ci	}
172987da915Sopenharmony_ci	if (!a->non_resident) {
173987da915Sopenharmony_ci		/* Attribute is resident. */
174987da915Sopenharmony_ci
175987da915Sopenharmony_ci		/* Sanity check. */
176987da915Sopenharmony_ci		if (le32_to_cpu(a->value_length) + le16_to_cpu(a->value_offset)
177987da915Sopenharmony_ci				> le32_to_cpu(a->length)) {
178987da915Sopenharmony_ci			return 0;
179987da915Sopenharmony_ci		}
180987da915Sopenharmony_ci
181987da915Sopenharmony_ci		memcpy(b, (const char*)a + le16_to_cpu(a->value_offset),
182987da915Sopenharmony_ci				le32_to_cpu(a->value_length));
183987da915Sopenharmony_ci		errno = 0;
184987da915Sopenharmony_ci		return (s64)le32_to_cpu(a->value_length);
185987da915Sopenharmony_ci	}
186987da915Sopenharmony_ci
187987da915Sopenharmony_ci	/* Attribute is not resident. */
188987da915Sopenharmony_ci
189987da915Sopenharmony_ci	/* If no data, return 0. */
190987da915Sopenharmony_ci	if (!(a->data_size)) {
191987da915Sopenharmony_ci		errno = 0;
192987da915Sopenharmony_ci		return 0;
193987da915Sopenharmony_ci	}
194987da915Sopenharmony_ci	/*
195987da915Sopenharmony_ci	 * FIXME: What about attribute lists?!? (AIA)
196987da915Sopenharmony_ci	 */
197987da915Sopenharmony_ci	/* Decompress the mapping pairs array into a runlist. */
198987da915Sopenharmony_ci	rl = ntfs_mapping_pairs_decompress(vol, a, NULL);
199987da915Sopenharmony_ci	if (!rl) {
200987da915Sopenharmony_ci		errno = EINVAL;
201987da915Sopenharmony_ci		return 0;
202987da915Sopenharmony_ci	}
203987da915Sopenharmony_ci	/*
204987da915Sopenharmony_ci	 * FIXED: We were overflowing here in a nasty fashion when we
205987da915Sopenharmony_ci	 * reach the last cluster in the runlist as the buffer will
206987da915Sopenharmony_ci	 * only be big enough to hold data_size bytes while we are
207987da915Sopenharmony_ci	 * reading in allocated_size bytes which is usually larger
208987da915Sopenharmony_ci	 * than data_size, since the actual data is unlikely to have a
209987da915Sopenharmony_ci	 * size equal to a multiple of the cluster size!
210987da915Sopenharmony_ci	 * FIXED2:  We were also overflowing here in the same fashion
211987da915Sopenharmony_ci	 * when the data_size was more than one run smaller than the
212987da915Sopenharmony_ci	 * allocated size which happens with Windows XP sometimes.
213987da915Sopenharmony_ci	 */
214987da915Sopenharmony_ci	/* Now load all clusters in the runlist into b. */
215987da915Sopenharmony_ci	for (i = 0, total = 0; rl[i].length; i++) {
216987da915Sopenharmony_ci		if (total + (rl[i].length << vol->cluster_size_bits) >=
217987da915Sopenharmony_ci				sle64_to_cpu(a->data_size)) {
218987da915Sopenharmony_ci			unsigned char *intbuf = NULL;
219987da915Sopenharmony_ci			s64 intlth;
220987da915Sopenharmony_ci			/*
221987da915Sopenharmony_ci			 * We have reached the last run so we were going to
222987da915Sopenharmony_ci			 * overflow when executing the ntfs_pread() which is
223987da915Sopenharmony_ci			 * BAAAAAAAD!
224987da915Sopenharmony_ci			 * Temporary fix:
225987da915Sopenharmony_ci			 *	Allocate a new buffer with size:
226987da915Sopenharmony_ci			 *	rl[i].length << vol->cluster_size_bits, do the
227987da915Sopenharmony_ci			 *	read into our buffer, then memcpy the correct
228987da915Sopenharmony_ci			 *	amount of data into the caller supplied buffer,
229987da915Sopenharmony_ci			 *	free our buffer, and continue.
230987da915Sopenharmony_ci			 * We have reached the end of data size so we were
231987da915Sopenharmony_ci			 * going to overflow in the same fashion.
232987da915Sopenharmony_ci			 * Temporary fix:  same as above.
233987da915Sopenharmony_ci			 *
234987da915Sopenharmony_ci			 * For safety, limit the amount to read to the
235987da915Sopenharmony_ci			 * needed size, knowing that the whole attribute
236987da915Sopenharmony_ci			 * size has been checked to be <= 0x40000.
237987da915Sopenharmony_ci			 */
238987da915Sopenharmony_ci			intlth = (sle64_to_cpu(a->data_size) - total
239987da915Sopenharmony_ci					+ vol->cluster_size - 1)
240987da915Sopenharmony_ci					>> vol->cluster_size_bits;
241987da915Sopenharmony_ci			if (rl[i].length < intlth)
242987da915Sopenharmony_ci				intlth = rl[i].length;
243987da915Sopenharmony_ci			intbuf = (u8*)ntfs_malloc(intlth
244987da915Sopenharmony_ci						<< vol->cluster_size_bits);
245987da915Sopenharmony_ci			if (!intbuf) {
246987da915Sopenharmony_ci				free(rl);
247987da915Sopenharmony_ci				return 0;
248987da915Sopenharmony_ci			}
249987da915Sopenharmony_ci			/*
250987da915Sopenharmony_ci			 * FIXME: If compressed file: Only read if lcn != -1.
251987da915Sopenharmony_ci			 * Otherwise, we are dealing with a sparse run and we
252987da915Sopenharmony_ci			 * just memset the user buffer to 0 for the length of
253987da915Sopenharmony_ci			 * the run, which should be 16 (= compression unit
254987da915Sopenharmony_ci			 * size).
255987da915Sopenharmony_ci			 * FIXME: Really only when file is compressed, or can
256987da915Sopenharmony_ci			 * we have sparse runs in uncompressed files as well?
257987da915Sopenharmony_ci			 * - Yes we can, in sparse files! But not necessarily
258987da915Sopenharmony_ci			 * size of 16, just run length.
259987da915Sopenharmony_ci			 */
260987da915Sopenharmony_ci			r = ntfs_pread(vol->dev,
261987da915Sopenharmony_ci					rl[i].lcn << vol->cluster_size_bits,
262987da915Sopenharmony_ci					intlth << vol->cluster_size_bits,
263987da915Sopenharmony_ci					intbuf);
264987da915Sopenharmony_ci			if (r != intlth << vol->cluster_size_bits) {
265987da915Sopenharmony_ci#define ESTR "Error reading attribute value"
266987da915Sopenharmony_ci				if (r == -1)
267987da915Sopenharmony_ci					ntfs_log_perror(ESTR);
268987da915Sopenharmony_ci				else if (r < intlth <<
269987da915Sopenharmony_ci						vol->cluster_size_bits) {
270987da915Sopenharmony_ci					ntfs_log_debug(ESTR ": Ran out of input data.\n");
271987da915Sopenharmony_ci					errno = EIO;
272987da915Sopenharmony_ci				} else {
273987da915Sopenharmony_ci					ntfs_log_debug(ESTR ": unknown error\n");
274987da915Sopenharmony_ci					errno = EIO;
275987da915Sopenharmony_ci				}
276987da915Sopenharmony_ci#undef ESTR
277987da915Sopenharmony_ci				free(rl);
278987da915Sopenharmony_ci				free(intbuf);
279987da915Sopenharmony_ci				return 0;
280987da915Sopenharmony_ci			}
281987da915Sopenharmony_ci			memcpy(b + total, intbuf, sle64_to_cpu(a->data_size) -
282987da915Sopenharmony_ci					total);
283987da915Sopenharmony_ci			free(intbuf);
284987da915Sopenharmony_ci			total = sle64_to_cpu(a->data_size);
285987da915Sopenharmony_ci			break;
286987da915Sopenharmony_ci		}
287987da915Sopenharmony_ci		/*
288987da915Sopenharmony_ci		 * FIXME: If compressed file: Only read if lcn != -1.
289987da915Sopenharmony_ci		 * Otherwise, we are dealing with a sparse run and we just
290987da915Sopenharmony_ci		 * memset the user buffer to 0 for the length of the run, which
291987da915Sopenharmony_ci		 * should be 16 (= compression unit size).
292987da915Sopenharmony_ci		 * FIXME: Really only when file is compressed, or can
293987da915Sopenharmony_ci		 * we have sparse runs in uncompressed files as well?
294987da915Sopenharmony_ci		 * - Yes we can, in sparse files! But not necessarily size of
295987da915Sopenharmony_ci		 * 16, just run length.
296987da915Sopenharmony_ci		 */
297987da915Sopenharmony_ci		r = ntfs_pread(vol->dev, rl[i].lcn << vol->cluster_size_bits,
298987da915Sopenharmony_ci				rl[i].length << vol->cluster_size_bits,
299987da915Sopenharmony_ci				b + total);
300987da915Sopenharmony_ci		if (r != rl[i].length << vol->cluster_size_bits) {
301987da915Sopenharmony_ci#define ESTR "Error reading attribute value"
302987da915Sopenharmony_ci			if (r == -1)
303987da915Sopenharmony_ci				ntfs_log_perror(ESTR);
304987da915Sopenharmony_ci			else if (r < rl[i].length << vol->cluster_size_bits) {
305987da915Sopenharmony_ci				ntfs_log_debug(ESTR ": Ran out of input data.\n");
306987da915Sopenharmony_ci				errno = EIO;
307987da915Sopenharmony_ci			} else {
308987da915Sopenharmony_ci				ntfs_log_debug(ESTR ": unknown error\n");
309987da915Sopenharmony_ci				errno = EIO;
310987da915Sopenharmony_ci			}
311987da915Sopenharmony_ci#undef ESTR
312987da915Sopenharmony_ci			free(rl);
313987da915Sopenharmony_ci			return 0;
314987da915Sopenharmony_ci		}
315987da915Sopenharmony_ci		total += r;
316987da915Sopenharmony_ci	}
317987da915Sopenharmony_ci	free(rl);
318987da915Sopenharmony_ci	return total;
319987da915Sopenharmony_ci}
320987da915Sopenharmony_ci
321987da915Sopenharmony_ci/* Already cleaned up code below, but still look for FIXME:... */
322987da915Sopenharmony_ci
323987da915Sopenharmony_ci/**
324987da915Sopenharmony_ci * __ntfs_attr_init - primary initialization of an ntfs attribute structure
325987da915Sopenharmony_ci * @na:		ntfs attribute to initialize
326987da915Sopenharmony_ci * @ni:		ntfs inode with which to initialize the ntfs attribute
327987da915Sopenharmony_ci * @type:	attribute type
328987da915Sopenharmony_ci * @name:	attribute name in little endian Unicode or NULL
329987da915Sopenharmony_ci * @name_len:	length of attribute @name in Unicode characters (if @name given)
330987da915Sopenharmony_ci *
331987da915Sopenharmony_ci * Initialize the ntfs attribute @na with @ni, @type, @name, and @name_len.
332987da915Sopenharmony_ci */
333987da915Sopenharmony_cistatic void __ntfs_attr_init(ntfs_attr *na, ntfs_inode *ni,
334987da915Sopenharmony_ci		const ATTR_TYPES type, ntfschar *name, const u32 name_len)
335987da915Sopenharmony_ci{
336987da915Sopenharmony_ci	na->rl = NULL;
337987da915Sopenharmony_ci	na->ni = ni;
338987da915Sopenharmony_ci	na->type = type;
339987da915Sopenharmony_ci	na->name = name;
340987da915Sopenharmony_ci	if (name)
341987da915Sopenharmony_ci		na->name_len = name_len;
342987da915Sopenharmony_ci	else
343987da915Sopenharmony_ci		na->name_len = 0;
344987da915Sopenharmony_ci}
345987da915Sopenharmony_ci
346987da915Sopenharmony_ci/**
347987da915Sopenharmony_ci * ntfs_attr_init - initialize an ntfs_attr with data sizes and status
348987da915Sopenharmony_ci * @na:
349987da915Sopenharmony_ci * @non_resident:
350987da915Sopenharmony_ci * @compressed:
351987da915Sopenharmony_ci * @encrypted:
352987da915Sopenharmony_ci * @sparse:
353987da915Sopenharmony_ci * @allocated_size:
354987da915Sopenharmony_ci * @data_size:
355987da915Sopenharmony_ci * @initialized_size:
356987da915Sopenharmony_ci * @compressed_size:
357987da915Sopenharmony_ci * @compression_unit:
358987da915Sopenharmony_ci *
359987da915Sopenharmony_ci * Final initialization for an ntfs attribute.
360987da915Sopenharmony_ci */
361987da915Sopenharmony_civoid ntfs_attr_init(ntfs_attr *na, const BOOL non_resident,
362987da915Sopenharmony_ci		const ATTR_FLAGS data_flags,
363987da915Sopenharmony_ci		const BOOL encrypted, const BOOL sparse,
364987da915Sopenharmony_ci		const s64 allocated_size, const s64 data_size,
365987da915Sopenharmony_ci		const s64 initialized_size, const s64 compressed_size,
366987da915Sopenharmony_ci		const u8 compression_unit)
367987da915Sopenharmony_ci{
368987da915Sopenharmony_ci	if (!NAttrInitialized(na)) {
369987da915Sopenharmony_ci		na->data_flags = data_flags;
370987da915Sopenharmony_ci		if (non_resident)
371987da915Sopenharmony_ci			NAttrSetNonResident(na);
372987da915Sopenharmony_ci		if (data_flags & ATTR_COMPRESSION_MASK)
373987da915Sopenharmony_ci			NAttrSetCompressed(na);
374987da915Sopenharmony_ci		if (encrypted)
375987da915Sopenharmony_ci			NAttrSetEncrypted(na);
376987da915Sopenharmony_ci		if (sparse)
377987da915Sopenharmony_ci			NAttrSetSparse(na);
378987da915Sopenharmony_ci		na->allocated_size = allocated_size;
379987da915Sopenharmony_ci		na->data_size = data_size;
380987da915Sopenharmony_ci		na->initialized_size = initialized_size;
381987da915Sopenharmony_ci		if ((data_flags & ATTR_COMPRESSION_MASK) || sparse) {
382987da915Sopenharmony_ci			ntfs_volume *vol = na->ni->vol;
383987da915Sopenharmony_ci
384987da915Sopenharmony_ci			na->compressed_size = compressed_size;
385987da915Sopenharmony_ci			na->compression_block_clusters = 1 << compression_unit;
386987da915Sopenharmony_ci			na->compression_block_size = 1 << (compression_unit +
387987da915Sopenharmony_ci					vol->cluster_size_bits);
388987da915Sopenharmony_ci			na->compression_block_size_bits = ffs(
389987da915Sopenharmony_ci					na->compression_block_size) - 1;
390987da915Sopenharmony_ci		}
391987da915Sopenharmony_ci		NAttrSetInitialized(na);
392987da915Sopenharmony_ci	}
393987da915Sopenharmony_ci}
394987da915Sopenharmony_ci
395987da915Sopenharmony_ci/**
396987da915Sopenharmony_ci * ntfs_attr_open - open an ntfs attribute for access
397987da915Sopenharmony_ci * @ni:		open ntfs inode in which the ntfs attribute resides
398987da915Sopenharmony_ci * @type:	attribute type
399987da915Sopenharmony_ci * @name:	attribute name in little endian Unicode or AT_UNNAMED or NULL
400987da915Sopenharmony_ci * @name_len:	length of attribute @name in Unicode characters (if @name given)
401987da915Sopenharmony_ci *
402987da915Sopenharmony_ci * Allocate a new ntfs attribute structure, initialize it with @ni, @type,
403987da915Sopenharmony_ci * @name, and @name_len, then return it. Return NULL on error with
404987da915Sopenharmony_ci * errno set to the error code.
405987da915Sopenharmony_ci *
406987da915Sopenharmony_ci * If @name is AT_UNNAMED look specifically for an unnamed attribute.  If you
407987da915Sopenharmony_ci * do not care whether the attribute is named or not set @name to NULL.  In
408987da915Sopenharmony_ci * both those cases @name_len is not used at all.
409987da915Sopenharmony_ci */
410987da915Sopenharmony_cintfs_attr *ntfs_attr_open(ntfs_inode *ni, const ATTR_TYPES type,
411987da915Sopenharmony_ci		ntfschar *name, u32 name_len)
412987da915Sopenharmony_ci{
413987da915Sopenharmony_ci	ntfs_attr_search_ctx *ctx;
414987da915Sopenharmony_ci	ntfs_attr *na = NULL;
415987da915Sopenharmony_ci	ntfschar *newname = NULL;
416987da915Sopenharmony_ci	ATTR_RECORD *a;
417987da915Sopenharmony_ci	le16 cs;
418987da915Sopenharmony_ci
419987da915Sopenharmony_ci	ntfs_log_enter("Entering for inode %lld, attr 0x%x.\n",
420987da915Sopenharmony_ci		       (unsigned long long)ni->mft_no, le32_to_cpu(type));
421987da915Sopenharmony_ci
422987da915Sopenharmony_ci	if (!ni || !ni->vol || !ni->mrec) {
423987da915Sopenharmony_ci		errno = EINVAL;
424987da915Sopenharmony_ci		goto out;
425987da915Sopenharmony_ci	}
426987da915Sopenharmony_ci	na = ntfs_calloc(sizeof(ntfs_attr));
427987da915Sopenharmony_ci	if (!na)
428987da915Sopenharmony_ci		goto out;
429987da915Sopenharmony_ci	if (!name_len)
430987da915Sopenharmony_ci		name = (ntfschar*)NULL;
431987da915Sopenharmony_ci	if (name && name != AT_UNNAMED && name != NTFS_INDEX_I30) {
432987da915Sopenharmony_ci		/* A null char leads to a short name and unallocated bytes */
433987da915Sopenharmony_ci		if (ntfs_ucsnlen(name, name_len) != name_len) {
434987da915Sopenharmony_ci			ntfs_log_error("Null character in attribute name"
435987da915Sopenharmony_ci				" of inode %lld\n",(long long)ni->mft_no);
436987da915Sopenharmony_ci			goto err_out;
437987da915Sopenharmony_ci		}
438987da915Sopenharmony_ci		name = ntfs_ucsndup(name, name_len);
439987da915Sopenharmony_ci		if (!name)
440987da915Sopenharmony_ci			goto err_out;
441987da915Sopenharmony_ci		newname = name;
442987da915Sopenharmony_ci	}
443987da915Sopenharmony_ci
444987da915Sopenharmony_ci	ctx = ntfs_attr_get_search_ctx(ni, NULL);
445987da915Sopenharmony_ci	if (!ctx)
446987da915Sopenharmony_ci		goto err_out;
447987da915Sopenharmony_ci
448987da915Sopenharmony_ci	if (ntfs_attr_lookup(type, name, name_len, 0, 0, NULL, 0, ctx))
449987da915Sopenharmony_ci		goto put_err_out;
450987da915Sopenharmony_ci
451987da915Sopenharmony_ci	a = ctx->attr;
452987da915Sopenharmony_ci
453987da915Sopenharmony_ci	if (!name) {
454987da915Sopenharmony_ci		if (a->name_length) {
455987da915Sopenharmony_ci			ntfschar *attr_name;
456987da915Sopenharmony_ci
457987da915Sopenharmony_ci			attr_name = (ntfschar*)((u8*)a
458987da915Sopenharmony_ci					+ le16_to_cpu(a->name_offset));
459987da915Sopenharmony_ci			/* A null character leads to illegal memory access */
460987da915Sopenharmony_ci			if (ntfs_ucsnlen(attr_name, a->name_length)
461987da915Sopenharmony_ci						!= a->name_length) {
462987da915Sopenharmony_ci				ntfs_log_error("Null character in attribute"
463987da915Sopenharmony_ci					" name in inode %lld\n",
464987da915Sopenharmony_ci					(long long)ni->mft_no);
465987da915Sopenharmony_ci				goto put_err_out;
466987da915Sopenharmony_ci			}
467987da915Sopenharmony_ci			name = ntfs_ucsndup(attr_name, a->name_length);
468987da915Sopenharmony_ci			if (!name)
469987da915Sopenharmony_ci				goto put_err_out;
470987da915Sopenharmony_ci			newname = name;
471987da915Sopenharmony_ci			name_len = a->name_length;
472987da915Sopenharmony_ci		} else {
473987da915Sopenharmony_ci			name = AT_UNNAMED;
474987da915Sopenharmony_ci			name_len = 0;
475987da915Sopenharmony_ci		}
476987da915Sopenharmony_ci	}
477987da915Sopenharmony_ci
478987da915Sopenharmony_ci	__ntfs_attr_init(na, ni, type, name, name_len);
479987da915Sopenharmony_ci
480987da915Sopenharmony_ci	/*
481987da915Sopenharmony_ci	 * Wipe the flags in case they are not zero for an attribute list
482987da915Sopenharmony_ci	 * attribute.  Windows does not complain about invalid flags and chkdsk
483987da915Sopenharmony_ci	 * does not detect or fix them so we need to cope with it, too.
484987da915Sopenharmony_ci	 */
485987da915Sopenharmony_ci	if (type == AT_ATTRIBUTE_LIST)
486987da915Sopenharmony_ci		a->flags = const_cpu_to_le16(0);
487987da915Sopenharmony_ci
488987da915Sopenharmony_ci	if ((type == AT_DATA)
489987da915Sopenharmony_ci	   && (a->non_resident ? !a->initialized_size : !a->value_length)) {
490987da915Sopenharmony_ci		/*
491987da915Sopenharmony_ci		 * Define/redefine the compression state if stream is
492987da915Sopenharmony_ci		 * empty, based on the compression mark on parent
493987da915Sopenharmony_ci		 * directory (for unnamed data streams) or on current
494987da915Sopenharmony_ci		 * inode (for named data streams). The compression mark
495987da915Sopenharmony_ci		 * may change any time, the compression state can only
496987da915Sopenharmony_ci		 * change when stream is wiped out.
497987da915Sopenharmony_ci		 *
498987da915Sopenharmony_ci		 * Also prevent compression on NTFS version < 3.0
499987da915Sopenharmony_ci		 * or cluster size > 4K or compression is disabled
500987da915Sopenharmony_ci		 */
501987da915Sopenharmony_ci		a->flags &= ~ATTR_COMPRESSION_MASK;
502987da915Sopenharmony_ci		if ((ni->flags & FILE_ATTR_COMPRESSED)
503987da915Sopenharmony_ci		    && (ni->vol->major_ver >= 3)
504987da915Sopenharmony_ci		    && NVolCompression(ni->vol)
505987da915Sopenharmony_ci		    && (ni->vol->cluster_size <= MAX_COMPRESSION_CLUSTER_SIZE))
506987da915Sopenharmony_ci			a->flags |= ATTR_IS_COMPRESSED;
507987da915Sopenharmony_ci	}
508987da915Sopenharmony_ci
509987da915Sopenharmony_ci	cs = a->flags & (ATTR_IS_COMPRESSED | ATTR_IS_SPARSE);
510987da915Sopenharmony_ci
511987da915Sopenharmony_ci	/* a file may be sparse though its unnamed data is not (cf $UsnJrnl) */
512987da915Sopenharmony_ci	if (na->type == AT_DATA && na->name == AT_UNNAMED &&
513987da915Sopenharmony_ci	    (((a->flags & ATTR_IS_SPARSE)     && !NAttrSparse(na)) ||
514987da915Sopenharmony_ci	     (!(a->flags & ATTR_IS_ENCRYPTED)  != !NAttrEncrypted(na)))) {
515987da915Sopenharmony_ci		errno = EIO;
516987da915Sopenharmony_ci		ntfs_log_perror("Inode %lld has corrupt attribute flags "
517987da915Sopenharmony_ci				"(0x%x <> 0x%x)",(unsigned long long)ni->mft_no,
518987da915Sopenharmony_ci				le16_to_cpu(a->flags), le32_to_cpu(na->ni->flags));
519987da915Sopenharmony_ci		goto put_err_out;
520987da915Sopenharmony_ci	}
521987da915Sopenharmony_ci
522987da915Sopenharmony_ci	if (a->non_resident) {
523987da915Sopenharmony_ci		if (((a->flags & ATTR_COMPRESSION_MASK)
524987da915Sopenharmony_ci			|| a->compression_unit)
525987da915Sopenharmony_ci		    && (ni->vol->major_ver < 3)) {
526987da915Sopenharmony_ci			errno = EIO;
527987da915Sopenharmony_ci			ntfs_log_perror("Compressed inode %lld not allowed"
528987da915Sopenharmony_ci					" on NTFS %d.%d",
529987da915Sopenharmony_ci					(unsigned long long)ni->mft_no,
530987da915Sopenharmony_ci					ni->vol->major_ver,
531987da915Sopenharmony_ci					ni->vol->major_ver);
532987da915Sopenharmony_ci			goto put_err_out;
533987da915Sopenharmony_ci		}
534987da915Sopenharmony_ci		if ((a->flags & ATTR_COMPRESSION_MASK)
535987da915Sopenharmony_ci				 && !a->compression_unit) {
536987da915Sopenharmony_ci			errno = EIO;
537987da915Sopenharmony_ci			ntfs_log_perror("Compressed inode %lld attr 0x%x has "
538987da915Sopenharmony_ci					"no compression unit",
539987da915Sopenharmony_ci					(unsigned long long)ni->mft_no, le32_to_cpu(type));
540987da915Sopenharmony_ci			goto put_err_out;
541987da915Sopenharmony_ci		}
542987da915Sopenharmony_ci		if ((a->flags & ATTR_COMPRESSION_MASK)
543987da915Sopenharmony_ci				 && (a->compression_unit
544987da915Sopenharmony_ci					!= STANDARD_COMPRESSION_UNIT)) {
545987da915Sopenharmony_ci			errno = EIO;
546987da915Sopenharmony_ci			ntfs_log_perror("Compressed inode %lld attr 0x%lx has "
547987da915Sopenharmony_ci					"an unsupported compression unit %d",
548987da915Sopenharmony_ci					(unsigned long long)ni->mft_no,
549987da915Sopenharmony_ci					(long)le32_to_cpu(type),
550987da915Sopenharmony_ci					(int)a->compression_unit);
551987da915Sopenharmony_ci			goto put_err_out;
552987da915Sopenharmony_ci		}
553987da915Sopenharmony_ci		ntfs_attr_init(na, TRUE, a->flags,
554987da915Sopenharmony_ci				a->flags & ATTR_IS_ENCRYPTED,
555987da915Sopenharmony_ci				a->flags & ATTR_IS_SPARSE,
556987da915Sopenharmony_ci				sle64_to_cpu(a->allocated_size),
557987da915Sopenharmony_ci				sle64_to_cpu(a->data_size),
558987da915Sopenharmony_ci				sle64_to_cpu(a->initialized_size),
559987da915Sopenharmony_ci				cs ? sle64_to_cpu(a->compressed_size) : 0,
560987da915Sopenharmony_ci				cs ? a->compression_unit : 0);
561987da915Sopenharmony_ci	} else {
562987da915Sopenharmony_ci		s64 l = le32_to_cpu(a->value_length);
563987da915Sopenharmony_ci		ntfs_attr_init(na, FALSE, a->flags,
564987da915Sopenharmony_ci				a->flags & ATTR_IS_ENCRYPTED,
565987da915Sopenharmony_ci				a->flags & ATTR_IS_SPARSE, (l + 7) & ~7, l, l,
566987da915Sopenharmony_ci				cs ? (l + 7) & ~7 : 0, 0);
567987da915Sopenharmony_ci	}
568987da915Sopenharmony_ci	ntfs_attr_put_search_ctx(ctx);
569987da915Sopenharmony_ciout:
570987da915Sopenharmony_ci	ntfs_log_leave("\n");
571987da915Sopenharmony_ci	return na;
572987da915Sopenharmony_ci
573987da915Sopenharmony_ciput_err_out:
574987da915Sopenharmony_ci	ntfs_attr_put_search_ctx(ctx);
575987da915Sopenharmony_cierr_out:
576987da915Sopenharmony_ci	free(newname);
577987da915Sopenharmony_ci	free(na);
578987da915Sopenharmony_ci	na = NULL;
579987da915Sopenharmony_ci	goto out;
580987da915Sopenharmony_ci}
581987da915Sopenharmony_ci
582987da915Sopenharmony_ci/**
583987da915Sopenharmony_ci * ntfs_attr_close - free an ntfs attribute structure
584987da915Sopenharmony_ci * @na:		ntfs attribute structure to free
585987da915Sopenharmony_ci *
586987da915Sopenharmony_ci * Release all memory associated with the ntfs attribute @na and then release
587987da915Sopenharmony_ci * @na itself.
588987da915Sopenharmony_ci */
589987da915Sopenharmony_civoid ntfs_attr_close(ntfs_attr *na)
590987da915Sopenharmony_ci{
591987da915Sopenharmony_ci	if (!na)
592987da915Sopenharmony_ci		return;
593987da915Sopenharmony_ci	if (NAttrNonResident(na) && na->rl)
594987da915Sopenharmony_ci		free(na->rl);
595987da915Sopenharmony_ci	/* Don't release if using an internal constant. */
596987da915Sopenharmony_ci	if (na->name != AT_UNNAMED && na->name != NTFS_INDEX_I30
597987da915Sopenharmony_ci				&& na->name != STREAM_SDS)
598987da915Sopenharmony_ci		free(na->name);
599987da915Sopenharmony_ci	free(na);
600987da915Sopenharmony_ci}
601987da915Sopenharmony_ci
602987da915Sopenharmony_ci/**
603987da915Sopenharmony_ci * ntfs_attr_map_runlist - map (a part of) a runlist of an ntfs attribute
604987da915Sopenharmony_ci * @na:		ntfs attribute for which to map (part of) a runlist
605987da915Sopenharmony_ci * @vcn:	map runlist part containing this vcn
606987da915Sopenharmony_ci *
607987da915Sopenharmony_ci * Map the part of a runlist containing the @vcn of the ntfs attribute @na.
608987da915Sopenharmony_ci *
609987da915Sopenharmony_ci * Return 0 on success and -1 on error with errno set to the error code.
610987da915Sopenharmony_ci */
611987da915Sopenharmony_ciint ntfs_attr_map_runlist(ntfs_attr *na, VCN vcn)
612987da915Sopenharmony_ci{
613987da915Sopenharmony_ci	LCN lcn;
614987da915Sopenharmony_ci	ntfs_attr_search_ctx *ctx;
615987da915Sopenharmony_ci
616987da915Sopenharmony_ci	ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x, vcn 0x%llx.\n",
617987da915Sopenharmony_ci		(unsigned long long)na->ni->mft_no, le32_to_cpu(na->type), (long long)vcn);
618987da915Sopenharmony_ci
619987da915Sopenharmony_ci	lcn = ntfs_rl_vcn_to_lcn(na->rl, vcn);
620987da915Sopenharmony_ci	if (lcn >= 0 || lcn == LCN_HOLE || lcn == LCN_ENOENT)
621987da915Sopenharmony_ci		return 0;
622987da915Sopenharmony_ci
623987da915Sopenharmony_ci	ctx = ntfs_attr_get_search_ctx(na->ni, NULL);
624987da915Sopenharmony_ci	if (!ctx)
625987da915Sopenharmony_ci		return -1;
626987da915Sopenharmony_ci
627987da915Sopenharmony_ci	/* Find the attribute in the mft record. */
628987da915Sopenharmony_ci	if (!ntfs_attr_lookup(na->type, na->name, na->name_len, CASE_SENSITIVE,
629987da915Sopenharmony_ci			vcn, NULL, 0, ctx)) {
630987da915Sopenharmony_ci		runlist_element *rl;
631987da915Sopenharmony_ci
632987da915Sopenharmony_ci		/* Decode the runlist. */
633987da915Sopenharmony_ci		rl = ntfs_mapping_pairs_decompress(na->ni->vol, ctx->attr,
634987da915Sopenharmony_ci				na->rl);
635987da915Sopenharmony_ci		if (rl) {
636987da915Sopenharmony_ci			na->rl = rl;
637987da915Sopenharmony_ci			ntfs_attr_put_search_ctx(ctx);
638987da915Sopenharmony_ci			return 0;
639987da915Sopenharmony_ci		}
640987da915Sopenharmony_ci	}
641987da915Sopenharmony_ci
642987da915Sopenharmony_ci	ntfs_attr_put_search_ctx(ctx);
643987da915Sopenharmony_ci	return -1;
644987da915Sopenharmony_ci}
645987da915Sopenharmony_ci
646987da915Sopenharmony_ci#if PARTIAL_RUNLIST_UPDATING
647987da915Sopenharmony_ci
648987da915Sopenharmony_ci/*
649987da915Sopenharmony_ci *		Map the runlist of an attribute from some point to the end
650987da915Sopenharmony_ci *
651987da915Sopenharmony_ci *	Returns 0 if success,
652987da915Sopenharmony_ci *		-1 if it failed (errno telling why)
653987da915Sopenharmony_ci */
654987da915Sopenharmony_ci
655987da915Sopenharmony_cistatic int ntfs_attr_map_partial_runlist(ntfs_attr *na, VCN vcn)
656987da915Sopenharmony_ci{
657987da915Sopenharmony_ci	VCN last_vcn;
658987da915Sopenharmony_ci	VCN highest_vcn;
659987da915Sopenharmony_ci	VCN needed;
660987da915Sopenharmony_ci	runlist_element *rl;
661987da915Sopenharmony_ci	ATTR_RECORD *a;
662987da915Sopenharmony_ci	BOOL startseen;
663987da915Sopenharmony_ci	ntfs_attr_search_ctx *ctx;
664987da915Sopenharmony_ci	BOOL done;
665987da915Sopenharmony_ci	BOOL newrunlist;
666987da915Sopenharmony_ci
667987da915Sopenharmony_ci	if (NAttrFullyMapped(na))
668987da915Sopenharmony_ci		return 0;
669987da915Sopenharmony_ci
670987da915Sopenharmony_ci	ctx = ntfs_attr_get_search_ctx(na->ni, NULL);
671987da915Sopenharmony_ci	if (!ctx)
672987da915Sopenharmony_ci		return -1;
673987da915Sopenharmony_ci
674987da915Sopenharmony_ci	/* Get the last vcn in the attribute. */
675987da915Sopenharmony_ci	last_vcn = na->allocated_size >> na->ni->vol->cluster_size_bits;
676987da915Sopenharmony_ci
677987da915Sopenharmony_ci	needed = vcn;
678987da915Sopenharmony_ci	highest_vcn = 0;
679987da915Sopenharmony_ci	startseen = FALSE;
680987da915Sopenharmony_ci	done = FALSE;
681987da915Sopenharmony_ci	rl = (runlist_element*)NULL;
682987da915Sopenharmony_ci	do {
683987da915Sopenharmony_ci		newrunlist = FALSE;
684987da915Sopenharmony_ci		/* Find the attribute in the mft record. */
685987da915Sopenharmony_ci		if (!ntfs_attr_lookup(na->type, na->name, na->name_len, CASE_SENSITIVE,
686987da915Sopenharmony_ci				needed, NULL, 0, ctx)) {
687987da915Sopenharmony_ci
688987da915Sopenharmony_ci			a = ctx->attr;
689987da915Sopenharmony_ci				/* Decode and merge the runlist. */
690987da915Sopenharmony_ci			if (ntfs_rl_vcn_to_lcn(na->rl, needed)
691987da915Sopenharmony_ci						== LCN_RL_NOT_MAPPED) {
692987da915Sopenharmony_ci				rl = ntfs_mapping_pairs_decompress(na->ni->vol,
693987da915Sopenharmony_ci					a, na->rl);
694987da915Sopenharmony_ci				newrunlist = TRUE;
695987da915Sopenharmony_ci			} else
696987da915Sopenharmony_ci				rl = na->rl;
697987da915Sopenharmony_ci			if (rl) {
698987da915Sopenharmony_ci				na->rl = rl;
699987da915Sopenharmony_ci				highest_vcn = sle64_to_cpu(a->highest_vcn);
700987da915Sopenharmony_ci				if (highest_vcn < needed) {
701987da915Sopenharmony_ci				/* corruption detection on unchanged runlists */
702987da915Sopenharmony_ci					if (newrunlist
703987da915Sopenharmony_ci					    && ((highest_vcn + 1) < last_vcn)) {
704987da915Sopenharmony_ci						ntfs_log_error("Corrupt attribute list\n");
705987da915Sopenharmony_ci						rl = (runlist_element*)NULL;
706987da915Sopenharmony_ci						errno = EIO;
707987da915Sopenharmony_ci					}
708987da915Sopenharmony_ci					done = TRUE;
709987da915Sopenharmony_ci				}
710987da915Sopenharmony_ci				needed = highest_vcn + 1;
711987da915Sopenharmony_ci				if (!a->lowest_vcn)
712987da915Sopenharmony_ci					startseen = TRUE;
713987da915Sopenharmony_ci			}
714987da915Sopenharmony_ci		} else {
715987da915Sopenharmony_ci			done = TRUE;
716987da915Sopenharmony_ci		}
717987da915Sopenharmony_ci	} while (rl && !done && (needed < last_vcn));
718987da915Sopenharmony_ci	ntfs_attr_put_search_ctx(ctx);
719987da915Sopenharmony_ci		/*
720987da915Sopenharmony_ci		 * Make sure we reached the end, unless the last
721987da915Sopenharmony_ci		 * runlist was modified earlier (using HOLES_DELAY
722987da915Sopenharmony_ci		 * leads to have a visibility over attributes which
723987da915Sopenharmony_ci		 * have not yet been fully updated)
724987da915Sopenharmony_ci		 */
725987da915Sopenharmony_ci	if (done && newrunlist && (needed < last_vcn)) {
726987da915Sopenharmony_ci		ntfs_log_error("End of runlist not reached\n");
727987da915Sopenharmony_ci		rl = (runlist_element*)NULL;
728987da915Sopenharmony_ci		errno = EIO;
729987da915Sopenharmony_ci	}
730987da915Sopenharmony_ci		/* mark fully mapped if we did so */
731987da915Sopenharmony_ci	if (rl && startseen)
732987da915Sopenharmony_ci		NAttrSetFullyMapped(na);
733987da915Sopenharmony_ci	return (rl ? 0 : -1);
734987da915Sopenharmony_ci}
735987da915Sopenharmony_ci
736987da915Sopenharmony_ci#endif
737987da915Sopenharmony_ci
738987da915Sopenharmony_ci/**
739987da915Sopenharmony_ci * ntfs_attr_map_whole_runlist - map the whole runlist of an ntfs attribute
740987da915Sopenharmony_ci * @na:		ntfs attribute for which to map the runlist
741987da915Sopenharmony_ci *
742987da915Sopenharmony_ci * Map the whole runlist of the ntfs attribute @na.  For an attribute made up
743987da915Sopenharmony_ci * of only one attribute extent this is the same as calling
744987da915Sopenharmony_ci * ntfs_attr_map_runlist(na, 0) but for an attribute with multiple extents this
745987da915Sopenharmony_ci * will map the runlist fragments from each of the extents thus giving access
746987da915Sopenharmony_ci * to the entirety of the disk allocation of an attribute.
747987da915Sopenharmony_ci *
748987da915Sopenharmony_ci * Return 0 on success and -1 on error with errno set to the error code.
749987da915Sopenharmony_ci */
750987da915Sopenharmony_ciint ntfs_attr_map_whole_runlist(ntfs_attr *na)
751987da915Sopenharmony_ci{
752987da915Sopenharmony_ci	VCN next_vcn, last_vcn, highest_vcn;
753987da915Sopenharmony_ci	ntfs_attr_search_ctx *ctx;
754987da915Sopenharmony_ci	ntfs_volume *vol = na->ni->vol;
755987da915Sopenharmony_ci	ATTR_RECORD *a;
756987da915Sopenharmony_ci	int ret = -1;
757987da915Sopenharmony_ci	int not_mapped;
758987da915Sopenharmony_ci
759987da915Sopenharmony_ci	ntfs_log_enter("Entering for inode %llu, attr 0x%x.\n",
760987da915Sopenharmony_ci		       (unsigned long long)na->ni->mft_no, le32_to_cpu(na->type));
761987da915Sopenharmony_ci
762987da915Sopenharmony_ci		/* avoid multiple full runlist mappings */
763987da915Sopenharmony_ci	if (NAttrFullyMapped(na)) {
764987da915Sopenharmony_ci		ret = 0;
765987da915Sopenharmony_ci		goto out;
766987da915Sopenharmony_ci	}
767987da915Sopenharmony_ci	ctx = ntfs_attr_get_search_ctx(na->ni, NULL);
768987da915Sopenharmony_ci	if (!ctx)
769987da915Sopenharmony_ci		goto out;
770987da915Sopenharmony_ci
771987da915Sopenharmony_ci	/* Map all attribute extents one by one. */
772987da915Sopenharmony_ci	next_vcn = last_vcn = highest_vcn = 0;
773987da915Sopenharmony_ci	a = NULL;
774987da915Sopenharmony_ci	while (1) {
775987da915Sopenharmony_ci		runlist_element *rl;
776987da915Sopenharmony_ci
777987da915Sopenharmony_ci		not_mapped = 0;
778987da915Sopenharmony_ci		if (ntfs_rl_vcn_to_lcn(na->rl, next_vcn) == LCN_RL_NOT_MAPPED)
779987da915Sopenharmony_ci			not_mapped = 1;
780987da915Sopenharmony_ci
781987da915Sopenharmony_ci		if (ntfs_attr_lookup(na->type, na->name, na->name_len,
782987da915Sopenharmony_ci				CASE_SENSITIVE, next_vcn, NULL, 0, ctx))
783987da915Sopenharmony_ci			break;
784987da915Sopenharmony_ci
785987da915Sopenharmony_ci		a = ctx->attr;
786987da915Sopenharmony_ci
787987da915Sopenharmony_ci		if (not_mapped) {
788987da915Sopenharmony_ci			/* Decode the runlist. */
789987da915Sopenharmony_ci			rl = ntfs_mapping_pairs_decompress(na->ni->vol,
790987da915Sopenharmony_ci								a, na->rl);
791987da915Sopenharmony_ci			if (!rl)
792987da915Sopenharmony_ci				goto err_out;
793987da915Sopenharmony_ci			na->rl = rl;
794987da915Sopenharmony_ci		}
795987da915Sopenharmony_ci
796987da915Sopenharmony_ci		/* Are we in the first extent? */
797987da915Sopenharmony_ci		if (!next_vcn) {
798987da915Sopenharmony_ci			 if (a->lowest_vcn) {
799987da915Sopenharmony_ci				 errno = EIO;
800987da915Sopenharmony_ci				 ntfs_log_perror("First extent of inode %llu "
801987da915Sopenharmony_ci					"attribute has non-zero lowest_vcn",
802987da915Sopenharmony_ci					(unsigned long long)na->ni->mft_no);
803987da915Sopenharmony_ci				 goto err_out;
804987da915Sopenharmony_ci			}
805987da915Sopenharmony_ci			/* Get the last vcn in the attribute. */
806987da915Sopenharmony_ci			last_vcn = sle64_to_cpu(a->allocated_size) >>
807987da915Sopenharmony_ci					vol->cluster_size_bits;
808987da915Sopenharmony_ci		}
809987da915Sopenharmony_ci
810987da915Sopenharmony_ci		/* Get the lowest vcn for the next extent. */
811987da915Sopenharmony_ci		highest_vcn = sle64_to_cpu(a->highest_vcn);
812987da915Sopenharmony_ci		next_vcn = highest_vcn + 1;
813987da915Sopenharmony_ci
814987da915Sopenharmony_ci		/* Only one extent or error, which we catch below. */
815987da915Sopenharmony_ci		if (next_vcn <= 0) {
816987da915Sopenharmony_ci			errno = ENOENT;
817987da915Sopenharmony_ci			break;
818987da915Sopenharmony_ci		}
819987da915Sopenharmony_ci
820987da915Sopenharmony_ci		/* Avoid endless loops due to corruption. */
821987da915Sopenharmony_ci		if (next_vcn < sle64_to_cpu(a->lowest_vcn)) {
822987da915Sopenharmony_ci			errno = EIO;
823987da915Sopenharmony_ci			ntfs_log_perror("Inode %llu has corrupt attribute list",
824987da915Sopenharmony_ci					(unsigned long long)na->ni->mft_no);
825987da915Sopenharmony_ci			goto err_out;
826987da915Sopenharmony_ci		}
827987da915Sopenharmony_ci	}
828987da915Sopenharmony_ci	if (!a) {
829987da915Sopenharmony_ci		ntfs_log_perror("Couldn't find attribute for runlist mapping");
830987da915Sopenharmony_ci		goto err_out;
831987da915Sopenharmony_ci	}
832987da915Sopenharmony_ci		/*
833987da915Sopenharmony_ci		 * Cannot check highest_vcn when the last runlist has
834987da915Sopenharmony_ci		 * been modified earlier, as runlists and sizes may be
835987da915Sopenharmony_ci		 * updated without highest_vcn being in sync, when
836987da915Sopenharmony_ci		 * HOLES_DELAY is used
837987da915Sopenharmony_ci		 */
838987da915Sopenharmony_ci	if (not_mapped && highest_vcn && highest_vcn != last_vcn - 1) {
839987da915Sopenharmony_ci		errno = EIO;
840987da915Sopenharmony_ci		ntfs_log_perror("Failed to load full runlist: inode: %llu "
841987da915Sopenharmony_ci				"highest_vcn: 0x%llx last_vcn: 0x%llx",
842987da915Sopenharmony_ci				(unsigned long long)na->ni->mft_no,
843987da915Sopenharmony_ci				(long long)highest_vcn, (long long)last_vcn);
844987da915Sopenharmony_ci		goto err_out;
845987da915Sopenharmony_ci	}
846987da915Sopenharmony_ci	if (errno == ENOENT) {
847987da915Sopenharmony_ci		NAttrSetFullyMapped(na);
848987da915Sopenharmony_ci		ret = 0;
849987da915Sopenharmony_ci	}
850987da915Sopenharmony_cierr_out:
851987da915Sopenharmony_ci	ntfs_attr_put_search_ctx(ctx);
852987da915Sopenharmony_ciout:
853987da915Sopenharmony_ci	ntfs_log_leave("\n");
854987da915Sopenharmony_ci	return ret;
855987da915Sopenharmony_ci}
856987da915Sopenharmony_ci
857987da915Sopenharmony_ci/**
858987da915Sopenharmony_ci * ntfs_attr_vcn_to_lcn - convert a vcn into a lcn given an ntfs attribute
859987da915Sopenharmony_ci * @na:		ntfs attribute whose runlist to use for conversion
860987da915Sopenharmony_ci * @vcn:	vcn to convert
861987da915Sopenharmony_ci *
862987da915Sopenharmony_ci * Convert the virtual cluster number @vcn of an attribute into a logical
863987da915Sopenharmony_ci * cluster number (lcn) of a device using the runlist @na->rl to map vcns to
864987da915Sopenharmony_ci * their corresponding lcns.
865987da915Sopenharmony_ci *
866987da915Sopenharmony_ci * If the @vcn is not mapped yet, attempt to map the attribute extent
867987da915Sopenharmony_ci * containing the @vcn and retry the vcn to lcn conversion.
868987da915Sopenharmony_ci *
869987da915Sopenharmony_ci * Since lcns must be >= 0, we use negative return values with special meaning:
870987da915Sopenharmony_ci *
871987da915Sopenharmony_ci * Return value		Meaning / Description
872987da915Sopenharmony_ci * ==========================================
873987da915Sopenharmony_ci *  -1 = LCN_HOLE	Hole / not allocated on disk.
874987da915Sopenharmony_ci *  -3 = LCN_ENOENT	There is no such vcn in the attribute.
875987da915Sopenharmony_ci *  -4 = LCN_EINVAL	Input parameter error.
876987da915Sopenharmony_ci *  -5 = LCN_EIO	Corrupt fs, disk i/o error, or not enough memory.
877987da915Sopenharmony_ci */
878987da915Sopenharmony_ciLCN ntfs_attr_vcn_to_lcn(ntfs_attr *na, const VCN vcn)
879987da915Sopenharmony_ci{
880987da915Sopenharmony_ci	LCN lcn;
881987da915Sopenharmony_ci	BOOL is_retry = FALSE;
882987da915Sopenharmony_ci
883987da915Sopenharmony_ci	if (!na || !NAttrNonResident(na) || vcn < 0)
884987da915Sopenharmony_ci		return (LCN)LCN_EINVAL;
885987da915Sopenharmony_ci
886987da915Sopenharmony_ci	ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x.\n", (unsigned long
887987da915Sopenharmony_ci			long)na->ni->mft_no, le32_to_cpu(na->type));
888987da915Sopenharmony_ciretry:
889987da915Sopenharmony_ci	/* Convert vcn to lcn. If that fails map the runlist and retry once. */
890987da915Sopenharmony_ci	lcn = ntfs_rl_vcn_to_lcn(na->rl, vcn);
891987da915Sopenharmony_ci	if (lcn >= 0)
892987da915Sopenharmony_ci		return lcn;
893987da915Sopenharmony_ci	if (!is_retry && !ntfs_attr_map_runlist(na, vcn)) {
894987da915Sopenharmony_ci		is_retry = TRUE;
895987da915Sopenharmony_ci		goto retry;
896987da915Sopenharmony_ci	}
897987da915Sopenharmony_ci	/*
898987da915Sopenharmony_ci	 * If the attempt to map the runlist failed, or we are getting
899987da915Sopenharmony_ci	 * LCN_RL_NOT_MAPPED despite having mapped the attribute extent
900987da915Sopenharmony_ci	 * successfully, something is really badly wrong...
901987da915Sopenharmony_ci	 */
902987da915Sopenharmony_ci	if (!is_retry || lcn == (LCN)LCN_RL_NOT_MAPPED)
903987da915Sopenharmony_ci		return (LCN)LCN_EIO;
904987da915Sopenharmony_ci	/* lcn contains the appropriate error code. */
905987da915Sopenharmony_ci	return lcn;
906987da915Sopenharmony_ci}
907987da915Sopenharmony_ci
908987da915Sopenharmony_ci/**
909987da915Sopenharmony_ci * ntfs_attr_find_vcn - find a vcn in the runlist of an ntfs attribute
910987da915Sopenharmony_ci * @na:		ntfs attribute whose runlist to search
911987da915Sopenharmony_ci * @vcn:	vcn to find
912987da915Sopenharmony_ci *
913987da915Sopenharmony_ci * Find the virtual cluster number @vcn in the runlist of the ntfs attribute
914987da915Sopenharmony_ci * @na and return the the address of the runlist element containing the @vcn.
915987da915Sopenharmony_ci *
916987da915Sopenharmony_ci * Note you need to distinguish between the lcn of the returned runlist
917987da915Sopenharmony_ci * element being >= 0 and LCN_HOLE. In the later case you have to return zeroes
918987da915Sopenharmony_ci * on read and allocate clusters on write. You need to update the runlist, the
919987da915Sopenharmony_ci * attribute itself as well as write the modified mft record to disk.
920987da915Sopenharmony_ci *
921987da915Sopenharmony_ci * If there is an error return NULL with errno set to the error code. The
922987da915Sopenharmony_ci * following error codes are defined:
923987da915Sopenharmony_ci *	EINVAL		Input parameter error.
924987da915Sopenharmony_ci *	ENOENT		There is no such vcn in the runlist.
925987da915Sopenharmony_ci *	ENOMEM		Not enough memory.
926987da915Sopenharmony_ci *	EIO		I/O error or corrupt metadata.
927987da915Sopenharmony_ci */
928987da915Sopenharmony_cirunlist_element *ntfs_attr_find_vcn(ntfs_attr *na, const VCN vcn)
929987da915Sopenharmony_ci{
930987da915Sopenharmony_ci	runlist_element *rl;
931987da915Sopenharmony_ci	BOOL is_retry = FALSE;
932987da915Sopenharmony_ci
933987da915Sopenharmony_ci	if (!na || !NAttrNonResident(na) || vcn < 0) {
934987da915Sopenharmony_ci		errno = EINVAL;
935987da915Sopenharmony_ci		return NULL;
936987da915Sopenharmony_ci	}
937987da915Sopenharmony_ci
938987da915Sopenharmony_ci	ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x, vcn %llx\n",
939987da915Sopenharmony_ci		       (unsigned long long)na->ni->mft_no, le32_to_cpu(na->type),
940987da915Sopenharmony_ci		       (long long)vcn);
941987da915Sopenharmony_ciretry:
942987da915Sopenharmony_ci	rl = na->rl;
943987da915Sopenharmony_ci	if (!rl)
944987da915Sopenharmony_ci		goto map_rl;
945987da915Sopenharmony_ci	if (vcn < rl[0].vcn)
946987da915Sopenharmony_ci		goto map_rl;
947987da915Sopenharmony_ci	while (rl->length) {
948987da915Sopenharmony_ci		if (vcn < rl[1].vcn) {
949987da915Sopenharmony_ci			if (rl->lcn >= (LCN)LCN_HOLE)
950987da915Sopenharmony_ci				return rl;
951987da915Sopenharmony_ci			break;
952987da915Sopenharmony_ci		}
953987da915Sopenharmony_ci		rl++;
954987da915Sopenharmony_ci	}
955987da915Sopenharmony_ci	switch (rl->lcn) {
956987da915Sopenharmony_ci	case (LCN)LCN_RL_NOT_MAPPED:
957987da915Sopenharmony_ci		goto map_rl;
958987da915Sopenharmony_ci	case (LCN)LCN_ENOENT:
959987da915Sopenharmony_ci		errno = ENOENT;
960987da915Sopenharmony_ci		break;
961987da915Sopenharmony_ci	case (LCN)LCN_EINVAL:
962987da915Sopenharmony_ci		errno = EINVAL;
963987da915Sopenharmony_ci		break;
964987da915Sopenharmony_ci	default:
965987da915Sopenharmony_ci		errno = EIO;
966987da915Sopenharmony_ci		break;
967987da915Sopenharmony_ci	}
968987da915Sopenharmony_ci	return NULL;
969987da915Sopenharmony_cimap_rl:
970987da915Sopenharmony_ci	/* The @vcn is in an unmapped region, map the runlist and retry. */
971987da915Sopenharmony_ci	if (!is_retry && !ntfs_attr_map_runlist(na, vcn)) {
972987da915Sopenharmony_ci		is_retry = TRUE;
973987da915Sopenharmony_ci		goto retry;
974987da915Sopenharmony_ci	}
975987da915Sopenharmony_ci	/*
976987da915Sopenharmony_ci	 * If we already retried or the mapping attempt failed something has
977987da915Sopenharmony_ci	 * gone badly wrong. EINVAL and ENOENT coming from a failed mapping
978987da915Sopenharmony_ci	 * attempt are equivalent to errors for us as they should not happen
979987da915Sopenharmony_ci	 * in our code paths.
980987da915Sopenharmony_ci	 */
981987da915Sopenharmony_ci	if (is_retry || errno == EINVAL || errno == ENOENT)
982987da915Sopenharmony_ci		errno = EIO;
983987da915Sopenharmony_ci	return NULL;
984987da915Sopenharmony_ci}
985987da915Sopenharmony_ci
986987da915Sopenharmony_ci/**
987987da915Sopenharmony_ci * ntfs_attr_pread_i - see description at ntfs_attr_pread()
988987da915Sopenharmony_ci */
989987da915Sopenharmony_cistatic s64 ntfs_attr_pread_i(ntfs_attr *na, const s64 pos, s64 count, void *b)
990987da915Sopenharmony_ci{
991987da915Sopenharmony_ci	s64 br, to_read, ofs, total, total2, max_read, max_init;
992987da915Sopenharmony_ci	ntfs_volume *vol;
993987da915Sopenharmony_ci	runlist_element *rl;
994987da915Sopenharmony_ci	u16 efs_padding_length;
995987da915Sopenharmony_ci
996987da915Sopenharmony_ci	/* Sanity checking arguments is done in ntfs_attr_pread(). */
997987da915Sopenharmony_ci
998987da915Sopenharmony_ci	if ((na->data_flags & ATTR_COMPRESSION_MASK) && NAttrNonResident(na)) {
999987da915Sopenharmony_ci		if ((na->data_flags & ATTR_COMPRESSION_MASK)
1000987da915Sopenharmony_ci		    == ATTR_IS_COMPRESSED)
1001987da915Sopenharmony_ci			return ntfs_compressed_attr_pread(na, pos, count, b);
1002987da915Sopenharmony_ci		else {
1003987da915Sopenharmony_ci				/* compression mode not supported */
1004987da915Sopenharmony_ci			errno = EOPNOTSUPP;
1005987da915Sopenharmony_ci			return -1;
1006987da915Sopenharmony_ci		}
1007987da915Sopenharmony_ci	}
1008987da915Sopenharmony_ci	/*
1009987da915Sopenharmony_ci	 * Encrypted non-resident attributes are not supported.  We return
1010987da915Sopenharmony_ci	 * access denied, which is what Windows NT4 does, too.
1011987da915Sopenharmony_ci	 * However, allow if mounted with efs_raw option
1012987da915Sopenharmony_ci	 */
1013987da915Sopenharmony_ci	vol = na->ni->vol;
1014987da915Sopenharmony_ci	if (!vol->efs_raw && NAttrEncrypted(na) && NAttrNonResident(na)) {
1015987da915Sopenharmony_ci		errno = EACCES;
1016987da915Sopenharmony_ci		return -1;
1017987da915Sopenharmony_ci	}
1018987da915Sopenharmony_ci
1019987da915Sopenharmony_ci	if (!count)
1020987da915Sopenharmony_ci		return 0;
1021987da915Sopenharmony_ci		/*
1022987da915Sopenharmony_ci		 * Truncate reads beyond end of attribute,
1023987da915Sopenharmony_ci		 * but round to next 512 byte boundary for encrypted
1024987da915Sopenharmony_ci		 * attributes with efs_raw mount option
1025987da915Sopenharmony_ci		 */
1026987da915Sopenharmony_ci	max_read = na->data_size;
1027987da915Sopenharmony_ci	max_init = na->initialized_size;
1028987da915Sopenharmony_ci	if (na->ni->vol->efs_raw
1029987da915Sopenharmony_ci	    && (na->data_flags & ATTR_IS_ENCRYPTED)
1030987da915Sopenharmony_ci	    && NAttrNonResident(na)) {
1031987da915Sopenharmony_ci		if (na->data_size != na->initialized_size) {
1032987da915Sopenharmony_ci			ntfs_log_error("uninitialized encrypted file not supported\n");
1033987da915Sopenharmony_ci			errno = EINVAL;
1034987da915Sopenharmony_ci			return -1;
1035987da915Sopenharmony_ci		}
1036987da915Sopenharmony_ci		max_init = max_read = ((na->data_size + 511) & ~511) + 2;
1037987da915Sopenharmony_ci	}
1038987da915Sopenharmony_ci	if (pos + count > max_read) {
1039987da915Sopenharmony_ci		if (pos >= max_read)
1040987da915Sopenharmony_ci			return 0;
1041987da915Sopenharmony_ci		count = max_read - pos;
1042987da915Sopenharmony_ci	}
1043987da915Sopenharmony_ci	/* If it is a resident attribute, get the value from the mft record. */
1044987da915Sopenharmony_ci	if (!NAttrNonResident(na)) {
1045987da915Sopenharmony_ci		ntfs_attr_search_ctx *ctx;
1046987da915Sopenharmony_ci		char *val;
1047987da915Sopenharmony_ci
1048987da915Sopenharmony_ci		ctx = ntfs_attr_get_search_ctx(na->ni, NULL);
1049987da915Sopenharmony_ci		if (!ctx)
1050987da915Sopenharmony_ci			return -1;
1051987da915Sopenharmony_ci		if (ntfs_attr_lookup(na->type, na->name, na->name_len, 0,
1052987da915Sopenharmony_ci				0, NULL, 0, ctx)) {
1053987da915Sopenharmony_cires_err_out:
1054987da915Sopenharmony_ci			ntfs_attr_put_search_ctx(ctx);
1055987da915Sopenharmony_ci			return -1;
1056987da915Sopenharmony_ci		}
1057987da915Sopenharmony_ci		val = (char*)ctx->attr + le16_to_cpu(ctx->attr->value_offset);
1058987da915Sopenharmony_ci		if (val < (char*)ctx->attr || val +
1059987da915Sopenharmony_ci				le32_to_cpu(ctx->attr->value_length) >
1060987da915Sopenharmony_ci				(char*)ctx->mrec + vol->mft_record_size) {
1061987da915Sopenharmony_ci			errno = EIO;
1062987da915Sopenharmony_ci			ntfs_log_perror("%s: Sanity check failed", __FUNCTION__);
1063987da915Sopenharmony_ci			goto res_err_out;
1064987da915Sopenharmony_ci		}
1065987da915Sopenharmony_ci		memcpy(b, val + pos, count);
1066987da915Sopenharmony_ci		ntfs_attr_put_search_ctx(ctx);
1067987da915Sopenharmony_ci		return count;
1068987da915Sopenharmony_ci	}
1069987da915Sopenharmony_ci	total = total2 = 0;
1070987da915Sopenharmony_ci	/* Zero out reads beyond initialized size. */
1071987da915Sopenharmony_ci	if (pos + count > max_init) {
1072987da915Sopenharmony_ci		if (pos >= max_init) {
1073987da915Sopenharmony_ci			memset(b, 0, count);
1074987da915Sopenharmony_ci			return count;
1075987da915Sopenharmony_ci		}
1076987da915Sopenharmony_ci		total2 = pos + count - max_init;
1077987da915Sopenharmony_ci		count -= total2;
1078987da915Sopenharmony_ci		memset((u8*)b + count, 0, total2);
1079987da915Sopenharmony_ci	}
1080987da915Sopenharmony_ci		/*
1081987da915Sopenharmony_ci		 * for encrypted non-resident attributes with efs_raw set
1082987da915Sopenharmony_ci		 * the last two bytes aren't read from disk but contain
1083987da915Sopenharmony_ci		 * the number of padding bytes so original size can be
1084987da915Sopenharmony_ci		 * restored
1085987da915Sopenharmony_ci		 */
1086987da915Sopenharmony_ci	if (na->ni->vol->efs_raw &&
1087987da915Sopenharmony_ci			(na->data_flags & ATTR_IS_ENCRYPTED) &&
1088987da915Sopenharmony_ci			((pos + count) > max_init-2)) {
1089987da915Sopenharmony_ci		efs_padding_length = 511 - ((na->data_size - 1) & 511);
1090987da915Sopenharmony_ci		if (pos+count == max_init) {
1091987da915Sopenharmony_ci			if (count == 1) {
1092987da915Sopenharmony_ci				*((u8*)b+count-1) = (u8)(efs_padding_length >> 8);
1093987da915Sopenharmony_ci				count--;
1094987da915Sopenharmony_ci				total2++;
1095987da915Sopenharmony_ci			} else {
1096987da915Sopenharmony_ci				*(le16*)((u8*)b+count-2) = cpu_to_le16(efs_padding_length);
1097987da915Sopenharmony_ci				count -= 2;
1098987da915Sopenharmony_ci				total2 +=2;
1099987da915Sopenharmony_ci			}
1100987da915Sopenharmony_ci		} else {
1101987da915Sopenharmony_ci			*((u8*)b+count-1) = (u8)(efs_padding_length & 0xff);
1102987da915Sopenharmony_ci			count--;
1103987da915Sopenharmony_ci			total2++;
1104987da915Sopenharmony_ci		}
1105987da915Sopenharmony_ci	}
1106987da915Sopenharmony_ci
1107987da915Sopenharmony_ci	/* Find the runlist element containing the vcn. */
1108987da915Sopenharmony_ci	rl = ntfs_attr_find_vcn(na, pos >> vol->cluster_size_bits);
1109987da915Sopenharmony_ci	if (!rl) {
1110987da915Sopenharmony_ci		/*
1111987da915Sopenharmony_ci		 * If the vcn is not present it is an out of bounds read.
1112987da915Sopenharmony_ci		 * However, we already truncated the read to the data_size,
1113987da915Sopenharmony_ci		 * so getting this here is an error.
1114987da915Sopenharmony_ci		 */
1115987da915Sopenharmony_ci		if (errno == ENOENT) {
1116987da915Sopenharmony_ci			errno = EIO;
1117987da915Sopenharmony_ci			ntfs_log_perror("%s: Failed to find VCN #1", __FUNCTION__);
1118987da915Sopenharmony_ci		}
1119987da915Sopenharmony_ci		return -1;
1120987da915Sopenharmony_ci	}
1121987da915Sopenharmony_ci	/*
1122987da915Sopenharmony_ci	 * Gather the requested data into the linear destination buffer. Note,
1123987da915Sopenharmony_ci	 * a partial final vcn is taken care of by the @count capping of read
1124987da915Sopenharmony_ci	 * length.
1125987da915Sopenharmony_ci	 */
1126987da915Sopenharmony_ci	ofs = pos - (rl->vcn << vol->cluster_size_bits);
1127987da915Sopenharmony_ci	for (; count; rl++, ofs = 0) {
1128987da915Sopenharmony_ci		if (rl->lcn == LCN_RL_NOT_MAPPED) {
1129987da915Sopenharmony_ci			rl = ntfs_attr_find_vcn(na, rl->vcn);
1130987da915Sopenharmony_ci			if (!rl) {
1131987da915Sopenharmony_ci				if (errno == ENOENT) {
1132987da915Sopenharmony_ci					errno = EIO;
1133987da915Sopenharmony_ci					ntfs_log_perror("%s: Failed to find VCN #2",
1134987da915Sopenharmony_ci							__FUNCTION__);
1135987da915Sopenharmony_ci				}
1136987da915Sopenharmony_ci				goto rl_err_out;
1137987da915Sopenharmony_ci			}
1138987da915Sopenharmony_ci			/* Needed for case when runs merged. */
1139987da915Sopenharmony_ci			ofs = pos + total - (rl->vcn << vol->cluster_size_bits);
1140987da915Sopenharmony_ci		}
1141987da915Sopenharmony_ci		if (!rl->length) {
1142987da915Sopenharmony_ci			errno = EIO;
1143987da915Sopenharmony_ci			ntfs_log_perror("%s: Zero run length", __FUNCTION__);
1144987da915Sopenharmony_ci			goto rl_err_out;
1145987da915Sopenharmony_ci		}
1146987da915Sopenharmony_ci		if (rl->lcn < (LCN)0) {
1147987da915Sopenharmony_ci			if (rl->lcn != (LCN)LCN_HOLE) {
1148987da915Sopenharmony_ci				ntfs_log_perror("%s: Bad run (%lld)",
1149987da915Sopenharmony_ci						__FUNCTION__,
1150987da915Sopenharmony_ci						(long long)rl->lcn);
1151987da915Sopenharmony_ci				goto rl_err_out;
1152987da915Sopenharmony_ci			}
1153987da915Sopenharmony_ci			/* It is a hole, just zero the matching @b range. */
1154987da915Sopenharmony_ci			to_read = min(count, (rl->length <<
1155987da915Sopenharmony_ci					vol->cluster_size_bits) - ofs);
1156987da915Sopenharmony_ci			memset(b, 0, to_read);
1157987da915Sopenharmony_ci			/* Update progress counters. */
1158987da915Sopenharmony_ci			total += to_read;
1159987da915Sopenharmony_ci			count -= to_read;
1160987da915Sopenharmony_ci			b = (u8*)b + to_read;
1161987da915Sopenharmony_ci			continue;
1162987da915Sopenharmony_ci		}
1163987da915Sopenharmony_ci		/* It is a real lcn, read it into @dst. */
1164987da915Sopenharmony_ci		to_read = min(count, (rl->length << vol->cluster_size_bits) -
1165987da915Sopenharmony_ci				ofs);
1166987da915Sopenharmony_ciretry:
1167987da915Sopenharmony_ci		ntfs_log_trace("Reading %lld bytes from vcn %lld, lcn %lld, ofs"
1168987da915Sopenharmony_ci				" %lld.\n", (long long)to_read, (long long)rl->vcn,
1169987da915Sopenharmony_ci			       (long long )rl->lcn, (long long)ofs);
1170987da915Sopenharmony_ci		br = ntfs_pread(vol->dev, (rl->lcn << vol->cluster_size_bits) +
1171987da915Sopenharmony_ci				ofs, to_read, b);
1172987da915Sopenharmony_ci		/* If everything ok, update progress counters and continue. */
1173987da915Sopenharmony_ci		if (br > 0) {
1174987da915Sopenharmony_ci			total += br;
1175987da915Sopenharmony_ci			count -= br;
1176987da915Sopenharmony_ci			b = (u8*)b + br;
1177987da915Sopenharmony_ci		}
1178987da915Sopenharmony_ci		if (br == to_read)
1179987da915Sopenharmony_ci			continue;
1180987da915Sopenharmony_ci		/* If the syscall was interrupted, try again. */
1181987da915Sopenharmony_ci		if (br == (s64)-1 && errno == EINTR)
1182987da915Sopenharmony_ci			goto retry;
1183987da915Sopenharmony_ci		if (total)
1184987da915Sopenharmony_ci			return total;
1185987da915Sopenharmony_ci		if (!br)
1186987da915Sopenharmony_ci			errno = EIO;
1187987da915Sopenharmony_ci		ntfs_log_perror("%s: ntfs_pread failed", __FUNCTION__);
1188987da915Sopenharmony_ci		return -1;
1189987da915Sopenharmony_ci	}
1190987da915Sopenharmony_ci	/* Finally, return the number of bytes read. */
1191987da915Sopenharmony_ci	return total + total2;
1192987da915Sopenharmony_cirl_err_out:
1193987da915Sopenharmony_ci	if (total)
1194987da915Sopenharmony_ci		return total;
1195987da915Sopenharmony_ci	errno = EIO;
1196987da915Sopenharmony_ci	return -1;
1197987da915Sopenharmony_ci}
1198987da915Sopenharmony_ci
1199987da915Sopenharmony_ci/**
1200987da915Sopenharmony_ci * ntfs_attr_pread - read from an attribute specified by an ntfs_attr structure
1201987da915Sopenharmony_ci * @na:		ntfs attribute to read from
1202987da915Sopenharmony_ci * @pos:	byte position in the attribute to begin reading from
1203987da915Sopenharmony_ci * @count:	number of bytes to read
1204987da915Sopenharmony_ci * @b:		output data buffer
1205987da915Sopenharmony_ci *
1206987da915Sopenharmony_ci * This function will read @count bytes starting at offset @pos from the ntfs
1207987da915Sopenharmony_ci * attribute @na into the data buffer @b.
1208987da915Sopenharmony_ci *
1209987da915Sopenharmony_ci * On success, return the number of successfully read bytes. If this number is
1210987da915Sopenharmony_ci * lower than @count this means that the read reached end of file or that an
1211987da915Sopenharmony_ci * error was encountered during the read so that the read is partial. 0 means
1212987da915Sopenharmony_ci * end of file or nothing was read (also return 0 when @count is 0).
1213987da915Sopenharmony_ci *
1214987da915Sopenharmony_ci * On error and nothing has been read, return -1 with errno set appropriately
1215987da915Sopenharmony_ci * to the return code of ntfs_pread(), or to EINVAL in case of invalid
1216987da915Sopenharmony_ci * arguments.
1217987da915Sopenharmony_ci */
1218987da915Sopenharmony_cis64 ntfs_attr_pread(ntfs_attr *na, const s64 pos, s64 count, void *b)
1219987da915Sopenharmony_ci{
1220987da915Sopenharmony_ci	s64 ret;
1221987da915Sopenharmony_ci
1222987da915Sopenharmony_ci	if (!na || !na->ni || !na->ni->vol || !b || pos < 0 || count < 0) {
1223987da915Sopenharmony_ci		errno = EINVAL;
1224987da915Sopenharmony_ci		ntfs_log_perror("%s: na=%p  b=%p  pos=%lld  count=%lld",
1225987da915Sopenharmony_ci				__FUNCTION__, na, b, (long long)pos,
1226987da915Sopenharmony_ci				(long long)count);
1227987da915Sopenharmony_ci		return -1;
1228987da915Sopenharmony_ci	}
1229987da915Sopenharmony_ci
1230987da915Sopenharmony_ci	ntfs_log_enter("Entering for inode %lld attr 0x%x pos %lld count "
1231987da915Sopenharmony_ci		       "%lld\n", (unsigned long long)na->ni->mft_no,
1232987da915Sopenharmony_ci		       le32_to_cpu(na->type), (long long)pos, (long long)count);
1233987da915Sopenharmony_ci
1234987da915Sopenharmony_ci	ret = ntfs_attr_pread_i(na, pos, count, b);
1235987da915Sopenharmony_ci
1236987da915Sopenharmony_ci	ntfs_log_leave("\n");
1237987da915Sopenharmony_ci	return ret;
1238987da915Sopenharmony_ci}
1239987da915Sopenharmony_ci
1240987da915Sopenharmony_cistatic int ntfs_attr_fill_zero(ntfs_attr *na, s64 pos, s64 count)
1241987da915Sopenharmony_ci{
1242987da915Sopenharmony_ci	char *buf;
1243987da915Sopenharmony_ci	s64 written, size, end = pos + count;
1244987da915Sopenharmony_ci	s64 ofsi;
1245987da915Sopenharmony_ci	const runlist_element *rli;
1246987da915Sopenharmony_ci	ntfs_volume *vol;
1247987da915Sopenharmony_ci	int ret = -1;
1248987da915Sopenharmony_ci
1249987da915Sopenharmony_ci	ntfs_log_trace("pos %lld, count %lld\n", (long long)pos,
1250987da915Sopenharmony_ci		       (long long)count);
1251987da915Sopenharmony_ci
1252987da915Sopenharmony_ci	if (!na || pos < 0 || count < 0) {
1253987da915Sopenharmony_ci		errno = EINVAL;
1254987da915Sopenharmony_ci		goto err_out;
1255987da915Sopenharmony_ci	}
1256987da915Sopenharmony_ci
1257987da915Sopenharmony_ci	buf = ntfs_calloc(NTFS_BUF_SIZE);
1258987da915Sopenharmony_ci	if (!buf)
1259987da915Sopenharmony_ci		goto err_out;
1260987da915Sopenharmony_ci
1261987da915Sopenharmony_ci	rli = na->rl;
1262987da915Sopenharmony_ci	ofsi = 0;
1263987da915Sopenharmony_ci	vol = na->ni->vol;
1264987da915Sopenharmony_ci	while (pos < end) {
1265987da915Sopenharmony_ci		while (rli->length && (ofsi + (rli->length <<
1266987da915Sopenharmony_ci	                        vol->cluster_size_bits) <= pos)) {
1267987da915Sopenharmony_ci	                ofsi += (rli->length << vol->cluster_size_bits);
1268987da915Sopenharmony_ci			rli++;
1269987da915Sopenharmony_ci		}
1270987da915Sopenharmony_ci		size = min(end - pos, NTFS_BUF_SIZE);
1271987da915Sopenharmony_ci			/*
1272987da915Sopenharmony_ci			 * If the zeroed block is fully within a hole,
1273987da915Sopenharmony_ci			 * we need not write anything, so advance as far
1274987da915Sopenharmony_ci			 * as possible within the hole.
1275987da915Sopenharmony_ci			 */
1276987da915Sopenharmony_ci		if ((rli->lcn == (LCN)LCN_HOLE)
1277987da915Sopenharmony_ci		    && (ofsi <= pos)
1278987da915Sopenharmony_ci		    && (ofsi + (rli->length << vol->cluster_size_bits)
1279987da915Sopenharmony_ci				>= (pos + size))) {
1280987da915Sopenharmony_ci			size = min(end - pos, ofsi - pos
1281987da915Sopenharmony_ci				+ (rli->length << vol->cluster_size_bits));
1282987da915Sopenharmony_ci			pos += size;
1283987da915Sopenharmony_ci		} else {
1284987da915Sopenharmony_ci			written = ntfs_rl_pwrite(vol, rli, ofsi, pos,
1285987da915Sopenharmony_ci							size, buf);
1286987da915Sopenharmony_ci			if (written <= 0) {
1287987da915Sopenharmony_ci				ntfs_log_perror("Failed to zero space");
1288987da915Sopenharmony_ci				goto err_free;
1289987da915Sopenharmony_ci			}
1290987da915Sopenharmony_ci			pos += written;
1291987da915Sopenharmony_ci		}
1292987da915Sopenharmony_ci	}
1293987da915Sopenharmony_ci
1294987da915Sopenharmony_ci	ret = 0;
1295987da915Sopenharmony_cierr_free:
1296987da915Sopenharmony_ci	free(buf);
1297987da915Sopenharmony_cierr_out:
1298987da915Sopenharmony_ci	return ret;
1299987da915Sopenharmony_ci}
1300987da915Sopenharmony_ci
1301987da915Sopenharmony_cistatic int ntfs_attr_fill_hole(ntfs_attr *na, s64 count, s64 *ofs,
1302987da915Sopenharmony_ci			       runlist_element **rl, VCN *update_from)
1303987da915Sopenharmony_ci{
1304987da915Sopenharmony_ci	s64 to_write;
1305987da915Sopenharmony_ci	s64 need;
1306987da915Sopenharmony_ci	ntfs_volume *vol = na->ni->vol;
1307987da915Sopenharmony_ci	int eo, ret = -1;
1308987da915Sopenharmony_ci	runlist *rlc;
1309987da915Sopenharmony_ci	LCN lcn_seek_from = -1;
1310987da915Sopenharmony_ci	VCN cur_vcn, from_vcn;
1311987da915Sopenharmony_ci
1312987da915Sopenharmony_ci	if (na->ni->mft_no == FILE_Bitmap) {
1313987da915Sopenharmony_ci		/*
1314987da915Sopenharmony_ci		 * Filling a hole in the main bitmap implies allocating
1315987da915Sopenharmony_ci		 * clusters, which is likely to imply updating the
1316987da915Sopenharmony_ci		 * bitmap in a cluster being allocated.
1317987da915Sopenharmony_ci		 * Not supported now, could lead to endless recursions.
1318987da915Sopenharmony_ci		 */
1319987da915Sopenharmony_ci		ntfs_log_error("Corrupt $BitMap not fully allocated\n");
1320987da915Sopenharmony_ci		errno = EIO;
1321987da915Sopenharmony_ci		goto err_out;
1322987da915Sopenharmony_ci	}
1323987da915Sopenharmony_ci	to_write = min(count, ((*rl)->length << vol->cluster_size_bits) - *ofs);
1324987da915Sopenharmony_ci
1325987da915Sopenharmony_ci	cur_vcn = (*rl)->vcn;
1326987da915Sopenharmony_ci	from_vcn = (*rl)->vcn + (*ofs >> vol->cluster_size_bits);
1327987da915Sopenharmony_ci
1328987da915Sopenharmony_ci	ntfs_log_trace("count: %lld, cur_vcn: %lld, from: %lld, to: %lld, ofs: "
1329987da915Sopenharmony_ci		       "%lld\n", (long long)count, (long long)cur_vcn,
1330987da915Sopenharmony_ci		       (long long)from_vcn, (long long)to_write, (long long)*ofs);
1331987da915Sopenharmony_ci
1332987da915Sopenharmony_ci	/* Map the runlist to be able to update mapping pairs later. */
1333987da915Sopenharmony_ci#if PARTIAL_RUNLIST_UPDATING
1334987da915Sopenharmony_ci	if (!na->rl) {
1335987da915Sopenharmony_ci		if (ntfs_attr_map_whole_runlist(na))
1336987da915Sopenharmony_ci			goto err_out;
1337987da915Sopenharmony_ci	} else {
1338987da915Sopenharmony_ci		/* make sure the run ahead of hole is mapped */
1339987da915Sopenharmony_ci		if ((*rl)->lcn == LCN_HOLE) {
1340987da915Sopenharmony_ci			if (ntfs_attr_map_partial_runlist(na,
1341987da915Sopenharmony_ci				(cur_vcn ? cur_vcn - 1 : cur_vcn)))
1342987da915Sopenharmony_ci					goto err_out;
1343987da915Sopenharmony_ci		}
1344987da915Sopenharmony_ci	}
1345987da915Sopenharmony_ci#else
1346987da915Sopenharmony_ci	if (ntfs_attr_map_whole_runlist(na))
1347987da915Sopenharmony_ci		goto err_out;
1348987da915Sopenharmony_ci#endif
1349987da915Sopenharmony_ci
1350987da915Sopenharmony_ci	/* Restore @*rl, it probably get lost during runlist mapping. */
1351987da915Sopenharmony_ci	*rl = ntfs_attr_find_vcn(na, cur_vcn);
1352987da915Sopenharmony_ci	if (!*rl) {
1353987da915Sopenharmony_ci		ntfs_log_error("Failed to find run after mapping runlist. "
1354987da915Sopenharmony_ci			       "Please report to %s.\n", NTFS_DEV_LIST);
1355987da915Sopenharmony_ci		errno = EIO;
1356987da915Sopenharmony_ci		goto err_out;
1357987da915Sopenharmony_ci	}
1358987da915Sopenharmony_ci
1359987da915Sopenharmony_ci	/* Search backwards to find the best lcn to start seek from. */
1360987da915Sopenharmony_ci	rlc = *rl;
1361987da915Sopenharmony_ci	while (rlc->vcn) {
1362987da915Sopenharmony_ci		rlc--;
1363987da915Sopenharmony_ci		if (rlc->lcn >= 0) {
1364987da915Sopenharmony_ci				/*
1365987da915Sopenharmony_ci				 * avoid fragmenting a compressed file
1366987da915Sopenharmony_ci				 * Windows does not do that, and that may
1367987da915Sopenharmony_ci				 * not be desirable for files which can
1368987da915Sopenharmony_ci				 * be updated
1369987da915Sopenharmony_ci				 */
1370987da915Sopenharmony_ci			if (na->data_flags & ATTR_COMPRESSION_MASK)
1371987da915Sopenharmony_ci				lcn_seek_from = rlc->lcn + rlc->length;
1372987da915Sopenharmony_ci			else
1373987da915Sopenharmony_ci				lcn_seek_from = rlc->lcn + (from_vcn - rlc->vcn);
1374987da915Sopenharmony_ci			break;
1375987da915Sopenharmony_ci		}
1376987da915Sopenharmony_ci	}
1377987da915Sopenharmony_ci	if (lcn_seek_from == -1) {
1378987da915Sopenharmony_ci		/* Backwards search failed, search forwards. */
1379987da915Sopenharmony_ci		rlc = *rl;
1380987da915Sopenharmony_ci		while (rlc->length) {
1381987da915Sopenharmony_ci			rlc++;
1382987da915Sopenharmony_ci			if (rlc->lcn >= 0) {
1383987da915Sopenharmony_ci				lcn_seek_from = rlc->lcn - (rlc->vcn - from_vcn);
1384987da915Sopenharmony_ci				if (lcn_seek_from < -1)
1385987da915Sopenharmony_ci					lcn_seek_from = -1;
1386987da915Sopenharmony_ci				break;
1387987da915Sopenharmony_ci			}
1388987da915Sopenharmony_ci		}
1389987da915Sopenharmony_ci	}
1390987da915Sopenharmony_ci
1391987da915Sopenharmony_ci	need = ((*ofs + to_write - 1) >> vol->cluster_size_bits)
1392987da915Sopenharmony_ci			 + 1 + (*rl)->vcn - from_vcn;
1393987da915Sopenharmony_ci	if ((na->data_flags & ATTR_COMPRESSION_MASK)
1394987da915Sopenharmony_ci	    && (need < na->compression_block_clusters)) {
1395987da915Sopenharmony_ci		/*
1396987da915Sopenharmony_ci		 * for a compressed file, be sure to allocate the full
1397987da915Sopenharmony_ci		 * compression block, as we may need space to decompress
1398987da915Sopenharmony_ci		 * existing compressed data.
1399987da915Sopenharmony_ci		 * So allocate the space common to compression block
1400987da915Sopenharmony_ci		 * and existing hole.
1401987da915Sopenharmony_ci		 */
1402987da915Sopenharmony_ci		VCN alloc_vcn;
1403987da915Sopenharmony_ci
1404987da915Sopenharmony_ci		if ((from_vcn & -na->compression_block_clusters) <= (*rl)->vcn)
1405987da915Sopenharmony_ci			alloc_vcn = (*rl)->vcn;
1406987da915Sopenharmony_ci		else
1407987da915Sopenharmony_ci			alloc_vcn = from_vcn & -na->compression_block_clusters;
1408987da915Sopenharmony_ci		need = (alloc_vcn | (na->compression_block_clusters - 1))
1409987da915Sopenharmony_ci			+ 1 - alloc_vcn;
1410987da915Sopenharmony_ci		if (need > (*rl)->length) {
1411987da915Sopenharmony_ci			ntfs_log_error("Cannot allocate %lld clusters"
1412987da915Sopenharmony_ci					" within a hole of %lld\n",
1413987da915Sopenharmony_ci					(long long)need,
1414987da915Sopenharmony_ci					(long long)(*rl)->length);
1415987da915Sopenharmony_ci			errno = EIO;
1416987da915Sopenharmony_ci			goto err_out;
1417987da915Sopenharmony_ci		}
1418987da915Sopenharmony_ci		rlc = ntfs_cluster_alloc(vol, alloc_vcn, need,
1419987da915Sopenharmony_ci				 lcn_seek_from, DATA_ZONE);
1420987da915Sopenharmony_ci	} else
1421987da915Sopenharmony_ci		rlc = ntfs_cluster_alloc(vol, from_vcn, need,
1422987da915Sopenharmony_ci				 lcn_seek_from, DATA_ZONE);
1423987da915Sopenharmony_ci	if (!rlc)
1424987da915Sopenharmony_ci		goto err_out;
1425987da915Sopenharmony_ci	if (na->data_flags & (ATTR_COMPRESSION_MASK | ATTR_IS_SPARSE))
1426987da915Sopenharmony_ci		na->compressed_size += need << vol->cluster_size_bits;
1427987da915Sopenharmony_ci
1428987da915Sopenharmony_ci	*rl = ntfs_runlists_merge(na->rl, rlc);
1429987da915Sopenharmony_ci	NAttrSetRunlistDirty(na);
1430987da915Sopenharmony_ci		/*
1431987da915Sopenharmony_ci		 * For a compressed attribute, we must be sure there are two
1432987da915Sopenharmony_ci		 * available entries, so reserve them before it gets too late.
1433987da915Sopenharmony_ci		 */
1434987da915Sopenharmony_ci	if (*rl && (na->data_flags & ATTR_COMPRESSION_MASK)) {
1435987da915Sopenharmony_ci		runlist_element *oldrl = na->rl;
1436987da915Sopenharmony_ci		na->rl = *rl;
1437987da915Sopenharmony_ci		*rl = ntfs_rl_extend(na,*rl,2);
1438987da915Sopenharmony_ci		if (!*rl) na->rl = oldrl; /* restore to original if failed */
1439987da915Sopenharmony_ci	}
1440987da915Sopenharmony_ci	if (!*rl) {
1441987da915Sopenharmony_ci		eo = errno;
1442987da915Sopenharmony_ci		ntfs_log_perror("Failed to merge runlists");
1443987da915Sopenharmony_ci		if (ntfs_cluster_free_from_rl(vol, rlc)) {
1444987da915Sopenharmony_ci			ntfs_log_perror("Failed to free hot clusters. "
1445987da915Sopenharmony_ci					"Please run chkdsk /f");
1446987da915Sopenharmony_ci		}
1447987da915Sopenharmony_ci		errno = eo;
1448987da915Sopenharmony_ci		goto err_out;
1449987da915Sopenharmony_ci	}
1450987da915Sopenharmony_ci	na->unused_runs = 2;
1451987da915Sopenharmony_ci	na->rl = *rl;
1452987da915Sopenharmony_ci	if ((*update_from == -1) || (from_vcn < *update_from))
1453987da915Sopenharmony_ci		*update_from = from_vcn;
1454987da915Sopenharmony_ci	*rl = ntfs_attr_find_vcn(na, cur_vcn);
1455987da915Sopenharmony_ci	if (!*rl) {
1456987da915Sopenharmony_ci		/*
1457987da915Sopenharmony_ci		 * It's definitely a BUG, if we failed to find @cur_vcn, because
1458987da915Sopenharmony_ci		 * we missed it during instantiating of the hole.
1459987da915Sopenharmony_ci		 */
1460987da915Sopenharmony_ci		ntfs_log_error("Failed to find run after hole instantiation. "
1461987da915Sopenharmony_ci			       "Please report to %s.\n", NTFS_DEV_LIST);
1462987da915Sopenharmony_ci		errno = EIO;
1463987da915Sopenharmony_ci		goto err_out;
1464987da915Sopenharmony_ci	}
1465987da915Sopenharmony_ci	/* If leaved part of the hole go to the next run. */
1466987da915Sopenharmony_ci	if ((*rl)->lcn < 0)
1467987da915Sopenharmony_ci		(*rl)++;
1468987da915Sopenharmony_ci	/* Now LCN shoudn't be less than 0. */
1469987da915Sopenharmony_ci	if ((*rl)->lcn < 0) {
1470987da915Sopenharmony_ci		ntfs_log_error("BUG! LCN is lesser than 0. "
1471987da915Sopenharmony_ci			       "Please report to the %s.\n", NTFS_DEV_LIST);
1472987da915Sopenharmony_ci		errno = EIO;
1473987da915Sopenharmony_ci		goto err_out;
1474987da915Sopenharmony_ci	}
1475987da915Sopenharmony_ci	if (*ofs) {
1476987da915Sopenharmony_ci		/* Clear non-sparse region from @cur_vcn to @*ofs. */
1477987da915Sopenharmony_ci		if (ntfs_attr_fill_zero(na, cur_vcn << vol->cluster_size_bits,
1478987da915Sopenharmony_ci					*ofs))
1479987da915Sopenharmony_ci			goto err_out;
1480987da915Sopenharmony_ci	}
1481987da915Sopenharmony_ci	if ((*rl)->vcn < cur_vcn) {
1482987da915Sopenharmony_ci		/*
1483987da915Sopenharmony_ci		 * Clusters that replaced hole are merged with
1484987da915Sopenharmony_ci		 * previous run, so we need to update offset.
1485987da915Sopenharmony_ci		 */
1486987da915Sopenharmony_ci		*ofs += (cur_vcn - (*rl)->vcn) << vol->cluster_size_bits;
1487987da915Sopenharmony_ci	}
1488987da915Sopenharmony_ci	if ((*rl)->vcn > cur_vcn) {
1489987da915Sopenharmony_ci		/*
1490987da915Sopenharmony_ci		 * We left part of the hole, so we need to update offset
1491987da915Sopenharmony_ci		 */
1492987da915Sopenharmony_ci		*ofs -= ((*rl)->vcn - cur_vcn) << vol->cluster_size_bits;
1493987da915Sopenharmony_ci	}
1494987da915Sopenharmony_ci
1495987da915Sopenharmony_ci	ret = 0;
1496987da915Sopenharmony_cierr_out:
1497987da915Sopenharmony_ci	return ret;
1498987da915Sopenharmony_ci}
1499987da915Sopenharmony_ci
1500987da915Sopenharmony_cistatic int stuff_hole(ntfs_attr *na, const s64 pos);
1501987da915Sopenharmony_ci
1502987da915Sopenharmony_ci/*
1503987da915Sopenharmony_ci *		Split an existing hole for overwriting with data
1504987da915Sopenharmony_ci *	The hole may have to be split into two or three parts, so
1505987da915Sopenharmony_ci *	that the overwritten part fits within a single compression block
1506987da915Sopenharmony_ci *
1507987da915Sopenharmony_ci *	No cluster allocation is needed, this will be done later in
1508987da915Sopenharmony_ci *	standard hole filling, hence no need to reserve runs for
1509987da915Sopenharmony_ci *	future needs.
1510987da915Sopenharmony_ci *
1511987da915Sopenharmony_ci *	Returns the number of clusters with existing compressed data
1512987da915Sopenharmony_ci *		in the compression block to be written to
1513987da915Sopenharmony_ci *		(or the full block, if it was a full hole)
1514987da915Sopenharmony_ci *		-1 if there were an error
1515987da915Sopenharmony_ci */
1516987da915Sopenharmony_ci
1517987da915Sopenharmony_cistatic int split_compressed_hole(ntfs_attr *na, runlist_element **prl,
1518987da915Sopenharmony_ci    		s64 pos, s64 count, VCN *update_from)
1519987da915Sopenharmony_ci{
1520987da915Sopenharmony_ci	int compressed_part;
1521987da915Sopenharmony_ci	int cluster_size_bits = na->ni->vol->cluster_size_bits;
1522987da915Sopenharmony_ci	runlist_element *rl = *prl;
1523987da915Sopenharmony_ci
1524987da915Sopenharmony_ci	compressed_part
1525987da915Sopenharmony_ci		= na->compression_block_clusters;
1526987da915Sopenharmony_ci		/* reserve entries in runlist if we have to split */
1527987da915Sopenharmony_ci	if (rl->length > na->compression_block_clusters) {
1528987da915Sopenharmony_ci		*prl = ntfs_rl_extend(na,*prl,2);
1529987da915Sopenharmony_ci		if (!*prl) {
1530987da915Sopenharmony_ci			compressed_part = -1;
1531987da915Sopenharmony_ci		} else {
1532987da915Sopenharmony_ci			rl = *prl;
1533987da915Sopenharmony_ci			na->unused_runs = 2;
1534987da915Sopenharmony_ci		}
1535987da915Sopenharmony_ci	}
1536987da915Sopenharmony_ci	if (*prl && (rl->length > na->compression_block_clusters)) {
1537987da915Sopenharmony_ci		/*
1538987da915Sopenharmony_ci		 * Locate the update part relative to beginning of
1539987da915Sopenharmony_ci		 * current run
1540987da915Sopenharmony_ci		 */
1541987da915Sopenharmony_ci		int beginwrite = (pos >> cluster_size_bits) - rl->vcn;
1542987da915Sopenharmony_ci		s32 endblock = (((pos + count - 1) >> cluster_size_bits)
1543987da915Sopenharmony_ci			| (na->compression_block_clusters - 1)) + 1 - rl->vcn;
1544987da915Sopenharmony_ci
1545987da915Sopenharmony_ci		compressed_part = na->compression_block_clusters
1546987da915Sopenharmony_ci			- (rl->length & (na->compression_block_clusters - 1));
1547987da915Sopenharmony_ci		if ((beginwrite + compressed_part) >= na->compression_block_clusters)
1548987da915Sopenharmony_ci			compressed_part = na->compression_block_clusters;
1549987da915Sopenharmony_ci			/*
1550987da915Sopenharmony_ci			 * if the run ends beyond end of needed block
1551987da915Sopenharmony_ci			 * we have to split the run
1552987da915Sopenharmony_ci			 */
1553987da915Sopenharmony_ci		if (endblock < rl[0].length) {
1554987da915Sopenharmony_ci			runlist_element *xrl;
1555987da915Sopenharmony_ci			int n;
1556987da915Sopenharmony_ci
1557987da915Sopenharmony_ci			/*
1558987da915Sopenharmony_ci			 * we have to split into three parts if the run
1559987da915Sopenharmony_ci			 * does not end within the first compression block.
1560987da915Sopenharmony_ci			 * This means the hole begins before the
1561987da915Sopenharmony_ci			 * compression block.
1562987da915Sopenharmony_ci			 */
1563987da915Sopenharmony_ci			if (endblock > na->compression_block_clusters) {
1564987da915Sopenharmony_ci				if (na->unused_runs < 2) {
1565987da915Sopenharmony_cintfs_log_error("No free run, case 1\n");
1566987da915Sopenharmony_ci				}
1567987da915Sopenharmony_ci				na->unused_runs -= 2;
1568987da915Sopenharmony_ci				xrl = rl;
1569987da915Sopenharmony_ci				n = 0;
1570987da915Sopenharmony_ci				while (xrl->length) {
1571987da915Sopenharmony_ci					xrl++;
1572987da915Sopenharmony_ci					n++;
1573987da915Sopenharmony_ci				}
1574987da915Sopenharmony_ci				do {
1575987da915Sopenharmony_ci					xrl[2] = *xrl;
1576987da915Sopenharmony_ci					xrl--;
1577987da915Sopenharmony_ci				} while (xrl != rl);
1578987da915Sopenharmony_ci				rl[1].length = na->compression_block_clusters;
1579987da915Sopenharmony_ci				rl[2].length = rl[0].length - endblock;
1580987da915Sopenharmony_ci				rl[0].length = endblock
1581987da915Sopenharmony_ci					- na->compression_block_clusters;
1582987da915Sopenharmony_ci				rl[1].lcn = LCN_HOLE;
1583987da915Sopenharmony_ci				rl[2].lcn = LCN_HOLE;
1584987da915Sopenharmony_ci				rl[1].vcn = rl[0].vcn + rl[0].length;
1585987da915Sopenharmony_ci				rl[2].vcn = rl[1].vcn
1586987da915Sopenharmony_ci					+ na->compression_block_clusters;
1587987da915Sopenharmony_ci				rl = ++(*prl);
1588987da915Sopenharmony_ci			} else {
1589987da915Sopenharmony_ci				/*
1590987da915Sopenharmony_ci				 * split into two parts and use the
1591987da915Sopenharmony_ci				 * first one
1592987da915Sopenharmony_ci				 */
1593987da915Sopenharmony_ci				if (!na->unused_runs) {
1594987da915Sopenharmony_cintfs_log_error("No free run, case 2\n");
1595987da915Sopenharmony_ci				}
1596987da915Sopenharmony_ci				na->unused_runs--;
1597987da915Sopenharmony_ci				xrl = rl;
1598987da915Sopenharmony_ci				n = 0;
1599987da915Sopenharmony_ci				while (xrl->length) {
1600987da915Sopenharmony_ci					xrl++;
1601987da915Sopenharmony_ci					n++;
1602987da915Sopenharmony_ci				}
1603987da915Sopenharmony_ci				do {
1604987da915Sopenharmony_ci					xrl[1] = *xrl;
1605987da915Sopenharmony_ci					xrl--;
1606987da915Sopenharmony_ci				} while (xrl != rl);
1607987da915Sopenharmony_ci				if (beginwrite < endblock) {
1608987da915Sopenharmony_ci					/* we will write into the first part of hole */
1609987da915Sopenharmony_ci					rl[1].length = rl[0].length - endblock;
1610987da915Sopenharmony_ci					rl[0].length = endblock;
1611987da915Sopenharmony_ci					rl[1].vcn = rl[0].vcn + rl[0].length;
1612987da915Sopenharmony_ci					rl[1].lcn = LCN_HOLE;
1613987da915Sopenharmony_ci				} else {
1614987da915Sopenharmony_ci					/* we will write into the second part of hole */
1615987da915Sopenharmony_ci// impossible ?
1616987da915Sopenharmony_ci					rl[1].length = rl[0].length - endblock;
1617987da915Sopenharmony_ci					rl[0].length = endblock;
1618987da915Sopenharmony_ci					rl[1].vcn = rl[0].vcn + rl[0].length;
1619987da915Sopenharmony_ci					rl[1].lcn = LCN_HOLE;
1620987da915Sopenharmony_ci					rl = ++(*prl);
1621987da915Sopenharmony_ci				}
1622987da915Sopenharmony_ci			}
1623987da915Sopenharmony_ci		} else {
1624987da915Sopenharmony_ci			if (rl[1].length) {
1625987da915Sopenharmony_ci				runlist_element *xrl;
1626987da915Sopenharmony_ci				int n;
1627987da915Sopenharmony_ci
1628987da915Sopenharmony_ci				/*
1629987da915Sopenharmony_ci				 * split into two parts and use the
1630987da915Sopenharmony_ci				 * last one
1631987da915Sopenharmony_ci				 */
1632987da915Sopenharmony_ci				if (!na->unused_runs) {
1633987da915Sopenharmony_cintfs_log_error("No free run, case 4\n");
1634987da915Sopenharmony_ci				}
1635987da915Sopenharmony_ci				na->unused_runs--;
1636987da915Sopenharmony_ci				xrl = rl;
1637987da915Sopenharmony_ci				n = 0;
1638987da915Sopenharmony_ci				while (xrl->length) {
1639987da915Sopenharmony_ci					xrl++;
1640987da915Sopenharmony_ci					n++;
1641987da915Sopenharmony_ci				}
1642987da915Sopenharmony_ci				do {
1643987da915Sopenharmony_ci					xrl[1] = *xrl;
1644987da915Sopenharmony_ci					xrl--;
1645987da915Sopenharmony_ci				} while (xrl != rl);
1646987da915Sopenharmony_ci			} else {
1647987da915Sopenharmony_ci				rl[2].lcn = rl[1].lcn;
1648987da915Sopenharmony_ci				rl[2].vcn = rl[1].vcn;
1649987da915Sopenharmony_ci				rl[2].length = rl[1].length;
1650987da915Sopenharmony_ci			}
1651987da915Sopenharmony_ci			rl[1].vcn -= na->compression_block_clusters;
1652987da915Sopenharmony_ci			rl[1].lcn = LCN_HOLE;
1653987da915Sopenharmony_ci			rl[1].length = na->compression_block_clusters;
1654987da915Sopenharmony_ci			rl[0].length -= na->compression_block_clusters;
1655987da915Sopenharmony_ci			if (pos >= (rl[1].vcn << cluster_size_bits)) {
1656987da915Sopenharmony_ci				rl = ++(*prl);
1657987da915Sopenharmony_ci			}
1658987da915Sopenharmony_ci		}
1659987da915Sopenharmony_ci	NAttrSetRunlistDirty(na);
1660987da915Sopenharmony_ci	if ((*update_from == -1) || ((*prl)->vcn < *update_from))
1661987da915Sopenharmony_ci		*update_from = (*prl)->vcn;
1662987da915Sopenharmony_ci	}
1663987da915Sopenharmony_ci	return (compressed_part);
1664987da915Sopenharmony_ci}
1665987da915Sopenharmony_ci
1666987da915Sopenharmony_ci/*
1667987da915Sopenharmony_ci *		Borrow space from adjacent hole for appending data
1668987da915Sopenharmony_ci *	The hole may have to be split so that the end of hole is not
1669987da915Sopenharmony_ci *	affected by cluster allocation and overwriting
1670987da915Sopenharmony_ci *	Cluster allocation is needed for the overwritten compression block
1671987da915Sopenharmony_ci *
1672987da915Sopenharmony_ci *	Must always leave two unused entries in the runlist
1673987da915Sopenharmony_ci *
1674987da915Sopenharmony_ci *	Returns the number of clusters with existing compressed data
1675987da915Sopenharmony_ci *		in the compression block to be written to
1676987da915Sopenharmony_ci *		-1 if there were an error
1677987da915Sopenharmony_ci */
1678987da915Sopenharmony_ci
1679987da915Sopenharmony_cistatic int borrow_from_hole(ntfs_attr *na, runlist_element **prl,
1680987da915Sopenharmony_ci    		s64 pos, s64 count, VCN *update_from, BOOL wasnonresident)
1681987da915Sopenharmony_ci{
1682987da915Sopenharmony_ci	int compressed_part = 0;
1683987da915Sopenharmony_ci	int cluster_size_bits = na->ni->vol->cluster_size_bits;
1684987da915Sopenharmony_ci	runlist_element *rl = *prl;
1685987da915Sopenharmony_ci	s32 endblock;
1686987da915Sopenharmony_ci	long long allocated;
1687987da915Sopenharmony_ci	runlist_element *zrl;
1688987da915Sopenharmony_ci	int irl;
1689987da915Sopenharmony_ci	BOOL undecided;
1690987da915Sopenharmony_ci	BOOL nothole;
1691987da915Sopenharmony_ci
1692987da915Sopenharmony_ci		/* check whether the compression block is fully allocated */
1693987da915Sopenharmony_ci	endblock = (((pos + count - 1) >> cluster_size_bits) | (na->compression_block_clusters - 1)) + 1 - rl->vcn;
1694987da915Sopenharmony_ci	allocated = 0;
1695987da915Sopenharmony_ci	zrl = rl;
1696987da915Sopenharmony_ci	irl = 0;
1697987da915Sopenharmony_ci	while (zrl->length && (zrl->lcn >= 0) && (allocated < endblock)) {
1698987da915Sopenharmony_ci		allocated += zrl->length;
1699987da915Sopenharmony_ci		zrl++;
1700987da915Sopenharmony_ci		irl++;
1701987da915Sopenharmony_ci	}
1702987da915Sopenharmony_ci
1703987da915Sopenharmony_ci	undecided = (allocated < endblock) && (zrl->lcn == LCN_RL_NOT_MAPPED);
1704987da915Sopenharmony_ci	nothole = (allocated >= endblock) || (zrl->lcn != LCN_HOLE);
1705987da915Sopenharmony_ci
1706987da915Sopenharmony_ci	if (undecided || nothole) {
1707987da915Sopenharmony_ci		runlist_element *orl = na->rl;
1708987da915Sopenharmony_ci		s64 olcn = (*prl)->lcn;
1709987da915Sopenharmony_ci#if PARTIAL_RUNLIST_UPDATING
1710987da915Sopenharmony_ci		VCN prevblock;
1711987da915Sopenharmony_ci#endif
1712987da915Sopenharmony_ci			/*
1713987da915Sopenharmony_ci			 * Map the runlist, unless it has not been created.
1714987da915Sopenharmony_ci			 * If appending data, a partial mapping from the
1715987da915Sopenharmony_ci			 * end of previous block will do.
1716987da915Sopenharmony_ci			 */
1717987da915Sopenharmony_ci		irl = *prl - na->rl;
1718987da915Sopenharmony_ci#if PARTIAL_RUNLIST_UPDATING
1719987da915Sopenharmony_ci		prevblock = pos >> cluster_size_bits;
1720987da915Sopenharmony_ci		if (prevblock)
1721987da915Sopenharmony_ci			prevblock--;
1722987da915Sopenharmony_ci		if (!NAttrBeingNonResident(na)
1723987da915Sopenharmony_ci		    && (NAttrDataAppending(na)
1724987da915Sopenharmony_ci			? ntfs_attr_map_partial_runlist(na,prevblock)
1725987da915Sopenharmony_ci			: ntfs_attr_map_whole_runlist(na))) {
1726987da915Sopenharmony_ci#else
1727987da915Sopenharmony_ci		if (!NAttrBeingNonResident(na)
1728987da915Sopenharmony_ci			&& ntfs_attr_map_whole_runlist(na)) {
1729987da915Sopenharmony_ci#endif
1730987da915Sopenharmony_ci			rl = (runlist_element*)NULL;
1731987da915Sopenharmony_ci		} else {
1732987da915Sopenharmony_ci			/*
1733987da915Sopenharmony_ci			 * Mapping the runlist may cause its relocation,
1734987da915Sopenharmony_ci			 * and relocation may be at the same place with
1735987da915Sopenharmony_ci			 * relocated contents.
1736987da915Sopenharmony_ci			 * Have to find the current run again when this
1737987da915Sopenharmony_ci			 * happens.
1738987da915Sopenharmony_ci			 */
1739987da915Sopenharmony_ci			if ((na->rl != orl) || ((*prl)->lcn != olcn)) {
1740987da915Sopenharmony_ci				zrl = &na->rl[irl];
1741987da915Sopenharmony_ci				while (zrl->length && (zrl->lcn != olcn))
1742987da915Sopenharmony_ci					zrl++;
1743987da915Sopenharmony_ci				*prl = zrl;
1744987da915Sopenharmony_ci			}
1745987da915Sopenharmony_ci			if (!(*prl)->length) {
1746987da915Sopenharmony_ci				 ntfs_log_error("Mapped run not found,"
1747987da915Sopenharmony_ci					" inode %lld lcn 0x%llx\n",
1748987da915Sopenharmony_ci					(long long)na->ni->mft_no,
1749987da915Sopenharmony_ci					(long long)olcn);
1750987da915Sopenharmony_ci				rl = (runlist_element*)NULL;
1751987da915Sopenharmony_ci			} else {
1752987da915Sopenharmony_ci				rl = ntfs_rl_extend(na,*prl,2);
1753987da915Sopenharmony_ci				na->unused_runs = 2;
1754987da915Sopenharmony_ci			}
1755987da915Sopenharmony_ci		}
1756987da915Sopenharmony_ci		*prl = rl;
1757987da915Sopenharmony_ci		if (rl && undecided) {
1758987da915Sopenharmony_ci			allocated = 0;
1759987da915Sopenharmony_ci			zrl = rl;
1760987da915Sopenharmony_ci			irl = 0;
1761987da915Sopenharmony_ci			while (zrl->length && (zrl->lcn >= 0)
1762987da915Sopenharmony_ci			    && (allocated < endblock)) {
1763987da915Sopenharmony_ci				allocated += zrl->length;
1764987da915Sopenharmony_ci				zrl++;
1765987da915Sopenharmony_ci				irl++;
1766987da915Sopenharmony_ci			}
1767987da915Sopenharmony_ci		}
1768987da915Sopenharmony_ci	}
1769987da915Sopenharmony_ci		/*
1770987da915Sopenharmony_ci		 * compression block not fully allocated and followed
1771987da915Sopenharmony_ci		 * by a hole : we must allocate in the hole.
1772987da915Sopenharmony_ci		 */
1773987da915Sopenharmony_ci	if (rl && (allocated < endblock) && (zrl->lcn == LCN_HOLE)) {
1774987da915Sopenharmony_ci		s64 xofs;
1775987da915Sopenharmony_ci
1776987da915Sopenharmony_ci			/*
1777987da915Sopenharmony_ci			 * split the hole if not fully needed
1778987da915Sopenharmony_ci			 */
1779987da915Sopenharmony_ci		if ((allocated + zrl->length) > endblock) {
1780987da915Sopenharmony_ci			runlist_element *xrl;
1781987da915Sopenharmony_ci
1782987da915Sopenharmony_ci			*prl = ntfs_rl_extend(na,*prl,1);
1783987da915Sopenharmony_ci			if (*prl) {
1784987da915Sopenharmony_ci					/* beware : rl was reallocated */
1785987da915Sopenharmony_ci				rl = *prl;
1786987da915Sopenharmony_ci				zrl = &rl[irl];
1787987da915Sopenharmony_ci				na->unused_runs = 0;
1788987da915Sopenharmony_ci				xrl = zrl;
1789987da915Sopenharmony_ci				while (xrl->length) xrl++;
1790987da915Sopenharmony_ci				do {
1791987da915Sopenharmony_ci					xrl[1] = *xrl;
1792987da915Sopenharmony_ci				} while (xrl-- != zrl);
1793987da915Sopenharmony_ci				zrl->length = endblock - allocated;
1794987da915Sopenharmony_ci				zrl[1].length -= zrl->length;
1795987da915Sopenharmony_ci				zrl[1].vcn = zrl->vcn + zrl->length;
1796987da915Sopenharmony_ci				NAttrSetRunlistDirty(na);
1797987da915Sopenharmony_ci			}
1798987da915Sopenharmony_ci		}
1799987da915Sopenharmony_ci		if (*prl) {
1800987da915Sopenharmony_ci			if (wasnonresident)
1801987da915Sopenharmony_ci				compressed_part = na->compression_block_clusters
1802987da915Sopenharmony_ci				   - zrl->length;
1803987da915Sopenharmony_ci			xofs = 0;
1804987da915Sopenharmony_ci			if (ntfs_attr_fill_hole(na,
1805987da915Sopenharmony_ci				    zrl->length << cluster_size_bits,
1806987da915Sopenharmony_ci				    &xofs, &zrl, update_from))
1807987da915Sopenharmony_ci					compressed_part = -1;
1808987da915Sopenharmony_ci			else {
1809987da915Sopenharmony_ci			/* go back to initial cluster, now reallocated */
1810987da915Sopenharmony_ci				while (zrl->vcn > (pos >> cluster_size_bits))
1811987da915Sopenharmony_ci					zrl--;
1812987da915Sopenharmony_ci				*prl = zrl;
1813987da915Sopenharmony_ci			}
1814987da915Sopenharmony_ci		}
1815987da915Sopenharmony_ci	}
1816987da915Sopenharmony_ci	if (!*prl) {
1817987da915Sopenharmony_ci		ntfs_log_error("No elements to borrow from a hole\n");
1818987da915Sopenharmony_ci		compressed_part = -1;
1819987da915Sopenharmony_ci	} else
1820987da915Sopenharmony_ci		if ((*update_from == -1) || ((*prl)->vcn < *update_from))
1821987da915Sopenharmony_ci			*update_from = (*prl)->vcn;
1822987da915Sopenharmony_ci	return (compressed_part);
1823987da915Sopenharmony_ci}
1824987da915Sopenharmony_ci
1825987da915Sopenharmony_cistatic int ntfs_attr_truncate_i(ntfs_attr *na, const s64 newsize,
1826987da915Sopenharmony_ci				hole_type holes);
1827987da915Sopenharmony_ci
1828987da915Sopenharmony_ci/**
1829987da915Sopenharmony_ci * ntfs_attr_pwrite - positioned write to an ntfs attribute
1830987da915Sopenharmony_ci * @na:		ntfs attribute to write to
1831987da915Sopenharmony_ci * @pos:	position in the attribute to write to
1832987da915Sopenharmony_ci * @count:	number of bytes to write
1833987da915Sopenharmony_ci * @b:		data buffer to write to disk
1834987da915Sopenharmony_ci *
1835987da915Sopenharmony_ci * This function will write @count bytes from data buffer @b to ntfs attribute
1836987da915Sopenharmony_ci * @na at position @pos.
1837987da915Sopenharmony_ci *
1838987da915Sopenharmony_ci * On success, return the number of successfully written bytes. If this number
1839987da915Sopenharmony_ci * is lower than @count this means that an error was encountered during the
1840987da915Sopenharmony_ci * write so that the write is partial. 0 means nothing was written (also return
1841987da915Sopenharmony_ci * 0 when @count is 0).
1842987da915Sopenharmony_ci *
1843987da915Sopenharmony_ci * On error and nothing has been written, return -1 with errno set
1844987da915Sopenharmony_ci * appropriately to the return code of ntfs_pwrite(), or to EINVAL in case of
1845987da915Sopenharmony_ci * invalid arguments.
1846987da915Sopenharmony_ci */
1847987da915Sopenharmony_cistatic s64 ntfs_attr_pwrite_i(ntfs_attr *na, const s64 pos, s64 count,
1848987da915Sopenharmony_ci								const void *b)
1849987da915Sopenharmony_ci{
1850987da915Sopenharmony_ci	s64 written, to_write, ofs, old_initialized_size, old_data_size;
1851987da915Sopenharmony_ci	s64 total = 0;
1852987da915Sopenharmony_ci	VCN update_from = -1;
1853987da915Sopenharmony_ci	ntfs_volume *vol;
1854987da915Sopenharmony_ci	s64 fullcount;
1855987da915Sopenharmony_ci	ntfs_attr_search_ctx *ctx = NULL;
1856987da915Sopenharmony_ci	runlist_element *rl;
1857987da915Sopenharmony_ci	s64 hole_end;
1858987da915Sopenharmony_ci	int eo;
1859987da915Sopenharmony_ci	int compressed_part;
1860987da915Sopenharmony_ci	struct {
1861987da915Sopenharmony_ci		unsigned int undo_initialized_size	: 1;
1862987da915Sopenharmony_ci		unsigned int undo_data_size		: 1;
1863987da915Sopenharmony_ci	} need_to = { 0, 0 };
1864987da915Sopenharmony_ci	BOOL wasnonresident = FALSE;
1865987da915Sopenharmony_ci	BOOL compressed;
1866987da915Sopenharmony_ci
1867987da915Sopenharmony_ci	vol = na->ni->vol;
1868987da915Sopenharmony_ci	compressed = (na->data_flags & ATTR_COMPRESSION_MASK)
1869987da915Sopenharmony_ci			 != const_cpu_to_le16(0);
1870987da915Sopenharmony_ci	na->unused_runs = 0; /* prepare overflow checks */
1871987da915Sopenharmony_ci	/*
1872987da915Sopenharmony_ci	 * Encrypted attributes are only supported in raw mode.  We return
1873987da915Sopenharmony_ci	 * access denied, which is what Windows NT4 does, too.
1874987da915Sopenharmony_ci	 * Moreover a file cannot be both encrypted and compressed.
1875987da915Sopenharmony_ci	 */
1876987da915Sopenharmony_ci	if ((na->data_flags & ATTR_IS_ENCRYPTED)
1877987da915Sopenharmony_ci	   && (compressed || !vol->efs_raw)) {
1878987da915Sopenharmony_ci		errno = EACCES;
1879987da915Sopenharmony_ci		goto errno_set;
1880987da915Sopenharmony_ci	}
1881987da915Sopenharmony_ci		/*
1882987da915Sopenharmony_ci		 * Fill the gap, when writing beyond the end of a compressed
1883987da915Sopenharmony_ci		 * file. This will make recursive calls
1884987da915Sopenharmony_ci		 */
1885987da915Sopenharmony_ci	if (compressed
1886987da915Sopenharmony_ci	    && (na->type == AT_DATA)
1887987da915Sopenharmony_ci	    && (pos > na->initialized_size)
1888987da915Sopenharmony_ci	    && stuff_hole(na,pos))
1889987da915Sopenharmony_ci		goto errno_set;
1890987da915Sopenharmony_ci	/* If this is a compressed attribute it needs special treatment. */
1891987da915Sopenharmony_ci	wasnonresident = NAttrNonResident(na) != 0;
1892987da915Sopenharmony_ci		/*
1893987da915Sopenharmony_ci		 * Compression is restricted to data streams and
1894987da915Sopenharmony_ci		 * only ATTR_IS_COMPRESSED compression mode is supported.
1895987da915Sopenharmony_ci                 */
1896987da915Sopenharmony_ci	if (compressed
1897987da915Sopenharmony_ci	    && ((na->type != AT_DATA)
1898987da915Sopenharmony_ci		|| ((na->data_flags & ATTR_COMPRESSION_MASK)
1899987da915Sopenharmony_ci			 != ATTR_IS_COMPRESSED))) {
1900987da915Sopenharmony_ci		errno = EOPNOTSUPP;
1901987da915Sopenharmony_ci		goto errno_set;
1902987da915Sopenharmony_ci	}
1903987da915Sopenharmony_ci
1904987da915Sopenharmony_ci	if (!count)
1905987da915Sopenharmony_ci		goto out;
1906987da915Sopenharmony_ci	/* for a compressed file, get prepared to reserve a full block */
1907987da915Sopenharmony_ci	fullcount = count;
1908987da915Sopenharmony_ci	/* If the write reaches beyond the end, extend the attribute. */
1909987da915Sopenharmony_ci	old_data_size = na->data_size;
1910987da915Sopenharmony_ci	/* identify whether this is appending to a non resident data attribute */
1911987da915Sopenharmony_ci	if ((na->type == AT_DATA) && (pos >= old_data_size)
1912987da915Sopenharmony_ci	    && NAttrNonResident(na))
1913987da915Sopenharmony_ci		NAttrSetDataAppending(na);
1914987da915Sopenharmony_ci	if (pos + count > na->data_size) {
1915987da915Sopenharmony_ci#if PARTIAL_RUNLIST_UPDATING
1916987da915Sopenharmony_ci		/*
1917987da915Sopenharmony_ci		 * When appending data, the attribute is first extended
1918987da915Sopenharmony_ci		 * before being filled with data. This may cause the
1919987da915Sopenharmony_ci		 * attribute to be made temporarily sparse, which
1920987da915Sopenharmony_ci		 * implies reformating the inode and reorganizing the
1921987da915Sopenharmony_ci		 * full runlist. To avoid unnecessary reorganization,
1922987da915Sopenharmony_ci		 * we avoid sparse testing until the data is filled in.
1923987da915Sopenharmony_ci		 */
1924987da915Sopenharmony_ci		if (ntfs_attr_truncate_i(na, pos + count,
1925987da915Sopenharmony_ci					(NAttrDataAppending(na) ?
1926987da915Sopenharmony_ci						HOLES_DELAY : HOLES_OK))) {
1927987da915Sopenharmony_ci			ntfs_log_perror("Failed to enlarge attribute");
1928987da915Sopenharmony_ci			goto errno_set;
1929987da915Sopenharmony_ci		}
1930987da915Sopenharmony_ci		/*
1931987da915Sopenharmony_ci		 * If we avoided updating the runlist, we must be sure
1932987da915Sopenharmony_ci		 * to cancel the enlargement and put back the runlist to
1933987da915Sopenharmony_ci		 * a clean state if we get into some error.
1934987da915Sopenharmony_ci		 */
1935987da915Sopenharmony_ci		if (NAttrDataAppending(na))
1936987da915Sopenharmony_ci			need_to.undo_data_size = 1;
1937987da915Sopenharmony_ci#else
1938987da915Sopenharmony_ci		if (ntfs_attr_truncate_i(na, pos + count, HOLES_OK)) {
1939987da915Sopenharmony_ci			ntfs_log_perror("Failed to enlarge attribute");
1940987da915Sopenharmony_ci			goto errno_set;
1941987da915Sopenharmony_ci		}
1942987da915Sopenharmony_ci#endif
1943987da915Sopenharmony_ci			/* resizing may change the compression mode */
1944987da915Sopenharmony_ci		compressed = (na->data_flags & ATTR_COMPRESSION_MASK)
1945987da915Sopenharmony_ci				!= const_cpu_to_le16(0);
1946987da915Sopenharmony_ci		need_to.undo_data_size = 1;
1947987da915Sopenharmony_ci	}
1948987da915Sopenharmony_ci		/*
1949987da915Sopenharmony_ci		 * For compressed data, a single full block was allocated
1950987da915Sopenharmony_ci		 * to deal with compression, possibly in a previous call.
1951987da915Sopenharmony_ci		 * We are not able to process several blocks because
1952987da915Sopenharmony_ci		 * some clusters are freed after compression and
1953987da915Sopenharmony_ci		 * new allocations have to be done before proceeding,
1954987da915Sopenharmony_ci		 * so truncate the requested count if needed (big buffers).
1955987da915Sopenharmony_ci		 */
1956987da915Sopenharmony_ci	if (compressed) {
1957987da915Sopenharmony_ci		fullcount = (pos | (na->compression_block_size - 1)) + 1 - pos;
1958987da915Sopenharmony_ci		if (count > fullcount)
1959987da915Sopenharmony_ci			count = fullcount;
1960987da915Sopenharmony_ci	}
1961987da915Sopenharmony_ci	old_initialized_size = na->initialized_size;
1962987da915Sopenharmony_ci	/* If it is a resident attribute, write the data to the mft record. */
1963987da915Sopenharmony_ci	if (!NAttrNonResident(na)) {
1964987da915Sopenharmony_ci		char *val;
1965987da915Sopenharmony_ci
1966987da915Sopenharmony_ci		ctx = ntfs_attr_get_search_ctx(na->ni, NULL);
1967987da915Sopenharmony_ci		if (!ctx)
1968987da915Sopenharmony_ci			goto err_out;
1969987da915Sopenharmony_ci		if (ntfs_attr_lookup(na->type, na->name, na->name_len, 0,
1970987da915Sopenharmony_ci				0, NULL, 0, ctx)) {
1971987da915Sopenharmony_ci			ntfs_log_perror("%s: lookup failed", __FUNCTION__);
1972987da915Sopenharmony_ci			goto err_out;
1973987da915Sopenharmony_ci		}
1974987da915Sopenharmony_ci		val = (char*)ctx->attr + le16_to_cpu(ctx->attr->value_offset);
1975987da915Sopenharmony_ci		if (val < (char*)ctx->attr || val +
1976987da915Sopenharmony_ci				le32_to_cpu(ctx->attr->value_length) >
1977987da915Sopenharmony_ci				(char*)ctx->mrec + vol->mft_record_size) {
1978987da915Sopenharmony_ci			errno = EIO;
1979987da915Sopenharmony_ci			ntfs_log_perror("%s: Sanity check failed", __FUNCTION__);
1980987da915Sopenharmony_ci			goto err_out;
1981987da915Sopenharmony_ci		}
1982987da915Sopenharmony_ci		memcpy(val + pos, b, count);
1983987da915Sopenharmony_ci		if (ntfs_mft_record_write(vol, ctx->ntfs_ino->mft_no,
1984987da915Sopenharmony_ci				ctx->mrec)) {
1985987da915Sopenharmony_ci			/*
1986987da915Sopenharmony_ci			 * NOTE: We are in a bad state at this moment. We have
1987987da915Sopenharmony_ci			 * dirtied the mft record but we failed to commit it to
1988987da915Sopenharmony_ci			 * disk. Since we have read the mft record ok before,
1989987da915Sopenharmony_ci			 * it is unlikely to fail writing it, so is ok to just
1990987da915Sopenharmony_ci			 * return error here... (AIA)
1991987da915Sopenharmony_ci			 */
1992987da915Sopenharmony_ci			ntfs_log_perror("%s: failed to write mft record", __FUNCTION__);
1993987da915Sopenharmony_ci			goto err_out;
1994987da915Sopenharmony_ci		}
1995987da915Sopenharmony_ci		ntfs_attr_put_search_ctx(ctx);
1996987da915Sopenharmony_ci		total = count;
1997987da915Sopenharmony_ci		goto out;
1998987da915Sopenharmony_ci	}
1999987da915Sopenharmony_ci
2000987da915Sopenharmony_ci	/* Handle writes beyond initialized_size. */
2001987da915Sopenharmony_ci
2002987da915Sopenharmony_ci	if (pos + count > na->initialized_size) {
2003987da915Sopenharmony_ci#if PARTIAL_RUNLIST_UPDATING
2004987da915Sopenharmony_ci		/*
2005987da915Sopenharmony_ci		 * When appending, we only need to map the end of the runlist,
2006987da915Sopenharmony_ci		 * starting at the last previously allocated run, so that
2007987da915Sopenharmony_ci		 * we are able a new one to it.
2008987da915Sopenharmony_ci		 * However, for compressed file, we need the full compression
2009987da915Sopenharmony_ci		 * block, which may be split in several extents.
2010987da915Sopenharmony_ci		 */
2011987da915Sopenharmony_ci		if (compressed && !NAttrDataAppending(na)) {
2012987da915Sopenharmony_ci			if (ntfs_attr_map_whole_runlist(na))
2013987da915Sopenharmony_ci				goto err_out;
2014987da915Sopenharmony_ci		} else {
2015987da915Sopenharmony_ci			VCN block_begin;
2016987da915Sopenharmony_ci
2017987da915Sopenharmony_ci			if (NAttrDataAppending(na)
2018987da915Sopenharmony_ci			    || (pos < na->initialized_size))
2019987da915Sopenharmony_ci				block_begin = pos >> vol->cluster_size_bits;
2020987da915Sopenharmony_ci			else
2021987da915Sopenharmony_ci				block_begin = na->initialized_size >> vol->cluster_size_bits;
2022987da915Sopenharmony_ci
2023987da915Sopenharmony_ci			if (compressed)
2024987da915Sopenharmony_ci				block_begin &= -na->compression_block_clusters;
2025987da915Sopenharmony_ci			if (block_begin)
2026987da915Sopenharmony_ci				block_begin--;
2027987da915Sopenharmony_ci			if (ntfs_attr_map_partial_runlist(na, block_begin))
2028987da915Sopenharmony_ci				goto err_out;
2029987da915Sopenharmony_ci			if ((update_from == -1) || (block_begin < update_from))
2030987da915Sopenharmony_ci				update_from = block_begin;
2031987da915Sopenharmony_ci		}
2032987da915Sopenharmony_ci#else
2033987da915Sopenharmony_ci			if (ntfs_attr_map_whole_runlist(na))
2034987da915Sopenharmony_ci				goto err_out;
2035987da915Sopenharmony_ci#endif
2036987da915Sopenharmony_ci		/*
2037987da915Sopenharmony_ci		 * For a compressed attribute, we must be sure there is an
2038987da915Sopenharmony_ci		 * available entry, and, when reopening a compressed file,
2039987da915Sopenharmony_ci		 * we may need to split a hole. So reserve the entries
2040987da915Sopenharmony_ci		 * before it gets too late.
2041987da915Sopenharmony_ci		 */
2042987da915Sopenharmony_ci		if (compressed) {
2043987da915Sopenharmony_ci			na->rl = ntfs_rl_extend(na,na->rl,2);
2044987da915Sopenharmony_ci			if (!na->rl)
2045987da915Sopenharmony_ci				goto err_out;
2046987da915Sopenharmony_ci			na->unused_runs = 2;
2047987da915Sopenharmony_ci		}
2048987da915Sopenharmony_ci		/* Set initialized_size to @pos + @count. */
2049987da915Sopenharmony_ci		ctx = ntfs_attr_get_search_ctx(na->ni, NULL);
2050987da915Sopenharmony_ci		if (!ctx)
2051987da915Sopenharmony_ci			goto err_out;
2052987da915Sopenharmony_ci		if (ntfs_attr_lookup(na->type, na->name, na->name_len, 0,
2053987da915Sopenharmony_ci				0, NULL, 0, ctx))
2054987da915Sopenharmony_ci			goto err_out;
2055987da915Sopenharmony_ci
2056987da915Sopenharmony_ci		/* If write starts beyond initialized_size, zero the gap. */
2057987da915Sopenharmony_ci		if (pos > na->initialized_size)
2058987da915Sopenharmony_ci			if (ntfs_attr_fill_zero(na, na->initialized_size,
2059987da915Sopenharmony_ci						pos - na->initialized_size))
2060987da915Sopenharmony_ci				goto err_out;
2061987da915Sopenharmony_ci
2062987da915Sopenharmony_ci		ctx->attr->initialized_size = cpu_to_sle64(pos + count);
2063987da915Sopenharmony_ci		/* fix data_size for compressed files */
2064987da915Sopenharmony_ci		if (compressed) {
2065987da915Sopenharmony_ci			na->data_size = pos + count;
2066987da915Sopenharmony_ci			ctx->attr->data_size = ctx->attr->initialized_size;
2067987da915Sopenharmony_ci		}
2068987da915Sopenharmony_ci		if (ntfs_mft_record_write(vol, ctx->ntfs_ino->mft_no,
2069987da915Sopenharmony_ci				ctx->mrec)) {
2070987da915Sopenharmony_ci			/*
2071987da915Sopenharmony_ci			 * Undo the change in the in-memory copy and send it
2072987da915Sopenharmony_ci			 * back for writing.
2073987da915Sopenharmony_ci			 */
2074987da915Sopenharmony_ci			ctx->attr->initialized_size =
2075987da915Sopenharmony_ci					cpu_to_sle64(old_initialized_size);
2076987da915Sopenharmony_ci			ntfs_mft_record_write(vol, ctx->ntfs_ino->mft_no,
2077987da915Sopenharmony_ci					ctx->mrec);
2078987da915Sopenharmony_ci			goto err_out;
2079987da915Sopenharmony_ci		}
2080987da915Sopenharmony_ci		na->initialized_size = pos + count;
2081987da915Sopenharmony_ci#if CACHE_NIDATA_SIZE
2082987da915Sopenharmony_ci		if (na->ni->mrec->flags & MFT_RECORD_IS_DIRECTORY
2083987da915Sopenharmony_ci		    ? na->type == AT_INDEX_ROOT && na->name == NTFS_INDEX_I30
2084987da915Sopenharmony_ci		    : na->type == AT_DATA && na->name == AT_UNNAMED) {
2085987da915Sopenharmony_ci			na->ni->data_size = na->data_size;
2086987da915Sopenharmony_ci			if ((compressed || NAttrSparse(na))
2087987da915Sopenharmony_ci					&& NAttrNonResident(na))
2088987da915Sopenharmony_ci				na->ni->allocated_size = na->compressed_size;
2089987da915Sopenharmony_ci			else
2090987da915Sopenharmony_ci				na->ni->allocated_size = na->allocated_size;
2091987da915Sopenharmony_ci			set_nino_flag(na->ni,KnownSize);
2092987da915Sopenharmony_ci		}
2093987da915Sopenharmony_ci#endif
2094987da915Sopenharmony_ci		ntfs_attr_put_search_ctx(ctx);
2095987da915Sopenharmony_ci		ctx = NULL;
2096987da915Sopenharmony_ci		/*
2097987da915Sopenharmony_ci		 * NOTE: At this point the initialized_size in the mft record
2098987da915Sopenharmony_ci		 * has been updated BUT there is random data on disk thus if
2099987da915Sopenharmony_ci		 * we decide to abort, we MUST change the initialized_size
2100987da915Sopenharmony_ci		 * again.
2101987da915Sopenharmony_ci		 */
2102987da915Sopenharmony_ci		need_to.undo_initialized_size = 1;
2103987da915Sopenharmony_ci	}
2104987da915Sopenharmony_ci	/* Find the runlist element containing the vcn. */
2105987da915Sopenharmony_ci	rl = ntfs_attr_find_vcn(na, pos >> vol->cluster_size_bits);
2106987da915Sopenharmony_ci	if (!rl) {
2107987da915Sopenharmony_ci		/*
2108987da915Sopenharmony_ci		 * If the vcn is not present it is an out of bounds write.
2109987da915Sopenharmony_ci		 * However, we already extended the size of the attribute,
2110987da915Sopenharmony_ci		 * so getting this here must be an error of some kind.
2111987da915Sopenharmony_ci		 */
2112987da915Sopenharmony_ci		if (errno == ENOENT) {
2113987da915Sopenharmony_ci			errno = EIO;
2114987da915Sopenharmony_ci			ntfs_log_perror("%s: Failed to find VCN #3", __FUNCTION__);
2115987da915Sopenharmony_ci		}
2116987da915Sopenharmony_ci		goto err_out;
2117987da915Sopenharmony_ci	}
2118987da915Sopenharmony_ci		/*
2119987da915Sopenharmony_ci		 * Determine if there is compressed data in the current
2120987da915Sopenharmony_ci		 * compression block (when appending to an existing file).
2121987da915Sopenharmony_ci		 * If so, decompression will be needed, and the full block
2122987da915Sopenharmony_ci		 * must be allocated to be identified as uncompressed.
2123987da915Sopenharmony_ci		 * This comes in two variants, depending on whether
2124987da915Sopenharmony_ci		 * compression has saved at least one cluster.
2125987da915Sopenharmony_ci		 * The compressed size can never be over full size by
2126987da915Sopenharmony_ci		 * more than 485 (maximum for 15 compression blocks
2127987da915Sopenharmony_ci		 * compressed to 4098 and the last 3640 bytes compressed
2128987da915Sopenharmony_ci		 * to 3640 + 3640/8 = 4095, with 15*2 + 4095 - 3640 = 485)
2129987da915Sopenharmony_ci		 * This is less than the smallest cluster, so the hole is
2130987da915Sopenharmony_ci		 * is never beyond the cluster next to the position of
2131987da915Sopenharmony_ci		 * the first uncompressed byte to write.
2132987da915Sopenharmony_ci		 */
2133987da915Sopenharmony_ci	compressed_part = 0;
2134987da915Sopenharmony_ci	if (compressed) {
2135987da915Sopenharmony_ci		if ((rl->lcn == (LCN)LCN_HOLE)
2136987da915Sopenharmony_ci		    && wasnonresident) {
2137987da915Sopenharmony_ci			if (rl->length < na->compression_block_clusters)
2138987da915Sopenharmony_ci				/*
2139987da915Sopenharmony_ci				 * the needed block is in a hole smaller
2140987da915Sopenharmony_ci				 * than the compression block : we can use
2141987da915Sopenharmony_ci				 * it fully
2142987da915Sopenharmony_ci				 */
2143987da915Sopenharmony_ci				compressed_part
2144987da915Sopenharmony_ci					= na->compression_block_clusters
2145987da915Sopenharmony_ci					   - rl->length;
2146987da915Sopenharmony_ci			else {
2147987da915Sopenharmony_ci				/*
2148987da915Sopenharmony_ci				 * the needed block is in a hole bigger
2149987da915Sopenharmony_ci				 * than the compression block : we must
2150987da915Sopenharmony_ci				 * split the hole and use it partially
2151987da915Sopenharmony_ci				 */
2152987da915Sopenharmony_ci				compressed_part = split_compressed_hole(na,
2153987da915Sopenharmony_ci					&rl, pos, count, &update_from);
2154987da915Sopenharmony_ci			}
2155987da915Sopenharmony_ci		} else {
2156987da915Sopenharmony_ci			if (rl->lcn >= 0) {
2157987da915Sopenharmony_ci				/*
2158987da915Sopenharmony_ci				 * the needed block contains data, make
2159987da915Sopenharmony_ci				 * sure the full compression block is
2160987da915Sopenharmony_ci				 * allocated. Borrow from hole if needed
2161987da915Sopenharmony_ci				 */
2162987da915Sopenharmony_ci				compressed_part = borrow_from_hole(na,
2163987da915Sopenharmony_ci					&rl, pos, count, &update_from,
2164987da915Sopenharmony_ci					wasnonresident);
2165987da915Sopenharmony_ci			}
2166987da915Sopenharmony_ci		}
2167987da915Sopenharmony_ci
2168987da915Sopenharmony_ci		if (compressed_part < 0)
2169987da915Sopenharmony_ci			goto err_out;
2170987da915Sopenharmony_ci
2171987da915Sopenharmony_ci			/* just making non-resident, so not yet compressed */
2172987da915Sopenharmony_ci		if (NAttrBeingNonResident(na)
2173987da915Sopenharmony_ci		    && (compressed_part < na->compression_block_clusters))
2174987da915Sopenharmony_ci			compressed_part = 0;
2175987da915Sopenharmony_ci	}
2176987da915Sopenharmony_ci	ofs = pos - (rl->vcn << vol->cluster_size_bits);
2177987da915Sopenharmony_ci	/*
2178987da915Sopenharmony_ci	 * Scatter the data from the linear data buffer to the volume. Note, a
2179987da915Sopenharmony_ci	 * partial final vcn is taken care of by the @count capping of write
2180987da915Sopenharmony_ci	 * length.
2181987da915Sopenharmony_ci	 */
2182987da915Sopenharmony_ci	for (hole_end = 0; count; rl++, ofs = 0) {
2183987da915Sopenharmony_ci		if (rl->lcn == LCN_RL_NOT_MAPPED) {
2184987da915Sopenharmony_ci			rl = ntfs_attr_find_vcn(na, rl->vcn);
2185987da915Sopenharmony_ci			if (!rl) {
2186987da915Sopenharmony_ci				if (errno == ENOENT) {
2187987da915Sopenharmony_ci					errno = EIO;
2188987da915Sopenharmony_ci					ntfs_log_perror("%s: Failed to find VCN"
2189987da915Sopenharmony_ci							" #4", __FUNCTION__);
2190987da915Sopenharmony_ci				}
2191987da915Sopenharmony_ci				goto rl_err_out;
2192987da915Sopenharmony_ci			}
2193987da915Sopenharmony_ci			/* Needed for case when runs merged. */
2194987da915Sopenharmony_ci			ofs = pos + total - (rl->vcn << vol->cluster_size_bits);
2195987da915Sopenharmony_ci		}
2196987da915Sopenharmony_ci		if (!rl->length) {
2197987da915Sopenharmony_ci			errno = EIO;
2198987da915Sopenharmony_ci			ntfs_log_perror("%s: Zero run length", __FUNCTION__);
2199987da915Sopenharmony_ci			goto rl_err_out;
2200987da915Sopenharmony_ci		}
2201987da915Sopenharmony_ci		if (rl->lcn < (LCN)0) {
2202987da915Sopenharmony_ci			hole_end = rl->vcn + rl->length;
2203987da915Sopenharmony_ci
2204987da915Sopenharmony_ci			if (rl->lcn != (LCN)LCN_HOLE) {
2205987da915Sopenharmony_ci				errno = EIO;
2206987da915Sopenharmony_ci				ntfs_log_perror("%s: Unexpected LCN (%lld)",
2207987da915Sopenharmony_ci						__FUNCTION__,
2208987da915Sopenharmony_ci						(long long)rl->lcn);
2209987da915Sopenharmony_ci				goto rl_err_out;
2210987da915Sopenharmony_ci			}
2211987da915Sopenharmony_ci			if (ntfs_attr_fill_hole(na, fullcount, &ofs, &rl,
2212987da915Sopenharmony_ci					 &update_from))
2213987da915Sopenharmony_ci				goto err_out;
2214987da915Sopenharmony_ci		}
2215987da915Sopenharmony_ci		if (compressed) {
2216987da915Sopenharmony_ci			while (rl->length
2217987da915Sopenharmony_ci			    && (ofs >= (rl->length << vol->cluster_size_bits))) {
2218987da915Sopenharmony_ci				ofs -= rl->length << vol->cluster_size_bits;
2219987da915Sopenharmony_ci				rl++;
2220987da915Sopenharmony_ci			}
2221987da915Sopenharmony_ci		}
2222987da915Sopenharmony_ci
2223987da915Sopenharmony_ci		/* It is a real lcn, write it to the volume. */
2224987da915Sopenharmony_ci		to_write = min(count, (rl->length << vol->cluster_size_bits) - ofs);
2225987da915Sopenharmony_ciretry:
2226987da915Sopenharmony_ci		ntfs_log_trace("Writing %lld bytes to vcn %lld, lcn %lld, ofs "
2227987da915Sopenharmony_ci			       "%lld.\n", (long long)to_write, (long long)rl->vcn,
2228987da915Sopenharmony_ci			       (long long)rl->lcn, (long long)ofs);
2229987da915Sopenharmony_ci		if (!NVolReadOnly(vol)) {
2230987da915Sopenharmony_ci
2231987da915Sopenharmony_ci			s64 wpos = (rl->lcn << vol->cluster_size_bits) + ofs;
2232987da915Sopenharmony_ci			s64 wend = (rl->vcn << vol->cluster_size_bits) + ofs + to_write;
2233987da915Sopenharmony_ci			u32 bsize = vol->cluster_size;
2234987da915Sopenharmony_ci			/* Byte size needed to zero fill a cluster */
2235987da915Sopenharmony_ci			s64 rounding = ((wend + bsize - 1) & ~(s64)(bsize - 1)) - wend;
2236987da915Sopenharmony_ci			/**
2237987da915Sopenharmony_ci			 * Zero fill to cluster boundary if we're writing at the
2238987da915Sopenharmony_ci			 * end of the attribute or into an ex-sparse cluster.
2239987da915Sopenharmony_ci			 * This will cause the kernel not to seek and read disk
2240987da915Sopenharmony_ci			 * blocks during write(2) to fill the end of the buffer
2241987da915Sopenharmony_ci			 * which increases write speed by 2-10 fold typically.
2242987da915Sopenharmony_ci			 *
2243987da915Sopenharmony_ci			 * This is done even for compressed files, because
2244987da915Sopenharmony_ci			 * data is generally first written uncompressed.
2245987da915Sopenharmony_ci			 */
2246987da915Sopenharmony_ci			if (rounding && ((wend == na->initialized_size) ||
2247987da915Sopenharmony_ci				(wend < (hole_end << vol->cluster_size_bits)))){
2248987da915Sopenharmony_ci
2249987da915Sopenharmony_ci				char *cb;
2250987da915Sopenharmony_ci
2251987da915Sopenharmony_ci				rounding += to_write;
2252987da915Sopenharmony_ci
2253987da915Sopenharmony_ci				cb = ntfs_malloc(rounding);
2254987da915Sopenharmony_ci				if (!cb)
2255987da915Sopenharmony_ci					goto err_out;
2256987da915Sopenharmony_ci
2257987da915Sopenharmony_ci				memcpy(cb, b, to_write);
2258987da915Sopenharmony_ci				memset(cb + to_write, 0, rounding - to_write);
2259987da915Sopenharmony_ci
2260987da915Sopenharmony_ci				if (compressed) {
2261987da915Sopenharmony_ci					written = ntfs_compressed_pwrite(na,
2262987da915Sopenharmony_ci						rl, wpos, ofs, to_write,
2263987da915Sopenharmony_ci						rounding, cb, compressed_part,
2264987da915Sopenharmony_ci						&update_from);
2265987da915Sopenharmony_ci				} else {
2266987da915Sopenharmony_ci					written = ntfs_pwrite(vol->dev, wpos,
2267987da915Sopenharmony_ci						rounding, cb);
2268987da915Sopenharmony_ci					if (written == rounding)
2269987da915Sopenharmony_ci						written = to_write;
2270987da915Sopenharmony_ci				}
2271987da915Sopenharmony_ci
2272987da915Sopenharmony_ci				free(cb);
2273987da915Sopenharmony_ci			} else {
2274987da915Sopenharmony_ci				if (compressed) {
2275987da915Sopenharmony_ci					written = ntfs_compressed_pwrite(na,
2276987da915Sopenharmony_ci						rl, wpos, ofs, to_write,
2277987da915Sopenharmony_ci						to_write, b, compressed_part,
2278987da915Sopenharmony_ci						&update_from);
2279987da915Sopenharmony_ci				} else
2280987da915Sopenharmony_ci					written = ntfs_pwrite(vol->dev, wpos,
2281987da915Sopenharmony_ci						to_write, b);
2282987da915Sopenharmony_ci			}
2283987da915Sopenharmony_ci		} else
2284987da915Sopenharmony_ci			written = to_write;
2285987da915Sopenharmony_ci		/* If everything ok, update progress counters and continue. */
2286987da915Sopenharmony_ci		if (written > 0) {
2287987da915Sopenharmony_ci			total += written;
2288987da915Sopenharmony_ci			count -= written;
2289987da915Sopenharmony_ci			fullcount -= written;
2290987da915Sopenharmony_ci			b = (const u8*)b + written;
2291987da915Sopenharmony_ci		}
2292987da915Sopenharmony_ci		if (written != to_write) {
2293987da915Sopenharmony_ci			/* Partial write cannot be dealt with, stop there */
2294987da915Sopenharmony_ci			/* If the syscall was interrupted, try again. */
2295987da915Sopenharmony_ci			if (written == (s64)-1 && errno == EINTR)
2296987da915Sopenharmony_ci				goto retry;
2297987da915Sopenharmony_ci			if (!written)
2298987da915Sopenharmony_ci				errno = EIO;
2299987da915Sopenharmony_ci			goto rl_err_out;
2300987da915Sopenharmony_ci		}
2301987da915Sopenharmony_ci		compressed_part = 0;
2302987da915Sopenharmony_ci	}
2303987da915Sopenharmony_cidone:
2304987da915Sopenharmony_ci	if (ctx)
2305987da915Sopenharmony_ci		ntfs_attr_put_search_ctx(ctx);
2306987da915Sopenharmony_ci		/*
2307987da915Sopenharmony_ci		 *	 Update mapping pairs if needed.
2308987da915Sopenharmony_ci		 * For a compressed file, we try to make a partial update
2309987da915Sopenharmony_ci		 * of the mapping list. This makes a difference only if
2310987da915Sopenharmony_ci		 * inode extents were needed.
2311987da915Sopenharmony_ci		 */
2312987da915Sopenharmony_ci	if (NAttrRunlistDirty(na)) {
2313987da915Sopenharmony_ci		if (ntfs_attr_update_mapping_pairs(na,
2314987da915Sopenharmony_ci				(update_from < 0 ? 0 : update_from))) {
2315987da915Sopenharmony_ci			/*
2316987da915Sopenharmony_ci			 * FIXME: trying to recover by goto rl_err_out;
2317987da915Sopenharmony_ci			 * could cause driver hang by infinite looping.
2318987da915Sopenharmony_ci			 */
2319987da915Sopenharmony_ci			total = -1;
2320987da915Sopenharmony_ci			goto out;
2321987da915Sopenharmony_ci		}
2322987da915Sopenharmony_ci		if (!wasnonresident)
2323987da915Sopenharmony_ci			NAttrClearBeingNonResident(na);
2324987da915Sopenharmony_ci		NAttrClearDataAppending(na);
2325987da915Sopenharmony_ci	}
2326987da915Sopenharmony_ciout:
2327987da915Sopenharmony_ci	return total;
2328987da915Sopenharmony_cirl_err_out:
2329987da915Sopenharmony_ci	eo = errno;
2330987da915Sopenharmony_ci	if (total) {
2331987da915Sopenharmony_ci		if (need_to.undo_initialized_size) {
2332987da915Sopenharmony_ci			if (pos + total > na->initialized_size)
2333987da915Sopenharmony_ci				goto done;
2334987da915Sopenharmony_ci			/*
2335987da915Sopenharmony_ci			 * TODO: Need to try to change initialized_size. If it
2336987da915Sopenharmony_ci			 * succeeds goto done, otherwise goto err_out. (AIA)
2337987da915Sopenharmony_ci			 */
2338987da915Sopenharmony_ci			goto err_out;
2339987da915Sopenharmony_ci		}
2340987da915Sopenharmony_ci		goto done;
2341987da915Sopenharmony_ci	}
2342987da915Sopenharmony_ci	errno = eo;
2343987da915Sopenharmony_cierr_out:
2344987da915Sopenharmony_ci	eo = errno;
2345987da915Sopenharmony_ci	if (need_to.undo_initialized_size) {
2346987da915Sopenharmony_ci		int err;
2347987da915Sopenharmony_ci
2348987da915Sopenharmony_ci		err = 0;
2349987da915Sopenharmony_ci		if (!ctx) {
2350987da915Sopenharmony_ci			ctx = ntfs_attr_get_search_ctx(na->ni, NULL);
2351987da915Sopenharmony_ci			if (!ctx)
2352987da915Sopenharmony_ci				err = 1;
2353987da915Sopenharmony_ci		} else
2354987da915Sopenharmony_ci			ntfs_attr_reinit_search_ctx(ctx);
2355987da915Sopenharmony_ci		if (!err) {
2356987da915Sopenharmony_ci			err = ntfs_attr_lookup(na->type, na->name,
2357987da915Sopenharmony_ci					na->name_len, 0, 0, NULL, 0, ctx);
2358987da915Sopenharmony_ci			if (!err) {
2359987da915Sopenharmony_ci				na->initialized_size = old_initialized_size;
2360987da915Sopenharmony_ci				ctx->attr->initialized_size = cpu_to_sle64(
2361987da915Sopenharmony_ci						old_initialized_size);
2362987da915Sopenharmony_ci				err = ntfs_mft_record_write(vol,
2363987da915Sopenharmony_ci						ctx->ntfs_ino->mft_no,
2364987da915Sopenharmony_ci						ctx->mrec);
2365987da915Sopenharmony_ci			}
2366987da915Sopenharmony_ci		}
2367987da915Sopenharmony_ci		if (err) {
2368987da915Sopenharmony_ci			/*
2369987da915Sopenharmony_ci			 * FIXME: At this stage could try to recover by filling
2370987da915Sopenharmony_ci			 * old_initialized_size -> new_initialized_size with
2371987da915Sopenharmony_ci			 * data or at least zeroes. (AIA)
2372987da915Sopenharmony_ci			 */
2373987da915Sopenharmony_ci			ntfs_log_error("Eeek! Failed to recover from error. "
2374987da915Sopenharmony_ci					"Leaving metadata in inconsistent "
2375987da915Sopenharmony_ci					"state! Run chkdsk!\n");
2376987da915Sopenharmony_ci		}
2377987da915Sopenharmony_ci	}
2378987da915Sopenharmony_ci	if (ctx)
2379987da915Sopenharmony_ci		ntfs_attr_put_search_ctx(ctx);
2380987da915Sopenharmony_ci	/* Update mapping pairs if needed. */
2381987da915Sopenharmony_ci	if (NAttrRunlistDirty(na))
2382987da915Sopenharmony_ci		ntfs_attr_update_mapping_pairs(na, 0);
2383987da915Sopenharmony_ci	/* Restore original data_size if needed. */
2384987da915Sopenharmony_ci	if (need_to.undo_data_size
2385987da915Sopenharmony_ci			&& ntfs_attr_truncate_i(na, old_data_size, HOLES_OK))
2386987da915Sopenharmony_ci		ntfs_log_perror("Failed to restore data_size");
2387987da915Sopenharmony_ci	errno = eo;
2388987da915Sopenharmony_cierrno_set:
2389987da915Sopenharmony_ci	total = -1;
2390987da915Sopenharmony_ci	goto out;
2391987da915Sopenharmony_ci}
2392987da915Sopenharmony_ci
2393987da915Sopenharmony_cis64 ntfs_attr_pwrite(ntfs_attr *na, const s64 pos, s64 count, const void *b)
2394987da915Sopenharmony_ci{
2395987da915Sopenharmony_ci	s64 total;
2396987da915Sopenharmony_ci	s64 written;
2397987da915Sopenharmony_ci
2398987da915Sopenharmony_ci	ntfs_log_enter("Entering for inode %lld, attr 0x%x, pos 0x%llx, count "
2399987da915Sopenharmony_ci		       "0x%llx.\n", (long long)na->ni->mft_no, le32_to_cpu(na->type),
2400987da915Sopenharmony_ci		       (long long)pos, (long long)count);
2401987da915Sopenharmony_ci
2402987da915Sopenharmony_ci	total = 0;
2403987da915Sopenharmony_ci	if (!na || !na->ni || !na->ni->vol || !b || pos < 0 || count < 0) {
2404987da915Sopenharmony_ci		errno = EINVAL;
2405987da915Sopenharmony_ci		written = -1;
2406987da915Sopenharmony_ci		ntfs_log_perror("%s", __FUNCTION__);
2407987da915Sopenharmony_ci		goto out;
2408987da915Sopenharmony_ci	}
2409987da915Sopenharmony_ci
2410987da915Sopenharmony_ci		/*
2411987da915Sopenharmony_ci		 * Compressed attributes may be written partially, so
2412987da915Sopenharmony_ci		 * we may have to iterate.
2413987da915Sopenharmony_ci		 */
2414987da915Sopenharmony_ci	do {
2415987da915Sopenharmony_ci		written = ntfs_attr_pwrite_i(na, pos + total,
2416987da915Sopenharmony_ci				count - total, (const u8*)b + total);
2417987da915Sopenharmony_ci		if (written > 0)
2418987da915Sopenharmony_ci			total += written;
2419987da915Sopenharmony_ci	} while ((written > 0) && (total < count));
2420987da915Sopenharmony_ciout :
2421987da915Sopenharmony_ci	ntfs_log_leave("\n");
2422987da915Sopenharmony_ci	return (total > 0 ? total : written);
2423987da915Sopenharmony_ci}
2424987da915Sopenharmony_ci
2425987da915Sopenharmony_ci
2426987da915Sopenharmony_ciint ntfs_attr_pclose(ntfs_attr *na)
2427987da915Sopenharmony_ci{
2428987da915Sopenharmony_ci	s64 ofs;
2429987da915Sopenharmony_ci	int failed;
2430987da915Sopenharmony_ci	BOOL ok = TRUE;
2431987da915Sopenharmony_ci	VCN update_from = -1;
2432987da915Sopenharmony_ci	ntfs_volume *vol;
2433987da915Sopenharmony_ci	ntfs_attr_search_ctx *ctx = NULL;
2434987da915Sopenharmony_ci	runlist_element *rl;
2435987da915Sopenharmony_ci	int eo;
2436987da915Sopenharmony_ci	int compressed_part;
2437987da915Sopenharmony_ci	BOOL compressed;
2438987da915Sopenharmony_ci
2439987da915Sopenharmony_ci	ntfs_log_enter("Entering for inode 0x%llx, attr 0x%x.\n",
2440987da915Sopenharmony_ci			(unsigned long long)na->ni->mft_no,
2441987da915Sopenharmony_ci			le32_to_cpu(na->type));
2442987da915Sopenharmony_ci
2443987da915Sopenharmony_ci	if (!na || !na->ni || !na->ni->vol) {
2444987da915Sopenharmony_ci		errno = EINVAL;
2445987da915Sopenharmony_ci		ntfs_log_perror("%s", __FUNCTION__);
2446987da915Sopenharmony_ci		goto errno_set;
2447987da915Sopenharmony_ci	}
2448987da915Sopenharmony_ci	vol = na->ni->vol;
2449987da915Sopenharmony_ci	na->unused_runs = 0;
2450987da915Sopenharmony_ci	compressed = (na->data_flags & ATTR_COMPRESSION_MASK)
2451987da915Sopenharmony_ci			 != const_cpu_to_le16(0);
2452987da915Sopenharmony_ci	/*
2453987da915Sopenharmony_ci	 * Encrypted non-resident attributes are not supported.  We return
2454987da915Sopenharmony_ci	 * access denied, which is what Windows NT4 does, too.
2455987da915Sopenharmony_ci	 */
2456987da915Sopenharmony_ci	if (NAttrEncrypted(na) && NAttrNonResident(na)) {
2457987da915Sopenharmony_ci		errno = EACCES;
2458987da915Sopenharmony_ci		goto errno_set;
2459987da915Sopenharmony_ci	}
2460987da915Sopenharmony_ci	/* If this is not a compressed attribute get out */
2461987da915Sopenharmony_ci	/* same if it is resident */
2462987da915Sopenharmony_ci	if (!compressed || !NAttrNonResident(na))
2463987da915Sopenharmony_ci		goto out;
2464987da915Sopenharmony_ci
2465987da915Sopenharmony_ci		/* safety check : no recursion on close */
2466987da915Sopenharmony_ci	if (NAttrComprClosing(na)) {
2467987da915Sopenharmony_ci		errno = EIO;
2468987da915Sopenharmony_ci		ntfs_log_error("Bad ntfs_attr_pclose"
2469987da915Sopenharmony_ci				" recursion on inode %lld\n",
2470987da915Sopenharmony_ci				(long long)na->ni->mft_no);
2471987da915Sopenharmony_ci		goto out;
2472987da915Sopenharmony_ci	}
2473987da915Sopenharmony_ci	NAttrSetComprClosing(na);
2474987da915Sopenharmony_ci		/*
2475987da915Sopenharmony_ci		 * For a compressed attribute, we must be sure there are two
2476987da915Sopenharmony_ci		 * available entries, so reserve them before it gets too late.
2477987da915Sopenharmony_ci		 */
2478987da915Sopenharmony_ci	if (ntfs_attr_map_whole_runlist(na))
2479987da915Sopenharmony_ci		goto err_out;
2480987da915Sopenharmony_ci	na->rl = ntfs_rl_extend(na,na->rl,2);
2481987da915Sopenharmony_ci	if (!na->rl)
2482987da915Sopenharmony_ci		goto err_out;
2483987da915Sopenharmony_ci	na->unused_runs = 2;
2484987da915Sopenharmony_ci	/* Find the runlist element containing the terminal vcn. */
2485987da915Sopenharmony_ci	rl = ntfs_attr_find_vcn(na, (na->initialized_size - 1) >> vol->cluster_size_bits);
2486987da915Sopenharmony_ci	if (!rl) {
2487987da915Sopenharmony_ci		/*
2488987da915Sopenharmony_ci		 * If the vcn is not present it is an out of bounds write.
2489987da915Sopenharmony_ci		 * However, we have already written the last byte uncompressed,
2490987da915Sopenharmony_ci		 * so getting this here must be an error of some kind.
2491987da915Sopenharmony_ci		 */
2492987da915Sopenharmony_ci		if (errno == ENOENT) {
2493987da915Sopenharmony_ci			errno = EIO;
2494987da915Sopenharmony_ci			ntfs_log_perror("%s: Failed to find VCN #5", __FUNCTION__);
2495987da915Sopenharmony_ci		}
2496987da915Sopenharmony_ci		goto err_out;
2497987da915Sopenharmony_ci	}
2498987da915Sopenharmony_ci	/*
2499987da915Sopenharmony_ci	 * Scatter the data from the linear data buffer to the volume. Note, a
2500987da915Sopenharmony_ci	 * partial final vcn is taken care of by the @count capping of write
2501987da915Sopenharmony_ci	 * length.
2502987da915Sopenharmony_ci	 */
2503987da915Sopenharmony_ci	compressed_part = 0;
2504987da915Sopenharmony_ci 	if (rl->lcn >= 0) {
2505987da915Sopenharmony_ci		runlist_element *xrl;
2506987da915Sopenharmony_ci
2507987da915Sopenharmony_ci		xrl = rl;
2508987da915Sopenharmony_ci		do {
2509987da915Sopenharmony_ci			xrl++;
2510987da915Sopenharmony_ci		} while (xrl->lcn >= 0);
2511987da915Sopenharmony_ci		compressed_part = (-xrl->length)
2512987da915Sopenharmony_ci					& (na->compression_block_clusters - 1);
2513987da915Sopenharmony_ci	} else
2514987da915Sopenharmony_ci		if (rl->lcn == (LCN)LCN_HOLE) {
2515987da915Sopenharmony_ci			if (rl->length < na->compression_block_clusters)
2516987da915Sopenharmony_ci				compressed_part
2517987da915Sopenharmony_ci        	                        = na->compression_block_clusters
2518987da915Sopenharmony_ci                	                           - rl->length;
2519987da915Sopenharmony_ci			else
2520987da915Sopenharmony_ci				compressed_part
2521987da915Sopenharmony_ci					= na->compression_block_clusters;
2522987da915Sopenharmony_ci		}
2523987da915Sopenharmony_ci		/* done, if the last block set was compressed */
2524987da915Sopenharmony_ci	if (compressed_part)
2525987da915Sopenharmony_ci		goto out;
2526987da915Sopenharmony_ci
2527987da915Sopenharmony_ci	ofs = na->initialized_size - (rl->vcn << vol->cluster_size_bits);
2528987da915Sopenharmony_ci
2529987da915Sopenharmony_ci	if (rl->lcn == LCN_RL_NOT_MAPPED) {
2530987da915Sopenharmony_ci		rl = ntfs_attr_find_vcn(na, rl->vcn);
2531987da915Sopenharmony_ci		if (!rl) {
2532987da915Sopenharmony_ci			if (errno == ENOENT) {
2533987da915Sopenharmony_ci				errno = EIO;
2534987da915Sopenharmony_ci				ntfs_log_perror("%s: Failed to find VCN"
2535987da915Sopenharmony_ci						" #6", __FUNCTION__);
2536987da915Sopenharmony_ci			}
2537987da915Sopenharmony_ci			goto rl_err_out;
2538987da915Sopenharmony_ci		}
2539987da915Sopenharmony_ci			/* Needed for case when runs merged. */
2540987da915Sopenharmony_ci		ofs = na->initialized_size - (rl->vcn << vol->cluster_size_bits);
2541987da915Sopenharmony_ci	}
2542987da915Sopenharmony_ci	if (!rl->length) {
2543987da915Sopenharmony_ci		errno = EIO;
2544987da915Sopenharmony_ci		ntfs_log_perror("%s: Zero run length", __FUNCTION__);
2545987da915Sopenharmony_ci		goto rl_err_out;
2546987da915Sopenharmony_ci	}
2547987da915Sopenharmony_ci	if (rl->lcn < (LCN)0) {
2548987da915Sopenharmony_ci		if (rl->lcn != (LCN)LCN_HOLE) {
2549987da915Sopenharmony_ci			errno = EIO;
2550987da915Sopenharmony_ci			ntfs_log_perror("%s: Unexpected LCN (%lld)",
2551987da915Sopenharmony_ci					__FUNCTION__,
2552987da915Sopenharmony_ci					(long long)rl->lcn);
2553987da915Sopenharmony_ci			goto rl_err_out;
2554987da915Sopenharmony_ci		}
2555987da915Sopenharmony_ci
2556987da915Sopenharmony_ci		if (ntfs_attr_fill_hole(na, (s64)0, &ofs, &rl, &update_from))
2557987da915Sopenharmony_ci			goto err_out;
2558987da915Sopenharmony_ci	}
2559987da915Sopenharmony_ci	while (rl->length
2560987da915Sopenharmony_ci	    && (ofs >= (rl->length << vol->cluster_size_bits))) {
2561987da915Sopenharmony_ci		ofs -= rl->length << vol->cluster_size_bits;
2562987da915Sopenharmony_ci		rl++;
2563987da915Sopenharmony_ci	}
2564987da915Sopenharmony_ci
2565987da915Sopenharmony_ciretry:
2566987da915Sopenharmony_ci	failed = 0;
2567987da915Sopenharmony_ci	if (update_from < 0) update_from = 0;
2568987da915Sopenharmony_ci	if (!NVolReadOnly(vol)) {
2569987da915Sopenharmony_ci		failed = ntfs_compressed_close(na, rl, ofs, &update_from);
2570987da915Sopenharmony_ci#if CACHE_NIDATA_SIZE
2571987da915Sopenharmony_ci		if (na->ni->mrec->flags & MFT_RECORD_IS_DIRECTORY
2572987da915Sopenharmony_ci		    ? na->type == AT_INDEX_ROOT && na->name == NTFS_INDEX_I30
2573987da915Sopenharmony_ci		    : na->type == AT_DATA && na->name == AT_UNNAMED) {
2574987da915Sopenharmony_ci			na->ni->data_size = na->data_size;
2575987da915Sopenharmony_ci			na->ni->allocated_size = na->compressed_size;
2576987da915Sopenharmony_ci			set_nino_flag(na->ni,KnownSize);
2577987da915Sopenharmony_ci		}
2578987da915Sopenharmony_ci#endif
2579987da915Sopenharmony_ci	}
2580987da915Sopenharmony_ci	if (failed) {
2581987da915Sopenharmony_ci		/* If the syscall was interrupted, try again. */
2582987da915Sopenharmony_ci		if (errno == EINTR)
2583987da915Sopenharmony_ci			goto retry;
2584987da915Sopenharmony_ci		else
2585987da915Sopenharmony_ci			goto rl_err_out;
2586987da915Sopenharmony_ci	}
2587987da915Sopenharmony_ci	if (ctx)
2588987da915Sopenharmony_ci		ntfs_attr_put_search_ctx(ctx);
2589987da915Sopenharmony_ci	/* Update mapping pairs if needed. */
2590987da915Sopenharmony_ci	if (NAttrFullyMapped(na))
2591987da915Sopenharmony_ci		if (ntfs_attr_update_mapping_pairs(na, update_from)) {
2592987da915Sopenharmony_ci			/*
2593987da915Sopenharmony_ci			 * FIXME: trying to recover by goto rl_err_out;
2594987da915Sopenharmony_ci			 * could cause driver hang by infinite looping.
2595987da915Sopenharmony_ci			 */
2596987da915Sopenharmony_ci			ok = FALSE;
2597987da915Sopenharmony_ci			goto out;
2598987da915Sopenharmony_ci	}
2599987da915Sopenharmony_ciout:
2600987da915Sopenharmony_ci	NAttrClearComprClosing(na);
2601987da915Sopenharmony_ci	ntfs_log_leave("\n");
2602987da915Sopenharmony_ci	return (!ok);
2603987da915Sopenharmony_cirl_err_out:
2604987da915Sopenharmony_ci		/*
2605987da915Sopenharmony_ci		 * need not restore old sizes, only compressed_size
2606987da915Sopenharmony_ci		 * can have changed. It has been set according to
2607987da915Sopenharmony_ci		 * the current runlist while updating the mapping pairs,
2608987da915Sopenharmony_ci		 * and must be kept consistent with the runlists.
2609987da915Sopenharmony_ci		 */
2610987da915Sopenharmony_cierr_out:
2611987da915Sopenharmony_ci	eo = errno;
2612987da915Sopenharmony_ci	if (ctx)
2613987da915Sopenharmony_ci		ntfs_attr_put_search_ctx(ctx);
2614987da915Sopenharmony_ci	/* Update mapping pairs if needed. */
2615987da915Sopenharmony_ci	if (NAttrFullyMapped(na))
2616987da915Sopenharmony_ci		ntfs_attr_update_mapping_pairs(na, 0);
2617987da915Sopenharmony_ci	errno = eo;
2618987da915Sopenharmony_cierrno_set:
2619987da915Sopenharmony_ci	ok = FALSE;
2620987da915Sopenharmony_ci	goto out;
2621987da915Sopenharmony_ci}
2622987da915Sopenharmony_ci
2623987da915Sopenharmony_ci/**
2624987da915Sopenharmony_ci * ntfs_attr_mst_pread - multi sector transfer protected ntfs attribute read
2625987da915Sopenharmony_ci * @na:		multi sector transfer protected ntfs attribute to read from
2626987da915Sopenharmony_ci * @pos:	byte position in the attribute to begin reading from
2627987da915Sopenharmony_ci * @bk_cnt:	number of mst protected blocks to read
2628987da915Sopenharmony_ci * @bk_size:	size of each mst protected block in bytes
2629987da915Sopenharmony_ci * @dst:	output data buffer
2630987da915Sopenharmony_ci *
2631987da915Sopenharmony_ci * This function will read @bk_cnt blocks of size @bk_size bytes each starting
2632987da915Sopenharmony_ci * at offset @pos from the ntfs attribute @na into the data buffer @b.
2633987da915Sopenharmony_ci *
2634987da915Sopenharmony_ci * On success, the multi sector transfer fixups are applied and the number of
2635987da915Sopenharmony_ci * read blocks is returned. If this number is lower than @bk_cnt this means
2636987da915Sopenharmony_ci * that the read has either reached end of attribute or that an error was
2637987da915Sopenharmony_ci * encountered during the read so that the read is partial. 0 means end of
2638987da915Sopenharmony_ci * attribute or nothing to read (also return 0 when @bk_cnt or @bk_size are 0).
2639987da915Sopenharmony_ci *
2640987da915Sopenharmony_ci * On error and nothing has been read, return -1 with errno set appropriately
2641987da915Sopenharmony_ci * to the return code of ntfs_attr_pread() or to EINVAL in case of invalid
2642987da915Sopenharmony_ci * arguments.
2643987da915Sopenharmony_ci *
2644987da915Sopenharmony_ci * NOTE: If an incomplete multi sector transfer is detected the magic is
2645987da915Sopenharmony_ci * changed to BAAD but no error is returned, i.e. it is possible that any of
2646987da915Sopenharmony_ci * the returned blocks have multi sector transfer errors. This should be
2647987da915Sopenharmony_ci * detected by the caller by checking each block with is_baad_recordp(&block).
2648987da915Sopenharmony_ci * The reasoning is that we want to fixup as many blocks as possible and we
2649987da915Sopenharmony_ci * want to return even bad ones to the caller so, e.g. in case of ntfsck, the
2650987da915Sopenharmony_ci * errors can be repaired.
2651987da915Sopenharmony_ci */
2652987da915Sopenharmony_cis64 ntfs_attr_mst_pread(ntfs_attr *na, const s64 pos, const s64 bk_cnt,
2653987da915Sopenharmony_ci		const u32 bk_size, void *dst)
2654987da915Sopenharmony_ci{
2655987da915Sopenharmony_ci	s64 br;
2656987da915Sopenharmony_ci	u8 *end;
2657987da915Sopenharmony_ci	BOOL warn;
2658987da915Sopenharmony_ci
2659987da915Sopenharmony_ci	ntfs_log_trace("Entering for inode 0x%llx, attr type 0x%x, pos 0x%llx.\n",
2660987da915Sopenharmony_ci			(unsigned long long)na->ni->mft_no, le32_to_cpu(na->type),
2661987da915Sopenharmony_ci			(long long)pos);
2662987da915Sopenharmony_ci	if (bk_cnt < 0 || bk_size % NTFS_BLOCK_SIZE) {
2663987da915Sopenharmony_ci		errno = EINVAL;
2664987da915Sopenharmony_ci		ntfs_log_perror("%s", __FUNCTION__);
2665987da915Sopenharmony_ci		return -1;
2666987da915Sopenharmony_ci	}
2667987da915Sopenharmony_ci	br = ntfs_attr_pread(na, pos, bk_cnt * bk_size, dst);
2668987da915Sopenharmony_ci	if (br <= 0)
2669987da915Sopenharmony_ci		return br;
2670987da915Sopenharmony_ci	br /= bk_size;
2671987da915Sopenharmony_ci		/* log errors unless silenced */
2672987da915Sopenharmony_ci	warn = !na->ni || !na->ni->vol || !NVolNoFixupWarn(na->ni->vol);
2673987da915Sopenharmony_ci	for (end = (u8*)dst + br * bk_size; (u8*)dst < end; dst = (u8*)dst +
2674987da915Sopenharmony_ci			bk_size)
2675987da915Sopenharmony_ci		ntfs_mst_post_read_fixup_warn((NTFS_RECORD*)dst, bk_size, warn);
2676987da915Sopenharmony_ci	/* Finally, return the number of blocks read. */
2677987da915Sopenharmony_ci	return br;
2678987da915Sopenharmony_ci}
2679987da915Sopenharmony_ci
2680987da915Sopenharmony_ci/**
2681987da915Sopenharmony_ci * ntfs_attr_mst_pwrite - multi sector transfer protected ntfs attribute write
2682987da915Sopenharmony_ci * @na:		multi sector transfer protected ntfs attribute to write to
2683987da915Sopenharmony_ci * @pos:	position in the attribute to write to
2684987da915Sopenharmony_ci * @bk_cnt:	number of mst protected blocks to write
2685987da915Sopenharmony_ci * @bk_size:	size of each mst protected block in bytes
2686987da915Sopenharmony_ci * @src:	data buffer to write to disk
2687987da915Sopenharmony_ci *
2688987da915Sopenharmony_ci * This function will write @bk_cnt blocks of size @bk_size bytes each from
2689987da915Sopenharmony_ci * data buffer @b to multi sector transfer (mst) protected ntfs attribute @na
2690987da915Sopenharmony_ci * at position @pos.
2691987da915Sopenharmony_ci *
2692987da915Sopenharmony_ci * On success, return the number of successfully written blocks. If this number
2693987da915Sopenharmony_ci * is lower than @bk_cnt this means that an error was encountered during the
2694987da915Sopenharmony_ci * write so that the write is partial. 0 means nothing was written (also
2695987da915Sopenharmony_ci * return 0 when @bk_cnt or @bk_size are 0).
2696987da915Sopenharmony_ci *
2697987da915Sopenharmony_ci * On error and nothing has been written, return -1 with errno set
2698987da915Sopenharmony_ci * appropriately to the return code of ntfs_attr_pwrite(), or to EINVAL in case
2699987da915Sopenharmony_ci * of invalid arguments.
2700987da915Sopenharmony_ci *
2701987da915Sopenharmony_ci * NOTE: We mst protect the data, write it, then mst deprotect it using a quick
2702987da915Sopenharmony_ci * deprotect algorithm (no checking). This saves us from making a copy before
2703987da915Sopenharmony_ci * the write and at the same time causes the usn to be incremented in the
2704987da915Sopenharmony_ci * buffer. This conceptually fits in better with the idea that cached data is
2705987da915Sopenharmony_ci * always deprotected and protection is performed when the data is actually
2706987da915Sopenharmony_ci * going to hit the disk and the cache is immediately deprotected again
2707987da915Sopenharmony_ci * simulating an mst read on the written data. This way cache coherency is
2708987da915Sopenharmony_ci * achieved.
2709987da915Sopenharmony_ci */
2710987da915Sopenharmony_cis64 ntfs_attr_mst_pwrite(ntfs_attr *na, const s64 pos, s64 bk_cnt,
2711987da915Sopenharmony_ci		const u32 bk_size, void *src)
2712987da915Sopenharmony_ci{
2713987da915Sopenharmony_ci	s64 written, i;
2714987da915Sopenharmony_ci
2715987da915Sopenharmony_ci	ntfs_log_trace("Entering for inode 0x%llx, attr type 0x%x, pos 0x%llx.\n",
2716987da915Sopenharmony_ci			(unsigned long long)na->ni->mft_no, le32_to_cpu(na->type),
2717987da915Sopenharmony_ci			(long long)pos);
2718987da915Sopenharmony_ci	if (bk_cnt < 0 || bk_size % NTFS_BLOCK_SIZE) {
2719987da915Sopenharmony_ci		errno = EINVAL;
2720987da915Sopenharmony_ci		return -1;
2721987da915Sopenharmony_ci	}
2722987da915Sopenharmony_ci	if (!bk_cnt)
2723987da915Sopenharmony_ci		return 0;
2724987da915Sopenharmony_ci	/* Prepare data for writing. */
2725987da915Sopenharmony_ci	for (i = 0; i < bk_cnt; ++i) {
2726987da915Sopenharmony_ci		int err;
2727987da915Sopenharmony_ci
2728987da915Sopenharmony_ci		err = ntfs_mst_pre_write_fixup((NTFS_RECORD*)
2729987da915Sopenharmony_ci				((u8*)src + i * bk_size), bk_size);
2730987da915Sopenharmony_ci		if (err < 0) {
2731987da915Sopenharmony_ci			/* Abort write at this position. */
2732987da915Sopenharmony_ci			ntfs_log_perror("%s #1", __FUNCTION__);
2733987da915Sopenharmony_ci			if (!i)
2734987da915Sopenharmony_ci				return err;
2735987da915Sopenharmony_ci			bk_cnt = i;
2736987da915Sopenharmony_ci			break;
2737987da915Sopenharmony_ci		}
2738987da915Sopenharmony_ci	}
2739987da915Sopenharmony_ci	/* Write the prepared data. */
2740987da915Sopenharmony_ci	written = ntfs_attr_pwrite(na, pos, bk_cnt * bk_size, src);
2741987da915Sopenharmony_ci	if (written <= 0) {
2742987da915Sopenharmony_ci		ntfs_log_perror("%s: written=%lld", __FUNCTION__,
2743987da915Sopenharmony_ci				(long long)written);
2744987da915Sopenharmony_ci	}
2745987da915Sopenharmony_ci	/* Quickly deprotect the data again. */
2746987da915Sopenharmony_ci	for (i = 0; i < bk_cnt; ++i)
2747987da915Sopenharmony_ci		ntfs_mst_post_write_fixup((NTFS_RECORD*)((u8*)src + i *
2748987da915Sopenharmony_ci				bk_size));
2749987da915Sopenharmony_ci	if (written <= 0)
2750987da915Sopenharmony_ci		return written;
2751987da915Sopenharmony_ci	/* Finally, return the number of complete blocks written. */
2752987da915Sopenharmony_ci	return written / bk_size;
2753987da915Sopenharmony_ci}
2754987da915Sopenharmony_ci
2755987da915Sopenharmony_ci/**
2756987da915Sopenharmony_ci * ntfs_attr_find - find (next) attribute in mft record
2757987da915Sopenharmony_ci * @type:	attribute type to find
2758987da915Sopenharmony_ci * @name:	attribute name to find (optional, i.e. NULL means don't care)
2759987da915Sopenharmony_ci * @name_len:	attribute name length (only needed if @name present)
2760987da915Sopenharmony_ci * @ic:		IGNORE_CASE or CASE_SENSITIVE (ignored if @name not present)
2761987da915Sopenharmony_ci * @val:	attribute value to find (optional, resident attributes only)
2762987da915Sopenharmony_ci * @val_len:	attribute value length
2763987da915Sopenharmony_ci * @ctx:	search context with mft record and attribute to search from
2764987da915Sopenharmony_ci *
2765987da915Sopenharmony_ci * You shouldn't need to call this function directly. Use lookup_attr() instead.
2766987da915Sopenharmony_ci *
2767987da915Sopenharmony_ci * ntfs_attr_find() takes a search context @ctx as parameter and searches the
2768987da915Sopenharmony_ci * mft record specified by @ctx->mrec, beginning at @ctx->attr, for an
2769987da915Sopenharmony_ci * attribute of @type, optionally @name and @val. If found, ntfs_attr_find()
2770987da915Sopenharmony_ci * returns 0 and @ctx->attr will point to the found attribute.
2771987da915Sopenharmony_ci *
2772987da915Sopenharmony_ci * If not found, ntfs_attr_find() returns -1, with errno set to ENOENT and
2773987da915Sopenharmony_ci * @ctx->attr will point to the attribute before which the attribute being
2774987da915Sopenharmony_ci * searched for would need to be inserted if such an action were to be desired.
2775987da915Sopenharmony_ci *
2776987da915Sopenharmony_ci * On actual error, ntfs_attr_find() returns -1 with errno set to the error
2777987da915Sopenharmony_ci * code but not to ENOENT.  In this case @ctx->attr is undefined and in
2778987da915Sopenharmony_ci * particular do not rely on it not changing.
2779987da915Sopenharmony_ci *
2780987da915Sopenharmony_ci * If @ctx->is_first is TRUE, the search begins with @ctx->attr itself. If it
2781987da915Sopenharmony_ci * is FALSE, the search begins after @ctx->attr.
2782987da915Sopenharmony_ci *
2783987da915Sopenharmony_ci * If @type is AT_UNUSED, return the first found attribute, i.e. one can
2784987da915Sopenharmony_ci * enumerate all attributes by setting @type to AT_UNUSED and then calling
2785987da915Sopenharmony_ci * ntfs_attr_find() repeatedly until it returns -1 with errno set to ENOENT to
2786987da915Sopenharmony_ci * indicate that there are no more entries. During the enumeration, each
2787987da915Sopenharmony_ci * successful call of ntfs_attr_find() will return the next attribute in the
2788987da915Sopenharmony_ci * mft record @ctx->mrec.
2789987da915Sopenharmony_ci *
2790987da915Sopenharmony_ci * If @type is AT_END, seek to the end and return -1 with errno set to ENOENT.
2791987da915Sopenharmony_ci * AT_END is not a valid attribute, its length is zero for example, thus it is
2792987da915Sopenharmony_ci * safer to return error instead of success in this case. This also allows us
2793987da915Sopenharmony_ci * to interoperate cleanly with ntfs_external_attr_find().
2794987da915Sopenharmony_ci *
2795987da915Sopenharmony_ci * If @name is AT_UNNAMED search for an unnamed attribute. If @name is present
2796987da915Sopenharmony_ci * but not AT_UNNAMED search for a named attribute matching @name. Otherwise,
2797987da915Sopenharmony_ci * match both named and unnamed attributes.
2798987da915Sopenharmony_ci *
2799987da915Sopenharmony_ci * If @ic is IGNORE_CASE, the @name comparison is not case sensitive and
2800987da915Sopenharmony_ci * @ctx->ntfs_ino must be set to the ntfs inode to which the mft record
2801987da915Sopenharmony_ci * @ctx->mrec belongs. This is so we can get at the ntfs volume and hence at
2802987da915Sopenharmony_ci * the upcase table. If @ic is CASE_SENSITIVE, the comparison is case
2803987da915Sopenharmony_ci * sensitive. When @name is present, @name_len is the @name length in Unicode
2804987da915Sopenharmony_ci * characters.
2805987da915Sopenharmony_ci *
2806987da915Sopenharmony_ci * If @name is not present (NULL), we assume that the unnamed attribute is
2807987da915Sopenharmony_ci * being searched for.
2808987da915Sopenharmony_ci *
2809987da915Sopenharmony_ci * Finally, the resident attribute value @val is looked for, if present.
2810987da915Sopenharmony_ci * If @val is not present (NULL), @val_len is ignored.
2811987da915Sopenharmony_ci *
2812987da915Sopenharmony_ci * ntfs_attr_find() only searches the specified mft record and it ignores the
2813987da915Sopenharmony_ci * presence of an attribute list attribute (unless it is the one being searched
2814987da915Sopenharmony_ci * for, obviously). If you need to take attribute lists into consideration, use
2815987da915Sopenharmony_ci * ntfs_attr_lookup() instead (see below). This also means that you cannot use
2816987da915Sopenharmony_ci * ntfs_attr_find() to search for extent records of non-resident attributes, as
2817987da915Sopenharmony_ci * extents with lowest_vcn != 0 are usually described by the attribute list
2818987da915Sopenharmony_ci * attribute only. - Note that it is possible that the first extent is only in
2819987da915Sopenharmony_ci * the attribute list while the last extent is in the base mft record, so don't
2820987da915Sopenharmony_ci * rely on being able to find the first extent in the base mft record.
2821987da915Sopenharmony_ci *
2822987da915Sopenharmony_ci * Warning: Never use @val when looking for attribute types which can be
2823987da915Sopenharmony_ci *	    non-resident as this most likely will result in a crash!
2824987da915Sopenharmony_ci */
2825987da915Sopenharmony_cistatic int ntfs_attr_find(const ATTR_TYPES type, const ntfschar *name,
2826987da915Sopenharmony_ci		const u32 name_len, const IGNORE_CASE_BOOL ic,
2827987da915Sopenharmony_ci		const u8 *val, const u32 val_len, ntfs_attr_search_ctx *ctx)
2828987da915Sopenharmony_ci{
2829987da915Sopenharmony_ci	ATTR_RECORD *a;
2830987da915Sopenharmony_ci	ntfs_volume *vol;
2831987da915Sopenharmony_ci	ntfschar *upcase;
2832987da915Sopenharmony_ci	ptrdiff_t offs;
2833987da915Sopenharmony_ci	ptrdiff_t space;
2834987da915Sopenharmony_ci	u32 upcase_len;
2835987da915Sopenharmony_ci
2836987da915Sopenharmony_ci	ntfs_log_trace("attribute type 0x%x.\n", le32_to_cpu(type));
2837987da915Sopenharmony_ci
2838987da915Sopenharmony_ci	if (ctx->ntfs_ino) {
2839987da915Sopenharmony_ci		vol = ctx->ntfs_ino->vol;
2840987da915Sopenharmony_ci		upcase = vol->upcase;
2841987da915Sopenharmony_ci		upcase_len = vol->upcase_len;
2842987da915Sopenharmony_ci	} else {
2843987da915Sopenharmony_ci		if (name && name != AT_UNNAMED) {
2844987da915Sopenharmony_ci			errno = EINVAL;
2845987da915Sopenharmony_ci			ntfs_log_perror("%s", __FUNCTION__);
2846987da915Sopenharmony_ci			return -1;
2847987da915Sopenharmony_ci		}
2848987da915Sopenharmony_ci		vol = NULL;
2849987da915Sopenharmony_ci		upcase = NULL;
2850987da915Sopenharmony_ci		upcase_len = 0;
2851987da915Sopenharmony_ci	}
2852987da915Sopenharmony_ci	/*
2853987da915Sopenharmony_ci	 * Iterate over attributes in mft record starting at @ctx->attr, or the
2854987da915Sopenharmony_ci	 * attribute following that, if @ctx->is_first is TRUE.
2855987da915Sopenharmony_ci	 */
2856987da915Sopenharmony_ci	if (ctx->is_first) {
2857987da915Sopenharmony_ci		a = ctx->attr;
2858987da915Sopenharmony_ci		ctx->is_first = FALSE;
2859987da915Sopenharmony_ci	} else
2860987da915Sopenharmony_ci		a = (ATTR_RECORD*)((char*)ctx->attr +
2861987da915Sopenharmony_ci				le32_to_cpu(ctx->attr->length));
2862987da915Sopenharmony_ci	for (;;	a = (ATTR_RECORD*)((char*)a + le32_to_cpu(a->length))) {
2863987da915Sopenharmony_ci		/*
2864987da915Sopenharmony_ci		 * Make sure the attribute fully lies within the MFT record
2865987da915Sopenharmony_ci		 * and we can safely access its minimal fields.
2866987da915Sopenharmony_ci		 */
2867987da915Sopenharmony_ci		offs = p2n(a) - p2n(ctx->mrec);
2868987da915Sopenharmony_ci		space = le32_to_cpu(ctx->mrec->bytes_in_use) - offs;
2869987da915Sopenharmony_ci		if ((offs < 0)
2870987da915Sopenharmony_ci		    || (((space < (ptrdiff_t)offsetof(ATTR_RECORD,
2871987da915Sopenharmony_ci						resident_end))
2872987da915Sopenharmony_ci			|| (space < (ptrdiff_t)le32_to_cpu(a->length)))
2873987da915Sopenharmony_ci			    && ((space < 4) || (a->type != AT_END))))
2874987da915Sopenharmony_ci			break;
2875987da915Sopenharmony_ci		ctx->attr = a;
2876987da915Sopenharmony_ci		if (((type != AT_UNUSED) && (le32_to_cpu(a->type) >
2877987da915Sopenharmony_ci				le32_to_cpu(type))) ||
2878987da915Sopenharmony_ci				(a->type == AT_END)) {
2879987da915Sopenharmony_ci			errno = ENOENT;
2880987da915Sopenharmony_ci			return -1;
2881987da915Sopenharmony_ci		}
2882987da915Sopenharmony_ci		if (!a->length)
2883987da915Sopenharmony_ci			break;
2884987da915Sopenharmony_ci		/* If this is an enumeration return this attribute. */
2885987da915Sopenharmony_ci		if (type == AT_UNUSED)
2886987da915Sopenharmony_ci			return 0;
2887987da915Sopenharmony_ci		if (a->type != type)
2888987da915Sopenharmony_ci			continue;
2889987da915Sopenharmony_ci		/*
2890987da915Sopenharmony_ci		 * If @name is AT_UNNAMED we want an unnamed attribute.
2891987da915Sopenharmony_ci		 * If @name is present, compare the two names.
2892987da915Sopenharmony_ci		 * Otherwise, match any attribute.
2893987da915Sopenharmony_ci		 */
2894987da915Sopenharmony_ci		if (name == AT_UNNAMED) {
2895987da915Sopenharmony_ci			/* The search failed if the found attribute is named. */
2896987da915Sopenharmony_ci			if (a->name_length) {
2897987da915Sopenharmony_ci				errno = ENOENT;
2898987da915Sopenharmony_ci				return -1;
2899987da915Sopenharmony_ci			}
2900987da915Sopenharmony_ci		} else {
2901987da915Sopenharmony_ci			register int rc;
2902987da915Sopenharmony_ci
2903987da915Sopenharmony_ci			if (a->name_length
2904987da915Sopenharmony_ci			    && ((le16_to_cpu(a->name_offset)
2905987da915Sopenharmony_ci					+ a->name_length * sizeof(ntfschar))
2906987da915Sopenharmony_ci					> le32_to_cpu(a->length))) {
2907987da915Sopenharmony_ci				ntfs_log_error("Corrupt attribute name"
2908987da915Sopenharmony_ci					" in MFT record %lld\n",
2909987da915Sopenharmony_ci					(long long)ctx->ntfs_ino->mft_no);
2910987da915Sopenharmony_ci				break;
2911987da915Sopenharmony_ci			}
2912987da915Sopenharmony_ci			if (name && ((rc = ntfs_names_full_collate(name,
2913987da915Sopenharmony_ci					name_len, (ntfschar*)((char*)a +
2914987da915Sopenharmony_ci						le16_to_cpu(a->name_offset)),
2915987da915Sopenharmony_ci					a->name_length, ic,
2916987da915Sopenharmony_ci					upcase, upcase_len)))) {
2917987da915Sopenharmony_ci				/*
2918987da915Sopenharmony_ci				 * If @name collates before a->name,
2919987da915Sopenharmony_ci				 * there is no matching attribute.
2920987da915Sopenharmony_ci				 */
2921987da915Sopenharmony_ci				if (rc < 0) {
2922987da915Sopenharmony_ci					errno = ENOENT;
2923987da915Sopenharmony_ci					return -1;
2924987da915Sopenharmony_ci				}
2925987da915Sopenharmony_ci			/* If the strings are not equal, continue search. */
2926987da915Sopenharmony_ci			continue;
2927987da915Sopenharmony_ci			}
2928987da915Sopenharmony_ci		}
2929987da915Sopenharmony_ci		/*
2930987da915Sopenharmony_ci		 * The names match or @name not present and attribute is
2931987da915Sopenharmony_ci		 * unnamed. If no @val specified, we have found the attribute
2932987da915Sopenharmony_ci		 * and are done.
2933987da915Sopenharmony_ci		 */
2934987da915Sopenharmony_ci		if (!val)
2935987da915Sopenharmony_ci			return 0;
2936987da915Sopenharmony_ci		/* @val is present; compare values. */
2937987da915Sopenharmony_ci		else {
2938987da915Sopenharmony_ci			register int rc;
2939987da915Sopenharmony_ci
2940987da915Sopenharmony_ci			rc = memcmp(val, (char*)a +le16_to_cpu(a->value_offset),
2941987da915Sopenharmony_ci					min(val_len,
2942987da915Sopenharmony_ci					le32_to_cpu(a->value_length)));
2943987da915Sopenharmony_ci			/*
2944987da915Sopenharmony_ci			 * If @val collates before the current attribute's
2945987da915Sopenharmony_ci			 * value, there is no matching attribute.
2946987da915Sopenharmony_ci			 */
2947987da915Sopenharmony_ci			if (!rc) {
2948987da915Sopenharmony_ci				register u32 avl;
2949987da915Sopenharmony_ci				avl = le32_to_cpu(a->value_length);
2950987da915Sopenharmony_ci				if (val_len == avl)
2951987da915Sopenharmony_ci					return 0;
2952987da915Sopenharmony_ci				if (val_len < avl) {
2953987da915Sopenharmony_ci					errno = ENOENT;
2954987da915Sopenharmony_ci					return -1;
2955987da915Sopenharmony_ci				}
2956987da915Sopenharmony_ci			} else if (rc < 0) {
2957987da915Sopenharmony_ci				errno = ENOENT;
2958987da915Sopenharmony_ci				return -1;
2959987da915Sopenharmony_ci			}
2960987da915Sopenharmony_ci		}
2961987da915Sopenharmony_ci	}
2962987da915Sopenharmony_ci	errno = EIO;
2963987da915Sopenharmony_ci	ntfs_log_perror("%s: Corrupt inode (%lld)", __FUNCTION__,
2964987da915Sopenharmony_ci			ctx->ntfs_ino ? (long long)ctx->ntfs_ino->mft_no : -1);
2965987da915Sopenharmony_ci	return -1;
2966987da915Sopenharmony_ci}
2967987da915Sopenharmony_ci
2968987da915Sopenharmony_civoid ntfs_attr_name_free(char **name)
2969987da915Sopenharmony_ci{
2970987da915Sopenharmony_ci	if (*name) {
2971987da915Sopenharmony_ci		free(*name);
2972987da915Sopenharmony_ci		*name = NULL;
2973987da915Sopenharmony_ci	}
2974987da915Sopenharmony_ci}
2975987da915Sopenharmony_ci
2976987da915Sopenharmony_cichar *ntfs_attr_name_get(const ntfschar *uname, const int uname_len)
2977987da915Sopenharmony_ci{
2978987da915Sopenharmony_ci	char *name = NULL;
2979987da915Sopenharmony_ci	int name_len;
2980987da915Sopenharmony_ci
2981987da915Sopenharmony_ci	name_len = ntfs_ucstombs(uname, uname_len, &name, 0);
2982987da915Sopenharmony_ci	if (name_len < 0) {
2983987da915Sopenharmony_ci		ntfs_log_perror("ntfs_ucstombs");
2984987da915Sopenharmony_ci		return NULL;
2985987da915Sopenharmony_ci
2986987da915Sopenharmony_ci	} else if (name_len > 0)
2987987da915Sopenharmony_ci		return name;
2988987da915Sopenharmony_ci
2989987da915Sopenharmony_ci	ntfs_attr_name_free(&name);
2990987da915Sopenharmony_ci	return NULL;
2991987da915Sopenharmony_ci}
2992987da915Sopenharmony_ci
2993987da915Sopenharmony_ci/**
2994987da915Sopenharmony_ci * ntfs_external_attr_find - find an attribute in the attribute list of an inode
2995987da915Sopenharmony_ci * @type:	attribute type to find
2996987da915Sopenharmony_ci * @name:	attribute name to find (optional, i.e. NULL means don't care)
2997987da915Sopenharmony_ci * @name_len:	attribute name length (only needed if @name present)
2998987da915Sopenharmony_ci * @ic:		IGNORE_CASE or CASE_SENSITIVE (ignored if @name not present)
2999987da915Sopenharmony_ci * @lowest_vcn:	lowest vcn to find (optional, non-resident attributes only)
3000987da915Sopenharmony_ci * @val:	attribute value to find (optional, resident attributes only)
3001987da915Sopenharmony_ci * @val_len:	attribute value length
3002987da915Sopenharmony_ci * @ctx:	search context with mft record and attribute to search from
3003987da915Sopenharmony_ci *
3004987da915Sopenharmony_ci * You shouldn't need to call this function directly. Use ntfs_attr_lookup()
3005987da915Sopenharmony_ci * instead.
3006987da915Sopenharmony_ci *
3007987da915Sopenharmony_ci * Find an attribute by searching the attribute list for the corresponding
3008987da915Sopenharmony_ci * attribute list entry. Having found the entry, map the mft record for read
3009987da915Sopenharmony_ci * if the attribute is in a different mft record/inode, find the attribute in
3010987da915Sopenharmony_ci * there and return it.
3011987da915Sopenharmony_ci *
3012987da915Sopenharmony_ci * If @type is AT_UNUSED, return the first found attribute, i.e. one can
3013987da915Sopenharmony_ci * enumerate all attributes by setting @type to AT_UNUSED and then calling
3014987da915Sopenharmony_ci * ntfs_external_attr_find() repeatedly until it returns -1 with errno set to
3015987da915Sopenharmony_ci * ENOENT to indicate that there are no more entries. During the enumeration,
3016987da915Sopenharmony_ci * each successful call of ntfs_external_attr_find() will return the next
3017987da915Sopenharmony_ci * attribute described by the attribute list of the base mft record described
3018987da915Sopenharmony_ci * by the search context @ctx.
3019987da915Sopenharmony_ci *
3020987da915Sopenharmony_ci * If @type is AT_END, seek to the end of the base mft record ignoring the
3021987da915Sopenharmony_ci * attribute list completely and return -1 with errno set to ENOENT.  AT_END is
3022987da915Sopenharmony_ci * not a valid attribute, its length is zero for example, thus it is safer to
3023987da915Sopenharmony_ci * return error instead of success in this case.
3024987da915Sopenharmony_ci *
3025987da915Sopenharmony_ci * If @name is AT_UNNAMED search for an unnamed attribute. If @name is present
3026987da915Sopenharmony_ci * but not AT_UNNAMED search for a named attribute matching @name. Otherwise,
3027987da915Sopenharmony_ci * match both named and unnamed attributes.
3028987da915Sopenharmony_ci *
3029987da915Sopenharmony_ci * On first search @ctx->ntfs_ino must be the inode of the base mft record and
3030987da915Sopenharmony_ci * @ctx must have been obtained from a call to ntfs_attr_get_search_ctx().
3031987da915Sopenharmony_ci * On subsequent calls, @ctx->ntfs_ino can be any extent inode, too
3032987da915Sopenharmony_ci * (@ctx->base_ntfs_ino is then the base inode).
3033987da915Sopenharmony_ci *
3034987da915Sopenharmony_ci * After finishing with the attribute/mft record you need to call
3035987da915Sopenharmony_ci * ntfs_attr_put_search_ctx() to cleanup the search context (unmapping any
3036987da915Sopenharmony_ci * mapped extent inodes, etc).
3037987da915Sopenharmony_ci *
3038987da915Sopenharmony_ci * Return 0 if the search was successful and -1 if not, with errno set to the
3039987da915Sopenharmony_ci * error code.
3040987da915Sopenharmony_ci *
3041987da915Sopenharmony_ci * On success, @ctx->attr is the found attribute, it is in mft record
3042987da915Sopenharmony_ci * @ctx->mrec, and @ctx->al_entry is the attribute list entry for this
3043987da915Sopenharmony_ci * attribute with @ctx->base_* being the base mft record to which @ctx->attr
3044987da915Sopenharmony_ci * belongs.
3045987da915Sopenharmony_ci *
3046987da915Sopenharmony_ci * On error ENOENT, i.e. attribute not found, @ctx->attr is set to the
3047987da915Sopenharmony_ci * attribute which collates just after the attribute being searched for in the
3048987da915Sopenharmony_ci * base ntfs inode, i.e. if one wants to add the attribute to the mft record
3049987da915Sopenharmony_ci * this is the correct place to insert it into, and if there is not enough
3050987da915Sopenharmony_ci * space, the attribute should be placed in an extent mft record.
3051987da915Sopenharmony_ci * @ctx->al_entry points to the position within @ctx->base_ntfs_ino->attr_list
3052987da915Sopenharmony_ci * at which the new attribute's attribute list entry should be inserted.  The
3053987da915Sopenharmony_ci * other @ctx fields, base_ntfs_ino, base_mrec, and base_attr are set to NULL.
3054987da915Sopenharmony_ci * The only exception to this is when @type is AT_END, in which case
3055987da915Sopenharmony_ci * @ctx->al_entry is set to NULL also (see above).
3056987da915Sopenharmony_ci *
3057987da915Sopenharmony_ci * The following error codes are defined:
3058987da915Sopenharmony_ci *	ENOENT	Attribute not found, not an error as such.
3059987da915Sopenharmony_ci *	EINVAL	Invalid arguments.
3060987da915Sopenharmony_ci *	EIO	I/O error or corrupt data structures found.
3061987da915Sopenharmony_ci *	ENOMEM	Not enough memory to allocate necessary buffers.
3062987da915Sopenharmony_ci */
3063987da915Sopenharmony_cistatic int ntfs_external_attr_find(ATTR_TYPES type, const ntfschar *name,
3064987da915Sopenharmony_ci		const u32 name_len, const IGNORE_CASE_BOOL ic,
3065987da915Sopenharmony_ci		const VCN lowest_vcn, const u8 *val, const u32 val_len,
3066987da915Sopenharmony_ci		ntfs_attr_search_ctx *ctx)
3067987da915Sopenharmony_ci{
3068987da915Sopenharmony_ci	ntfs_inode *base_ni, *ni;
3069987da915Sopenharmony_ci	ntfs_volume *vol;
3070987da915Sopenharmony_ci	ATTR_LIST_ENTRY *al_entry, *next_al_entry;
3071987da915Sopenharmony_ci	u8 *al_start, *al_end;
3072987da915Sopenharmony_ci	ATTR_RECORD *a;
3073987da915Sopenharmony_ci	ntfschar *al_name;
3074987da915Sopenharmony_ci	ptrdiff_t offs;
3075987da915Sopenharmony_ci	ptrdiff_t space;
3076987da915Sopenharmony_ci	u32 al_name_len;
3077987da915Sopenharmony_ci	BOOL is_first_search = FALSE;
3078987da915Sopenharmony_ci
3079987da915Sopenharmony_ci	ni = ctx->ntfs_ino;
3080987da915Sopenharmony_ci	base_ni = ctx->base_ntfs_ino;
3081987da915Sopenharmony_ci	ntfs_log_trace("Entering for inode %lld, attribute type 0x%x.\n",
3082987da915Sopenharmony_ci			(unsigned long long)ni->mft_no, le32_to_cpu(type));
3083987da915Sopenharmony_ci	if (!base_ni) {
3084987da915Sopenharmony_ci		/* First call happens with the base mft record. */
3085987da915Sopenharmony_ci		base_ni = ctx->base_ntfs_ino = ctx->ntfs_ino;
3086987da915Sopenharmony_ci		ctx->base_mrec = ctx->mrec;
3087987da915Sopenharmony_ci	}
3088987da915Sopenharmony_ci	if (ni == base_ni)
3089987da915Sopenharmony_ci		ctx->base_attr = ctx->attr;
3090987da915Sopenharmony_ci	if (type == AT_END)
3091987da915Sopenharmony_ci		goto not_found;
3092987da915Sopenharmony_ci	vol = base_ni->vol;
3093987da915Sopenharmony_ci	al_start = base_ni->attr_list;
3094987da915Sopenharmony_ci	al_end = al_start + base_ni->attr_list_size;
3095987da915Sopenharmony_ci	if (!ctx->al_entry) {
3096987da915Sopenharmony_ci		ctx->al_entry = (ATTR_LIST_ENTRY*)al_start;
3097987da915Sopenharmony_ci		is_first_search = TRUE;
3098987da915Sopenharmony_ci	}
3099987da915Sopenharmony_ci	/*
3100987da915Sopenharmony_ci	 * Iterate over entries in attribute list starting at @ctx->al_entry,
3101987da915Sopenharmony_ci	 * or the entry following that, if @ctx->is_first is TRUE.
3102987da915Sopenharmony_ci	 */
3103987da915Sopenharmony_ci	if (ctx->is_first) {
3104987da915Sopenharmony_ci		al_entry = ctx->al_entry;
3105987da915Sopenharmony_ci		ctx->is_first = FALSE;
3106987da915Sopenharmony_ci		/*
3107987da915Sopenharmony_ci		 * If an enumeration and the first attribute is higher than
3108987da915Sopenharmony_ci		 * the attribute list itself, need to return the attribute list
3109987da915Sopenharmony_ci		 * attribute.
3110987da915Sopenharmony_ci		 */
3111987da915Sopenharmony_ci		if ((type == AT_UNUSED) && is_first_search &&
3112987da915Sopenharmony_ci				le32_to_cpu(al_entry->type) >
3113987da915Sopenharmony_ci				le32_to_cpu(AT_ATTRIBUTE_LIST))
3114987da915Sopenharmony_ci			goto find_attr_list_attr;
3115987da915Sopenharmony_ci	} else {
3116987da915Sopenharmony_ci			/* Check for small entry */
3117987da915Sopenharmony_ci		if (((p2n(al_end) - p2n(ctx->al_entry))
3118987da915Sopenharmony_ci				< (long)offsetof(ATTR_LIST_ENTRY, name))
3119987da915Sopenharmony_ci		    || (le16_to_cpu(ctx->al_entry->length) & 7)
3120987da915Sopenharmony_ci		    || (le16_to_cpu(ctx->al_entry->length)
3121987da915Sopenharmony_ci				< offsetof(ATTR_LIST_ENTRY, name)))
3122987da915Sopenharmony_ci			goto corrupt;
3123987da915Sopenharmony_ci
3124987da915Sopenharmony_ci		al_entry = (ATTR_LIST_ENTRY*)((char*)ctx->al_entry +
3125987da915Sopenharmony_ci				le16_to_cpu(ctx->al_entry->length));
3126987da915Sopenharmony_ci		if ((u8*)al_entry == al_end)
3127987da915Sopenharmony_ci			goto not_found;
3128987da915Sopenharmony_ci			/* Preliminary check for small entry */
3129987da915Sopenharmony_ci		if ((p2n(al_end) - p2n(al_entry))
3130987da915Sopenharmony_ci				< (long)offsetof(ATTR_LIST_ENTRY, name))
3131987da915Sopenharmony_ci			goto corrupt;
3132987da915Sopenharmony_ci		/*
3133987da915Sopenharmony_ci		 * If this is an enumeration and the attribute list attribute
3134987da915Sopenharmony_ci		 * is the next one in the enumeration sequence, just return the
3135987da915Sopenharmony_ci		 * attribute list attribute from the base mft record as it is
3136987da915Sopenharmony_ci		 * not listed in the attribute list itself.
3137987da915Sopenharmony_ci		 */
3138987da915Sopenharmony_ci		if ((type == AT_UNUSED) && le32_to_cpu(ctx->al_entry->type) <
3139987da915Sopenharmony_ci				le32_to_cpu(AT_ATTRIBUTE_LIST) &&
3140987da915Sopenharmony_ci				le32_to_cpu(al_entry->type) >
3141987da915Sopenharmony_ci				le32_to_cpu(AT_ATTRIBUTE_LIST)) {
3142987da915Sopenharmony_ci			int rc;
3143987da915Sopenharmony_cifind_attr_list_attr:
3144987da915Sopenharmony_ci
3145987da915Sopenharmony_ci			/* Check for bogus calls. */
3146987da915Sopenharmony_ci			if (name || name_len || val || val_len || lowest_vcn) {
3147987da915Sopenharmony_ci				errno = EINVAL;
3148987da915Sopenharmony_ci				ntfs_log_perror("%s", __FUNCTION__);
3149987da915Sopenharmony_ci				return -1;
3150987da915Sopenharmony_ci			}
3151987da915Sopenharmony_ci
3152987da915Sopenharmony_ci			/* We want the base record. */
3153987da915Sopenharmony_ci			ctx->ntfs_ino = base_ni;
3154987da915Sopenharmony_ci			ctx->mrec = ctx->base_mrec;
3155987da915Sopenharmony_ci			ctx->is_first = TRUE;
3156987da915Sopenharmony_ci			/* Sanity checks are performed elsewhere. */
3157987da915Sopenharmony_ci			ctx->attr = (ATTR_RECORD*)((u8*)ctx->mrec +
3158987da915Sopenharmony_ci					le16_to_cpu(ctx->mrec->attrs_offset));
3159987da915Sopenharmony_ci
3160987da915Sopenharmony_ci			/* Find the attribute list attribute. */
3161987da915Sopenharmony_ci			rc = ntfs_attr_find(AT_ATTRIBUTE_LIST, NULL, 0,
3162987da915Sopenharmony_ci					IGNORE_CASE, NULL, 0, ctx);
3163987da915Sopenharmony_ci
3164987da915Sopenharmony_ci			/*
3165987da915Sopenharmony_ci			 * Setup the search context so the correct
3166987da915Sopenharmony_ci			 * attribute is returned next time round.
3167987da915Sopenharmony_ci			 */
3168987da915Sopenharmony_ci			ctx->al_entry = al_entry;
3169987da915Sopenharmony_ci			ctx->is_first = TRUE;
3170987da915Sopenharmony_ci
3171987da915Sopenharmony_ci			/* Got it. Done. */
3172987da915Sopenharmony_ci			if (!rc)
3173987da915Sopenharmony_ci				return 0;
3174987da915Sopenharmony_ci
3175987da915Sopenharmony_ci			/* Error! If other than not found return it. */
3176987da915Sopenharmony_ci			if (errno != ENOENT)
3177987da915Sopenharmony_ci				return rc;
3178987da915Sopenharmony_ci
3179987da915Sopenharmony_ci			/* Not found?!? Absurd! */
3180987da915Sopenharmony_ci			errno = EIO;
3181987da915Sopenharmony_ci			ntfs_log_error("Attribute list wasn't found");
3182987da915Sopenharmony_ci			return -1;
3183987da915Sopenharmony_ci		}
3184987da915Sopenharmony_ci	}
3185987da915Sopenharmony_ci	for (;; al_entry = next_al_entry) {
3186987da915Sopenharmony_ci		/* Out of bounds check. */
3187987da915Sopenharmony_ci		if ((u8*)al_entry < base_ni->attr_list ||
3188987da915Sopenharmony_ci				(u8*)al_entry > al_end)
3189987da915Sopenharmony_ci			break;	/* Inode is corrupt. */
3190987da915Sopenharmony_ci		ctx->al_entry = al_entry;
3191987da915Sopenharmony_ci		/* Catch the end of the attribute list. */
3192987da915Sopenharmony_ci		if ((u8*)al_entry == al_end)
3193987da915Sopenharmony_ci			goto not_found;
3194987da915Sopenharmony_ci
3195987da915Sopenharmony_ci		if ((((u8*)al_entry + offsetof(ATTR_LIST_ENTRY, name)) > al_end)
3196987da915Sopenharmony_ci		    || ((u8*)al_entry + le16_to_cpu(al_entry->length) > al_end)
3197987da915Sopenharmony_ci		    || (le16_to_cpu(al_entry->length) & 7)
3198987da915Sopenharmony_ci		    || (le16_to_cpu(al_entry->length)
3199987da915Sopenharmony_ci				< offsetof(ATTR_LIST_ENTRY, name_length))
3200987da915Sopenharmony_ci		    || (al_entry->name_length
3201987da915Sopenharmony_ci			&& ((u8*)al_entry + al_entry->name_offset
3202987da915Sopenharmony_ci				+ al_entry->name_length * sizeof(ntfschar))
3203987da915Sopenharmony_ci				> al_end))
3204987da915Sopenharmony_ci			break; /* corrupt */
3205987da915Sopenharmony_ci
3206987da915Sopenharmony_ci		next_al_entry = (ATTR_LIST_ENTRY*)((u8*)al_entry +
3207987da915Sopenharmony_ci				le16_to_cpu(al_entry->length));
3208987da915Sopenharmony_ci		if (type != AT_UNUSED) {
3209987da915Sopenharmony_ci			if (le32_to_cpu(al_entry->type) > le32_to_cpu(type))
3210987da915Sopenharmony_ci				goto not_found;
3211987da915Sopenharmony_ci			if (type != al_entry->type)
3212987da915Sopenharmony_ci				continue;
3213987da915Sopenharmony_ci		}
3214987da915Sopenharmony_ci		al_name_len = al_entry->name_length;
3215987da915Sopenharmony_ci		al_name = (ntfschar*)((u8*)al_entry + al_entry->name_offset);
3216987da915Sopenharmony_ci		/*
3217987da915Sopenharmony_ci		 * If !@type we want the attribute represented by this
3218987da915Sopenharmony_ci		 * attribute list entry.
3219987da915Sopenharmony_ci		 */
3220987da915Sopenharmony_ci		if (type == AT_UNUSED)
3221987da915Sopenharmony_ci			goto is_enumeration;
3222987da915Sopenharmony_ci		/*
3223987da915Sopenharmony_ci		 * If @name is AT_UNNAMED we want an unnamed attribute.
3224987da915Sopenharmony_ci		 * If @name is present, compare the two names.
3225987da915Sopenharmony_ci		 * Otherwise, match any attribute.
3226987da915Sopenharmony_ci		 */
3227987da915Sopenharmony_ci		if (name == AT_UNNAMED) {
3228987da915Sopenharmony_ci			if (al_name_len)
3229987da915Sopenharmony_ci				goto not_found;
3230987da915Sopenharmony_ci		} else {
3231987da915Sopenharmony_ci			int rc;
3232987da915Sopenharmony_ci
3233987da915Sopenharmony_ci			if (name && ((rc = ntfs_names_full_collate(name,
3234987da915Sopenharmony_ci					name_len, al_name, al_name_len, ic,
3235987da915Sopenharmony_ci					vol->upcase, vol->upcase_len)))) {
3236987da915Sopenharmony_ci
3237987da915Sopenharmony_ci				/*
3238987da915Sopenharmony_ci				 * If @name collates before al_name,
3239987da915Sopenharmony_ci				 * there is no matching attribute.
3240987da915Sopenharmony_ci				 */
3241987da915Sopenharmony_ci				if (rc < 0)
3242987da915Sopenharmony_ci					goto not_found;
3243987da915Sopenharmony_ci				/* If the strings are not equal, continue search. */
3244987da915Sopenharmony_ci				continue;
3245987da915Sopenharmony_ci			}
3246987da915Sopenharmony_ci		}
3247987da915Sopenharmony_ci		/*
3248987da915Sopenharmony_ci		 * The names match or @name not present and attribute is
3249987da915Sopenharmony_ci		 * unnamed. Now check @lowest_vcn. Continue search if the
3250987da915Sopenharmony_ci		 * next attribute list entry still fits @lowest_vcn. Otherwise
3251987da915Sopenharmony_ci		 * we have reached the right one or the search has failed.
3252987da915Sopenharmony_ci		 */
3253987da915Sopenharmony_ci		if (lowest_vcn && (u8*)next_al_entry >= al_start	    &&
3254987da915Sopenharmony_ci				(u8*)next_al_entry + 6 < al_end	    &&
3255987da915Sopenharmony_ci				(u8*)next_al_entry + le16_to_cpu(
3256987da915Sopenharmony_ci					next_al_entry->length) <= al_end    &&
3257987da915Sopenharmony_ci				sle64_to_cpu(next_al_entry->lowest_vcn) <=
3258987da915Sopenharmony_ci					lowest_vcn			    &&
3259987da915Sopenharmony_ci				next_al_entry->type == al_entry->type	    &&
3260987da915Sopenharmony_ci				next_al_entry->name_length == al_name_len   &&
3261987da915Sopenharmony_ci				ntfs_names_are_equal((ntfschar*)((char*)
3262987da915Sopenharmony_ci					next_al_entry +
3263987da915Sopenharmony_ci					next_al_entry->name_offset),
3264987da915Sopenharmony_ci					next_al_entry->name_length,
3265987da915Sopenharmony_ci					al_name, al_name_len, CASE_SENSITIVE,
3266987da915Sopenharmony_ci					vol->upcase, vol->upcase_len))
3267987da915Sopenharmony_ci			continue;
3268987da915Sopenharmony_ciis_enumeration:
3269987da915Sopenharmony_ci		if (MREF_LE(al_entry->mft_reference) == ni->mft_no) {
3270987da915Sopenharmony_ci			if (MSEQNO_LE(al_entry->mft_reference) !=
3271987da915Sopenharmony_ci					le16_to_cpu(
3272987da915Sopenharmony_ci					ni->mrec->sequence_number)) {
3273987da915Sopenharmony_ci				ntfs_log_error("Found stale mft reference in "
3274987da915Sopenharmony_ci						"attribute list!\n");
3275987da915Sopenharmony_ci				break;
3276987da915Sopenharmony_ci			}
3277987da915Sopenharmony_ci		} else { /* Mft references do not match. */
3278987da915Sopenharmony_ci			/* Do we want the base record back? */
3279987da915Sopenharmony_ci			if (MREF_LE(al_entry->mft_reference) ==
3280987da915Sopenharmony_ci					base_ni->mft_no) {
3281987da915Sopenharmony_ci				ni = ctx->ntfs_ino = base_ni;
3282987da915Sopenharmony_ci				ctx->mrec = ctx->base_mrec;
3283987da915Sopenharmony_ci			} else {
3284987da915Sopenharmony_ci				/* We want an extent record. */
3285987da915Sopenharmony_ci				if (!vol->mft_na) {
3286987da915Sopenharmony_ci					ntfs_log_perror("$MFT not ready for "
3287987da915Sopenharmony_ci					    "opening an extent to inode %lld\n",
3288987da915Sopenharmony_ci					    (long long)base_ni->mft_no);
3289987da915Sopenharmony_ci					break;
3290987da915Sopenharmony_ci				}
3291987da915Sopenharmony_ci				ni = ntfs_extent_inode_open(base_ni,
3292987da915Sopenharmony_ci						al_entry->mft_reference);
3293987da915Sopenharmony_ci				if (!ni)
3294987da915Sopenharmony_ci					break;
3295987da915Sopenharmony_ci				ctx->ntfs_ino = ni;
3296987da915Sopenharmony_ci				ctx->mrec = ni->mrec;
3297987da915Sopenharmony_ci			}
3298987da915Sopenharmony_ci		}
3299987da915Sopenharmony_ci		a = ctx->attr = (ATTR_RECORD*)((char*)ctx->mrec +
3300987da915Sopenharmony_ci				le16_to_cpu(ctx->mrec->attrs_offset));
3301987da915Sopenharmony_ci		/*
3302987da915Sopenharmony_ci		 * ctx->ntfs_ino, ctx->mrec, and ctx->attr now point to the
3303987da915Sopenharmony_ci		 * mft record containing the attribute represented by the
3304987da915Sopenharmony_ci		 * current al_entry.
3305987da915Sopenharmony_ci		 *
3306987da915Sopenharmony_ci		 * We could call into ntfs_attr_find() to find the right
3307987da915Sopenharmony_ci		 * attribute in this mft record but this would be less
3308987da915Sopenharmony_ci		 * efficient and not quite accurate as ntfs_attr_find() ignores
3309987da915Sopenharmony_ci		 * the attribute instance numbers for example which become
3310987da915Sopenharmony_ci		 * important when one plays with attribute lists. Also, because
3311987da915Sopenharmony_ci		 * a proper match has been found in the attribute list entry
3312987da915Sopenharmony_ci		 * above, the comparison can now be optimized. So it is worth
3313987da915Sopenharmony_ci		 * re-implementing a simplified ntfs_attr_find() here.
3314987da915Sopenharmony_ci		 *
3315987da915Sopenharmony_ci		 * Use a manual loop so we can still use break and continue
3316987da915Sopenharmony_ci		 * with the same meanings as above.
3317987da915Sopenharmony_ci		 */
3318987da915Sopenharmony_cido_next_attr_loop:
3319987da915Sopenharmony_ci		/*
3320987da915Sopenharmony_ci		 * Make sure the attribute fully lies within the MFT record
3321987da915Sopenharmony_ci		 * and we can safely access its minimal fields.
3322987da915Sopenharmony_ci		 */
3323987da915Sopenharmony_ci		offs = p2n(a) - p2n(ctx->mrec);
3324987da915Sopenharmony_ci		space = le32_to_cpu(ctx->mrec->bytes_in_use) - offs;
3325987da915Sopenharmony_ci		if (offs < 0)
3326987da915Sopenharmony_ci			break;
3327987da915Sopenharmony_ci		if ((space >= 4) && (a->type == AT_END))
3328987da915Sopenharmony_ci			continue;
3329987da915Sopenharmony_ci		if ((space < (ptrdiff_t)offsetof(ATTR_RECORD, resident_end))
3330987da915Sopenharmony_ci		    || (space < (ptrdiff_t)le32_to_cpu(a->length)))
3331987da915Sopenharmony_ci			break;
3332987da915Sopenharmony_ci		if (al_entry->instance != a->instance)
3333987da915Sopenharmony_ci			goto do_next_attr;
3334987da915Sopenharmony_ci		/*
3335987da915Sopenharmony_ci		 * If the type and/or the name are/is mismatched between the
3336987da915Sopenharmony_ci		 * attribute list entry and the attribute record, there is
3337987da915Sopenharmony_ci		 * corruption so we break and return error EIO.
3338987da915Sopenharmony_ci		 */
3339987da915Sopenharmony_ci		if (al_entry->type != a->type)
3340987da915Sopenharmony_ci			break;
3341987da915Sopenharmony_ci		if (!ntfs_names_are_equal((ntfschar*)((char*)a +
3342987da915Sopenharmony_ci				le16_to_cpu(a->name_offset)),
3343987da915Sopenharmony_ci				a->name_length, al_name,
3344987da915Sopenharmony_ci				al_name_len, CASE_SENSITIVE,
3345987da915Sopenharmony_ci				vol->upcase, vol->upcase_len))
3346987da915Sopenharmony_ci			break;
3347987da915Sopenharmony_ci		ctx->attr = a;
3348987da915Sopenharmony_ci		/*
3349987da915Sopenharmony_ci		 * If no @val specified or @val specified and it matches, we
3350987da915Sopenharmony_ci		 * have found it! Also, if !@type, it is an enumeration, so we
3351987da915Sopenharmony_ci		 * want the current attribute.
3352987da915Sopenharmony_ci		 */
3353987da915Sopenharmony_ci		if ((type == AT_UNUSED) || !val || (!a->non_resident &&
3354987da915Sopenharmony_ci				le32_to_cpu(a->value_length) == val_len &&
3355987da915Sopenharmony_ci				!memcmp((char*)a + le16_to_cpu(a->value_offset),
3356987da915Sopenharmony_ci				val, val_len))) {
3357987da915Sopenharmony_ci			return 0;
3358987da915Sopenharmony_ci		}
3359987da915Sopenharmony_cido_next_attr:
3360987da915Sopenharmony_ci		/* Proceed to the next attribute in the current mft record. */
3361987da915Sopenharmony_ci		a = (ATTR_RECORD*)((char*)a + le32_to_cpu(a->length));
3362987da915Sopenharmony_ci		goto do_next_attr_loop;
3363987da915Sopenharmony_ci	}
3364987da915Sopenharmony_cicorrupt :
3365987da915Sopenharmony_ci	if (ni != base_ni) {
3366987da915Sopenharmony_ci		ctx->ntfs_ino = base_ni;
3367987da915Sopenharmony_ci		ctx->mrec = ctx->base_mrec;
3368987da915Sopenharmony_ci		ctx->attr = ctx->base_attr;
3369987da915Sopenharmony_ci	}
3370987da915Sopenharmony_ci	errno = EIO;
3371987da915Sopenharmony_ci	ntfs_log_error("Corrupt attribute list entry in MFT record %lld\n",
3372987da915Sopenharmony_ci			(long long)base_ni->mft_no);
3373987da915Sopenharmony_ci	return -1;
3374987da915Sopenharmony_cinot_found:
3375987da915Sopenharmony_ci	/*
3376987da915Sopenharmony_ci	 * If we were looking for AT_END or we were enumerating and reached the
3377987da915Sopenharmony_ci	 * end, we reset the search context @ctx and use ntfs_attr_find() to
3378987da915Sopenharmony_ci	 * seek to the end of the base mft record.
3379987da915Sopenharmony_ci	 */
3380987da915Sopenharmony_ci	if (type == AT_UNUSED || type == AT_END) {
3381987da915Sopenharmony_ci		ntfs_attr_reinit_search_ctx(ctx);
3382987da915Sopenharmony_ci		return ntfs_attr_find(AT_END, name, name_len, ic, val, val_len,
3383987da915Sopenharmony_ci				ctx);
3384987da915Sopenharmony_ci	}
3385987da915Sopenharmony_ci	/*
3386987da915Sopenharmony_ci	 * The attribute wasn't found.  Before we return, we want to ensure
3387987da915Sopenharmony_ci	 * @ctx->mrec and @ctx->attr indicate the position at which the
3388987da915Sopenharmony_ci	 * attribute should be inserted in the base mft record.  Since we also
3389987da915Sopenharmony_ci	 * want to preserve @ctx->al_entry we cannot reinitialize the search
3390987da915Sopenharmony_ci	 * context using ntfs_attr_reinit_search_ctx() as this would set
3391987da915Sopenharmony_ci	 * @ctx->al_entry to NULL.  Thus we do the necessary bits manually (see
3392987da915Sopenharmony_ci	 * ntfs_attr_init_search_ctx() below).  Note, we _only_ preserve
3393987da915Sopenharmony_ci	 * @ctx->al_entry as the remaining fields (base_*) are identical to
3394987da915Sopenharmony_ci	 * their non base_ counterparts and we cannot set @ctx->base_attr
3395987da915Sopenharmony_ci	 * correctly yet as we do not know what @ctx->attr will be set to by
3396987da915Sopenharmony_ci	 * the call to ntfs_attr_find() below.
3397987da915Sopenharmony_ci	 */
3398987da915Sopenharmony_ci	ctx->mrec = ctx->base_mrec;
3399987da915Sopenharmony_ci	ctx->attr = (ATTR_RECORD*)((u8*)ctx->mrec +
3400987da915Sopenharmony_ci			le16_to_cpu(ctx->mrec->attrs_offset));
3401987da915Sopenharmony_ci	ctx->is_first = TRUE;
3402987da915Sopenharmony_ci	ctx->ntfs_ino = ctx->base_ntfs_ino;
3403987da915Sopenharmony_ci	ctx->base_ntfs_ino = NULL;
3404987da915Sopenharmony_ci	ctx->base_mrec = NULL;
3405987da915Sopenharmony_ci	ctx->base_attr = NULL;
3406987da915Sopenharmony_ci	/*
3407987da915Sopenharmony_ci	 * In case there are multiple matches in the base mft record, need to
3408987da915Sopenharmony_ci	 * keep enumerating until we get an attribute not found response (or
3409987da915Sopenharmony_ci	 * another error), otherwise we would keep returning the same attribute
3410987da915Sopenharmony_ci	 * over and over again and all programs using us for enumeration would
3411987da915Sopenharmony_ci	 * lock up in a tight loop.
3412987da915Sopenharmony_ci	 */
3413987da915Sopenharmony_ci	{
3414987da915Sopenharmony_ci		int ret;
3415987da915Sopenharmony_ci
3416987da915Sopenharmony_ci		do {
3417987da915Sopenharmony_ci			ret = ntfs_attr_find(type, name, name_len, ic, val,
3418987da915Sopenharmony_ci					val_len, ctx);
3419987da915Sopenharmony_ci		} while (!ret);
3420987da915Sopenharmony_ci		return ret;
3421987da915Sopenharmony_ci	}
3422987da915Sopenharmony_ci}
3423987da915Sopenharmony_ci
3424987da915Sopenharmony_ci/*
3425987da915Sopenharmony_ci *		Check the consistency of an attribute
3426987da915Sopenharmony_ci *
3427987da915Sopenharmony_ci *	Do the general consistency checks of the selected attribute :
3428987da915Sopenharmony_ci *	- the required fields can be accessed
3429987da915Sopenharmony_ci *	- the variable fields do not overflow
3430987da915Sopenharmony_ci *	- the attribute is [non-]resident if it must be
3431987da915Sopenharmony_ci *	- miscelleaneous checks
3432987da915Sopenharmony_ci *
3433987da915Sopenharmony_ci *	Returns 0 if the checks pass
3434987da915Sopenharmony_ci *		-1 with errno = EIO otherwise
3435987da915Sopenharmony_ci */
3436987da915Sopenharmony_ci
3437987da915Sopenharmony_ciint ntfs_attr_inconsistent(const ATTR_RECORD *a, const MFT_REF mref)
3438987da915Sopenharmony_ci{
3439987da915Sopenharmony_ci	const FILE_NAME_ATTR *fn;
3440987da915Sopenharmony_ci	const INDEX_ROOT *ir;
3441987da915Sopenharmony_ci	u64 inum;
3442987da915Sopenharmony_ci	int ret;
3443987da915Sopenharmony_ci
3444987da915Sopenharmony_ci	/*
3445987da915Sopenharmony_ci	 * The attribute was found to fully lie within the MFT
3446987da915Sopenharmony_ci	 * record, now make sure its relevant parts (name, runlist,
3447987da915Sopenharmony_ci	 * value) also lie within. The first step is to make sure
3448987da915Sopenharmony_ci	 * the attribute has the minimum length so that accesses to
3449987da915Sopenharmony_ci	 * the lengths and offsets of these parts are safe.
3450987da915Sopenharmony_ci	 */
3451987da915Sopenharmony_ci	ret = 0;
3452987da915Sopenharmony_ci	inum = MREF(mref);
3453987da915Sopenharmony_ci	if (a->non_resident) {
3454987da915Sopenharmony_ci		if ((a->non_resident != 1)
3455987da915Sopenharmony_ci		    || (le32_to_cpu(a->length)
3456987da915Sopenharmony_ci			< offsetof(ATTR_RECORD, non_resident_end))
3457987da915Sopenharmony_ci		    || (le16_to_cpu(a->mapping_pairs_offset)
3458987da915Sopenharmony_ci				>= le32_to_cpu(a->length))
3459987da915Sopenharmony_ci		    || (a->name_length
3460987da915Sopenharmony_ci			 && (((u32)le16_to_cpu(a->name_offset)
3461987da915Sopenharmony_ci				+ a->name_length * sizeof(ntfschar))
3462987da915Sopenharmony_ci				> le32_to_cpu(a->length)))
3463987da915Sopenharmony_ci		    || (le64_to_cpu(a->highest_vcn)
3464987da915Sopenharmony_ci				< le64_to_cpu(a->lowest_vcn))) {
3465987da915Sopenharmony_ci			ntfs_log_error("Corrupt non resident attribute"
3466987da915Sopenharmony_ci				" 0x%x in MFT record %lld\n",
3467987da915Sopenharmony_ci				(int)le32_to_cpu(a->type),
3468987da915Sopenharmony_ci				(long long)inum);
3469987da915Sopenharmony_ci			errno = EIO;
3470987da915Sopenharmony_ci			ret = -1;
3471987da915Sopenharmony_ci		}
3472987da915Sopenharmony_ci	} else {
3473987da915Sopenharmony_ci		if ((le32_to_cpu(a->length)
3474987da915Sopenharmony_ci			< offsetof(ATTR_RECORD, resident_end))
3475987da915Sopenharmony_ci		    || (le32_to_cpu(a->value_length) & 0xff000000)
3476987da915Sopenharmony_ci		    || (a->value_length
3477987da915Sopenharmony_ci			&& ((le16_to_cpu(a->value_offset)
3478987da915Sopenharmony_ci				+ le32_to_cpu(a->value_length))
3479987da915Sopenharmony_ci				> le32_to_cpu(a->length)))
3480987da915Sopenharmony_ci		    || (a->name_length
3481987da915Sopenharmony_ci			&& (((u32)le16_to_cpu(a->name_offset)
3482987da915Sopenharmony_ci				+ a->name_length * sizeof(ntfschar))
3483987da915Sopenharmony_ci				> le32_to_cpu(a->length)))) {
3484987da915Sopenharmony_ci			ntfs_log_error("Corrupt resident attribute"
3485987da915Sopenharmony_ci				" 0x%x in MFT record %lld\n",
3486987da915Sopenharmony_ci				(int)le32_to_cpu(a->type),
3487987da915Sopenharmony_ci				(long long)inum);
3488987da915Sopenharmony_ci			errno = EIO;
3489987da915Sopenharmony_ci			ret = -1;
3490987da915Sopenharmony_ci		}
3491987da915Sopenharmony_ci	}
3492987da915Sopenharmony_ci	if (!ret) {
3493987da915Sopenharmony_ci		/*
3494987da915Sopenharmony_ci		 * Checking whether an attribute must be [non-]resident
3495987da915Sopenharmony_ci		 * is hard-coded for well-known ones. This should be
3496987da915Sopenharmony_ci		 * done through ntfs_attr_can_be_non_resident(), based on
3497987da915Sopenharmony_ci		 * $AttrDef, but this would give an easy way to bypass
3498987da915Sopenharmony_ci		 * the checks.
3499987da915Sopenharmony_ci		 * Attributes which are not well-known are not checked.
3500987da915Sopenharmony_ci		 *
3501987da915Sopenharmony_ci		 * Note : at this stage we know that a->length and
3502987da915Sopenharmony_ci		 * a->value_length cannot look like being negative.
3503987da915Sopenharmony_ci		 */
3504987da915Sopenharmony_ci		switch(a->type) {
3505987da915Sopenharmony_ci		case AT_FILE_NAME :
3506987da915Sopenharmony_ci			/* Check file names are resident and do not overflow */
3507987da915Sopenharmony_ci			fn = (const FILE_NAME_ATTR*)((const u8*)a
3508987da915Sopenharmony_ci				+ le16_to_cpu(a->value_offset));
3509987da915Sopenharmony_ci			if (a->non_resident
3510987da915Sopenharmony_ci			    || (le32_to_cpu(a->value_length)
3511987da915Sopenharmony_ci				< offsetof(FILE_NAME_ATTR, file_name))
3512987da915Sopenharmony_ci			    || !fn->file_name_length
3513987da915Sopenharmony_ci			    || ((fn->file_name_length * sizeof(ntfschar)
3514987da915Sopenharmony_ci				+ offsetof(FILE_NAME_ATTR, file_name))
3515987da915Sopenharmony_ci				> le32_to_cpu(a->value_length))) {
3516987da915Sopenharmony_ci				ntfs_log_error("Corrupt file name"
3517987da915Sopenharmony_ci					" attribute in MFT record %lld.\n",
3518987da915Sopenharmony_ci					(long long)inum);
3519987da915Sopenharmony_ci				errno = EIO;
3520987da915Sopenharmony_ci				ret = -1;
3521987da915Sopenharmony_ci			}
3522987da915Sopenharmony_ci			break;
3523987da915Sopenharmony_ci		case AT_INDEX_ROOT :
3524987da915Sopenharmony_ci			/* Check root index is resident and does not overflow */
3525987da915Sopenharmony_ci			ir = (const INDEX_ROOT*)((const u8*)a +
3526987da915Sopenharmony_ci				le16_to_cpu(a->value_offset));
3527987da915Sopenharmony_ci			/* index.allocated_size may overflow while resizing */
3528987da915Sopenharmony_ci			if (a->non_resident
3529987da915Sopenharmony_ci			    || (le32_to_cpu(a->value_length)
3530987da915Sopenharmony_ci				< offsetof(INDEX_ROOT, index.reserved))
3531987da915Sopenharmony_ci			    || (le32_to_cpu(ir->index.entries_offset)
3532987da915Sopenharmony_ci				< sizeof(INDEX_HEADER))
3533987da915Sopenharmony_ci			    || (le32_to_cpu(ir->index.index_length)
3534987da915Sopenharmony_ci				< le32_to_cpu(ir->index.entries_offset))
3535987da915Sopenharmony_ci			    || (le32_to_cpu(ir->index.allocated_size)
3536987da915Sopenharmony_ci				< le32_to_cpu(ir->index.index_length))
3537987da915Sopenharmony_ci			    || (le32_to_cpu(a->value_length)
3538987da915Sopenharmony_ci				< (le32_to_cpu(ir->index.allocated_size)
3539987da915Sopenharmony_ci				    + offsetof(INDEX_ROOT, reserved)))) {
3540987da915Sopenharmony_ci				ntfs_log_error("Corrupt index root"
3541987da915Sopenharmony_ci					" in MFT record %lld.\n",
3542987da915Sopenharmony_ci					(long long)inum);
3543987da915Sopenharmony_ci				errno = EIO;
3544987da915Sopenharmony_ci				ret = -1;
3545987da915Sopenharmony_ci			}
3546987da915Sopenharmony_ci			break;
3547987da915Sopenharmony_ci		case AT_STANDARD_INFORMATION :
3548987da915Sopenharmony_ci			if (a->non_resident
3549987da915Sopenharmony_ci			    || (le32_to_cpu(a->value_length)
3550987da915Sopenharmony_ci					< offsetof(STANDARD_INFORMATION,
3551987da915Sopenharmony_ci							v1_end))) {
3552987da915Sopenharmony_ci				ntfs_log_error("Corrupt standard information"
3553987da915Sopenharmony_ci					" in MFT record %lld\n",
3554987da915Sopenharmony_ci					(long long)inum);
3555987da915Sopenharmony_ci				errno = EIO;
3556987da915Sopenharmony_ci				ret = -1;
3557987da915Sopenharmony_ci			}
3558987da915Sopenharmony_ci			break;
3559987da915Sopenharmony_ci		case AT_OBJECT_ID :
3560987da915Sopenharmony_ci			if (a->non_resident
3561987da915Sopenharmony_ci			    || (le32_to_cpu(a->value_length)
3562987da915Sopenharmony_ci					< sizeof(GUID))) {
3563987da915Sopenharmony_ci				ntfs_log_error("Corrupt object id"
3564987da915Sopenharmony_ci					" in MFT record %lld\n",
3565987da915Sopenharmony_ci					(long long)inum);
3566987da915Sopenharmony_ci				errno = EIO;
3567987da915Sopenharmony_ci				ret = -1;
3568987da915Sopenharmony_ci			}
3569987da915Sopenharmony_ci			break;
3570987da915Sopenharmony_ci		case AT_VOLUME_NAME :
3571987da915Sopenharmony_ci		case AT_EA_INFORMATION :
3572987da915Sopenharmony_ci			if (a->non_resident) {
3573987da915Sopenharmony_ci				ntfs_log_error("Attribute 0x%x in MFT record"
3574987da915Sopenharmony_ci					" %lld should be resident.\n",
3575987da915Sopenharmony_ci					(int)le32_to_cpu(a->type),
3576987da915Sopenharmony_ci					(long long)inum);
3577987da915Sopenharmony_ci				errno = EIO;
3578987da915Sopenharmony_ci				ret = -1;
3579987da915Sopenharmony_ci			}
3580987da915Sopenharmony_ci			break;
3581987da915Sopenharmony_ci		case AT_VOLUME_INFORMATION :
3582987da915Sopenharmony_ci			if (a->non_resident
3583987da915Sopenharmony_ci			    || (le32_to_cpu(a->value_length)
3584987da915Sopenharmony_ci					< sizeof(VOLUME_INFORMATION))) {
3585987da915Sopenharmony_ci				ntfs_log_error("Corrupt volume information"
3586987da915Sopenharmony_ci					" in MFT record %lld\n",
3587987da915Sopenharmony_ci					(long long)inum);
3588987da915Sopenharmony_ci				errno = EIO;
3589987da915Sopenharmony_ci				ret = -1;
3590987da915Sopenharmony_ci			}
3591987da915Sopenharmony_ci			break;
3592987da915Sopenharmony_ci		case AT_INDEX_ALLOCATION :
3593987da915Sopenharmony_ci			if (!a->non_resident) {
3594987da915Sopenharmony_ci				ntfs_log_error("Corrupt index allocation"
3595987da915Sopenharmony_ci					" in MFT record %lld",
3596987da915Sopenharmony_ci					(long long)inum);
3597987da915Sopenharmony_ci				errno = EIO;
3598987da915Sopenharmony_ci				ret = -1;
3599987da915Sopenharmony_ci			}
3600987da915Sopenharmony_ci			break;
3601987da915Sopenharmony_ci		default :
3602987da915Sopenharmony_ci			break;
3603987da915Sopenharmony_ci		}
3604987da915Sopenharmony_ci	}
3605987da915Sopenharmony_ci	return (ret);
3606987da915Sopenharmony_ci}
3607987da915Sopenharmony_ci
3608987da915Sopenharmony_ci/**
3609987da915Sopenharmony_ci * ntfs_attr_lookup - find an attribute in an ntfs inode
3610987da915Sopenharmony_ci * @type:	attribute type to find
3611987da915Sopenharmony_ci * @name:	attribute name to find (optional, i.e. NULL means don't care)
3612987da915Sopenharmony_ci * @name_len:	attribute name length (only needed if @name present)
3613987da915Sopenharmony_ci * @ic:		IGNORE_CASE or CASE_SENSITIVE (ignored if @name not present)
3614987da915Sopenharmony_ci * @lowest_vcn:	lowest vcn to find (optional, non-resident attributes only)
3615987da915Sopenharmony_ci * @val:	attribute value to find (optional, resident attributes only)
3616987da915Sopenharmony_ci * @val_len:	attribute value length
3617987da915Sopenharmony_ci * @ctx:	search context with mft record and attribute to search from
3618987da915Sopenharmony_ci *
3619987da915Sopenharmony_ci * Find an attribute in an ntfs inode. On first search @ctx->ntfs_ino must
3620987da915Sopenharmony_ci * be the base mft record and @ctx must have been obtained from a call to
3621987da915Sopenharmony_ci * ntfs_attr_get_search_ctx().
3622987da915Sopenharmony_ci *
3623987da915Sopenharmony_ci * This function transparently handles attribute lists and @ctx is used to
3624987da915Sopenharmony_ci * continue searches where they were left off at.
3625987da915Sopenharmony_ci *
3626987da915Sopenharmony_ci * If @type is AT_UNUSED, return the first found attribute, i.e. one can
3627987da915Sopenharmony_ci * enumerate all attributes by setting @type to AT_UNUSED and then calling
3628987da915Sopenharmony_ci * ntfs_attr_lookup() repeatedly until it returns -1 with errno set to ENOENT
3629987da915Sopenharmony_ci * to indicate that there are no more entries. During the enumeration, each
3630987da915Sopenharmony_ci * successful call of ntfs_attr_lookup() will return the next attribute, with
3631987da915Sopenharmony_ci * the current attribute being described by the search context @ctx.
3632987da915Sopenharmony_ci *
3633987da915Sopenharmony_ci * If @type is AT_END, seek to the end of the base mft record ignoring the
3634987da915Sopenharmony_ci * attribute list completely and return -1 with errno set to ENOENT.  AT_END is
3635987da915Sopenharmony_ci * not a valid attribute, its length is zero for example, thus it is safer to
3636987da915Sopenharmony_ci * return error instead of success in this case.  It should never be needed to
3637987da915Sopenharmony_ci * do this, but we implement the functionality because it allows for simpler
3638987da915Sopenharmony_ci * code inside ntfs_external_attr_find().
3639987da915Sopenharmony_ci *
3640987da915Sopenharmony_ci * If @name is AT_UNNAMED search for an unnamed attribute. If @name is present
3641987da915Sopenharmony_ci * but not AT_UNNAMED search for a named attribute matching @name. Otherwise,
3642987da915Sopenharmony_ci * match both named and unnamed attributes.
3643987da915Sopenharmony_ci *
3644987da915Sopenharmony_ci * After finishing with the attribute/mft record you need to call
3645987da915Sopenharmony_ci * ntfs_attr_put_search_ctx() to cleanup the search context (unmapping any
3646987da915Sopenharmony_ci * mapped extent inodes, etc).
3647987da915Sopenharmony_ci *
3648987da915Sopenharmony_ci * Return 0 if the search was successful and -1 if not, with errno set to the
3649987da915Sopenharmony_ci * error code.
3650987da915Sopenharmony_ci *
3651987da915Sopenharmony_ci * On success, @ctx->attr is the found attribute, it is in mft record
3652987da915Sopenharmony_ci * @ctx->mrec, and @ctx->al_entry is the attribute list entry for this
3653987da915Sopenharmony_ci * attribute with @ctx->base_* being the base mft record to which @ctx->attr
3654987da915Sopenharmony_ci * belongs.  If no attribute list attribute is present @ctx->al_entry and
3655987da915Sopenharmony_ci * @ctx->base_* are NULL.
3656987da915Sopenharmony_ci *
3657987da915Sopenharmony_ci * On error ENOENT, i.e. attribute not found, @ctx->attr is set to the
3658987da915Sopenharmony_ci * attribute which collates just after the attribute being searched for in the
3659987da915Sopenharmony_ci * base ntfs inode, i.e. if one wants to add the attribute to the mft record
3660987da915Sopenharmony_ci * this is the correct place to insert it into, and if there is not enough
3661987da915Sopenharmony_ci * space, the attribute should be placed in an extent mft record.
3662987da915Sopenharmony_ci * @ctx->al_entry points to the position within @ctx->base_ntfs_ino->attr_list
3663987da915Sopenharmony_ci * at which the new attribute's attribute list entry should be inserted.  The
3664987da915Sopenharmony_ci * other @ctx fields, base_ntfs_ino, base_mrec, and base_attr are set to NULL.
3665987da915Sopenharmony_ci * The only exception to this is when @type is AT_END, in which case
3666987da915Sopenharmony_ci * @ctx->al_entry is set to NULL also (see above).
3667987da915Sopenharmony_ci *
3668987da915Sopenharmony_ci *
3669987da915Sopenharmony_ci * The following error codes are defined:
3670987da915Sopenharmony_ci *	ENOENT	Attribute not found, not an error as such.
3671987da915Sopenharmony_ci *	EINVAL	Invalid arguments.
3672987da915Sopenharmony_ci *	EIO	I/O error or corrupt data structures found.
3673987da915Sopenharmony_ci *	ENOMEM	Not enough memory to allocate necessary buffers.
3674987da915Sopenharmony_ci */
3675987da915Sopenharmony_ciint ntfs_attr_lookup(const ATTR_TYPES type, const ntfschar *name,
3676987da915Sopenharmony_ci		const u32 name_len, const IGNORE_CASE_BOOL ic,
3677987da915Sopenharmony_ci		const VCN lowest_vcn, const u8 *val, const u32 val_len,
3678987da915Sopenharmony_ci		ntfs_attr_search_ctx *ctx)
3679987da915Sopenharmony_ci{
3680987da915Sopenharmony_ci	ntfs_volume *vol;
3681987da915Sopenharmony_ci	ntfs_inode *base_ni;
3682987da915Sopenharmony_ci	int ret = -1;
3683987da915Sopenharmony_ci
3684987da915Sopenharmony_ci	ntfs_log_enter("Entering for attribute type 0x%x\n", le32_to_cpu(type));
3685987da915Sopenharmony_ci
3686987da915Sopenharmony_ci	if (!ctx || !ctx->mrec || !ctx->attr || (name && name != AT_UNNAMED &&
3687987da915Sopenharmony_ci			(!ctx->ntfs_ino || !(vol = ctx->ntfs_ino->vol) ||
3688987da915Sopenharmony_ci			!vol->upcase || !vol->upcase_len))) {
3689987da915Sopenharmony_ci		errno = EINVAL;
3690987da915Sopenharmony_ci		ntfs_log_perror("%s", __FUNCTION__);
3691987da915Sopenharmony_ci		goto out;
3692987da915Sopenharmony_ci	}
3693987da915Sopenharmony_ci
3694987da915Sopenharmony_ci	if (ctx->base_ntfs_ino)
3695987da915Sopenharmony_ci		base_ni = ctx->base_ntfs_ino;
3696987da915Sopenharmony_ci	else
3697987da915Sopenharmony_ci		base_ni = ctx->ntfs_ino;
3698987da915Sopenharmony_ci	if (!base_ni || !NInoAttrList(base_ni) || type == AT_ATTRIBUTE_LIST)
3699987da915Sopenharmony_ci		ret = ntfs_attr_find(type, name, name_len, ic, val, val_len, ctx);
3700987da915Sopenharmony_ci	else
3701987da915Sopenharmony_ci		ret = ntfs_external_attr_find(type, name, name_len, ic,
3702987da915Sopenharmony_ci					      lowest_vcn, val, val_len, ctx);
3703987da915Sopenharmony_ciout:
3704987da915Sopenharmony_ci	ntfs_log_leave("\n");
3705987da915Sopenharmony_ci	return ret;
3706987da915Sopenharmony_ci}
3707987da915Sopenharmony_ci
3708987da915Sopenharmony_ci/**
3709987da915Sopenharmony_ci * ntfs_attr_position - find given or next attribute type in an ntfs inode
3710987da915Sopenharmony_ci * @type:	attribute type to start lookup
3711987da915Sopenharmony_ci * @ctx:	search context with mft record and attribute to search from
3712987da915Sopenharmony_ci *
3713987da915Sopenharmony_ci * Find an attribute type in an ntfs inode or the next attribute which is not
3714987da915Sopenharmony_ci * the AT_END attribute. Please see more details at ntfs_attr_lookup.
3715987da915Sopenharmony_ci *
3716987da915Sopenharmony_ci * Return 0 if the search was successful and -1 if not, with errno set to the
3717987da915Sopenharmony_ci * error code.
3718987da915Sopenharmony_ci *
3719987da915Sopenharmony_ci * The following error codes are defined:
3720987da915Sopenharmony_ci *	EINVAL	Invalid arguments.
3721987da915Sopenharmony_ci *	EIO	I/O error or corrupt data structures found.
3722987da915Sopenharmony_ci *	ENOMEM	Not enough memory to allocate necessary buffers.
3723987da915Sopenharmony_ci * 	ENOSPC  No attribute was found after 'type', only AT_END.
3724987da915Sopenharmony_ci */
3725987da915Sopenharmony_ciint ntfs_attr_position(const ATTR_TYPES type, ntfs_attr_search_ctx *ctx)
3726987da915Sopenharmony_ci{
3727987da915Sopenharmony_ci	if (ntfs_attr_lookup(type, NULL, 0, CASE_SENSITIVE, 0, NULL, 0, ctx)) {
3728987da915Sopenharmony_ci		if (errno != ENOENT)
3729987da915Sopenharmony_ci			return -1;
3730987da915Sopenharmony_ci		if (ctx->attr->type == AT_END) {
3731987da915Sopenharmony_ci			errno = ENOSPC;
3732987da915Sopenharmony_ci			return -1;
3733987da915Sopenharmony_ci		}
3734987da915Sopenharmony_ci	}
3735987da915Sopenharmony_ci	return 0;
3736987da915Sopenharmony_ci}
3737987da915Sopenharmony_ci
3738987da915Sopenharmony_ci/**
3739987da915Sopenharmony_ci * ntfs_attr_init_search_ctx - initialize an attribute search context
3740987da915Sopenharmony_ci * @ctx:	attribute search context to initialize
3741987da915Sopenharmony_ci * @ni:		ntfs inode with which to initialize the search context
3742987da915Sopenharmony_ci * @mrec:	mft record with which to initialize the search context
3743987da915Sopenharmony_ci *
3744987da915Sopenharmony_ci * Initialize the attribute search context @ctx with @ni and @mrec.
3745987da915Sopenharmony_ci */
3746987da915Sopenharmony_cistatic void ntfs_attr_init_search_ctx(ntfs_attr_search_ctx *ctx,
3747987da915Sopenharmony_ci		ntfs_inode *ni, MFT_RECORD *mrec)
3748987da915Sopenharmony_ci{
3749987da915Sopenharmony_ci	if (!mrec)
3750987da915Sopenharmony_ci		mrec = ni->mrec;
3751987da915Sopenharmony_ci	ctx->mrec = mrec;
3752987da915Sopenharmony_ci	/* Sanity checks are performed elsewhere. */
3753987da915Sopenharmony_ci	ctx->attr = (ATTR_RECORD*)((u8*)mrec + le16_to_cpu(mrec->attrs_offset));
3754987da915Sopenharmony_ci	ctx->is_first = TRUE;
3755987da915Sopenharmony_ci	ctx->ntfs_ino = ni;
3756987da915Sopenharmony_ci	ctx->al_entry = NULL;
3757987da915Sopenharmony_ci	ctx->base_ntfs_ino = NULL;
3758987da915Sopenharmony_ci	ctx->base_mrec = NULL;
3759987da915Sopenharmony_ci	ctx->base_attr = NULL;
3760987da915Sopenharmony_ci}
3761987da915Sopenharmony_ci
3762987da915Sopenharmony_ci/**
3763987da915Sopenharmony_ci * ntfs_attr_reinit_search_ctx - reinitialize an attribute search context
3764987da915Sopenharmony_ci * @ctx:	attribute search context to reinitialize
3765987da915Sopenharmony_ci *
3766987da915Sopenharmony_ci * Reinitialize the attribute search context @ctx.
3767987da915Sopenharmony_ci *
3768987da915Sopenharmony_ci * This is used when a search for a new attribute is being started to reset
3769987da915Sopenharmony_ci * the search context to the beginning.
3770987da915Sopenharmony_ci */
3771987da915Sopenharmony_civoid ntfs_attr_reinit_search_ctx(ntfs_attr_search_ctx *ctx)
3772987da915Sopenharmony_ci{
3773987da915Sopenharmony_ci	if (!ctx->base_ntfs_ino) {
3774987da915Sopenharmony_ci		/* No attribute list. */
3775987da915Sopenharmony_ci		ctx->is_first = TRUE;
3776987da915Sopenharmony_ci		/* Sanity checks are performed elsewhere. */
3777987da915Sopenharmony_ci		ctx->attr = (ATTR_RECORD*)((u8*)ctx->mrec +
3778987da915Sopenharmony_ci				le16_to_cpu(ctx->mrec->attrs_offset));
3779987da915Sopenharmony_ci		/*
3780987da915Sopenharmony_ci		 * This needs resetting due to ntfs_external_attr_find() which
3781987da915Sopenharmony_ci		 * can leave it set despite having zeroed ctx->base_ntfs_ino.
3782987da915Sopenharmony_ci		 */
3783987da915Sopenharmony_ci		ctx->al_entry = NULL;
3784987da915Sopenharmony_ci		return;
3785987da915Sopenharmony_ci	} /* Attribute list. */
3786987da915Sopenharmony_ci	ntfs_attr_init_search_ctx(ctx, ctx->base_ntfs_ino, ctx->base_mrec);
3787987da915Sopenharmony_ci	return;
3788987da915Sopenharmony_ci}
3789987da915Sopenharmony_ci
3790987da915Sopenharmony_ci/**
3791987da915Sopenharmony_ci * ntfs_attr_get_search_ctx - allocate/initialize a new attribute search context
3792987da915Sopenharmony_ci * @ni:		ntfs inode with which to initialize the search context
3793987da915Sopenharmony_ci * @mrec:	mft record with which to initialize the search context
3794987da915Sopenharmony_ci *
3795987da915Sopenharmony_ci * Allocate a new attribute search context, initialize it with @ni and @mrec,
3796987da915Sopenharmony_ci * and return it. Return NULL on error with errno set.
3797987da915Sopenharmony_ci *
3798987da915Sopenharmony_ci * @mrec can be NULL, in which case the mft record is taken from @ni.
3799987da915Sopenharmony_ci *
3800987da915Sopenharmony_ci * Note: For low level utilities which know what they are doing we allow @ni to
3801987da915Sopenharmony_ci * be NULL and @mrec to be set.  Do NOT do this unless you understand the
3802987da915Sopenharmony_ci * implications!!!  For example it is no longer safe to call ntfs_attr_lookup().
3803987da915Sopenharmony_ci */
3804987da915Sopenharmony_cintfs_attr_search_ctx *ntfs_attr_get_search_ctx(ntfs_inode *ni, MFT_RECORD *mrec)
3805987da915Sopenharmony_ci{
3806987da915Sopenharmony_ci	ntfs_attr_search_ctx *ctx;
3807987da915Sopenharmony_ci
3808987da915Sopenharmony_ci	if (!ni && !mrec) {
3809987da915Sopenharmony_ci		errno = EINVAL;
3810987da915Sopenharmony_ci		ntfs_log_perror("NULL arguments");
3811987da915Sopenharmony_ci		return NULL;
3812987da915Sopenharmony_ci	}
3813987da915Sopenharmony_ci	ctx = ntfs_malloc(sizeof(ntfs_attr_search_ctx));
3814987da915Sopenharmony_ci	if (ctx)
3815987da915Sopenharmony_ci		ntfs_attr_init_search_ctx(ctx, ni, mrec);
3816987da915Sopenharmony_ci	return ctx;
3817987da915Sopenharmony_ci}
3818987da915Sopenharmony_ci
3819987da915Sopenharmony_ci/**
3820987da915Sopenharmony_ci * ntfs_attr_put_search_ctx - release an attribute search context
3821987da915Sopenharmony_ci * @ctx:	attribute search context to free
3822987da915Sopenharmony_ci *
3823987da915Sopenharmony_ci * Release the attribute search context @ctx.
3824987da915Sopenharmony_ci */
3825987da915Sopenharmony_civoid ntfs_attr_put_search_ctx(ntfs_attr_search_ctx *ctx)
3826987da915Sopenharmony_ci{
3827987da915Sopenharmony_ci	// NOTE: save errno if it could change and function stays void!
3828987da915Sopenharmony_ci	free(ctx);
3829987da915Sopenharmony_ci}
3830987da915Sopenharmony_ci
3831987da915Sopenharmony_ci/**
3832987da915Sopenharmony_ci * ntfs_attr_find_in_attrdef - find an attribute in the $AttrDef system file
3833987da915Sopenharmony_ci * @vol:	ntfs volume to which the attribute belongs
3834987da915Sopenharmony_ci * @type:	attribute type which to find
3835987da915Sopenharmony_ci *
3836987da915Sopenharmony_ci * Search for the attribute definition record corresponding to the attribute
3837987da915Sopenharmony_ci * @type in the $AttrDef system file.
3838987da915Sopenharmony_ci *
3839987da915Sopenharmony_ci * Return the attribute type definition record if found and NULL if not found
3840987da915Sopenharmony_ci * or an error occurred. On error the error code is stored in errno. The
3841987da915Sopenharmony_ci * following error codes are defined:
3842987da915Sopenharmony_ci *	ENOENT	- The attribute @type is not specified in $AttrDef.
3843987da915Sopenharmony_ci *	EINVAL	- Invalid parameters (e.g. @vol is not valid).
3844987da915Sopenharmony_ci */
3845987da915Sopenharmony_ciATTR_DEF *ntfs_attr_find_in_attrdef(const ntfs_volume *vol,
3846987da915Sopenharmony_ci		const ATTR_TYPES type)
3847987da915Sopenharmony_ci{
3848987da915Sopenharmony_ci	ATTR_DEF *ad;
3849987da915Sopenharmony_ci
3850987da915Sopenharmony_ci	if (!vol || !vol->attrdef || !type) {
3851987da915Sopenharmony_ci		errno = EINVAL;
3852987da915Sopenharmony_ci		ntfs_log_perror("%s: type=%d", __FUNCTION__, le32_to_cpu(type));
3853987da915Sopenharmony_ci		return NULL;
3854987da915Sopenharmony_ci	}
3855987da915Sopenharmony_ci	for (ad = vol->attrdef; ((ptrdiff_t)((u8*)ad - (u8*)vol->attrdef
3856987da915Sopenharmony_ci				+ sizeof(ATTR_DEF)) <= vol->attrdef_len)
3857987da915Sopenharmony_ci			&& ad->type; ++ad) {
3858987da915Sopenharmony_ci		/* We haven't found it yet, carry on searching. */
3859987da915Sopenharmony_ci		if (le32_to_cpu(ad->type) < le32_to_cpu(type))
3860987da915Sopenharmony_ci			continue;
3861987da915Sopenharmony_ci		/* We found the attribute; return it. */
3862987da915Sopenharmony_ci		if (ad->type == type)
3863987da915Sopenharmony_ci			return ad;
3864987da915Sopenharmony_ci		/* We have gone too far already. No point in continuing. */
3865987da915Sopenharmony_ci		break;
3866987da915Sopenharmony_ci	}
3867987da915Sopenharmony_ci	errno = ENOENT;
3868987da915Sopenharmony_ci	ntfs_log_perror("%s: type=%d", __FUNCTION__, le32_to_cpu(type));
3869987da915Sopenharmony_ci	return NULL;
3870987da915Sopenharmony_ci}
3871987da915Sopenharmony_ci
3872987da915Sopenharmony_ci/**
3873987da915Sopenharmony_ci * ntfs_attr_size_bounds_check - check a size of an attribute type for validity
3874987da915Sopenharmony_ci * @vol:	ntfs volume to which the attribute belongs
3875987da915Sopenharmony_ci * @type:	attribute type which to check
3876987da915Sopenharmony_ci * @size:	size which to check
3877987da915Sopenharmony_ci *
3878987da915Sopenharmony_ci * Check whether the @size in bytes is valid for an attribute of @type on the
3879987da915Sopenharmony_ci * ntfs volume @vol. This information is obtained from $AttrDef system file.
3880987da915Sopenharmony_ci *
3881987da915Sopenharmony_ci * Return 0 if valid and -1 if not valid or an error occurred. On error the
3882987da915Sopenharmony_ci * error code is stored in errno. The following error codes are defined:
3883987da915Sopenharmony_ci *	ERANGE	- @size is not valid for the attribute @type.
3884987da915Sopenharmony_ci *	ENOENT	- The attribute @type is not specified in $AttrDef.
3885987da915Sopenharmony_ci *	EINVAL	- Invalid parameters (e.g. @size is < 0 or @vol is not valid).
3886987da915Sopenharmony_ci */
3887987da915Sopenharmony_ciint ntfs_attr_size_bounds_check(const ntfs_volume *vol, const ATTR_TYPES type,
3888987da915Sopenharmony_ci		const s64 size)
3889987da915Sopenharmony_ci{
3890987da915Sopenharmony_ci	ATTR_DEF *ad;
3891987da915Sopenharmony_ci	s64 min_size, max_size;
3892987da915Sopenharmony_ci
3893987da915Sopenharmony_ci	if (size < 0) {
3894987da915Sopenharmony_ci		errno = EINVAL;
3895987da915Sopenharmony_ci		ntfs_log_perror("%s: size=%lld", __FUNCTION__,
3896987da915Sopenharmony_ci				(long long)size);
3897987da915Sopenharmony_ci		return -1;
3898987da915Sopenharmony_ci	}
3899987da915Sopenharmony_ci
3900987da915Sopenharmony_ci	/*
3901987da915Sopenharmony_ci	 * $ATTRIBUTE_LIST shouldn't be greater than 0x40000, otherwise
3902987da915Sopenharmony_ci	 * Windows would crash. This is not listed in the AttrDef.
3903987da915Sopenharmony_ci	 */
3904987da915Sopenharmony_ci	if (type == AT_ATTRIBUTE_LIST && size > 0x40000) {
3905987da915Sopenharmony_ci		errno = ERANGE;
3906987da915Sopenharmony_ci		ntfs_log_perror("Too large attrlist (%lld)", (long long)size);
3907987da915Sopenharmony_ci		return -1;
3908987da915Sopenharmony_ci	}
3909987da915Sopenharmony_ci
3910987da915Sopenharmony_ci	ad = ntfs_attr_find_in_attrdef(vol, type);
3911987da915Sopenharmony_ci	if (!ad)
3912987da915Sopenharmony_ci		return -1;
3913987da915Sopenharmony_ci
3914987da915Sopenharmony_ci	min_size = sle64_to_cpu(ad->min_size);
3915987da915Sopenharmony_ci	max_size = sle64_to_cpu(ad->max_size);
3916987da915Sopenharmony_ci
3917987da915Sopenharmony_ci	/* The $AttrDef generated by Windows specifies 2 as min_size for the
3918987da915Sopenharmony_ci	 * volume name attribute, but in reality Windows sets it to 0 when
3919987da915Sopenharmony_ci	 * clearing the volume name. If we want to be able to clear the volume
3920987da915Sopenharmony_ci	 * name we must also accept 0 as min_size, despite the $AttrDef
3921987da915Sopenharmony_ci	 * definition. */
3922987da915Sopenharmony_ci	if(type == AT_VOLUME_NAME)
3923987da915Sopenharmony_ci		min_size = 0;
3924987da915Sopenharmony_ci
3925987da915Sopenharmony_ci	if ((min_size && (size < min_size)) ||
3926987da915Sopenharmony_ci	    ((max_size > 0) && (size > max_size))) {
3927987da915Sopenharmony_ci		errno = ERANGE;
3928987da915Sopenharmony_ci		ntfs_log_perror("Attr type %d size check failed (min,size,max="
3929987da915Sopenharmony_ci			"%lld,%lld,%lld)", le32_to_cpu(type), (long long)min_size,
3930987da915Sopenharmony_ci			(long long)size, (long long)max_size);
3931987da915Sopenharmony_ci		return -1;
3932987da915Sopenharmony_ci	}
3933987da915Sopenharmony_ci	return 0;
3934987da915Sopenharmony_ci}
3935987da915Sopenharmony_ci
3936987da915Sopenharmony_ci/**
3937987da915Sopenharmony_ci * ntfs_attr_can_be_non_resident - check if an attribute can be non-resident
3938987da915Sopenharmony_ci * @vol:	ntfs volume to which the attribute belongs
3939987da915Sopenharmony_ci * @type:	attribute type to check
3940987da915Sopenharmony_ci * @name:	attribute name to check
3941987da915Sopenharmony_ci * @name_len:	attribute name length
3942987da915Sopenharmony_ci *
3943987da915Sopenharmony_ci * Check whether the attribute of @type and @name with name length @name_len on
3944987da915Sopenharmony_ci * the ntfs volume @vol is allowed to be non-resident.  This information is
3945987da915Sopenharmony_ci * obtained from $AttrDef system file and is augmented by rules imposed by
3946987da915Sopenharmony_ci * Microsoft (e.g. see http://support.microsoft.com/kb/974729/).
3947987da915Sopenharmony_ci *
3948987da915Sopenharmony_ci * Return 0 if the attribute is allowed to be non-resident and -1 if not or an
3949987da915Sopenharmony_ci * error occurred. On error the error code is stored in errno. The following
3950987da915Sopenharmony_ci * error codes are defined:
3951987da915Sopenharmony_ci *	EPERM	- The attribute is not allowed to be non-resident.
3952987da915Sopenharmony_ci *	ENOENT	- The attribute @type is not specified in $AttrDef.
3953987da915Sopenharmony_ci *	EINVAL	- Invalid parameters (e.g. @vol is not valid).
3954987da915Sopenharmony_ci */
3955987da915Sopenharmony_cistatic int ntfs_attr_can_be_non_resident(const ntfs_volume *vol, const ATTR_TYPES type,
3956987da915Sopenharmony_ci					const ntfschar *name, int name_len)
3957987da915Sopenharmony_ci{
3958987da915Sopenharmony_ci	ATTR_DEF *ad;
3959987da915Sopenharmony_ci	BOOL allowed;
3960987da915Sopenharmony_ci
3961987da915Sopenharmony_ci	/*
3962987da915Sopenharmony_ci	 * Microsoft has decreed that $LOGGED_UTILITY_STREAM attributes with a
3963987da915Sopenharmony_ci	 * name of $TXF_DATA must be resident despite the entry for
3964987da915Sopenharmony_ci	 * $LOGGED_UTILITY_STREAM in $AttrDef allowing them to be non-resident.
3965987da915Sopenharmony_ci	 * Failure to obey this on the root directory mft record of a volume
3966987da915Sopenharmony_ci	 * causes Windows Vista and later to see the volume as a RAW volume and
3967987da915Sopenharmony_ci	 * thus cannot mount it at all.
3968987da915Sopenharmony_ci	 */
3969987da915Sopenharmony_ci	if ((type == AT_LOGGED_UTILITY_STREAM)
3970987da915Sopenharmony_ci	    && name
3971987da915Sopenharmony_ci	    && ntfs_names_are_equal(TXF_DATA, 9, name, name_len,
3972987da915Sopenharmony_ci			CASE_SENSITIVE, vol->upcase, vol->upcase_len))
3973987da915Sopenharmony_ci		allowed = FALSE;
3974987da915Sopenharmony_ci	else {
3975987da915Sopenharmony_ci		/* Find the attribute definition record in $AttrDef. */
3976987da915Sopenharmony_ci		ad = ntfs_attr_find_in_attrdef(vol, type);
3977987da915Sopenharmony_ci		if (!ad)
3978987da915Sopenharmony_ci			return -1;
3979987da915Sopenharmony_ci		/* Check the flags and return the result. */
3980987da915Sopenharmony_ci		allowed = !(ad->flags & ATTR_DEF_RESIDENT);
3981987da915Sopenharmony_ci	}
3982987da915Sopenharmony_ci	if (!allowed) {
3983987da915Sopenharmony_ci		errno = EPERM;
3984987da915Sopenharmony_ci		ntfs_log_trace("Attribute can't be non-resident\n");
3985987da915Sopenharmony_ci		return -1;
3986987da915Sopenharmony_ci	}
3987987da915Sopenharmony_ci	return 0;
3988987da915Sopenharmony_ci}
3989987da915Sopenharmony_ci
3990987da915Sopenharmony_ci/**
3991987da915Sopenharmony_ci * ntfs_attr_can_be_resident - check if an attribute can be resident
3992987da915Sopenharmony_ci * @vol:	ntfs volume to which the attribute belongs
3993987da915Sopenharmony_ci * @type:	attribute type which to check
3994987da915Sopenharmony_ci *
3995987da915Sopenharmony_ci * Check whether the attribute of @type on the ntfs volume @vol is allowed to
3996987da915Sopenharmony_ci * be resident. This information is derived from our ntfs knowledge and may
3997987da915Sopenharmony_ci * not be completely accurate, especially when user defined attributes are
3998987da915Sopenharmony_ci * present. Basically we allow everything to be resident except for index
3999987da915Sopenharmony_ci * allocation and extended attribute attributes.
4000987da915Sopenharmony_ci *
4001987da915Sopenharmony_ci * Return 0 if the attribute is allowed to be resident and -1 if not or an
4002987da915Sopenharmony_ci * error occurred. On error the error code is stored in errno. The following
4003987da915Sopenharmony_ci * error codes are defined:
4004987da915Sopenharmony_ci *	EPERM	- The attribute is not allowed to be resident.
4005987da915Sopenharmony_ci *	EINVAL	- Invalid parameters (e.g. @vol is not valid).
4006987da915Sopenharmony_ci *
4007987da915Sopenharmony_ci * Warning: In the system file $MFT the attribute $Bitmap must be non-resident
4008987da915Sopenharmony_ci *	    otherwise windows will not boot (blue screen of death)!  We cannot
4009987da915Sopenharmony_ci *	    check for this here as we don't know which inode's $Bitmap is being
4010987da915Sopenharmony_ci *	    asked about so the caller needs to special case this.
4011987da915Sopenharmony_ci */
4012987da915Sopenharmony_ciint ntfs_attr_can_be_resident(const ntfs_volume *vol, const ATTR_TYPES type)
4013987da915Sopenharmony_ci{
4014987da915Sopenharmony_ci	if (!vol || !vol->attrdef || !type) {
4015987da915Sopenharmony_ci		errno = EINVAL;
4016987da915Sopenharmony_ci		return -1;
4017987da915Sopenharmony_ci	}
4018987da915Sopenharmony_ci	if (type != AT_INDEX_ALLOCATION)
4019987da915Sopenharmony_ci		return 0;
4020987da915Sopenharmony_ci
4021987da915Sopenharmony_ci	ntfs_log_trace("Attribute can't be resident\n");
4022987da915Sopenharmony_ci	errno = EPERM;
4023987da915Sopenharmony_ci	return -1;
4024987da915Sopenharmony_ci}
4025987da915Sopenharmony_ci
4026987da915Sopenharmony_ci/**
4027987da915Sopenharmony_ci * ntfs_make_room_for_attr - make room for an attribute inside an mft record
4028987da915Sopenharmony_ci * @m:		mft record
4029987da915Sopenharmony_ci * @pos:	position at which to make space
4030987da915Sopenharmony_ci * @size:	byte size to make available at this position
4031987da915Sopenharmony_ci *
4032987da915Sopenharmony_ci * @pos points to the attribute in front of which we want to make space.
4033987da915Sopenharmony_ci *
4034987da915Sopenharmony_ci * Return 0 on success or -1 on error. On error the error code is stored in
4035987da915Sopenharmony_ci * errno. Possible error codes are:
4036987da915Sopenharmony_ci *	ENOSPC	- There is not enough space available to complete operation. The
4037987da915Sopenharmony_ci *		  caller has to make space before calling this.
4038987da915Sopenharmony_ci *	EINVAL	- Input parameters were faulty.
4039987da915Sopenharmony_ci */
4040987da915Sopenharmony_ciint ntfs_make_room_for_attr(MFT_RECORD *m, u8 *pos, u32 size)
4041987da915Sopenharmony_ci{
4042987da915Sopenharmony_ci	u32 biu;
4043987da915Sopenharmony_ci
4044987da915Sopenharmony_ci	ntfs_log_trace("Entering for pos 0x%d, size %u.\n",
4045987da915Sopenharmony_ci		(int)(pos - (u8*)m), (unsigned) size);
4046987da915Sopenharmony_ci
4047987da915Sopenharmony_ci	/* Make size 8-byte alignment. */
4048987da915Sopenharmony_ci	size = (size + 7) & ~7;
4049987da915Sopenharmony_ci
4050987da915Sopenharmony_ci	/* Rigorous consistency checks. */
4051987da915Sopenharmony_ci	if (!m || !pos || pos < (u8*)m) {
4052987da915Sopenharmony_ci		errno = EINVAL;
4053987da915Sopenharmony_ci		ntfs_log_perror("%s: pos=%p  m=%p", __FUNCTION__, pos, m);
4054987da915Sopenharmony_ci		return -1;
4055987da915Sopenharmony_ci	}
4056987da915Sopenharmony_ci	/* The -8 is for the attribute terminator. */
4057987da915Sopenharmony_ci	if (pos - (u8*)m > (int)le32_to_cpu(m->bytes_in_use) - 8) {
4058987da915Sopenharmony_ci		errno = EINVAL;
4059987da915Sopenharmony_ci		return -1;
4060987da915Sopenharmony_ci	}
4061987da915Sopenharmony_ci	/* Nothing to do. */
4062987da915Sopenharmony_ci	if (!size)
4063987da915Sopenharmony_ci		return 0;
4064987da915Sopenharmony_ci
4065987da915Sopenharmony_ci	biu = le32_to_cpu(m->bytes_in_use);
4066987da915Sopenharmony_ci	/* Do we have enough space? */
4067987da915Sopenharmony_ci	if (biu + size > le32_to_cpu(m->bytes_allocated) ||
4068987da915Sopenharmony_ci	    pos + size > (u8*)m + le32_to_cpu(m->bytes_allocated)) {
4069987da915Sopenharmony_ci		errno = ENOSPC;
4070987da915Sopenharmony_ci		ntfs_log_trace("No enough space in the MFT record\n");
4071987da915Sopenharmony_ci		return -1;
4072987da915Sopenharmony_ci	}
4073987da915Sopenharmony_ci	/* Move everything after pos to pos + size. */
4074987da915Sopenharmony_ci	memmove(pos + size, pos, biu - (pos - (u8*)m));
4075987da915Sopenharmony_ci	/* Update mft record. */
4076987da915Sopenharmony_ci	m->bytes_in_use = cpu_to_le32(biu + size);
4077987da915Sopenharmony_ci	return 0;
4078987da915Sopenharmony_ci}
4079987da915Sopenharmony_ci
4080987da915Sopenharmony_ci/**
4081987da915Sopenharmony_ci * ntfs_resident_attr_record_add - add resident attribute to inode
4082987da915Sopenharmony_ci * @ni:		opened ntfs inode to which MFT record add attribute
4083987da915Sopenharmony_ci * @type:	type of the new attribute
4084987da915Sopenharmony_ci * @name:	name of the new attribute
4085987da915Sopenharmony_ci * @name_len:	name length of the new attribute
4086987da915Sopenharmony_ci * @val:	value of the new attribute
4087987da915Sopenharmony_ci * @size:	size of new attribute (length of @val, if @val != NULL)
4088987da915Sopenharmony_ci * @flags:	flags of the new attribute
4089987da915Sopenharmony_ci *
4090987da915Sopenharmony_ci * Return offset to attribute from the beginning of the mft record on success
4091987da915Sopenharmony_ci * and -1 on error. On error the error code is stored in errno.
4092987da915Sopenharmony_ci * Possible error codes are:
4093987da915Sopenharmony_ci *	EINVAL	- Invalid arguments passed to function.
4094987da915Sopenharmony_ci *	EEXIST	- Attribute of such type and with same name already exists.
4095987da915Sopenharmony_ci *	EIO	- I/O error occurred or damaged filesystem.
4096987da915Sopenharmony_ci */
4097987da915Sopenharmony_ciint ntfs_resident_attr_record_add(ntfs_inode *ni, ATTR_TYPES type,
4098987da915Sopenharmony_ci			const ntfschar *name, u8 name_len, const u8 *val,
4099987da915Sopenharmony_ci			u32 size, ATTR_FLAGS data_flags)
4100987da915Sopenharmony_ci{
4101987da915Sopenharmony_ci	ntfs_attr_search_ctx *ctx;
4102987da915Sopenharmony_ci	u32 length;
4103987da915Sopenharmony_ci	ATTR_RECORD *a;
4104987da915Sopenharmony_ci	MFT_RECORD *m;
4105987da915Sopenharmony_ci	int err, offset;
4106987da915Sopenharmony_ci	ntfs_inode *base_ni;
4107987da915Sopenharmony_ci
4108987da915Sopenharmony_ci	ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x, flags 0x%x.\n",
4109987da915Sopenharmony_ci		(long long) ni->mft_no, (unsigned) le32_to_cpu(type), (unsigned) le16_to_cpu(data_flags));
4110987da915Sopenharmony_ci
4111987da915Sopenharmony_ci	if (!ni || (!name && name_len)) {
4112987da915Sopenharmony_ci		errno = EINVAL;
4113987da915Sopenharmony_ci		return -1;
4114987da915Sopenharmony_ci	}
4115987da915Sopenharmony_ci
4116987da915Sopenharmony_ci	if (ntfs_attr_can_be_resident(ni->vol, type)) {
4117987da915Sopenharmony_ci		if (errno == EPERM)
4118987da915Sopenharmony_ci			ntfs_log_trace("Attribute can't be resident.\n");
4119987da915Sopenharmony_ci		else
4120987da915Sopenharmony_ci			ntfs_log_trace("ntfs_attr_can_be_resident failed.\n");
4121987da915Sopenharmony_ci		return -1;
4122987da915Sopenharmony_ci	}
4123987da915Sopenharmony_ci
4124987da915Sopenharmony_ci	/* Locate place where record should be. */
4125987da915Sopenharmony_ci	ctx = ntfs_attr_get_search_ctx(ni, NULL);
4126987da915Sopenharmony_ci	if (!ctx)
4127987da915Sopenharmony_ci		return -1;
4128987da915Sopenharmony_ci	/*
4129987da915Sopenharmony_ci	 * Use ntfs_attr_find instead of ntfs_attr_lookup to find place for
4130987da915Sopenharmony_ci	 * attribute in @ni->mrec, not any extent inode in case if @ni is base
4131987da915Sopenharmony_ci	 * file record.
4132987da915Sopenharmony_ci	 */
4133987da915Sopenharmony_ci	if (!ntfs_attr_find(type, name, name_len, CASE_SENSITIVE, val, size,
4134987da915Sopenharmony_ci			ctx)) {
4135987da915Sopenharmony_ci		err = EEXIST;
4136987da915Sopenharmony_ci		ntfs_log_trace("Attribute already present.\n");
4137987da915Sopenharmony_ci		goto put_err_out;
4138987da915Sopenharmony_ci	}
4139987da915Sopenharmony_ci	if (errno != ENOENT) {
4140987da915Sopenharmony_ci		err = EIO;
4141987da915Sopenharmony_ci		goto put_err_out;
4142987da915Sopenharmony_ci	}
4143987da915Sopenharmony_ci	a = ctx->attr;
4144987da915Sopenharmony_ci	m = ctx->mrec;
4145987da915Sopenharmony_ci
4146987da915Sopenharmony_ci	/* Make room for attribute. */
4147987da915Sopenharmony_ci	length = offsetof(ATTR_RECORD, resident_end) +
4148987da915Sopenharmony_ci				((name_len * sizeof(ntfschar) + 7) & ~7) +
4149987da915Sopenharmony_ci				((size + 7) & ~7);
4150987da915Sopenharmony_ci	if (ntfs_make_room_for_attr(ctx->mrec, (u8*) ctx->attr, length)) {
4151987da915Sopenharmony_ci		err = errno;
4152987da915Sopenharmony_ci		ntfs_log_trace("Failed to make room for attribute.\n");
4153987da915Sopenharmony_ci		goto put_err_out;
4154987da915Sopenharmony_ci	}
4155987da915Sopenharmony_ci
4156987da915Sopenharmony_ci	/* Setup record fields. */
4157987da915Sopenharmony_ci	offset = ((u8*)a - (u8*)m);
4158987da915Sopenharmony_ci	a->type = type;
4159987da915Sopenharmony_ci	a->length = cpu_to_le32(length);
4160987da915Sopenharmony_ci	a->non_resident = 0;
4161987da915Sopenharmony_ci	a->name_length = name_len;
4162987da915Sopenharmony_ci	a->name_offset = (name_len
4163987da915Sopenharmony_ci		? const_cpu_to_le16(offsetof(ATTR_RECORD, resident_end))
4164987da915Sopenharmony_ci		: const_cpu_to_le16(0));
4165987da915Sopenharmony_ci	a->flags = data_flags;
4166987da915Sopenharmony_ci	a->instance = m->next_attr_instance;
4167987da915Sopenharmony_ci	a->value_length = cpu_to_le32(size);
4168987da915Sopenharmony_ci	a->value_offset = cpu_to_le16(length - ((size + 7) & ~7));
4169987da915Sopenharmony_ci	if (val)
4170987da915Sopenharmony_ci		memcpy((u8*)a + le16_to_cpu(a->value_offset), val, size);
4171987da915Sopenharmony_ci	else
4172987da915Sopenharmony_ci		memset((u8*)a + le16_to_cpu(a->value_offset), 0, size);
4173987da915Sopenharmony_ci	if (type == AT_FILE_NAME)
4174987da915Sopenharmony_ci		a->resident_flags = RESIDENT_ATTR_IS_INDEXED;
4175987da915Sopenharmony_ci	else
4176987da915Sopenharmony_ci		a->resident_flags = 0;
4177987da915Sopenharmony_ci	if (name_len)
4178987da915Sopenharmony_ci		memcpy((u8*)a + le16_to_cpu(a->name_offset),
4179987da915Sopenharmony_ci			name, sizeof(ntfschar) * name_len);
4180987da915Sopenharmony_ci	m->next_attr_instance =
4181987da915Sopenharmony_ci		cpu_to_le16((le16_to_cpu(m->next_attr_instance) + 1) & 0xffff);
4182987da915Sopenharmony_ci	if (ni->nr_extents == -1)
4183987da915Sopenharmony_ci		base_ni = ni->base_ni;
4184987da915Sopenharmony_ci	else
4185987da915Sopenharmony_ci		base_ni = ni;
4186987da915Sopenharmony_ci	if (type != AT_ATTRIBUTE_LIST && NInoAttrList(base_ni)) {
4187987da915Sopenharmony_ci		if (ntfs_attrlist_entry_add(ni, a)) {
4188987da915Sopenharmony_ci			err = errno;
4189987da915Sopenharmony_ci			ntfs_attr_record_resize(m, a, 0);
4190987da915Sopenharmony_ci			ntfs_log_trace("Failed add attribute entry to "
4191987da915Sopenharmony_ci					"ATTRIBUTE_LIST.\n");
4192987da915Sopenharmony_ci			goto put_err_out;
4193987da915Sopenharmony_ci		}
4194987da915Sopenharmony_ci	}
4195987da915Sopenharmony_ci	if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY
4196987da915Sopenharmony_ci	    ? type == AT_INDEX_ROOT && name == NTFS_INDEX_I30
4197987da915Sopenharmony_ci	    : type == AT_DATA && name == AT_UNNAMED) {
4198987da915Sopenharmony_ci		ni->data_size = size;
4199987da915Sopenharmony_ci		ni->allocated_size = (size + 7) & ~7;
4200987da915Sopenharmony_ci		set_nino_flag(ni,KnownSize);
4201987da915Sopenharmony_ci	}
4202987da915Sopenharmony_ci	ntfs_inode_mark_dirty(ni);
4203987da915Sopenharmony_ci	ntfs_attr_put_search_ctx(ctx);
4204987da915Sopenharmony_ci	return offset;
4205987da915Sopenharmony_ciput_err_out:
4206987da915Sopenharmony_ci	ntfs_attr_put_search_ctx(ctx);
4207987da915Sopenharmony_ci	errno = err;
4208987da915Sopenharmony_ci	return -1;
4209987da915Sopenharmony_ci}
4210987da915Sopenharmony_ci
4211987da915Sopenharmony_ci/**
4212987da915Sopenharmony_ci * ntfs_non_resident_attr_record_add - add extent of non-resident attribute
4213987da915Sopenharmony_ci * @ni:			opened ntfs inode to which MFT record add attribute
4214987da915Sopenharmony_ci * @type:		type of the new attribute extent
4215987da915Sopenharmony_ci * @name:		name of the new attribute extent
4216987da915Sopenharmony_ci * @name_len:		name length of the new attribute extent
4217987da915Sopenharmony_ci * @lowest_vcn:		lowest vcn of the new attribute extent
4218987da915Sopenharmony_ci * @dataruns_size:	dataruns size of the new attribute extent
4219987da915Sopenharmony_ci * @flags:		flags of the new attribute extent
4220987da915Sopenharmony_ci *
4221987da915Sopenharmony_ci * Return offset to attribute from the beginning of the mft record on success
4222987da915Sopenharmony_ci * and -1 on error. On error the error code is stored in errno.
4223987da915Sopenharmony_ci * Possible error codes are:
4224987da915Sopenharmony_ci *	EINVAL	- Invalid arguments passed to function.
4225987da915Sopenharmony_ci *	EEXIST	- Attribute of such type, with same lowest vcn and with same
4226987da915Sopenharmony_ci *		  name already exists.
4227987da915Sopenharmony_ci *	EIO	- I/O error occurred or damaged filesystem.
4228987da915Sopenharmony_ci */
4229987da915Sopenharmony_ciint ntfs_non_resident_attr_record_add(ntfs_inode *ni, ATTR_TYPES type,
4230987da915Sopenharmony_ci		const ntfschar *name, u8 name_len, VCN lowest_vcn, int dataruns_size,
4231987da915Sopenharmony_ci		ATTR_FLAGS flags)
4232987da915Sopenharmony_ci{
4233987da915Sopenharmony_ci	ntfs_attr_search_ctx *ctx;
4234987da915Sopenharmony_ci	u32 length;
4235987da915Sopenharmony_ci	ATTR_RECORD *a;
4236987da915Sopenharmony_ci	MFT_RECORD *m;
4237987da915Sopenharmony_ci	ntfs_inode *base_ni;
4238987da915Sopenharmony_ci	int err, offset;
4239987da915Sopenharmony_ci
4240987da915Sopenharmony_ci	ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x, lowest_vcn %lld, "
4241987da915Sopenharmony_ci			"dataruns_size %d, flags 0x%x.\n",
4242987da915Sopenharmony_ci			(long long) ni->mft_no, (unsigned) le32_to_cpu(type),
4243987da915Sopenharmony_ci			(long long) lowest_vcn, dataruns_size, (unsigned) le16_to_cpu(flags));
4244987da915Sopenharmony_ci
4245987da915Sopenharmony_ci	if (!ni || dataruns_size <= 0 || (!name && name_len)) {
4246987da915Sopenharmony_ci		errno = EINVAL;
4247987da915Sopenharmony_ci		return -1;
4248987da915Sopenharmony_ci	}
4249987da915Sopenharmony_ci
4250987da915Sopenharmony_ci	if (ntfs_attr_can_be_non_resident(ni->vol, type, name, name_len)) {
4251987da915Sopenharmony_ci		if (errno == EPERM)
4252987da915Sopenharmony_ci			ntfs_log_perror("Attribute can't be non resident");
4253987da915Sopenharmony_ci		else
4254987da915Sopenharmony_ci			ntfs_log_perror("ntfs_attr_can_be_non_resident failed");
4255987da915Sopenharmony_ci		return -1;
4256987da915Sopenharmony_ci	}
4257987da915Sopenharmony_ci
4258987da915Sopenharmony_ci	/* Locate place where record should be. */
4259987da915Sopenharmony_ci	ctx = ntfs_attr_get_search_ctx(ni, NULL);
4260987da915Sopenharmony_ci	if (!ctx)
4261987da915Sopenharmony_ci		return -1;
4262987da915Sopenharmony_ci	/*
4263987da915Sopenharmony_ci	 * Use ntfs_attr_find instead of ntfs_attr_lookup to find place for
4264987da915Sopenharmony_ci	 * attribute in @ni->mrec, not any extent inode in case if @ni is base
4265987da915Sopenharmony_ci	 * file record.
4266987da915Sopenharmony_ci	 */
4267987da915Sopenharmony_ci	if (!ntfs_attr_find(type, name, name_len, CASE_SENSITIVE, NULL, 0,
4268987da915Sopenharmony_ci			ctx)) {
4269987da915Sopenharmony_ci		err = EEXIST;
4270987da915Sopenharmony_ci		ntfs_log_perror("Attribute 0x%x already present", le32_to_cpu(type));
4271987da915Sopenharmony_ci		goto put_err_out;
4272987da915Sopenharmony_ci	}
4273987da915Sopenharmony_ci	if (errno != ENOENT) {
4274987da915Sopenharmony_ci		ntfs_log_perror("ntfs_attr_find failed");
4275987da915Sopenharmony_ci		err = EIO;
4276987da915Sopenharmony_ci		goto put_err_out;
4277987da915Sopenharmony_ci	}
4278987da915Sopenharmony_ci	a = ctx->attr;
4279987da915Sopenharmony_ci	m = ctx->mrec;
4280987da915Sopenharmony_ci
4281987da915Sopenharmony_ci	/* Make room for attribute. */
4282987da915Sopenharmony_ci	dataruns_size = (dataruns_size + 7) & ~7;
4283987da915Sopenharmony_ci	length = offsetof(ATTR_RECORD, compressed_size) + ((sizeof(ntfschar) *
4284987da915Sopenharmony_ci			name_len + 7) & ~7) + dataruns_size +
4285987da915Sopenharmony_ci			((flags & (ATTR_IS_COMPRESSED | ATTR_IS_SPARSE)) ?
4286987da915Sopenharmony_ci			sizeof(a->compressed_size) : 0);
4287987da915Sopenharmony_ci	if (ntfs_make_room_for_attr(ctx->mrec, (u8*) ctx->attr, length)) {
4288987da915Sopenharmony_ci		err = errno;
4289987da915Sopenharmony_ci		ntfs_log_perror("Failed to make room for attribute");
4290987da915Sopenharmony_ci		goto put_err_out;
4291987da915Sopenharmony_ci	}
4292987da915Sopenharmony_ci
4293987da915Sopenharmony_ci	/* Setup record fields. */
4294987da915Sopenharmony_ci	a->type = type;
4295987da915Sopenharmony_ci	a->length = cpu_to_le32(length);
4296987da915Sopenharmony_ci	a->non_resident = 1;
4297987da915Sopenharmony_ci	a->name_length = name_len;
4298987da915Sopenharmony_ci	a->name_offset = cpu_to_le16(offsetof(ATTR_RECORD, compressed_size) +
4299987da915Sopenharmony_ci			((flags & (ATTR_IS_COMPRESSED | ATTR_IS_SPARSE)) ?
4300987da915Sopenharmony_ci			sizeof(a->compressed_size) : 0));
4301987da915Sopenharmony_ci	a->flags = flags;
4302987da915Sopenharmony_ci	a->instance = m->next_attr_instance;
4303987da915Sopenharmony_ci	a->lowest_vcn = cpu_to_sle64(lowest_vcn);
4304987da915Sopenharmony_ci	a->mapping_pairs_offset = cpu_to_le16(length - dataruns_size);
4305987da915Sopenharmony_ci	a->compression_unit = (flags & ATTR_IS_COMPRESSED)
4306987da915Sopenharmony_ci			? STANDARD_COMPRESSION_UNIT : 0;
4307987da915Sopenharmony_ci	/* If @lowest_vcn == 0, than setup empty attribute. */
4308987da915Sopenharmony_ci	if (!lowest_vcn) {
4309987da915Sopenharmony_ci		a->highest_vcn = const_cpu_to_sle64(-1);
4310987da915Sopenharmony_ci		a->allocated_size = const_cpu_to_sle64(0);
4311987da915Sopenharmony_ci		a->data_size = const_cpu_to_sle64(0);
4312987da915Sopenharmony_ci		a->initialized_size = const_cpu_to_sle64(0);
4313987da915Sopenharmony_ci		/* Set empty mapping pairs. */
4314987da915Sopenharmony_ci		*((u8*)a + le16_to_cpu(a->mapping_pairs_offset)) = 0;
4315987da915Sopenharmony_ci	}
4316987da915Sopenharmony_ci	if (name_len)
4317987da915Sopenharmony_ci		memcpy((u8*)a + le16_to_cpu(a->name_offset),
4318987da915Sopenharmony_ci			name, sizeof(ntfschar) * name_len);
4319987da915Sopenharmony_ci	m->next_attr_instance =
4320987da915Sopenharmony_ci		cpu_to_le16((le16_to_cpu(m->next_attr_instance) + 1) & 0xffff);
4321987da915Sopenharmony_ci	if (ni->nr_extents == -1)
4322987da915Sopenharmony_ci		base_ni = ni->base_ni;
4323987da915Sopenharmony_ci	else
4324987da915Sopenharmony_ci		base_ni = ni;
4325987da915Sopenharmony_ci	if (type != AT_ATTRIBUTE_LIST && NInoAttrList(base_ni)) {
4326987da915Sopenharmony_ci		if (ntfs_attrlist_entry_add(ni, a)) {
4327987da915Sopenharmony_ci			err = errno;
4328987da915Sopenharmony_ci			ntfs_log_perror("Failed add attr entry to attrlist");
4329987da915Sopenharmony_ci			ntfs_attr_record_resize(m, a, 0);
4330987da915Sopenharmony_ci			goto put_err_out;
4331987da915Sopenharmony_ci		}
4332987da915Sopenharmony_ci	}
4333987da915Sopenharmony_ci	ntfs_inode_mark_dirty(ni);
4334987da915Sopenharmony_ci	/*
4335987da915Sopenharmony_ci	 * Locate offset from start of the MFT record where new attribute is
4336987da915Sopenharmony_ci	 * placed. We need relookup it, because record maybe moved during
4337987da915Sopenharmony_ci	 * update of attribute list.
4338987da915Sopenharmony_ci	 */
4339987da915Sopenharmony_ci	ntfs_attr_reinit_search_ctx(ctx);
4340987da915Sopenharmony_ci	if (ntfs_attr_lookup(type, name, name_len, CASE_SENSITIVE,
4341987da915Sopenharmony_ci					lowest_vcn, NULL, 0, ctx)) {
4342987da915Sopenharmony_ci		ntfs_log_perror("%s: attribute lookup failed", __FUNCTION__);
4343987da915Sopenharmony_ci		ntfs_attr_put_search_ctx(ctx);
4344987da915Sopenharmony_ci		return -1;
4345987da915Sopenharmony_ci
4346987da915Sopenharmony_ci	}
4347987da915Sopenharmony_ci	offset = (u8*)ctx->attr - (u8*)ctx->mrec;
4348987da915Sopenharmony_ci	ntfs_attr_put_search_ctx(ctx);
4349987da915Sopenharmony_ci	return offset;
4350987da915Sopenharmony_ciput_err_out:
4351987da915Sopenharmony_ci	ntfs_attr_put_search_ctx(ctx);
4352987da915Sopenharmony_ci	errno = err;
4353987da915Sopenharmony_ci	return -1;
4354987da915Sopenharmony_ci}
4355987da915Sopenharmony_ci
4356987da915Sopenharmony_ci/**
4357987da915Sopenharmony_ci * ntfs_attr_record_rm - remove attribute extent
4358987da915Sopenharmony_ci * @ctx:	search context describing the attribute which should be removed
4359987da915Sopenharmony_ci *
4360987da915Sopenharmony_ci * If this function succeed, user should reinit search context if he/she wants
4361987da915Sopenharmony_ci * use it anymore.
4362987da915Sopenharmony_ci *
4363987da915Sopenharmony_ci * Return 0 on success and -1 on error. On error the error code is stored in
4364987da915Sopenharmony_ci * errno. Possible error codes are:
4365987da915Sopenharmony_ci *	EINVAL	- Invalid arguments passed to function.
4366987da915Sopenharmony_ci *	EIO	- I/O error occurred or damaged filesystem.
4367987da915Sopenharmony_ci */
4368987da915Sopenharmony_ciint ntfs_attr_record_rm(ntfs_attr_search_ctx *ctx)
4369987da915Sopenharmony_ci{
4370987da915Sopenharmony_ci	ntfs_inode *base_ni, *ni;
4371987da915Sopenharmony_ci	ATTR_TYPES type;
4372987da915Sopenharmony_ci
4373987da915Sopenharmony_ci	if (!ctx || !ctx->ntfs_ino || !ctx->mrec || !ctx->attr) {
4374987da915Sopenharmony_ci		errno = EINVAL;
4375987da915Sopenharmony_ci		return -1;
4376987da915Sopenharmony_ci	}
4377987da915Sopenharmony_ci
4378987da915Sopenharmony_ci	ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x.\n",
4379987da915Sopenharmony_ci			(long long) ctx->ntfs_ino->mft_no,
4380987da915Sopenharmony_ci			(unsigned) le32_to_cpu(ctx->attr->type));
4381987da915Sopenharmony_ci	type = ctx->attr->type;
4382987da915Sopenharmony_ci	ni = ctx->ntfs_ino;
4383987da915Sopenharmony_ci	if (ctx->base_ntfs_ino)
4384987da915Sopenharmony_ci		base_ni = ctx->base_ntfs_ino;
4385987da915Sopenharmony_ci	else
4386987da915Sopenharmony_ci		base_ni = ctx->ntfs_ino;
4387987da915Sopenharmony_ci
4388987da915Sopenharmony_ci	/* Remove attribute itself. */
4389987da915Sopenharmony_ci	if (ntfs_attr_record_resize(ctx->mrec, ctx->attr, 0)) {
4390987da915Sopenharmony_ci		ntfs_log_trace("Couldn't remove attribute record. Bug or damaged MFT "
4391987da915Sopenharmony_ci				"record.\n");
4392987da915Sopenharmony_ci		if (NInoAttrList(base_ni) && type != AT_ATTRIBUTE_LIST)
4393987da915Sopenharmony_ci			if (ntfs_attrlist_entry_add(ni, ctx->attr))
4394987da915Sopenharmony_ci				ntfs_log_trace("Rollback failed. Leaving inconstant "
4395987da915Sopenharmony_ci						"metadata.\n");
4396987da915Sopenharmony_ci		errno = EIO;
4397987da915Sopenharmony_ci		return -1;
4398987da915Sopenharmony_ci	}
4399987da915Sopenharmony_ci	ntfs_inode_mark_dirty(ni);
4400987da915Sopenharmony_ci
4401987da915Sopenharmony_ci	/*
4402987da915Sopenharmony_ci	 * Remove record from $ATTRIBUTE_LIST if present and we don't want
4403987da915Sopenharmony_ci	 * delete $ATTRIBUTE_LIST itself.
4404987da915Sopenharmony_ci	 */
4405987da915Sopenharmony_ci	if (NInoAttrList(base_ni) && type != AT_ATTRIBUTE_LIST) {
4406987da915Sopenharmony_ci		if (ntfs_attrlist_entry_rm(ctx)) {
4407987da915Sopenharmony_ci			ntfs_log_trace("Couldn't delete record from "
4408987da915Sopenharmony_ci					"$ATTRIBUTE_LIST.\n");
4409987da915Sopenharmony_ci			return -1;
4410987da915Sopenharmony_ci		}
4411987da915Sopenharmony_ci	}
4412987da915Sopenharmony_ci
4413987da915Sopenharmony_ci	/* Post $ATTRIBUTE_LIST delete setup. */
4414987da915Sopenharmony_ci	if (type == AT_ATTRIBUTE_LIST) {
4415987da915Sopenharmony_ci		if (NInoAttrList(base_ni) && base_ni->attr_list)
4416987da915Sopenharmony_ci			free(base_ni->attr_list);
4417987da915Sopenharmony_ci		base_ni->attr_list = NULL;
4418987da915Sopenharmony_ci		NInoClearAttrList(base_ni);
4419987da915Sopenharmony_ci		NInoAttrListClearDirty(base_ni);
4420987da915Sopenharmony_ci	}
4421987da915Sopenharmony_ci
4422987da915Sopenharmony_ci	/* Free MFT record, if it doesn't contain attributes. */
4423987da915Sopenharmony_ci	if (le32_to_cpu(ctx->mrec->bytes_in_use) -
4424987da915Sopenharmony_ci			le16_to_cpu(ctx->mrec->attrs_offset) == 8) {
4425987da915Sopenharmony_ci		if (ntfs_mft_record_free(ni->vol, ni)) {
4426987da915Sopenharmony_ci			// FIXME: We need rollback here.
4427987da915Sopenharmony_ci			ntfs_log_trace("Couldn't free MFT record.\n");
4428987da915Sopenharmony_ci			errno = EIO;
4429987da915Sopenharmony_ci			return -1;
4430987da915Sopenharmony_ci		}
4431987da915Sopenharmony_ci		/* Remove done if we freed base inode. */
4432987da915Sopenharmony_ci		if (ni == base_ni)
4433987da915Sopenharmony_ci			return 0;
4434987da915Sopenharmony_ci	}
4435987da915Sopenharmony_ci
4436987da915Sopenharmony_ci	if (type == AT_ATTRIBUTE_LIST || !NInoAttrList(base_ni))
4437987da915Sopenharmony_ci		return 0;
4438987da915Sopenharmony_ci
4439987da915Sopenharmony_ci	/* Remove attribute list if we don't need it any more. */
4440987da915Sopenharmony_ci	if (!ntfs_attrlist_need(base_ni)) {
4441987da915Sopenharmony_ci		ntfs_attr_reinit_search_ctx(ctx);
4442987da915Sopenharmony_ci		if (ntfs_attr_lookup(AT_ATTRIBUTE_LIST, NULL, 0, CASE_SENSITIVE,
4443987da915Sopenharmony_ci				0, NULL, 0, ctx)) {
4444987da915Sopenharmony_ci			/*
4445987da915Sopenharmony_ci			 * FIXME: Should we succeed here? Definitely something
4446987da915Sopenharmony_ci			 * goes wrong because NInoAttrList(base_ni) returned
4447987da915Sopenharmony_ci			 * that we have got attribute list.
4448987da915Sopenharmony_ci			 */
4449987da915Sopenharmony_ci			ntfs_log_trace("Couldn't find attribute list. Succeed "
4450987da915Sopenharmony_ci					"anyway.\n");
4451987da915Sopenharmony_ci			return 0;
4452987da915Sopenharmony_ci		}
4453987da915Sopenharmony_ci		/* Deallocate clusters. */
4454987da915Sopenharmony_ci		if (ctx->attr->non_resident) {
4455987da915Sopenharmony_ci			runlist *al_rl;
4456987da915Sopenharmony_ci
4457987da915Sopenharmony_ci			al_rl = ntfs_mapping_pairs_decompress(base_ni->vol,
4458987da915Sopenharmony_ci					ctx->attr, NULL);
4459987da915Sopenharmony_ci			if (!al_rl) {
4460987da915Sopenharmony_ci				ntfs_log_trace("Couldn't decompress attribute list "
4461987da915Sopenharmony_ci						"runlist. Succeed anyway.\n");
4462987da915Sopenharmony_ci				return 0;
4463987da915Sopenharmony_ci			}
4464987da915Sopenharmony_ci			if (ntfs_cluster_free_from_rl(base_ni->vol, al_rl)) {
4465987da915Sopenharmony_ci				ntfs_log_trace("Leaking clusters! Run chkdsk. "
4466987da915Sopenharmony_ci						"Couldn't free clusters from "
4467987da915Sopenharmony_ci						"attribute list runlist.\n");
4468987da915Sopenharmony_ci			}
4469987da915Sopenharmony_ci			free(al_rl);
4470987da915Sopenharmony_ci		}
4471987da915Sopenharmony_ci		/* Remove attribute record itself. */
4472987da915Sopenharmony_ci		if (ntfs_attr_record_rm(ctx)) {
4473987da915Sopenharmony_ci			/*
4474987da915Sopenharmony_ci			 * FIXME: Should we succeed here? BTW, chkdsk doesn't
4475987da915Sopenharmony_ci			 * complain if it find MFT record with attribute list,
4476987da915Sopenharmony_ci			 * but without extents.
4477987da915Sopenharmony_ci			 */
4478987da915Sopenharmony_ci			ntfs_log_trace("Couldn't remove attribute list. Succeed "
4479987da915Sopenharmony_ci					"anyway.\n");
4480987da915Sopenharmony_ci			return 0;
4481987da915Sopenharmony_ci		}
4482987da915Sopenharmony_ci	}
4483987da915Sopenharmony_ci	return 0;
4484987da915Sopenharmony_ci}
4485987da915Sopenharmony_ci
4486987da915Sopenharmony_ci/**
4487987da915Sopenharmony_ci * ntfs_attr_add - add attribute to inode
4488987da915Sopenharmony_ci * @ni:		opened ntfs inode to which add attribute
4489987da915Sopenharmony_ci * @type:	type of the new attribute
4490987da915Sopenharmony_ci * @name:	name in unicode of the new attribute
4491987da915Sopenharmony_ci * @name_len:	name length in unicode characters of the new attribute
4492987da915Sopenharmony_ci * @val:	value of new attribute
4493987da915Sopenharmony_ci * @size:	size of the new attribute / length of @val (if specified)
4494987da915Sopenharmony_ci *
4495987da915Sopenharmony_ci * @val should always be specified for always resident attributes (eg. FILE_NAME
4496987da915Sopenharmony_ci * attribute), for attributes that can become non-resident @val can be NULL
4497987da915Sopenharmony_ci * (eg. DATA attribute). @size can be specified even if @val is NULL, in this
4498987da915Sopenharmony_ci * case data size will be equal to @size and initialized size will be equal
4499987da915Sopenharmony_ci * to 0.
4500987da915Sopenharmony_ci *
4501987da915Sopenharmony_ci * If inode haven't got enough space to add attribute, add attribute to one of
4502987da915Sopenharmony_ci * it extents, if no extents present or no one of them have enough space, than
4503987da915Sopenharmony_ci * allocate new extent and add attribute to it.
4504987da915Sopenharmony_ci *
4505987da915Sopenharmony_ci * If on one of this steps attribute list is needed but not present, than it is
4506987da915Sopenharmony_ci * added transparently to caller. So, this function should not be called with
4507987da915Sopenharmony_ci * @type == AT_ATTRIBUTE_LIST, if you really need to add attribute list call
4508987da915Sopenharmony_ci * ntfs_inode_add_attrlist instead.
4509987da915Sopenharmony_ci *
4510987da915Sopenharmony_ci * On success return 0. On error return -1 with errno set to the error code.
4511987da915Sopenharmony_ci */
4512987da915Sopenharmony_ciint ntfs_attr_add(ntfs_inode *ni, ATTR_TYPES type,
4513987da915Sopenharmony_ci		ntfschar *name, u8 name_len, const u8 *val, s64 size)
4514987da915Sopenharmony_ci{
4515987da915Sopenharmony_ci	u32 attr_rec_size;
4516987da915Sopenharmony_ci	int err, i, offset;
4517987da915Sopenharmony_ci	BOOL is_resident;
4518987da915Sopenharmony_ci	BOOL can_be_non_resident = FALSE;
4519987da915Sopenharmony_ci	ntfs_inode *attr_ni;
4520987da915Sopenharmony_ci	ntfs_attr *na;
4521987da915Sopenharmony_ci	ATTR_FLAGS data_flags;
4522987da915Sopenharmony_ci
4523987da915Sopenharmony_ci	if (!ni || size < 0 || type == AT_ATTRIBUTE_LIST) {
4524987da915Sopenharmony_ci		errno = EINVAL;
4525987da915Sopenharmony_ci		ntfs_log_perror("%s: ni=%p  size=%lld", __FUNCTION__, ni,
4526987da915Sopenharmony_ci				(long long)size);
4527987da915Sopenharmony_ci		return -1;
4528987da915Sopenharmony_ci	}
4529987da915Sopenharmony_ci
4530987da915Sopenharmony_ci	ntfs_log_trace("Entering for inode %lld, attr %x, size %lld.\n",
4531987da915Sopenharmony_ci			(long long)ni->mft_no, le32_to_cpu(type), (long long)size);
4532987da915Sopenharmony_ci
4533987da915Sopenharmony_ci	if (ni->nr_extents == -1)
4534987da915Sopenharmony_ci		ni = ni->base_ni;
4535987da915Sopenharmony_ci
4536987da915Sopenharmony_ci	/* Check the attribute type and the size. */
4537987da915Sopenharmony_ci	if (ntfs_attr_size_bounds_check(ni->vol, type, size)) {
4538987da915Sopenharmony_ci		if (errno == ENOENT)
4539987da915Sopenharmony_ci			errno = EIO;
4540987da915Sopenharmony_ci		return -1;
4541987da915Sopenharmony_ci	}
4542987da915Sopenharmony_ci
4543987da915Sopenharmony_ci	/* Sanity checks for always resident attributes. */
4544987da915Sopenharmony_ci	if (ntfs_attr_can_be_non_resident(ni->vol, type, name, name_len)) {
4545987da915Sopenharmony_ci		if (errno != EPERM) {
4546987da915Sopenharmony_ci			err = errno;
4547987da915Sopenharmony_ci			ntfs_log_perror("ntfs_attr_can_be_non_resident failed");
4548987da915Sopenharmony_ci			goto err_out;
4549987da915Sopenharmony_ci		}
4550987da915Sopenharmony_ci		/* @val is mandatory. */
4551987da915Sopenharmony_ci		if (!val) {
4552987da915Sopenharmony_ci			errno = EINVAL;
4553987da915Sopenharmony_ci			ntfs_log_perror("val is mandatory for always resident "
4554987da915Sopenharmony_ci					"attributes");
4555987da915Sopenharmony_ci			return -1;
4556987da915Sopenharmony_ci		}
4557987da915Sopenharmony_ci		if (size > ni->vol->mft_record_size) {
4558987da915Sopenharmony_ci			errno = ERANGE;
4559987da915Sopenharmony_ci			ntfs_log_perror("Attribute is too big");
4560987da915Sopenharmony_ci			return -1;
4561987da915Sopenharmony_ci		}
4562987da915Sopenharmony_ci	} else
4563987da915Sopenharmony_ci		can_be_non_resident = TRUE;
4564987da915Sopenharmony_ci
4565987da915Sopenharmony_ci	/*
4566987da915Sopenharmony_ci	 * Determine resident or not will be new attribute. We add 8 to size in
4567987da915Sopenharmony_ci	 * non resident case for mapping pairs.
4568987da915Sopenharmony_ci	 */
4569987da915Sopenharmony_ci	if (!ntfs_attr_can_be_resident(ni->vol, type)) {
4570987da915Sopenharmony_ci		is_resident = TRUE;
4571987da915Sopenharmony_ci	} else {
4572987da915Sopenharmony_ci		if (errno != EPERM) {
4573987da915Sopenharmony_ci			err = errno;
4574987da915Sopenharmony_ci			ntfs_log_perror("ntfs_attr_can_be_resident failed");
4575987da915Sopenharmony_ci			goto err_out;
4576987da915Sopenharmony_ci		}
4577987da915Sopenharmony_ci		is_resident = FALSE;
4578987da915Sopenharmony_ci	}
4579987da915Sopenharmony_ci	/* Calculate attribute record size. */
4580987da915Sopenharmony_ci	if (is_resident)
4581987da915Sopenharmony_ci		attr_rec_size = offsetof(ATTR_RECORD, resident_end) +
4582987da915Sopenharmony_ci				((name_len * sizeof(ntfschar) + 7) & ~7) +
4583987da915Sopenharmony_ci				((size + 7) & ~7);
4584987da915Sopenharmony_ci	else
4585987da915Sopenharmony_ci		attr_rec_size = offsetof(ATTR_RECORD, non_resident_end) +
4586987da915Sopenharmony_ci				((name_len * sizeof(ntfschar) + 7) & ~7) + 8;
4587987da915Sopenharmony_ci
4588987da915Sopenharmony_ci	/*
4589987da915Sopenharmony_ci	 * If we have enough free space for the new attribute in the base MFT
4590987da915Sopenharmony_ci	 * record, then add attribute to it.
4591987da915Sopenharmony_ci	 */
4592987da915Sopenharmony_ci	if (le32_to_cpu(ni->mrec->bytes_allocated) -
4593987da915Sopenharmony_ci			le32_to_cpu(ni->mrec->bytes_in_use) >= attr_rec_size) {
4594987da915Sopenharmony_ci		attr_ni = ni;
4595987da915Sopenharmony_ci		goto add_attr_record;
4596987da915Sopenharmony_ci	}
4597987da915Sopenharmony_ci
4598987da915Sopenharmony_ci	/* Try to add to extent inodes. */
4599987da915Sopenharmony_ci	if (ntfs_inode_attach_all_extents(ni)) {
4600987da915Sopenharmony_ci		err = errno;
4601987da915Sopenharmony_ci		ntfs_log_perror("Failed to attach all extents to inode");
4602987da915Sopenharmony_ci		goto err_out;
4603987da915Sopenharmony_ci	}
4604987da915Sopenharmony_ci	for (i = 0; i < ni->nr_extents; i++) {
4605987da915Sopenharmony_ci		attr_ni = ni->extent_nis[i];
4606987da915Sopenharmony_ci		if (le32_to_cpu(attr_ni->mrec->bytes_allocated) -
4607987da915Sopenharmony_ci				le32_to_cpu(attr_ni->mrec->bytes_in_use) >=
4608987da915Sopenharmony_ci				attr_rec_size)
4609987da915Sopenharmony_ci			goto add_attr_record;
4610987da915Sopenharmony_ci	}
4611987da915Sopenharmony_ci
4612987da915Sopenharmony_ci	/* There is no extent that contain enough space for new attribute. */
4613987da915Sopenharmony_ci	if (!NInoAttrList(ni)) {
4614987da915Sopenharmony_ci		/* Add attribute list not present, add it and retry. */
4615987da915Sopenharmony_ci		if (ntfs_inode_add_attrlist(ni)) {
4616987da915Sopenharmony_ci			err = errno;
4617987da915Sopenharmony_ci			ntfs_log_perror("Failed to add attribute list");
4618987da915Sopenharmony_ci			goto err_out;
4619987da915Sopenharmony_ci		}
4620987da915Sopenharmony_ci		return ntfs_attr_add(ni, type, name, name_len, val, size);
4621987da915Sopenharmony_ci	}
4622987da915Sopenharmony_ci	/* Allocate new extent. */
4623987da915Sopenharmony_ci	attr_ni = ntfs_mft_record_alloc(ni->vol, ni);
4624987da915Sopenharmony_ci	if (!attr_ni) {
4625987da915Sopenharmony_ci		err = errno;
4626987da915Sopenharmony_ci		ntfs_log_perror("Failed to allocate extent record");
4627987da915Sopenharmony_ci		goto err_out;
4628987da915Sopenharmony_ci	}
4629987da915Sopenharmony_ci
4630987da915Sopenharmony_ciadd_attr_record:
4631987da915Sopenharmony_ci	if ((ni->flags & FILE_ATTR_COMPRESSED)
4632987da915Sopenharmony_ci	    && (ni->vol->major_ver >= 3)
4633987da915Sopenharmony_ci	    && NVolCompression(ni->vol)
4634987da915Sopenharmony_ci	    && (ni->vol->cluster_size <= MAX_COMPRESSION_CLUSTER_SIZE)
4635987da915Sopenharmony_ci	    && ((type == AT_DATA)
4636987da915Sopenharmony_ci	       || ((type == AT_INDEX_ROOT) && (name == NTFS_INDEX_I30))))
4637987da915Sopenharmony_ci		data_flags = ATTR_IS_COMPRESSED;
4638987da915Sopenharmony_ci	else
4639987da915Sopenharmony_ci		data_flags = const_cpu_to_le16(0);
4640987da915Sopenharmony_ci	if (is_resident) {
4641987da915Sopenharmony_ci		/* Add resident attribute. */
4642987da915Sopenharmony_ci		offset = ntfs_resident_attr_record_add(attr_ni, type, name,
4643987da915Sopenharmony_ci				name_len, val, size, data_flags);
4644987da915Sopenharmony_ci		if (offset < 0) {
4645987da915Sopenharmony_ci			if (errno == ENOSPC && can_be_non_resident)
4646987da915Sopenharmony_ci				goto add_non_resident;
4647987da915Sopenharmony_ci			err = errno;
4648987da915Sopenharmony_ci			ntfs_log_perror("Failed to add resident attribute");
4649987da915Sopenharmony_ci			goto free_err_out;
4650987da915Sopenharmony_ci		}
4651987da915Sopenharmony_ci		return 0;
4652987da915Sopenharmony_ci	}
4653987da915Sopenharmony_ci
4654987da915Sopenharmony_ciadd_non_resident:
4655987da915Sopenharmony_ci	/* Add non resident attribute. */
4656987da915Sopenharmony_ci	offset = ntfs_non_resident_attr_record_add(attr_ni, type, name,
4657987da915Sopenharmony_ci				name_len, 0, 8, data_flags);
4658987da915Sopenharmony_ci	if (offset < 0) {
4659987da915Sopenharmony_ci		err = errno;
4660987da915Sopenharmony_ci		ntfs_log_perror("Failed to add non resident attribute");
4661987da915Sopenharmony_ci		goto free_err_out;
4662987da915Sopenharmony_ci	}
4663987da915Sopenharmony_ci
4664987da915Sopenharmony_ci	/* If @size == 0, we are done. */
4665987da915Sopenharmony_ci	if (!size)
4666987da915Sopenharmony_ci		return 0;
4667987da915Sopenharmony_ci
4668987da915Sopenharmony_ci	/* Open new attribute and resize it. */
4669987da915Sopenharmony_ci	na = ntfs_attr_open(ni, type, name, name_len);
4670987da915Sopenharmony_ci	if (!na) {
4671987da915Sopenharmony_ci		err = errno;
4672987da915Sopenharmony_ci		ntfs_log_perror("Failed to open just added attribute");
4673987da915Sopenharmony_ci		goto rm_attr_err_out;
4674987da915Sopenharmony_ci	}
4675987da915Sopenharmony_ci	/* Resize and set attribute value. */
4676987da915Sopenharmony_ci	if (ntfs_attr_truncate_i(na, size, HOLES_OK) ||
4677987da915Sopenharmony_ci			(val && (ntfs_attr_pwrite(na, 0, size, val) != size))) {
4678987da915Sopenharmony_ci		err = errno;
4679987da915Sopenharmony_ci		ntfs_log_perror("Failed to initialize just added attribute");
4680987da915Sopenharmony_ci		if (ntfs_attr_rm(na))
4681987da915Sopenharmony_ci			ntfs_log_perror("Failed to remove just added attribute");
4682987da915Sopenharmony_ci		ntfs_attr_close(na);
4683987da915Sopenharmony_ci		goto err_out;
4684987da915Sopenharmony_ci	}
4685987da915Sopenharmony_ci	ntfs_attr_close(na);
4686987da915Sopenharmony_ci	return 0;
4687987da915Sopenharmony_ci
4688987da915Sopenharmony_cirm_attr_err_out:
4689987da915Sopenharmony_ci	/* Remove just added attribute. */
4690987da915Sopenharmony_ci	if (ntfs_attr_record_resize(attr_ni->mrec,
4691987da915Sopenharmony_ci			(ATTR_RECORD*)((u8*)attr_ni->mrec + offset), 0))
4692987da915Sopenharmony_ci		ntfs_log_perror("Failed to remove just added attribute #2");
4693987da915Sopenharmony_cifree_err_out:
4694987da915Sopenharmony_ci	/* Free MFT record, if it doesn't contain attributes. */
4695987da915Sopenharmony_ci	if (le32_to_cpu(attr_ni->mrec->bytes_in_use) -
4696987da915Sopenharmony_ci			le16_to_cpu(attr_ni->mrec->attrs_offset) == 8)
4697987da915Sopenharmony_ci		if (ntfs_mft_record_free(attr_ni->vol, attr_ni))
4698987da915Sopenharmony_ci			ntfs_log_perror("Failed to free MFT record");
4699987da915Sopenharmony_cierr_out:
4700987da915Sopenharmony_ci	errno = err;
4701987da915Sopenharmony_ci	return -1;
4702987da915Sopenharmony_ci}
4703987da915Sopenharmony_ci
4704987da915Sopenharmony_ci/*
4705987da915Sopenharmony_ci *		Change an attribute flag
4706987da915Sopenharmony_ci */
4707987da915Sopenharmony_ci
4708987da915Sopenharmony_ciint ntfs_attr_set_flags(ntfs_inode *ni, ATTR_TYPES type, const ntfschar *name,
4709987da915Sopenharmony_ci		u8 name_len, ATTR_FLAGS flags, ATTR_FLAGS mask)
4710987da915Sopenharmony_ci{
4711987da915Sopenharmony_ci	ntfs_attr_search_ctx *ctx;
4712987da915Sopenharmony_ci	int res;
4713987da915Sopenharmony_ci
4714987da915Sopenharmony_ci	res = -1;
4715987da915Sopenharmony_ci	/* Search for designated attribute */
4716987da915Sopenharmony_ci	ctx = ntfs_attr_get_search_ctx(ni, NULL);
4717987da915Sopenharmony_ci	if (ctx) {
4718987da915Sopenharmony_ci		if (!ntfs_attr_lookup(type, name, name_len,
4719987da915Sopenharmony_ci					CASE_SENSITIVE, 0, NULL, 0, ctx)) {
4720987da915Sopenharmony_ci			/* do the requested change (all small endian le16) */
4721987da915Sopenharmony_ci			ctx->attr->flags = (ctx->attr->flags & ~mask)
4722987da915Sopenharmony_ci						| (flags & mask);
4723987da915Sopenharmony_ci			NInoSetDirty(ni);
4724987da915Sopenharmony_ci			res = 0;
4725987da915Sopenharmony_ci		}
4726987da915Sopenharmony_ci		ntfs_attr_put_search_ctx(ctx);
4727987da915Sopenharmony_ci	}
4728987da915Sopenharmony_ci	return (res);
4729987da915Sopenharmony_ci}
4730987da915Sopenharmony_ci
4731987da915Sopenharmony_ci
4732987da915Sopenharmony_ci/**
4733987da915Sopenharmony_ci * ntfs_attr_rm - remove attribute from ntfs inode
4734987da915Sopenharmony_ci * @na:		opened ntfs attribute to delete
4735987da915Sopenharmony_ci *
4736987da915Sopenharmony_ci * Remove attribute and all it's extents from ntfs inode. If attribute was non
4737987da915Sopenharmony_ci * resident also free all clusters allocated by attribute.
4738987da915Sopenharmony_ci *
4739987da915Sopenharmony_ci * Return 0 on success or -1 on error with errno set to the error code.
4740987da915Sopenharmony_ci */
4741987da915Sopenharmony_ciint ntfs_attr_rm(ntfs_attr *na)
4742987da915Sopenharmony_ci{
4743987da915Sopenharmony_ci	ntfs_attr_search_ctx *ctx;
4744987da915Sopenharmony_ci	int ret = 0;
4745987da915Sopenharmony_ci
4746987da915Sopenharmony_ci	if (!na) {
4747987da915Sopenharmony_ci		ntfs_log_trace("Invalid arguments passed.\n");
4748987da915Sopenharmony_ci		errno = EINVAL;
4749987da915Sopenharmony_ci		return -1;
4750987da915Sopenharmony_ci	}
4751987da915Sopenharmony_ci
4752987da915Sopenharmony_ci	ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x.\n",
4753987da915Sopenharmony_ci		(long long) na->ni->mft_no, le32_to_cpu(na->type));
4754987da915Sopenharmony_ci
4755987da915Sopenharmony_ci	/* Free cluster allocation. */
4756987da915Sopenharmony_ci	if (NAttrNonResident(na)) {
4757987da915Sopenharmony_ci		if (ntfs_attr_map_whole_runlist(na))
4758987da915Sopenharmony_ci			return -1;
4759987da915Sopenharmony_ci		if (ntfs_cluster_free(na->ni->vol, na, 0, -1) < 0) {
4760987da915Sopenharmony_ci			ntfs_log_trace("Failed to free cluster allocation. Leaving "
4761987da915Sopenharmony_ci					"inconstant metadata.\n");
4762987da915Sopenharmony_ci			ret = -1;
4763987da915Sopenharmony_ci		}
4764987da915Sopenharmony_ci	}
4765987da915Sopenharmony_ci
4766987da915Sopenharmony_ci	/* Search for attribute extents and remove them all. */
4767987da915Sopenharmony_ci	ctx = ntfs_attr_get_search_ctx(na->ni, NULL);
4768987da915Sopenharmony_ci	if (!ctx)
4769987da915Sopenharmony_ci		return -1;
4770987da915Sopenharmony_ci	while (!ntfs_attr_lookup(na->type, na->name, na->name_len,
4771987da915Sopenharmony_ci				CASE_SENSITIVE, 0, NULL, 0, ctx)) {
4772987da915Sopenharmony_ci		if (ntfs_attr_record_rm(ctx)) {
4773987da915Sopenharmony_ci			ntfs_log_trace("Failed to remove attribute extent. Leaving "
4774987da915Sopenharmony_ci					"inconstant metadata.\n");
4775987da915Sopenharmony_ci			ret = -1;
4776987da915Sopenharmony_ci		}
4777987da915Sopenharmony_ci		ntfs_attr_reinit_search_ctx(ctx);
4778987da915Sopenharmony_ci	}
4779987da915Sopenharmony_ci	ntfs_attr_put_search_ctx(ctx);
4780987da915Sopenharmony_ci	if (errno != ENOENT) {
4781987da915Sopenharmony_ci		ntfs_log_trace("Attribute lookup failed. Probably leaving inconstant "
4782987da915Sopenharmony_ci				"metadata.\n");
4783987da915Sopenharmony_ci		ret = -1;
4784987da915Sopenharmony_ci	}
4785987da915Sopenharmony_ci
4786987da915Sopenharmony_ci	return ret;
4787987da915Sopenharmony_ci}
4788987da915Sopenharmony_ci
4789987da915Sopenharmony_ci/**
4790987da915Sopenharmony_ci * ntfs_attr_record_resize - resize an attribute record
4791987da915Sopenharmony_ci * @m:		mft record containing attribute record
4792987da915Sopenharmony_ci * @a:		attribute record to resize
4793987da915Sopenharmony_ci * @new_size:	new size in bytes to which to resize the attribute record @a
4794987da915Sopenharmony_ci *
4795987da915Sopenharmony_ci * Resize the attribute record @a, i.e. the resident part of the attribute, in
4796987da915Sopenharmony_ci * the mft record @m to @new_size bytes.
4797987da915Sopenharmony_ci *
4798987da915Sopenharmony_ci * Return 0 on success and -1 on error with errno set to the error code.
4799987da915Sopenharmony_ci * The following error codes are defined:
4800987da915Sopenharmony_ci *	ENOSPC	- Not enough space in the mft record @m to perform the resize.
4801987da915Sopenharmony_ci * Note that on error no modifications have been performed whatsoever.
4802987da915Sopenharmony_ci *
4803987da915Sopenharmony_ci * Warning: If you make a record smaller without having copied all the data you
4804987da915Sopenharmony_ci *	    are interested in the data may be overwritten!
4805987da915Sopenharmony_ci */
4806987da915Sopenharmony_ciint ntfs_attr_record_resize(MFT_RECORD *m, ATTR_RECORD *a, u32 new_size)
4807987da915Sopenharmony_ci{
4808987da915Sopenharmony_ci	u32 old_size, alloc_size, attr_size;
4809987da915Sopenharmony_ci
4810987da915Sopenharmony_ci	old_size   = le32_to_cpu(m->bytes_in_use);
4811987da915Sopenharmony_ci	alloc_size = le32_to_cpu(m->bytes_allocated);
4812987da915Sopenharmony_ci	attr_size  = le32_to_cpu(a->length);
4813987da915Sopenharmony_ci
4814987da915Sopenharmony_ci	ntfs_log_trace("Sizes: old=%u alloc=%u attr=%u new=%u\n",
4815987da915Sopenharmony_ci		       (unsigned)old_size, (unsigned)alloc_size,
4816987da915Sopenharmony_ci		       (unsigned)attr_size, (unsigned)new_size);
4817987da915Sopenharmony_ci
4818987da915Sopenharmony_ci	/* Align to 8 bytes, just in case the caller hasn't. */
4819987da915Sopenharmony_ci	new_size = (new_size + 7) & ~7;
4820987da915Sopenharmony_ci
4821987da915Sopenharmony_ci	/* If the actual attribute length has changed, move things around. */
4822987da915Sopenharmony_ci	if (new_size != attr_size) {
4823987da915Sopenharmony_ci
4824987da915Sopenharmony_ci		u32 new_muse = old_size - attr_size + new_size;
4825987da915Sopenharmony_ci
4826987da915Sopenharmony_ci		/* Not enough space in this mft record. */
4827987da915Sopenharmony_ci		if (new_muse > alloc_size) {
4828987da915Sopenharmony_ci			errno = ENOSPC;
4829987da915Sopenharmony_ci			ntfs_log_trace("Not enough space in the MFT record "
4830987da915Sopenharmony_ci				       "(%u > %u)\n", new_muse, alloc_size);
4831987da915Sopenharmony_ci			return -1;
4832987da915Sopenharmony_ci		}
4833987da915Sopenharmony_ci
4834987da915Sopenharmony_ci		if (a->type == AT_INDEX_ROOT && new_size > attr_size &&
4835987da915Sopenharmony_ci		    new_muse + 120 > alloc_size && old_size + 120 <= alloc_size) {
4836987da915Sopenharmony_ci			errno = ENOSPC;
4837987da915Sopenharmony_ci			ntfs_log_trace("Too big INDEX_ROOT (%u > %u)\n",
4838987da915Sopenharmony_ci					new_muse, alloc_size);
4839987da915Sopenharmony_ci			return STATUS_RESIDENT_ATTRIBUTE_FILLED_MFT;
4840987da915Sopenharmony_ci		}
4841987da915Sopenharmony_ci
4842987da915Sopenharmony_ci		/* Move attributes following @a to their new location. */
4843987da915Sopenharmony_ci		if (((u8 *)m + old_size) < ((u8 *)a + attr_size)) {
4844987da915Sopenharmony_ci			ntfs_log_error("Attribute 0x%x overflows"
4845987da915Sopenharmony_ci				" from MFT record\n",
4846987da915Sopenharmony_ci				(int)le32_to_cpu(a->type));
4847987da915Sopenharmony_ci			errno = EIO;
4848987da915Sopenharmony_ci			return (-1);
4849987da915Sopenharmony_ci		}
4850987da915Sopenharmony_ci		memmove((u8 *)a + new_size, (u8 *)a + attr_size,
4851987da915Sopenharmony_ci			old_size - ((u8 *)a - (u8 *)m) - attr_size);
4852987da915Sopenharmony_ci
4853987da915Sopenharmony_ci		/* Adjust @m to reflect the change in used space. */
4854987da915Sopenharmony_ci		m->bytes_in_use = cpu_to_le32(new_muse);
4855987da915Sopenharmony_ci
4856987da915Sopenharmony_ci		/* Adjust @a to reflect the new size. */
4857987da915Sopenharmony_ci		if (new_size >= offsetof(ATTR_REC, length) + sizeof(a->length))
4858987da915Sopenharmony_ci			a->length = cpu_to_le32(new_size);
4859987da915Sopenharmony_ci	}
4860987da915Sopenharmony_ci	return 0;
4861987da915Sopenharmony_ci}
4862987da915Sopenharmony_ci
4863987da915Sopenharmony_ci/**
4864987da915Sopenharmony_ci * ntfs_resident_attr_value_resize - resize the value of a resident attribute
4865987da915Sopenharmony_ci * @m:		mft record containing attribute record
4866987da915Sopenharmony_ci * @a:		attribute record whose value to resize
4867987da915Sopenharmony_ci * @new_size:	new size in bytes to which to resize the attribute value of @a
4868987da915Sopenharmony_ci *
4869987da915Sopenharmony_ci * Resize the value of the attribute @a in the mft record @m to @new_size bytes.
4870987da915Sopenharmony_ci * If the value is made bigger, the newly "allocated" space is cleared.
4871987da915Sopenharmony_ci *
4872987da915Sopenharmony_ci * Return 0 on success and -1 on error with errno set to the error code.
4873987da915Sopenharmony_ci * The following error codes are defined:
4874987da915Sopenharmony_ci *	ENOSPC	- Not enough space in the mft record @m to perform the resize.
4875987da915Sopenharmony_ci * Note that on error no modifications have been performed whatsoever.
4876987da915Sopenharmony_ci */
4877987da915Sopenharmony_ciint ntfs_resident_attr_value_resize(MFT_RECORD *m, ATTR_RECORD *a,
4878987da915Sopenharmony_ci		const u32 new_size)
4879987da915Sopenharmony_ci{
4880987da915Sopenharmony_ci	int ret;
4881987da915Sopenharmony_ci
4882987da915Sopenharmony_ci	ntfs_log_trace("Entering for new size %u.\n", (unsigned)new_size);
4883987da915Sopenharmony_ci
4884987da915Sopenharmony_ci	if (!a->value_length) {
4885987da915Sopenharmony_ci			/* Offset is unsafe when no value */
4886987da915Sopenharmony_ci		int offset = ((offsetof(ATTR_RECORD, resident_end)
4887987da915Sopenharmony_ci			+ a->name_length*sizeof(ntfschar) - 1) | 7) + 1;
4888987da915Sopenharmony_ci		a->value_offset = cpu_to_le16(offset);
4889987da915Sopenharmony_ci	}
4890987da915Sopenharmony_ci
4891987da915Sopenharmony_ci	/* Resize the resident part of the attribute record. */
4892987da915Sopenharmony_ci	if ((ret = ntfs_attr_record_resize(m, a, (le16_to_cpu(a->value_offset) +
4893987da915Sopenharmony_ci			new_size + 7) & ~7)) < 0)
4894987da915Sopenharmony_ci		return ret;
4895987da915Sopenharmony_ci	/*
4896987da915Sopenharmony_ci	 * If we made the attribute value bigger, clear the area between the
4897987da915Sopenharmony_ci	 * old size and @new_size.
4898987da915Sopenharmony_ci	 */
4899987da915Sopenharmony_ci	if (new_size > le32_to_cpu(a->value_length))
4900987da915Sopenharmony_ci		memset((u8*)a + le16_to_cpu(a->value_offset) +
4901987da915Sopenharmony_ci				le32_to_cpu(a->value_length), 0, new_size -
4902987da915Sopenharmony_ci				le32_to_cpu(a->value_length));
4903987da915Sopenharmony_ci	/* Finally update the length of the attribute value. */
4904987da915Sopenharmony_ci	a->value_length = cpu_to_le32(new_size);
4905987da915Sopenharmony_ci	return 0;
4906987da915Sopenharmony_ci}
4907987da915Sopenharmony_ci
4908987da915Sopenharmony_ci/**
4909987da915Sopenharmony_ci * ntfs_attr_record_move_to - move attribute record to target inode
4910987da915Sopenharmony_ci * @ctx:	attribute search context describing the attribute record
4911987da915Sopenharmony_ci * @ni:		opened ntfs inode to which move attribute record
4912987da915Sopenharmony_ci *
4913987da915Sopenharmony_ci * If this function succeed, user should reinit search context if he/she wants
4914987da915Sopenharmony_ci * use it anymore.
4915987da915Sopenharmony_ci *
4916987da915Sopenharmony_ci * Return 0 on success and -1 on error with errno set to the error code.
4917987da915Sopenharmony_ci */
4918987da915Sopenharmony_ciint ntfs_attr_record_move_to(ntfs_attr_search_ctx *ctx, ntfs_inode *ni)
4919987da915Sopenharmony_ci{
4920987da915Sopenharmony_ci	ntfs_attr_search_ctx *nctx;
4921987da915Sopenharmony_ci	ATTR_RECORD *a;
4922987da915Sopenharmony_ci	int err;
4923987da915Sopenharmony_ci
4924987da915Sopenharmony_ci	if (!ctx || !ctx->attr || !ctx->ntfs_ino || !ni) {
4925987da915Sopenharmony_ci		ntfs_log_trace("Invalid arguments passed.\n");
4926987da915Sopenharmony_ci		errno = EINVAL;
4927987da915Sopenharmony_ci		return -1;
4928987da915Sopenharmony_ci	}
4929987da915Sopenharmony_ci
4930987da915Sopenharmony_ci	ntfs_log_trace("Entering for ctx->attr->type 0x%x, ctx->ntfs_ino->mft_no "
4931987da915Sopenharmony_ci			"0x%llx, ni->mft_no 0x%llx.\n",
4932987da915Sopenharmony_ci			(unsigned) le32_to_cpu(ctx->attr->type),
4933987da915Sopenharmony_ci			(long long) ctx->ntfs_ino->mft_no,
4934987da915Sopenharmony_ci			(long long) ni->mft_no);
4935987da915Sopenharmony_ci
4936987da915Sopenharmony_ci	if (ctx->ntfs_ino == ni)
4937987da915Sopenharmony_ci		return 0;
4938987da915Sopenharmony_ci
4939987da915Sopenharmony_ci	if (!ctx->al_entry) {
4940987da915Sopenharmony_ci		ntfs_log_trace("Inode should contain attribute list to use this "
4941987da915Sopenharmony_ci				"function.\n");
4942987da915Sopenharmony_ci		errno = EINVAL;
4943987da915Sopenharmony_ci		return -1;
4944987da915Sopenharmony_ci	}
4945987da915Sopenharmony_ci
4946987da915Sopenharmony_ci	/* Find place in MFT record where attribute will be moved. */
4947987da915Sopenharmony_ci	a = ctx->attr;
4948987da915Sopenharmony_ci	nctx = ntfs_attr_get_search_ctx(ni, NULL);
4949987da915Sopenharmony_ci	if (!nctx)
4950987da915Sopenharmony_ci		return -1;
4951987da915Sopenharmony_ci
4952987da915Sopenharmony_ci	/*
4953987da915Sopenharmony_ci	 * Use ntfs_attr_find instead of ntfs_attr_lookup to find place for
4954987da915Sopenharmony_ci	 * attribute in @ni->mrec, not any extent inode in case if @ni is base
4955987da915Sopenharmony_ci	 * file record.
4956987da915Sopenharmony_ci	 */
4957987da915Sopenharmony_ci	if (!ntfs_attr_find(a->type, (ntfschar*)((u8*)a + le16_to_cpu(
4958987da915Sopenharmony_ci			a->name_offset)), a->name_length, CASE_SENSITIVE, NULL,
4959987da915Sopenharmony_ci			0, nctx)) {
4960987da915Sopenharmony_ci		ntfs_log_trace("Attribute of such type, with same name already "
4961987da915Sopenharmony_ci				"present in this MFT record.\n");
4962987da915Sopenharmony_ci		err = EEXIST;
4963987da915Sopenharmony_ci		goto put_err_out;
4964987da915Sopenharmony_ci	}
4965987da915Sopenharmony_ci	if (errno != ENOENT) {
4966987da915Sopenharmony_ci		err = errno;
4967987da915Sopenharmony_ci		ntfs_log_debug("Attribute lookup failed.\n");
4968987da915Sopenharmony_ci		goto put_err_out;
4969987da915Sopenharmony_ci	}
4970987da915Sopenharmony_ci
4971987da915Sopenharmony_ci	/* Make space and move attribute. */
4972987da915Sopenharmony_ci	if (ntfs_make_room_for_attr(ni->mrec, (u8*) nctx->attr,
4973987da915Sopenharmony_ci					le32_to_cpu(a->length))) {
4974987da915Sopenharmony_ci		err = errno;
4975987da915Sopenharmony_ci		ntfs_log_trace("Couldn't make space for attribute.\n");
4976987da915Sopenharmony_ci		goto put_err_out;
4977987da915Sopenharmony_ci	}
4978987da915Sopenharmony_ci	memcpy(nctx->attr, a, le32_to_cpu(a->length));
4979987da915Sopenharmony_ci	nctx->attr->instance = nctx->mrec->next_attr_instance;
4980987da915Sopenharmony_ci	nctx->mrec->next_attr_instance = cpu_to_le16(
4981987da915Sopenharmony_ci		(le16_to_cpu(nctx->mrec->next_attr_instance) + 1) & 0xffff);
4982987da915Sopenharmony_ci	ntfs_attr_record_resize(ctx->mrec, a, 0);
4983987da915Sopenharmony_ci	ntfs_inode_mark_dirty(ctx->ntfs_ino);
4984987da915Sopenharmony_ci	ntfs_inode_mark_dirty(ni);
4985987da915Sopenharmony_ci
4986987da915Sopenharmony_ci	/* Update attribute list. */
4987987da915Sopenharmony_ci	ctx->al_entry->mft_reference =
4988987da915Sopenharmony_ci		MK_LE_MREF(ni->mft_no, le16_to_cpu(ni->mrec->sequence_number));
4989987da915Sopenharmony_ci	ctx->al_entry->instance = nctx->attr->instance;
4990987da915Sopenharmony_ci	ntfs_attrlist_mark_dirty(ni);
4991987da915Sopenharmony_ci
4992987da915Sopenharmony_ci	ntfs_attr_put_search_ctx(nctx);
4993987da915Sopenharmony_ci	return 0;
4994987da915Sopenharmony_ciput_err_out:
4995987da915Sopenharmony_ci	ntfs_attr_put_search_ctx(nctx);
4996987da915Sopenharmony_ci	errno = err;
4997987da915Sopenharmony_ci	return -1;
4998987da915Sopenharmony_ci}
4999987da915Sopenharmony_ci
5000987da915Sopenharmony_ci/**
5001987da915Sopenharmony_ci * ntfs_attr_record_move_away - move away attribute record from it's mft record
5002987da915Sopenharmony_ci * @ctx:	attribute search context describing the attribute record
5003987da915Sopenharmony_ci * @extra:	minimum amount of free space in the new holder of record
5004987da915Sopenharmony_ci *
5005987da915Sopenharmony_ci * New attribute record holder must have free @extra bytes after moving
5006987da915Sopenharmony_ci * attribute record to it.
5007987da915Sopenharmony_ci *
5008987da915Sopenharmony_ci * If this function succeed, user should reinit search context if he/she wants
5009987da915Sopenharmony_ci * use it anymore.
5010987da915Sopenharmony_ci *
5011987da915Sopenharmony_ci * Return 0 on success and -1 on error with errno set to the error code.
5012987da915Sopenharmony_ci */
5013987da915Sopenharmony_ciint ntfs_attr_record_move_away(ntfs_attr_search_ctx *ctx, int extra)
5014987da915Sopenharmony_ci{
5015987da915Sopenharmony_ci	ntfs_inode *base_ni, *ni;
5016987da915Sopenharmony_ci	MFT_RECORD *m;
5017987da915Sopenharmony_ci	int i;
5018987da915Sopenharmony_ci
5019987da915Sopenharmony_ci	if (!ctx || !ctx->attr || !ctx->ntfs_ino || extra < 0) {
5020987da915Sopenharmony_ci		errno = EINVAL;
5021987da915Sopenharmony_ci		ntfs_log_perror("%s: ctx=%p ctx->attr=%p extra=%d", __FUNCTION__,
5022987da915Sopenharmony_ci				ctx, ctx ? ctx->attr : NULL, extra);
5023987da915Sopenharmony_ci		return -1;
5024987da915Sopenharmony_ci	}
5025987da915Sopenharmony_ci
5026987da915Sopenharmony_ci	ntfs_log_trace("Entering for attr 0x%x, inode %llu\n",
5027987da915Sopenharmony_ci			(unsigned) le32_to_cpu(ctx->attr->type),
5028987da915Sopenharmony_ci			(unsigned long long)ctx->ntfs_ino->mft_no);
5029987da915Sopenharmony_ci
5030987da915Sopenharmony_ci	if (ctx->ntfs_ino->nr_extents == -1)
5031987da915Sopenharmony_ci		base_ni = ctx->base_ntfs_ino;
5032987da915Sopenharmony_ci	else
5033987da915Sopenharmony_ci		base_ni = ctx->ntfs_ino;
5034987da915Sopenharmony_ci
5035987da915Sopenharmony_ci	if (!NInoAttrList(base_ni)) {
5036987da915Sopenharmony_ci		errno = EINVAL;
5037987da915Sopenharmony_ci		ntfs_log_perror("Inode %llu has no attrlist",
5038987da915Sopenharmony_ci				(unsigned long long)base_ni->mft_no);
5039987da915Sopenharmony_ci		return -1;
5040987da915Sopenharmony_ci	}
5041987da915Sopenharmony_ci
5042987da915Sopenharmony_ci	if (ntfs_inode_attach_all_extents(ctx->ntfs_ino)) {
5043987da915Sopenharmony_ci		ntfs_log_perror("Couldn't attach extents, inode=%llu",
5044987da915Sopenharmony_ci				(unsigned long long)base_ni->mft_no);
5045987da915Sopenharmony_ci		return -1;
5046987da915Sopenharmony_ci	}
5047987da915Sopenharmony_ci
5048987da915Sopenharmony_ci	/* Walk through all extents and try to move attribute to them. */
5049987da915Sopenharmony_ci	for (i = 0; i < base_ni->nr_extents; i++) {
5050987da915Sopenharmony_ci		ni = base_ni->extent_nis[i];
5051987da915Sopenharmony_ci		m = ni->mrec;
5052987da915Sopenharmony_ci
5053987da915Sopenharmony_ci		if (ctx->ntfs_ino->mft_no == ni->mft_no)
5054987da915Sopenharmony_ci			continue;
5055987da915Sopenharmony_ci
5056987da915Sopenharmony_ci		if (le32_to_cpu(m->bytes_allocated) -
5057987da915Sopenharmony_ci				le32_to_cpu(m->bytes_in_use) <
5058987da915Sopenharmony_ci				le32_to_cpu(ctx->attr->length) + extra)
5059987da915Sopenharmony_ci			continue;
5060987da915Sopenharmony_ci
5061987da915Sopenharmony_ci		/*
5062987da915Sopenharmony_ci		 * ntfs_attr_record_move_to can fail if extent with other lowest
5063987da915Sopenharmony_ci		 * VCN already present in inode we trying move record to. So,
5064987da915Sopenharmony_ci		 * do not return error.
5065987da915Sopenharmony_ci		 */
5066987da915Sopenharmony_ci		if (!ntfs_attr_record_move_to(ctx, ni))
5067987da915Sopenharmony_ci			return 0;
5068987da915Sopenharmony_ci	}
5069987da915Sopenharmony_ci
5070987da915Sopenharmony_ci	/*
5071987da915Sopenharmony_ci	 * Failed to move attribute to one of the current extents, so allocate
5072987da915Sopenharmony_ci	 * new extent and move attribute to it.
5073987da915Sopenharmony_ci	 */
5074987da915Sopenharmony_ci	ni = ntfs_mft_record_alloc(base_ni->vol, base_ni);
5075987da915Sopenharmony_ci	if (!ni) {
5076987da915Sopenharmony_ci		ntfs_log_perror("Couldn't allocate MFT record");
5077987da915Sopenharmony_ci		return -1;
5078987da915Sopenharmony_ci	}
5079987da915Sopenharmony_ci	if (ntfs_attr_record_move_to(ctx, ni)) {
5080987da915Sopenharmony_ci		ntfs_log_perror("Couldn't move attribute to MFT record");
5081987da915Sopenharmony_ci		return -1;
5082987da915Sopenharmony_ci	}
5083987da915Sopenharmony_ci	return 0;
5084987da915Sopenharmony_ci}
5085987da915Sopenharmony_ci
5086987da915Sopenharmony_ci/**
5087987da915Sopenharmony_ci * ntfs_attr_make_non_resident - convert a resident to a non-resident attribute
5088987da915Sopenharmony_ci * @na:		open ntfs attribute to make non-resident
5089987da915Sopenharmony_ci * @ctx:	ntfs search context describing the attribute
5090987da915Sopenharmony_ci *
5091987da915Sopenharmony_ci * Convert a resident ntfs attribute to a non-resident one.
5092987da915Sopenharmony_ci *
5093987da915Sopenharmony_ci * Return 0 on success and -1 on error with errno set to the error code. The
5094987da915Sopenharmony_ci * following error codes are defined:
5095987da915Sopenharmony_ci *	EPERM	- The attribute is not allowed to be non-resident.
5096987da915Sopenharmony_ci *	TODO: others...
5097987da915Sopenharmony_ci *
5098987da915Sopenharmony_ci * NOTE to self: No changes in the attribute list are required to move from
5099987da915Sopenharmony_ci *		 a resident to a non-resident attribute.
5100987da915Sopenharmony_ci *
5101987da915Sopenharmony_ci * Warning: We do not set the inode dirty and we do not write out anything!
5102987da915Sopenharmony_ci *	    We expect the caller to do this as this is a fairly low level
5103987da915Sopenharmony_ci *	    function and it is likely there will be further changes made.
5104987da915Sopenharmony_ci */
5105987da915Sopenharmony_ciint ntfs_attr_make_non_resident(ntfs_attr *na,
5106987da915Sopenharmony_ci		ntfs_attr_search_ctx *ctx)
5107987da915Sopenharmony_ci{
5108987da915Sopenharmony_ci	s64 new_allocated_size, bw;
5109987da915Sopenharmony_ci	ntfs_volume *vol = na->ni->vol;
5110987da915Sopenharmony_ci	ATTR_REC *a = ctx->attr;
5111987da915Sopenharmony_ci	runlist *rl;
5112987da915Sopenharmony_ci	int mp_size, mp_ofs, name_ofs, arec_size, err;
5113987da915Sopenharmony_ci
5114987da915Sopenharmony_ci	ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x.\n", (unsigned long
5115987da915Sopenharmony_ci			long)na->ni->mft_no, le32_to_cpu(na->type));
5116987da915Sopenharmony_ci
5117987da915Sopenharmony_ci	/* Some preliminary sanity checking. */
5118987da915Sopenharmony_ci	if (NAttrNonResident(na)) {
5119987da915Sopenharmony_ci		ntfs_log_trace("Eeek!  Trying to make non-resident attribute "
5120987da915Sopenharmony_ci				"non-resident.  Aborting...\n");
5121987da915Sopenharmony_ci		errno = EINVAL;
5122987da915Sopenharmony_ci		return -1;
5123987da915Sopenharmony_ci	}
5124987da915Sopenharmony_ci
5125987da915Sopenharmony_ci	/* Check that the attribute is allowed to be non-resident. */
5126987da915Sopenharmony_ci	if (ntfs_attr_can_be_non_resident(vol, na->type, na->name, na->name_len))
5127987da915Sopenharmony_ci		return -1;
5128987da915Sopenharmony_ci
5129987da915Sopenharmony_ci	new_allocated_size = (le32_to_cpu(a->value_length) + vol->cluster_size
5130987da915Sopenharmony_ci			- 1) & ~(vol->cluster_size - 1);
5131987da915Sopenharmony_ci
5132987da915Sopenharmony_ci	if (new_allocated_size > 0) {
5133987da915Sopenharmony_ci			if ((a->flags & ATTR_COMPRESSION_MASK)
5134987da915Sopenharmony_ci					== ATTR_IS_COMPRESSED) {
5135987da915Sopenharmony_ci				/* must allocate full compression blocks */
5136987da915Sopenharmony_ci				new_allocated_size = ((new_allocated_size - 1)
5137987da915Sopenharmony_ci					| ((1L << (STANDARD_COMPRESSION_UNIT
5138987da915Sopenharmony_ci					   + vol->cluster_size_bits)) - 1)) + 1;
5139987da915Sopenharmony_ci			}
5140987da915Sopenharmony_ci		/* Start by allocating clusters to hold the attribute value. */
5141987da915Sopenharmony_ci		rl = ntfs_cluster_alloc(vol, 0, new_allocated_size >>
5142987da915Sopenharmony_ci				vol->cluster_size_bits, -1, DATA_ZONE);
5143987da915Sopenharmony_ci		if (!rl)
5144987da915Sopenharmony_ci			return -1;
5145987da915Sopenharmony_ci	} else
5146987da915Sopenharmony_ci		rl = NULL;
5147987da915Sopenharmony_ci	/*
5148987da915Sopenharmony_ci	 * Setup the in-memory attribute structure to be non-resident so that
5149987da915Sopenharmony_ci	 * we can use ntfs_attr_pwrite().
5150987da915Sopenharmony_ci	 */
5151987da915Sopenharmony_ci	NAttrSetNonResident(na);
5152987da915Sopenharmony_ci	NAttrSetBeingNonResident(na);
5153987da915Sopenharmony_ci	na->rl = rl;
5154987da915Sopenharmony_ci	na->allocated_size = new_allocated_size;
5155987da915Sopenharmony_ci	na->data_size = na->initialized_size = le32_to_cpu(a->value_length);
5156987da915Sopenharmony_ci	/*
5157987da915Sopenharmony_ci	 * FIXME: For now just clear all of these as we don't support them when
5158987da915Sopenharmony_ci	 * writing.
5159987da915Sopenharmony_ci	 */
5160987da915Sopenharmony_ci	NAttrClearSparse(na);
5161987da915Sopenharmony_ci	NAttrClearEncrypted(na);
5162987da915Sopenharmony_ci	if ((a->flags & ATTR_COMPRESSION_MASK) == ATTR_IS_COMPRESSED) {
5163987da915Sopenharmony_ci			/* set compression writing parameters */
5164987da915Sopenharmony_ci		na->compression_block_size
5165987da915Sopenharmony_ci			= 1 << (STANDARD_COMPRESSION_UNIT + vol->cluster_size_bits);
5166987da915Sopenharmony_ci		na->compression_block_clusters = 1 << STANDARD_COMPRESSION_UNIT;
5167987da915Sopenharmony_ci	}
5168987da915Sopenharmony_ci
5169987da915Sopenharmony_ci	if (rl) {
5170987da915Sopenharmony_ci		/* Now copy the attribute value to the allocated cluster(s). */
5171987da915Sopenharmony_ci		bw = ntfs_attr_pwrite(na, 0, le32_to_cpu(a->value_length),
5172987da915Sopenharmony_ci				(u8*)a + le16_to_cpu(a->value_offset));
5173987da915Sopenharmony_ci		if (bw != le32_to_cpu(a->value_length)) {
5174987da915Sopenharmony_ci			err = errno;
5175987da915Sopenharmony_ci			ntfs_log_debug("Eeek!  Failed to write out attribute value "
5176987da915Sopenharmony_ci					"(bw = %lli, errno = %i).  "
5177987da915Sopenharmony_ci					"Aborting...\n", (long long)bw, err);
5178987da915Sopenharmony_ci			if (bw >= 0)
5179987da915Sopenharmony_ci				err = EIO;
5180987da915Sopenharmony_ci			goto cluster_free_err_out;
5181987da915Sopenharmony_ci		}
5182987da915Sopenharmony_ci	}
5183987da915Sopenharmony_ci	/* Determine the size of the mapping pairs array. */
5184987da915Sopenharmony_ci	mp_size = ntfs_get_size_for_mapping_pairs(vol, rl, 0, INT_MAX);
5185987da915Sopenharmony_ci	if (mp_size < 0) {
5186987da915Sopenharmony_ci		err = errno;
5187987da915Sopenharmony_ci		ntfs_log_debug("Eeek!  Failed to get size for mapping pairs array.  "
5188987da915Sopenharmony_ci				"Aborting...\n");
5189987da915Sopenharmony_ci		goto cluster_free_err_out;
5190987da915Sopenharmony_ci	}
5191987da915Sopenharmony_ci	/* Calculate new offsets for the name and the mapping pairs array. */
5192987da915Sopenharmony_ci	if (na->ni->flags & FILE_ATTR_COMPRESSED)
5193987da915Sopenharmony_ci		name_ofs = (sizeof(ATTR_REC) + 7) & ~7;
5194987da915Sopenharmony_ci	else
5195987da915Sopenharmony_ci		name_ofs = (sizeof(ATTR_REC) - sizeof(a->compressed_size) + 7) & ~7;
5196987da915Sopenharmony_ci	mp_ofs = (name_ofs + a->name_length * sizeof(ntfschar) + 7) & ~7;
5197987da915Sopenharmony_ci	/*
5198987da915Sopenharmony_ci	 * Determine the size of the resident part of the non-resident
5199987da915Sopenharmony_ci	 * attribute record. (Not compressed thus no compressed_size element
5200987da915Sopenharmony_ci	 * present.)
5201987da915Sopenharmony_ci	 */
5202987da915Sopenharmony_ci	arec_size = (mp_ofs + mp_size + 7) & ~7;
5203987da915Sopenharmony_ci
5204987da915Sopenharmony_ci	/* Resize the resident part of the attribute record. */
5205987da915Sopenharmony_ci	if (ntfs_attr_record_resize(ctx->mrec, a, arec_size) < 0) {
5206987da915Sopenharmony_ci		err = errno;
5207987da915Sopenharmony_ci		goto cluster_free_err_out;
5208987da915Sopenharmony_ci	}
5209987da915Sopenharmony_ci
5210987da915Sopenharmony_ci	/*
5211987da915Sopenharmony_ci	 * Convert the resident part of the attribute record to describe a
5212987da915Sopenharmony_ci	 * non-resident attribute.
5213987da915Sopenharmony_ci	 */
5214987da915Sopenharmony_ci	a->non_resident = 1;
5215987da915Sopenharmony_ci
5216987da915Sopenharmony_ci	/* Move the attribute name if it exists and update the offset. */
5217987da915Sopenharmony_ci	if (a->name_length)
5218987da915Sopenharmony_ci		memmove((u8*)a + name_ofs, (u8*)a + le16_to_cpu(a->name_offset),
5219987da915Sopenharmony_ci				a->name_length * sizeof(ntfschar));
5220987da915Sopenharmony_ci	a->name_offset = cpu_to_le16(name_ofs);
5221987da915Sopenharmony_ci
5222987da915Sopenharmony_ci	/* Setup the fields specific to non-resident attributes. */
5223987da915Sopenharmony_ci	a->lowest_vcn = const_cpu_to_sle64(0);
5224987da915Sopenharmony_ci	a->highest_vcn = cpu_to_sle64((new_allocated_size - 1) >>
5225987da915Sopenharmony_ci						vol->cluster_size_bits);
5226987da915Sopenharmony_ci
5227987da915Sopenharmony_ci	a->mapping_pairs_offset = cpu_to_le16(mp_ofs);
5228987da915Sopenharmony_ci
5229987da915Sopenharmony_ci	/*
5230987da915Sopenharmony_ci	 * Update the flags to match the in-memory ones.
5231987da915Sopenharmony_ci	 * However cannot change the compression state if we had
5232987da915Sopenharmony_ci	 * a fuse_file_info open with a mark for release.
5233987da915Sopenharmony_ci	 * The decisions about compression can only be made when
5234987da915Sopenharmony_ci	 * creating/recreating the stream, not when making non resident.
5235987da915Sopenharmony_ci	 */
5236987da915Sopenharmony_ci	a->flags &= ~(ATTR_IS_SPARSE | ATTR_IS_ENCRYPTED);
5237987da915Sopenharmony_ci	if ((a->flags & ATTR_COMPRESSION_MASK) == ATTR_IS_COMPRESSED) {
5238987da915Sopenharmony_ci			/* support only ATTR_IS_COMPRESSED compression mode */
5239987da915Sopenharmony_ci		a->compression_unit = STANDARD_COMPRESSION_UNIT;
5240987da915Sopenharmony_ci		a->compressed_size = const_cpu_to_sle64(0);
5241987da915Sopenharmony_ci	} else {
5242987da915Sopenharmony_ci		a->compression_unit = 0;
5243987da915Sopenharmony_ci		a->flags &= ~ATTR_COMPRESSION_MASK;
5244987da915Sopenharmony_ci		na->data_flags = a->flags;
5245987da915Sopenharmony_ci	}
5246987da915Sopenharmony_ci
5247987da915Sopenharmony_ci	memset(&a->reserved1, 0, sizeof(a->reserved1));
5248987da915Sopenharmony_ci
5249987da915Sopenharmony_ci	a->allocated_size = cpu_to_sle64(new_allocated_size);
5250987da915Sopenharmony_ci	a->data_size = a->initialized_size = cpu_to_sle64(na->data_size);
5251987da915Sopenharmony_ci
5252987da915Sopenharmony_ci	/* Generate the mapping pairs array in the attribute record. */
5253987da915Sopenharmony_ci	if (ntfs_mapping_pairs_build(vol, (u8*)a + mp_ofs, arec_size - mp_ofs,
5254987da915Sopenharmony_ci			rl, 0, NULL) < 0) {
5255987da915Sopenharmony_ci		// FIXME: Eeek! We need rollback! (AIA)
5256987da915Sopenharmony_ci		ntfs_log_trace("Eeek!  Failed to build mapping pairs.  Leaving "
5257987da915Sopenharmony_ci				"corrupt attribute record on disk.  In memory "
5258987da915Sopenharmony_ci				"runlist is still intact!  Error code is %i.  "
5259987da915Sopenharmony_ci				"FIXME:  Need to rollback instead!\n", errno);
5260987da915Sopenharmony_ci		return -1;
5261987da915Sopenharmony_ci	}
5262987da915Sopenharmony_ci
5263987da915Sopenharmony_ci	/* Done! */
5264987da915Sopenharmony_ci	return 0;
5265987da915Sopenharmony_ci
5266987da915Sopenharmony_cicluster_free_err_out:
5267987da915Sopenharmony_ci	if (rl && ntfs_cluster_free(vol, na, 0, -1) < 0)
5268987da915Sopenharmony_ci		ntfs_log_trace("Eeek!  Failed to release allocated clusters in error "
5269987da915Sopenharmony_ci				"code path.  Leaving inconsistent metadata...\n");
5270987da915Sopenharmony_ci	NAttrClearNonResident(na);
5271987da915Sopenharmony_ci	NAttrClearFullyMapped(na);
5272987da915Sopenharmony_ci	na->allocated_size = na->data_size;
5273987da915Sopenharmony_ci	na->rl = NULL;
5274987da915Sopenharmony_ci	free(rl);
5275987da915Sopenharmony_ci	errno = err;
5276987da915Sopenharmony_ci	return -1;
5277987da915Sopenharmony_ci}
5278987da915Sopenharmony_ci
5279987da915Sopenharmony_ci
5280987da915Sopenharmony_cistatic int ntfs_resident_attr_resize(ntfs_attr *na, const s64 newsize);
5281987da915Sopenharmony_ci
5282987da915Sopenharmony_ci/**
5283987da915Sopenharmony_ci * ntfs_resident_attr_resize - resize a resident, open ntfs attribute
5284987da915Sopenharmony_ci * @na:		resident ntfs attribute to resize
5285987da915Sopenharmony_ci * @newsize:	new size (in bytes) to which to resize the attribute
5286987da915Sopenharmony_ci *
5287987da915Sopenharmony_ci * Change the size of a resident, open ntfs attribute @na to @newsize bytes.
5288987da915Sopenharmony_ci * Can also be used to force an attribute non-resident. In this case, the
5289987da915Sopenharmony_ci * size cannot be changed.
5290987da915Sopenharmony_ci *
5291987da915Sopenharmony_ci * On success return 0
5292987da915Sopenharmony_ci * On error return values are:
5293987da915Sopenharmony_ci * 	STATUS_RESIDENT_ATTRIBUTE_FILLED_MFT
5294987da915Sopenharmony_ci * 	STATUS_ERROR - otherwise
5295987da915Sopenharmony_ci * The following error codes are defined:
5296987da915Sopenharmony_ci *	ENOMEM - Not enough memory to complete operation.
5297987da915Sopenharmony_ci *	ERANGE - @newsize is not valid for the attribute type of @na.
5298987da915Sopenharmony_ci *	ENOSPC - There is no enough space in base mft to resize $ATTRIBUTE_LIST.
5299987da915Sopenharmony_ci */
5300987da915Sopenharmony_cistatic int ntfs_resident_attr_resize_i(ntfs_attr *na, const s64 newsize,
5301987da915Sopenharmony_ci			hole_type holes)
5302987da915Sopenharmony_ci{
5303987da915Sopenharmony_ci	ntfs_attr_search_ctx *ctx;
5304987da915Sopenharmony_ci	ntfs_volume *vol;
5305987da915Sopenharmony_ci	ntfs_inode *ni;
5306987da915Sopenharmony_ci	int err, ret = STATUS_ERROR;
5307987da915Sopenharmony_ci
5308987da915Sopenharmony_ci	ntfs_log_trace("Inode 0x%llx attr 0x%x new size %lld\n",
5309987da915Sopenharmony_ci		       (unsigned long long)na->ni->mft_no, le32_to_cpu(na->type),
5310987da915Sopenharmony_ci		       (long long)newsize);
5311987da915Sopenharmony_ci
5312987da915Sopenharmony_ci	/* Get the attribute record that needs modification. */
5313987da915Sopenharmony_ci	ctx = ntfs_attr_get_search_ctx(na->ni, NULL);
5314987da915Sopenharmony_ci	if (!ctx)
5315987da915Sopenharmony_ci		return -1;
5316987da915Sopenharmony_ci	if (ntfs_attr_lookup(na->type, na->name, na->name_len, 0, 0, NULL, 0,
5317987da915Sopenharmony_ci			ctx)) {
5318987da915Sopenharmony_ci		err = errno;
5319987da915Sopenharmony_ci		ntfs_log_perror("ntfs_attr_lookup failed");
5320987da915Sopenharmony_ci		goto put_err_out;
5321987da915Sopenharmony_ci	}
5322987da915Sopenharmony_ci	vol = na->ni->vol;
5323987da915Sopenharmony_ci	/*
5324987da915Sopenharmony_ci	 * Check the attribute type and the corresponding minimum and maximum
5325987da915Sopenharmony_ci	 * sizes against @newsize and fail if @newsize is out of bounds.
5326987da915Sopenharmony_ci	 */
5327987da915Sopenharmony_ci	if (ntfs_attr_size_bounds_check(vol, na->type, newsize) < 0) {
5328987da915Sopenharmony_ci		err = errno;
5329987da915Sopenharmony_ci		if (err == ENOENT)
5330987da915Sopenharmony_ci			err = EIO;
5331987da915Sopenharmony_ci		ntfs_log_perror("%s: bounds check failed", __FUNCTION__);
5332987da915Sopenharmony_ci		goto put_err_out;
5333987da915Sopenharmony_ci	}
5334987da915Sopenharmony_ci	/*
5335987da915Sopenharmony_ci	 * If @newsize is bigger than the mft record we need to make the
5336987da915Sopenharmony_ci	 * attribute non-resident if the attribute type supports it. If it is
5337987da915Sopenharmony_ci	 * smaller we can go ahead and attempt the resize.
5338987da915Sopenharmony_ci	 */
5339987da915Sopenharmony_ci	if ((newsize < vol->mft_record_size) && (holes != HOLES_NONRES)) {
5340987da915Sopenharmony_ci		/* Perform the resize of the attribute record. */
5341987da915Sopenharmony_ci		if (!(ret = ntfs_resident_attr_value_resize(ctx->mrec, ctx->attr,
5342987da915Sopenharmony_ci				newsize))) {
5343987da915Sopenharmony_ci			/* Update attribute size everywhere. */
5344987da915Sopenharmony_ci			na->data_size = na->initialized_size = newsize;
5345987da915Sopenharmony_ci			na->allocated_size = (newsize + 7) & ~7;
5346987da915Sopenharmony_ci			if ((na->data_flags & ATTR_COMPRESSION_MASK)
5347987da915Sopenharmony_ci			    || NAttrSparse(na))
5348987da915Sopenharmony_ci				na->compressed_size = na->allocated_size;
5349987da915Sopenharmony_ci			if (na->ni->mrec->flags & MFT_RECORD_IS_DIRECTORY
5350987da915Sopenharmony_ci			    ? na->type == AT_INDEX_ROOT && na->name == NTFS_INDEX_I30
5351987da915Sopenharmony_ci			    : na->type == AT_DATA && na->name == AT_UNNAMED) {
5352987da915Sopenharmony_ci				na->ni->data_size = na->data_size;
5353987da915Sopenharmony_ci				if (((na->data_flags & ATTR_COMPRESSION_MASK)
5354987da915Sopenharmony_ci					|| NAttrSparse(na))
5355987da915Sopenharmony_ci						&& NAttrNonResident(na))
5356987da915Sopenharmony_ci					na->ni->allocated_size
5357987da915Sopenharmony_ci						= na->compressed_size;
5358987da915Sopenharmony_ci				else
5359987da915Sopenharmony_ci					na->ni->allocated_size
5360987da915Sopenharmony_ci						= na->allocated_size;
5361987da915Sopenharmony_ci				set_nino_flag(na->ni,KnownSize);
5362987da915Sopenharmony_ci				if (na->type == AT_DATA)
5363987da915Sopenharmony_ci					NInoFileNameSetDirty(na->ni);
5364987da915Sopenharmony_ci			}
5365987da915Sopenharmony_ci			goto resize_done;
5366987da915Sopenharmony_ci		}
5367987da915Sopenharmony_ci		/* Prefer AT_INDEX_ALLOCATION instead of AT_ATTRIBUTE_LIST */
5368987da915Sopenharmony_ci		if (ret == STATUS_RESIDENT_ATTRIBUTE_FILLED_MFT) {
5369987da915Sopenharmony_ci			err = errno;
5370987da915Sopenharmony_ci			goto put_err_out;
5371987da915Sopenharmony_ci		}
5372987da915Sopenharmony_ci	}
5373987da915Sopenharmony_ci	/* There is not enough space in the mft record to perform the resize. */
5374987da915Sopenharmony_ci
5375987da915Sopenharmony_ci	/* Make the attribute non-resident if possible. */
5376987da915Sopenharmony_ci	if (!ntfs_attr_make_non_resident(na, ctx)) {
5377987da915Sopenharmony_ci		ntfs_inode_mark_dirty(ctx->ntfs_ino);
5378987da915Sopenharmony_ci		ntfs_attr_put_search_ctx(ctx);
5379987da915Sopenharmony_ci		/*
5380987da915Sopenharmony_ci		 * do not truncate when forcing non-resident, this
5381987da915Sopenharmony_ci		 * could cause the attribute to be made resident again,
5382987da915Sopenharmony_ci		 * so size changes are not allowed.
5383987da915Sopenharmony_ci		 */
5384987da915Sopenharmony_ci		if (holes == HOLES_NONRES) {
5385987da915Sopenharmony_ci			ret = 0;
5386987da915Sopenharmony_ci			if (newsize != na->data_size) {
5387987da915Sopenharmony_ci				ntfs_log_error("Cannot change size when"
5388987da915Sopenharmony_ci					" forcing non-resident\n");
5389987da915Sopenharmony_ci				errno = EIO;
5390987da915Sopenharmony_ci				ret = STATUS_ERROR;
5391987da915Sopenharmony_ci			}
5392987da915Sopenharmony_ci			return (ret);
5393987da915Sopenharmony_ci		}
5394987da915Sopenharmony_ci		/* Resize non-resident attribute */
5395987da915Sopenharmony_ci		return ntfs_attr_truncate_i(na, newsize, holes);
5396987da915Sopenharmony_ci	} else if (errno != ENOSPC && errno != EPERM) {
5397987da915Sopenharmony_ci		err = errno;
5398987da915Sopenharmony_ci		ntfs_log_perror("Failed to make attribute non-resident");
5399987da915Sopenharmony_ci		goto put_err_out;
5400987da915Sopenharmony_ci	}
5401987da915Sopenharmony_ci
5402987da915Sopenharmony_ci	/* Try to make other attributes non-resident and retry each time. */
5403987da915Sopenharmony_ci	ntfs_attr_init_search_ctx(ctx, NULL, na->ni->mrec);
5404987da915Sopenharmony_ci	while (!ntfs_attr_lookup(AT_UNUSED, NULL, 0, 0, 0, NULL, 0, ctx)) {
5405987da915Sopenharmony_ci		ntfs_attr *tna;
5406987da915Sopenharmony_ci		ATTR_RECORD *a;
5407987da915Sopenharmony_ci
5408987da915Sopenharmony_ci		a = ctx->attr;
5409987da915Sopenharmony_ci		if (a->non_resident)
5410987da915Sopenharmony_ci			continue;
5411987da915Sopenharmony_ci
5412987da915Sopenharmony_ci		/*
5413987da915Sopenharmony_ci		 * Check out whether convert is reasonable. Assume that mapping
5414987da915Sopenharmony_ci		 * pairs will take 8 bytes.
5415987da915Sopenharmony_ci		 */
5416987da915Sopenharmony_ci		if (le32_to_cpu(a->length) <= offsetof(ATTR_RECORD,
5417987da915Sopenharmony_ci				compressed_size) + ((a->name_length *
5418987da915Sopenharmony_ci				sizeof(ntfschar) + 7) & ~7) + 8)
5419987da915Sopenharmony_ci			continue;
5420987da915Sopenharmony_ci
5421987da915Sopenharmony_ci		tna = ntfs_attr_open(na->ni, a->type, (ntfschar*)((u8*)a +
5422987da915Sopenharmony_ci				le16_to_cpu(a->name_offset)), a->name_length);
5423987da915Sopenharmony_ci		if (!tna) {
5424987da915Sopenharmony_ci			err = errno;
5425987da915Sopenharmony_ci			ntfs_log_perror("Couldn't open attribute");
5426987da915Sopenharmony_ci			goto put_err_out;
5427987da915Sopenharmony_ci		}
5428987da915Sopenharmony_ci		if (ntfs_attr_make_non_resident(tna, ctx)) {
5429987da915Sopenharmony_ci			ntfs_attr_close(tna);
5430987da915Sopenharmony_ci			continue;
5431987da915Sopenharmony_ci		}
5432987da915Sopenharmony_ci		if ((tna->type == AT_DATA) && !tna->name_len) {
5433987da915Sopenharmony_ci			/*
5434987da915Sopenharmony_ci			 * If we had to make the unnamed data attribute
5435987da915Sopenharmony_ci			 * non-resident, propagate its new allocated size
5436987da915Sopenharmony_ci			 * to all name attributes and directory indexes
5437987da915Sopenharmony_ci			 */
5438987da915Sopenharmony_ci			tna->ni->allocated_size = tna->allocated_size;
5439987da915Sopenharmony_ci			NInoFileNameSetDirty(tna->ni);
5440987da915Sopenharmony_ci		}
5441987da915Sopenharmony_ci		if (((tna->data_flags & ATTR_COMPRESSION_MASK)
5442987da915Sopenharmony_ci						== ATTR_IS_COMPRESSED)
5443987da915Sopenharmony_ci		   && ntfs_attr_pclose(tna)) {
5444987da915Sopenharmony_ci			err = errno;
5445987da915Sopenharmony_ci			ntfs_attr_close(tna);
5446987da915Sopenharmony_ci			goto put_err_out;
5447987da915Sopenharmony_ci		}
5448987da915Sopenharmony_ci		ntfs_inode_mark_dirty(tna->ni);
5449987da915Sopenharmony_ci		ntfs_attr_close(tna);
5450987da915Sopenharmony_ci		ntfs_attr_put_search_ctx(ctx);
5451987da915Sopenharmony_ci		return ntfs_resident_attr_resize_i(na, newsize, holes);
5452987da915Sopenharmony_ci	}
5453987da915Sopenharmony_ci	/* Check whether error occurred. */
5454987da915Sopenharmony_ci	if (errno != ENOENT) {
5455987da915Sopenharmony_ci		err = errno;
5456987da915Sopenharmony_ci		ntfs_log_perror("%s: Attribute lookup failed 1", __FUNCTION__);
5457987da915Sopenharmony_ci		goto put_err_out;
5458987da915Sopenharmony_ci	}
5459987da915Sopenharmony_ci
5460987da915Sopenharmony_ci	/*
5461987da915Sopenharmony_ci	 * The standard information and attribute list attributes can't be
5462987da915Sopenharmony_ci	 * moved out from the base MFT record, so try to move out others.
5463987da915Sopenharmony_ci	 */
5464987da915Sopenharmony_ci	if (na->type==AT_STANDARD_INFORMATION || na->type==AT_ATTRIBUTE_LIST) {
5465987da915Sopenharmony_ci		ntfs_attr_put_search_ctx(ctx);
5466987da915Sopenharmony_ci		if (!NInoAttrList(na->ni) && ntfs_inode_add_attrlist(na->ni)) {
5467987da915Sopenharmony_ci			ntfs_log_perror("Could not add attribute list");
5468987da915Sopenharmony_ci			return -1;
5469987da915Sopenharmony_ci		}
5470987da915Sopenharmony_ci		if (ntfs_inode_free_space(na->ni, offsetof(ATTR_RECORD,
5471987da915Sopenharmony_ci				non_resident_end) + 8)) {
5472987da915Sopenharmony_ci			ntfs_log_perror("Could not free space in MFT record");
5473987da915Sopenharmony_ci			return -1;
5474987da915Sopenharmony_ci		}
5475987da915Sopenharmony_ci		return ntfs_resident_attr_resize_i(na, newsize, holes);
5476987da915Sopenharmony_ci	}
5477987da915Sopenharmony_ci
5478987da915Sopenharmony_ci	/*
5479987da915Sopenharmony_ci	 * Move the attribute to a new mft record, creating an attribute list
5480987da915Sopenharmony_ci	 * attribute or modifying it if it is already present.
5481987da915Sopenharmony_ci	 */
5482987da915Sopenharmony_ci
5483987da915Sopenharmony_ci	/* Point search context back to attribute which we need resize. */
5484987da915Sopenharmony_ci	ntfs_attr_init_search_ctx(ctx, na->ni, NULL);
5485987da915Sopenharmony_ci	if (ntfs_attr_lookup(na->type, na->name, na->name_len, CASE_SENSITIVE,
5486987da915Sopenharmony_ci			0, NULL, 0, ctx)) {
5487987da915Sopenharmony_ci		ntfs_log_perror("%s: Attribute lookup failed 2", __FUNCTION__);
5488987da915Sopenharmony_ci		err = errno;
5489987da915Sopenharmony_ci		goto put_err_out;
5490987da915Sopenharmony_ci	}
5491987da915Sopenharmony_ci
5492987da915Sopenharmony_ci	/*
5493987da915Sopenharmony_ci	 * Check whether attribute is already single in this MFT record.
5494987da915Sopenharmony_ci	 * 8 added for the attribute terminator.
5495987da915Sopenharmony_ci	 */
5496987da915Sopenharmony_ci	if (le32_to_cpu(ctx->mrec->bytes_in_use) ==
5497987da915Sopenharmony_ci			le16_to_cpu(ctx->mrec->attrs_offset) +
5498987da915Sopenharmony_ci			le32_to_cpu(ctx->attr->length) + 8) {
5499987da915Sopenharmony_ci		err = ENOSPC;
5500987da915Sopenharmony_ci		ntfs_log_trace("MFT record is filled with one attribute\n");
5501987da915Sopenharmony_ci		ret = STATUS_RESIDENT_ATTRIBUTE_FILLED_MFT;
5502987da915Sopenharmony_ci		goto put_err_out;
5503987da915Sopenharmony_ci	}
5504987da915Sopenharmony_ci
5505987da915Sopenharmony_ci	/* Add attribute list if not present. */
5506987da915Sopenharmony_ci	if (na->ni->nr_extents == -1)
5507987da915Sopenharmony_ci		ni = na->ni->base_ni;
5508987da915Sopenharmony_ci	else
5509987da915Sopenharmony_ci		ni = na->ni;
5510987da915Sopenharmony_ci	if (!NInoAttrList(ni)) {
5511987da915Sopenharmony_ci		ntfs_attr_put_search_ctx(ctx);
5512987da915Sopenharmony_ci		if (ntfs_inode_add_attrlist(ni))
5513987da915Sopenharmony_ci			return -1;
5514987da915Sopenharmony_ci		return ntfs_resident_attr_resize_i(na, newsize, holes);
5515987da915Sopenharmony_ci	}
5516987da915Sopenharmony_ci	/* Allocate new mft record. */
5517987da915Sopenharmony_ci	ni = ntfs_mft_record_alloc(vol, ni);
5518987da915Sopenharmony_ci	if (!ni) {
5519987da915Sopenharmony_ci		err = errno;
5520987da915Sopenharmony_ci		ntfs_log_perror("Couldn't allocate new MFT record");
5521987da915Sopenharmony_ci		goto put_err_out;
5522987da915Sopenharmony_ci	}
5523987da915Sopenharmony_ci	/* Move attribute to it. */
5524987da915Sopenharmony_ci	if (ntfs_attr_record_move_to(ctx, ni)) {
5525987da915Sopenharmony_ci		err = errno;
5526987da915Sopenharmony_ci		ntfs_log_perror("Couldn't move attribute to new MFT record");
5527987da915Sopenharmony_ci		goto put_err_out;
5528987da915Sopenharmony_ci	}
5529987da915Sopenharmony_ci	/* Update ntfs attribute. */
5530987da915Sopenharmony_ci	if (na->ni->nr_extents == -1)
5531987da915Sopenharmony_ci		na->ni = ni;
5532987da915Sopenharmony_ci
5533987da915Sopenharmony_ci	ntfs_attr_put_search_ctx(ctx);
5534987da915Sopenharmony_ci	/* Try to perform resize once again. */
5535987da915Sopenharmony_ci	return ntfs_resident_attr_resize_i(na, newsize, holes);
5536987da915Sopenharmony_ci
5537987da915Sopenharmony_ciresize_done:
5538987da915Sopenharmony_ci	/*
5539987da915Sopenharmony_ci	 * Set the inode (and its base inode if it exists) dirty so it is
5540987da915Sopenharmony_ci	 * written out later.
5541987da915Sopenharmony_ci	 */
5542987da915Sopenharmony_ci	ntfs_inode_mark_dirty(ctx->ntfs_ino);
5543987da915Sopenharmony_ci	ntfs_attr_put_search_ctx(ctx);
5544987da915Sopenharmony_ci	return 0;
5545987da915Sopenharmony_ciput_err_out:
5546987da915Sopenharmony_ci	ntfs_attr_put_search_ctx(ctx);
5547987da915Sopenharmony_ci	errno = err;
5548987da915Sopenharmony_ci	return ret;
5549987da915Sopenharmony_ci}
5550987da915Sopenharmony_ci
5551987da915Sopenharmony_cistatic int ntfs_resident_attr_resize(ntfs_attr *na, const s64 newsize)
5552987da915Sopenharmony_ci{
5553987da915Sopenharmony_ci	int ret;
5554987da915Sopenharmony_ci
5555987da915Sopenharmony_ci	ntfs_log_enter("Entering\n");
5556987da915Sopenharmony_ci	ret = ntfs_resident_attr_resize_i(na, newsize, HOLES_OK);
5557987da915Sopenharmony_ci	ntfs_log_leave("\n");
5558987da915Sopenharmony_ci	return ret;
5559987da915Sopenharmony_ci}
5560987da915Sopenharmony_ci
5561987da915Sopenharmony_ci/*
5562987da915Sopenharmony_ci *		Force an attribute to be made non-resident without
5563987da915Sopenharmony_ci *	changing its size.
5564987da915Sopenharmony_ci *
5565987da915Sopenharmony_ci *	This is particularly needed when the attribute has no data,
5566987da915Sopenharmony_ci *	as the non-resident variant requires more space in the MFT
5567987da915Sopenharmony_ci *	record, and may imply expelling some other attribute.
5568987da915Sopenharmony_ci *
5569987da915Sopenharmony_ci *	As a consequence the existing ntfs_attr_search_ctx's have to
5570987da915Sopenharmony_ci *	be closed or reinitialized.
5571987da915Sopenharmony_ci *
5572987da915Sopenharmony_ci *	returns 0 if successful,
5573987da915Sopenharmony_ci *		< 0 if failed, with errno telling why
5574987da915Sopenharmony_ci */
5575987da915Sopenharmony_ci
5576987da915Sopenharmony_ciint ntfs_attr_force_non_resident(ntfs_attr *na)
5577987da915Sopenharmony_ci{
5578987da915Sopenharmony_ci	int res;
5579987da915Sopenharmony_ci
5580987da915Sopenharmony_ci	res = ntfs_resident_attr_resize_i(na, na->data_size, HOLES_NONRES);
5581987da915Sopenharmony_ci	if (!res && !NAttrNonResident(na)) {
5582987da915Sopenharmony_ci		res = -1;
5583987da915Sopenharmony_ci		errno = EIO;
5584987da915Sopenharmony_ci		ntfs_log_error("Failed to force non-resident\n");
5585987da915Sopenharmony_ci	}
5586987da915Sopenharmony_ci	return (res);
5587987da915Sopenharmony_ci}
5588987da915Sopenharmony_ci
5589987da915Sopenharmony_ci/**
5590987da915Sopenharmony_ci * ntfs_attr_make_resident - convert a non-resident to a resident attribute
5591987da915Sopenharmony_ci * @na:		open ntfs attribute to make resident
5592987da915Sopenharmony_ci * @ctx:	ntfs search context describing the attribute
5593987da915Sopenharmony_ci *
5594987da915Sopenharmony_ci * Convert a non-resident ntfs attribute to a resident one.
5595987da915Sopenharmony_ci *
5596987da915Sopenharmony_ci * Return 0 on success and -1 on error with errno set to the error code. The
5597987da915Sopenharmony_ci * following error codes are defined:
5598987da915Sopenharmony_ci *	EINVAL	   - Invalid arguments passed.
5599987da915Sopenharmony_ci *	EPERM	   - The attribute is not allowed to be resident.
5600987da915Sopenharmony_ci *	EIO	   - I/O error, damaged inode or bug.
5601987da915Sopenharmony_ci *	ENOSPC	   - There is no enough space to perform conversion.
5602987da915Sopenharmony_ci *	EOPNOTSUPP - Requested conversion is not supported yet.
5603987da915Sopenharmony_ci *
5604987da915Sopenharmony_ci * Warning: We do not set the inode dirty and we do not write out anything!
5605987da915Sopenharmony_ci *	    We expect the caller to do this as this is a fairly low level
5606987da915Sopenharmony_ci *	    function and it is likely there will be further changes made.
5607987da915Sopenharmony_ci */
5608987da915Sopenharmony_cistatic int ntfs_attr_make_resident(ntfs_attr *na, ntfs_attr_search_ctx *ctx)
5609987da915Sopenharmony_ci{
5610987da915Sopenharmony_ci	ntfs_volume *vol = na->ni->vol;
5611987da915Sopenharmony_ci	ATTR_REC *a = ctx->attr;
5612987da915Sopenharmony_ci	int name_ofs, val_ofs, err = EIO;
5613987da915Sopenharmony_ci	s64 arec_size, bytes_read;
5614987da915Sopenharmony_ci
5615987da915Sopenharmony_ci	ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x.\n", (unsigned long
5616987da915Sopenharmony_ci			long)na->ni->mft_no, le32_to_cpu(na->type));
5617987da915Sopenharmony_ci
5618987da915Sopenharmony_ci	/* Should be called for the first extent of the attribute. */
5619987da915Sopenharmony_ci	if (sle64_to_cpu(a->lowest_vcn)) {
5620987da915Sopenharmony_ci		ntfs_log_trace("Eeek!  Should be called for the first extent of the "
5621987da915Sopenharmony_ci				"attribute.  Aborting...\n");
5622987da915Sopenharmony_ci		errno = EINVAL;
5623987da915Sopenharmony_ci		return -1;
5624987da915Sopenharmony_ci	}
5625987da915Sopenharmony_ci
5626987da915Sopenharmony_ci	/* Some preliminary sanity checking. */
5627987da915Sopenharmony_ci	if (!NAttrNonResident(na)) {
5628987da915Sopenharmony_ci		ntfs_log_trace("Eeek!  Trying to make resident attribute resident.  "
5629987da915Sopenharmony_ci				"Aborting...\n");
5630987da915Sopenharmony_ci		errno = EINVAL;
5631987da915Sopenharmony_ci		return -1;
5632987da915Sopenharmony_ci	}
5633987da915Sopenharmony_ci
5634987da915Sopenharmony_ci	/* Make sure this is not $MFT/$BITMAP or Windows will not boot! */
5635987da915Sopenharmony_ci	if (na->type == AT_BITMAP && na->ni->mft_no == FILE_MFT) {
5636987da915Sopenharmony_ci		errno = EPERM;
5637987da915Sopenharmony_ci		return -1;
5638987da915Sopenharmony_ci	}
5639987da915Sopenharmony_ci
5640987da915Sopenharmony_ci	/* Check that the attribute is allowed to be resident. */
5641987da915Sopenharmony_ci	if (ntfs_attr_can_be_resident(vol, na->type))
5642987da915Sopenharmony_ci		return -1;
5643987da915Sopenharmony_ci
5644987da915Sopenharmony_ci	if (na->data_flags & ATTR_IS_ENCRYPTED) {
5645987da915Sopenharmony_ci		ntfs_log_trace("Making encrypted streams resident is not "
5646987da915Sopenharmony_ci				"implemented yet.\n");
5647987da915Sopenharmony_ci		errno = EOPNOTSUPP;
5648987da915Sopenharmony_ci		return -1;
5649987da915Sopenharmony_ci	}
5650987da915Sopenharmony_ci
5651987da915Sopenharmony_ci	/* Work out offsets into and size of the resident attribute. */
5652987da915Sopenharmony_ci	name_ofs = 24; /* = sizeof(resident_ATTR_REC); */
5653987da915Sopenharmony_ci	val_ofs = (name_ofs + a->name_length * sizeof(ntfschar) + 7) & ~7;
5654987da915Sopenharmony_ci	arec_size = (val_ofs + na->data_size + 7) & ~7;
5655987da915Sopenharmony_ci
5656987da915Sopenharmony_ci	/* Sanity check the size before we start modifying the attribute. */
5657987da915Sopenharmony_ci	if (le32_to_cpu(ctx->mrec->bytes_in_use) - le32_to_cpu(a->length) +
5658987da915Sopenharmony_ci			arec_size > le32_to_cpu(ctx->mrec->bytes_allocated)) {
5659987da915Sopenharmony_ci		errno = ENOSPC;
5660987da915Sopenharmony_ci		ntfs_log_trace("Not enough space to make attribute resident\n");
5661987da915Sopenharmony_ci		return -1;
5662987da915Sopenharmony_ci	}
5663987da915Sopenharmony_ci
5664987da915Sopenharmony_ci	/* Read and cache the whole runlist if not already done. */
5665987da915Sopenharmony_ci	if (ntfs_attr_map_whole_runlist(na))
5666987da915Sopenharmony_ci		return -1;
5667987da915Sopenharmony_ci
5668987da915Sopenharmony_ci	/* Move the attribute name if it exists and update the offset. */
5669987da915Sopenharmony_ci	if (a->name_length) {
5670987da915Sopenharmony_ci		memmove((u8*)a + name_ofs, (u8*)a + le16_to_cpu(a->name_offset),
5671987da915Sopenharmony_ci				a->name_length * sizeof(ntfschar));
5672987da915Sopenharmony_ci	}
5673987da915Sopenharmony_ci	a->name_offset = cpu_to_le16(name_ofs);
5674987da915Sopenharmony_ci
5675987da915Sopenharmony_ci	/* Resize the resident part of the attribute record. */
5676987da915Sopenharmony_ci	if (ntfs_attr_record_resize(ctx->mrec, a, arec_size) < 0) {
5677987da915Sopenharmony_ci		/*
5678987da915Sopenharmony_ci		 * Bug, because ntfs_attr_record_resize should not fail (we
5679987da915Sopenharmony_ci		 * already checked that attribute fits MFT record).
5680987da915Sopenharmony_ci		 */
5681987da915Sopenharmony_ci		ntfs_log_error("BUG! Failed to resize attribute record. "
5682987da915Sopenharmony_ci				"Please report to the %s.  Aborting...\n",
5683987da915Sopenharmony_ci				NTFS_DEV_LIST);
5684987da915Sopenharmony_ci		errno = EIO;
5685987da915Sopenharmony_ci		return -1;
5686987da915Sopenharmony_ci	}
5687987da915Sopenharmony_ci
5688987da915Sopenharmony_ci	/* Convert the attribute record to describe a resident attribute. */
5689987da915Sopenharmony_ci	a->non_resident = 0;
5690987da915Sopenharmony_ci	a->flags = const_cpu_to_le16(0);
5691987da915Sopenharmony_ci	a->value_length = cpu_to_le32(na->data_size);
5692987da915Sopenharmony_ci	a->value_offset = cpu_to_le16(val_ofs);
5693987da915Sopenharmony_ci	/*
5694987da915Sopenharmony_ci	 *  If a data stream was wiped out, adjust the compression mode
5695987da915Sopenharmony_ci	 *  to current state of compression flag
5696987da915Sopenharmony_ci	 */
5697987da915Sopenharmony_ci	if (!na->data_size
5698987da915Sopenharmony_ci	    && (na->type == AT_DATA)
5699987da915Sopenharmony_ci	    && (na->ni->vol->major_ver >= 3)
5700987da915Sopenharmony_ci	    && NVolCompression(na->ni->vol)
5701987da915Sopenharmony_ci	    && (na->ni->vol->cluster_size <= MAX_COMPRESSION_CLUSTER_SIZE)
5702987da915Sopenharmony_ci	    && (na->ni->flags & FILE_ATTR_COMPRESSED)) {
5703987da915Sopenharmony_ci		a->flags |= ATTR_IS_COMPRESSED;
5704987da915Sopenharmony_ci		na->data_flags = a->flags;
5705987da915Sopenharmony_ci	}
5706987da915Sopenharmony_ci	/*
5707987da915Sopenharmony_ci	 * File names cannot be non-resident so we would never see this here
5708987da915Sopenharmony_ci	 * but at least it serves as a reminder that there may be attributes
5709987da915Sopenharmony_ci	 * for which we do need to set this flag. (AIA)
5710987da915Sopenharmony_ci	 */
5711987da915Sopenharmony_ci	if (a->type == AT_FILE_NAME)
5712987da915Sopenharmony_ci		a->resident_flags = RESIDENT_ATTR_IS_INDEXED;
5713987da915Sopenharmony_ci	else
5714987da915Sopenharmony_ci		a->resident_flags = 0;
5715987da915Sopenharmony_ci	a->reservedR = 0;
5716987da915Sopenharmony_ci
5717987da915Sopenharmony_ci	/* Sanity fixup...  Shouldn't really happen. (AIA) */
5718987da915Sopenharmony_ci	if (na->initialized_size > na->data_size)
5719987da915Sopenharmony_ci		na->initialized_size = na->data_size;
5720987da915Sopenharmony_ci
5721987da915Sopenharmony_ci	/* Copy data from run list to resident attribute value. */
5722987da915Sopenharmony_ci	bytes_read = ntfs_rl_pread(vol, na->rl, 0, na->initialized_size,
5723987da915Sopenharmony_ci			(u8*)a + val_ofs);
5724987da915Sopenharmony_ci	if (bytes_read != na->initialized_size) {
5725987da915Sopenharmony_ci		if (bytes_read < 0)
5726987da915Sopenharmony_ci			err = errno;
5727987da915Sopenharmony_ci		ntfs_log_trace("Eeek! Failed to read attribute data. Leaving "
5728987da915Sopenharmony_ci				"inconstant metadata. Run chkdsk.  "
5729987da915Sopenharmony_ci				"Aborting...\n");
5730987da915Sopenharmony_ci		errno = err;
5731987da915Sopenharmony_ci		return -1;
5732987da915Sopenharmony_ci	}
5733987da915Sopenharmony_ci
5734987da915Sopenharmony_ci	/* Clear memory in gap between initialized_size and data_size. */
5735987da915Sopenharmony_ci	if (na->initialized_size < na->data_size)
5736987da915Sopenharmony_ci		memset((u8*)a + val_ofs + na->initialized_size, 0,
5737987da915Sopenharmony_ci				na->data_size - na->initialized_size);
5738987da915Sopenharmony_ci
5739987da915Sopenharmony_ci	/*
5740987da915Sopenharmony_ci	 * Deallocate clusters from the runlist.
5741987da915Sopenharmony_ci	 *
5742987da915Sopenharmony_ci	 * NOTE: We can use ntfs_cluster_free() because we have already mapped
5743987da915Sopenharmony_ci	 * the whole run list and thus it doesn't matter that the attribute
5744987da915Sopenharmony_ci	 * record is in a transiently corrupted state at this moment in time.
5745987da915Sopenharmony_ci	 */
5746987da915Sopenharmony_ci	if (ntfs_cluster_free(vol, na, 0, -1) < 0) {
5747987da915Sopenharmony_ci		ntfs_log_perror("Eeek! Failed to release allocated clusters");
5748987da915Sopenharmony_ci		ntfs_log_trace("Ignoring error and leaving behind wasted "
5749987da915Sopenharmony_ci				"clusters.\n");
5750987da915Sopenharmony_ci	}
5751987da915Sopenharmony_ci
5752987da915Sopenharmony_ci	/* Throw away the now unused runlist. */
5753987da915Sopenharmony_ci	free(na->rl);
5754987da915Sopenharmony_ci	na->rl = NULL;
5755987da915Sopenharmony_ci
5756987da915Sopenharmony_ci	/* Update in-memory struct ntfs_attr. */
5757987da915Sopenharmony_ci	NAttrClearNonResident(na);
5758987da915Sopenharmony_ci	NAttrClearFullyMapped(na);
5759987da915Sopenharmony_ci	NAttrClearSparse(na);
5760987da915Sopenharmony_ci	NAttrClearEncrypted(na);
5761987da915Sopenharmony_ci	na->initialized_size = na->data_size;
5762987da915Sopenharmony_ci	na->allocated_size = na->compressed_size = (na->data_size + 7) & ~7;
5763987da915Sopenharmony_ci	na->compression_block_size = 0;
5764987da915Sopenharmony_ci	na->compression_block_size_bits = na->compression_block_clusters = 0;
5765987da915Sopenharmony_ci	return 0;
5766987da915Sopenharmony_ci}
5767987da915Sopenharmony_ci
5768987da915Sopenharmony_ci/*
5769987da915Sopenharmony_ci * If we are in the first extent, then set/clean sparse bit,
5770987da915Sopenharmony_ci * update allocated and compressed size.
5771987da915Sopenharmony_ci */
5772987da915Sopenharmony_cistatic int ntfs_attr_update_meta(ATTR_RECORD *a, ntfs_attr *na, MFT_RECORD *m,
5773987da915Sopenharmony_ci				hole_type holes, ntfs_attr_search_ctx *ctx)
5774987da915Sopenharmony_ci{
5775987da915Sopenharmony_ci	int sparse, ret = 0;
5776987da915Sopenharmony_ci
5777987da915Sopenharmony_ci	ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x\n",
5778987da915Sopenharmony_ci		       (unsigned long long)na->ni->mft_no, le32_to_cpu(na->type));
5779987da915Sopenharmony_ci
5780987da915Sopenharmony_ci	if (a->lowest_vcn)
5781987da915Sopenharmony_ci		goto out;
5782987da915Sopenharmony_ci
5783987da915Sopenharmony_ci	a->allocated_size = cpu_to_sle64(na->allocated_size);
5784987da915Sopenharmony_ci
5785987da915Sopenharmony_ci	/* Update sparse bit, unless this is an intermediate state */
5786987da915Sopenharmony_ci	if (holes == HOLES_DELAY)
5787987da915Sopenharmony_ci		sparse = (a->flags & ATTR_IS_SPARSE) != const_cpu_to_le16(0);
5788987da915Sopenharmony_ci	else {
5789987da915Sopenharmony_ci		sparse = ntfs_rl_sparse(na->rl);
5790987da915Sopenharmony_ci		if (sparse == -1) {
5791987da915Sopenharmony_ci			errno = EIO;
5792987da915Sopenharmony_ci			goto error;
5793987da915Sopenharmony_ci		}
5794987da915Sopenharmony_ci	}
5795987da915Sopenharmony_ci
5796987da915Sopenharmony_ci	/* Check whether attribute becomes sparse, unless check is delayed. */
5797987da915Sopenharmony_ci	if ((holes != HOLES_DELAY)
5798987da915Sopenharmony_ci	    && sparse
5799987da915Sopenharmony_ci	    && !(a->flags & (ATTR_IS_SPARSE | ATTR_IS_COMPRESSED))) {
5800987da915Sopenharmony_ci		/*
5801987da915Sopenharmony_ci		 * Move attribute to another mft record, if attribute is too
5802987da915Sopenharmony_ci		 * small to add compressed_size field to it and we have no
5803987da915Sopenharmony_ci		 * free space in the current mft record.
5804987da915Sopenharmony_ci		 */
5805987da915Sopenharmony_ci		if ((le32_to_cpu(a->length) -
5806987da915Sopenharmony_ci				le16_to_cpu(a->mapping_pairs_offset) == 8)
5807987da915Sopenharmony_ci		    && !(le32_to_cpu(m->bytes_allocated) -
5808987da915Sopenharmony_ci				le32_to_cpu(m->bytes_in_use))) {
5809987da915Sopenharmony_ci
5810987da915Sopenharmony_ci			if (!NInoAttrList(na->ni)) {
5811987da915Sopenharmony_ci				ntfs_attr_put_search_ctx(ctx);
5812987da915Sopenharmony_ci				if (ntfs_inode_add_attrlist(na->ni))
5813987da915Sopenharmony_ci					goto leave;
5814987da915Sopenharmony_ci				goto retry;
5815987da915Sopenharmony_ci			}
5816987da915Sopenharmony_ci			if (ntfs_attr_record_move_away(ctx, 8)) {
5817987da915Sopenharmony_ci				ntfs_log_perror("Failed to move attribute");
5818987da915Sopenharmony_ci				goto error;
5819987da915Sopenharmony_ci			}
5820987da915Sopenharmony_ci			ntfs_attr_put_search_ctx(ctx);
5821987da915Sopenharmony_ci			goto retry;
5822987da915Sopenharmony_ci		}
5823987da915Sopenharmony_ci		if (!(le32_to_cpu(a->length) - le16_to_cpu(
5824987da915Sopenharmony_ci						a->mapping_pairs_offset))) {
5825987da915Sopenharmony_ci			errno = EIO;
5826987da915Sopenharmony_ci			ntfs_log_perror("Mapping pairs space is 0");
5827987da915Sopenharmony_ci			goto error;
5828987da915Sopenharmony_ci		}
5829987da915Sopenharmony_ci
5830987da915Sopenharmony_ci		NAttrSetSparse(na);
5831987da915Sopenharmony_ci		a->flags |= ATTR_IS_SPARSE;
5832987da915Sopenharmony_ci		na->data_flags = a->flags;
5833987da915Sopenharmony_ci		a->compression_unit = STANDARD_COMPRESSION_UNIT;  /* Windows
5834987da915Sopenharmony_ci		 set it so, even if attribute is not actually compressed. */
5835987da915Sopenharmony_ci
5836987da915Sopenharmony_ci		memmove((u8*)a + le16_to_cpu(a->name_offset) + 8,
5837987da915Sopenharmony_ci			(u8*)a + le16_to_cpu(a->name_offset),
5838987da915Sopenharmony_ci			a->name_length * sizeof(ntfschar));
5839987da915Sopenharmony_ci
5840987da915Sopenharmony_ci		a->name_offset = cpu_to_le16(le16_to_cpu(a->name_offset) + 8);
5841987da915Sopenharmony_ci
5842987da915Sopenharmony_ci		a->mapping_pairs_offset =
5843987da915Sopenharmony_ci			cpu_to_le16(le16_to_cpu(a->mapping_pairs_offset) + 8);
5844987da915Sopenharmony_ci	}
5845987da915Sopenharmony_ci
5846987da915Sopenharmony_ci	/* Attribute no longer sparse. */
5847987da915Sopenharmony_ci	if (!sparse && (a->flags & ATTR_IS_SPARSE) &&
5848987da915Sopenharmony_ci	    !(a->flags & ATTR_IS_COMPRESSED)) {
5849987da915Sopenharmony_ci
5850987da915Sopenharmony_ci		NAttrClearSparse(na);
5851987da915Sopenharmony_ci		a->flags &= ~ATTR_IS_SPARSE;
5852987da915Sopenharmony_ci		na->data_flags = a->flags;
5853987da915Sopenharmony_ci		a->compression_unit = 0;
5854987da915Sopenharmony_ci
5855987da915Sopenharmony_ci		memmove((u8*)a + le16_to_cpu(a->name_offset) - 8,
5856987da915Sopenharmony_ci			(u8*)a + le16_to_cpu(a->name_offset),
5857987da915Sopenharmony_ci			a->name_length * sizeof(ntfschar));
5858987da915Sopenharmony_ci
5859987da915Sopenharmony_ci		if (le16_to_cpu(a->name_offset) >= 8)
5860987da915Sopenharmony_ci			a->name_offset = cpu_to_le16(le16_to_cpu(a->name_offset) - 8);
5861987da915Sopenharmony_ci
5862987da915Sopenharmony_ci		a->mapping_pairs_offset =
5863987da915Sopenharmony_ci			cpu_to_le16(le16_to_cpu(a->mapping_pairs_offset) - 8);
5864987da915Sopenharmony_ci	}
5865987da915Sopenharmony_ci
5866987da915Sopenharmony_ci	/* Update compressed size if required. */
5867987da915Sopenharmony_ci	if (NAttrFullyMapped(na)
5868987da915Sopenharmony_ci	    && (sparse || (na->data_flags & ATTR_COMPRESSION_MASK))) {
5869987da915Sopenharmony_ci		s64 new_compr_size;
5870987da915Sopenharmony_ci
5871987da915Sopenharmony_ci		new_compr_size = ntfs_rl_get_compressed_size(na->ni->vol, na->rl);
5872987da915Sopenharmony_ci		if (new_compr_size == -1)
5873987da915Sopenharmony_ci			goto error;
5874987da915Sopenharmony_ci
5875987da915Sopenharmony_ci		na->compressed_size = new_compr_size;
5876987da915Sopenharmony_ci		a->compressed_size = cpu_to_sle64(new_compr_size);
5877987da915Sopenharmony_ci	}
5878987da915Sopenharmony_ci	/*
5879987da915Sopenharmony_ci	 * Set FILE_NAME dirty flag, to update sparse bit and
5880987da915Sopenharmony_ci	 * allocated size in the index.
5881987da915Sopenharmony_ci	 */
5882987da915Sopenharmony_ci	if (na->type == AT_DATA && na->name == AT_UNNAMED) {
5883987da915Sopenharmony_ci		if (sparse || (na->data_flags & ATTR_COMPRESSION_MASK))
5884987da915Sopenharmony_ci			na->ni->allocated_size = na->compressed_size;
5885987da915Sopenharmony_ci		else
5886987da915Sopenharmony_ci			na->ni->allocated_size = na->allocated_size;
5887987da915Sopenharmony_ci		NInoFileNameSetDirty(na->ni);
5888987da915Sopenharmony_ci	}
5889987da915Sopenharmony_ciout:
5890987da915Sopenharmony_ci	return ret;
5891987da915Sopenharmony_cileave:	ret = -1; goto out;  /* return -1 */
5892987da915Sopenharmony_ciretry:	ret = -2; goto out;
5893987da915Sopenharmony_cierror:  ret = -3; goto out;
5894987da915Sopenharmony_ci}
5895987da915Sopenharmony_ci
5896987da915Sopenharmony_ci#define NTFS_VCN_DELETE_MARK -2
5897987da915Sopenharmony_ci/**
5898987da915Sopenharmony_ci * ntfs_attr_update_mapping_pairs_i - see ntfs_attr_update_mapping_pairs
5899987da915Sopenharmony_ci */
5900987da915Sopenharmony_cistatic int ntfs_attr_update_mapping_pairs_i(ntfs_attr *na, VCN from_vcn,
5901987da915Sopenharmony_ci					hole_type holes)
5902987da915Sopenharmony_ci{
5903987da915Sopenharmony_ci	ntfs_attr_search_ctx *ctx;
5904987da915Sopenharmony_ci	ntfs_inode *ni, *base_ni;
5905987da915Sopenharmony_ci	MFT_RECORD *m;
5906987da915Sopenharmony_ci	ATTR_RECORD *a;
5907987da915Sopenharmony_ci	VCN stop_vcn;
5908987da915Sopenharmony_ci	const runlist_element *stop_rl;
5909987da915Sopenharmony_ci	int err, mp_size, cur_max_mp_size, exp_max_mp_size, ret = -1;
5910987da915Sopenharmony_ci	BOOL finished_build;
5911987da915Sopenharmony_ci	BOOL first_updated = FALSE;
5912987da915Sopenharmony_ci
5913987da915Sopenharmony_ciretry:
5914987da915Sopenharmony_ci	if (!na || !na->rl) {
5915987da915Sopenharmony_ci		errno = EINVAL;
5916987da915Sopenharmony_ci		ntfs_log_perror("%s: na=%p", __FUNCTION__, na);
5917987da915Sopenharmony_ci		return -1;
5918987da915Sopenharmony_ci	}
5919987da915Sopenharmony_ci
5920987da915Sopenharmony_ci	ntfs_log_trace("Entering for inode %llu, attr 0x%x\n",
5921987da915Sopenharmony_ci		       (unsigned long long)na->ni->mft_no, le32_to_cpu(na->type));
5922987da915Sopenharmony_ci
5923987da915Sopenharmony_ci	if (!NAttrNonResident(na)) {
5924987da915Sopenharmony_ci		errno = EINVAL;
5925987da915Sopenharmony_ci		ntfs_log_perror("%s: resident attribute", __FUNCTION__);
5926987da915Sopenharmony_ci		return -1;
5927987da915Sopenharmony_ci	}
5928987da915Sopenharmony_ci
5929987da915Sopenharmony_ci#if PARTIAL_RUNLIST_UPDATING
5930987da915Sopenharmony_ci		/*
5931987da915Sopenharmony_ci		 * For a file just been made sparse, we will have
5932987da915Sopenharmony_ci		 * to reformat the first extent, so be sure the
5933987da915Sopenharmony_ci		 * runlist is fully mapped and fully processed.
5934987da915Sopenharmony_ci		 * Same if the file was sparse and is not any more.
5935987da915Sopenharmony_ci		 * Note : not needed if the full runlist is to be processed
5936987da915Sopenharmony_ci		 */
5937987da915Sopenharmony_ci	if ((holes != HOLES_DELAY)
5938987da915Sopenharmony_ci	   && (!NAttrFullyMapped(na) || from_vcn)
5939987da915Sopenharmony_ci	   && !(na->data_flags & ATTR_IS_COMPRESSED)) {
5940987da915Sopenharmony_ci		BOOL changed;
5941987da915Sopenharmony_ci
5942987da915Sopenharmony_ci		if (!(na->data_flags & ATTR_IS_SPARSE)) {
5943987da915Sopenharmony_ci			int sparse = 0;
5944987da915Sopenharmony_ci			runlist_element *xrl;
5945987da915Sopenharmony_ci
5946987da915Sopenharmony_ci				/*
5947987da915Sopenharmony_ci				 * If attribute was not sparse, we only
5948987da915Sopenharmony_ci				 * have to check whether there is a hole
5949987da915Sopenharmony_ci				 * in the updated region.
5950987da915Sopenharmony_ci				 */
5951987da915Sopenharmony_ci			for (xrl = na->rl; xrl->length; xrl++) {
5952987da915Sopenharmony_ci				if (xrl->lcn < 0) {
5953987da915Sopenharmony_ci					if (xrl->lcn == LCN_HOLE) {
5954987da915Sopenharmony_ci						sparse = 1;
5955987da915Sopenharmony_ci						break;
5956987da915Sopenharmony_ci					}
5957987da915Sopenharmony_ci					if (xrl->lcn != LCN_RL_NOT_MAPPED) {
5958987da915Sopenharmony_ci						sparse = -1;
5959987da915Sopenharmony_ci						break;
5960987da915Sopenharmony_ci					}
5961987da915Sopenharmony_ci				}
5962987da915Sopenharmony_ci			}
5963987da915Sopenharmony_ci			if (sparse < 0) {
5964987da915Sopenharmony_ci				ntfs_log_error("Could not check whether sparse\n");
5965987da915Sopenharmony_ci				errno = EIO;
5966987da915Sopenharmony_ci				return (-1);
5967987da915Sopenharmony_ci			}
5968987da915Sopenharmony_ci			changed = sparse > 0;
5969987da915Sopenharmony_ci		} else {
5970987da915Sopenharmony_ci				/*
5971987da915Sopenharmony_ci				 * If attribute was sparse, the compressed
5972987da915Sopenharmony_ci				 * size has been maintained, and it gives
5973987da915Sopenharmony_ci				 * and easy way to check whether the
5974987da915Sopenharmony_ci				 * attribute is still sparse.
5975987da915Sopenharmony_ci				 */
5976987da915Sopenharmony_ci			changed = (((na->data_size - 1)
5977987da915Sopenharmony_ci					| (na->ni->vol->cluster_size - 1)) + 1)
5978987da915Sopenharmony_ci				== na->compressed_size;
5979987da915Sopenharmony_ci		}
5980987da915Sopenharmony_ci		if (changed) {
5981987da915Sopenharmony_ci			if (ntfs_attr_map_whole_runlist(na)) {
5982987da915Sopenharmony_ci				ntfs_log_error("Could not map whole for sparse change\n");
5983987da915Sopenharmony_ci				errno = EIO;
5984987da915Sopenharmony_ci				return (-1);
5985987da915Sopenharmony_ci			}
5986987da915Sopenharmony_ci			from_vcn = 0;
5987987da915Sopenharmony_ci		}
5988987da915Sopenharmony_ci	}
5989987da915Sopenharmony_ci#endif
5990987da915Sopenharmony_ci	if (na->ni->nr_extents == -1)
5991987da915Sopenharmony_ci		base_ni = na->ni->base_ni;
5992987da915Sopenharmony_ci	else
5993987da915Sopenharmony_ci		base_ni = na->ni;
5994987da915Sopenharmony_ci
5995987da915Sopenharmony_ci	ctx = ntfs_attr_get_search_ctx(base_ni, NULL);
5996987da915Sopenharmony_ci	if (!ctx)
5997987da915Sopenharmony_ci		return -1;
5998987da915Sopenharmony_ci
5999987da915Sopenharmony_ci	/* Fill attribute records with new mapping pairs. */
6000987da915Sopenharmony_ci	stop_vcn = 0;
6001987da915Sopenharmony_ci	stop_rl = na->rl;
6002987da915Sopenharmony_ci	finished_build = FALSE;
6003987da915Sopenharmony_ci	while (!ntfs_attr_lookup(na->type, na->name, na->name_len,
6004987da915Sopenharmony_ci				CASE_SENSITIVE, from_vcn, NULL, 0, ctx)) {
6005987da915Sopenharmony_ci		a = ctx->attr;
6006987da915Sopenharmony_ci		m = ctx->mrec;
6007987da915Sopenharmony_ci		if (!a->lowest_vcn)
6008987da915Sopenharmony_ci			first_updated = TRUE;
6009987da915Sopenharmony_ci		/*
6010987da915Sopenharmony_ci		 * If runlist is updating not from the beginning, then set
6011987da915Sopenharmony_ci		 * @stop_vcn properly, i.e. to the lowest vcn of record that
6012987da915Sopenharmony_ci		 * contain @from_vcn. Also we do not need @from_vcn anymore,
6013987da915Sopenharmony_ci		 * set it to 0 to make ntfs_attr_lookup enumerate attributes.
6014987da915Sopenharmony_ci		 */
6015987da915Sopenharmony_ci		if (from_vcn) {
6016987da915Sopenharmony_ci			LCN first_lcn;
6017987da915Sopenharmony_ci
6018987da915Sopenharmony_ci			stop_vcn = sle64_to_cpu(a->lowest_vcn);
6019987da915Sopenharmony_ci			from_vcn = 0;
6020987da915Sopenharmony_ci			/*
6021987da915Sopenharmony_ci			 * Check whether the first run we need to update is
6022987da915Sopenharmony_ci			 * the last run in runlist, if so, then deallocate
6023987da915Sopenharmony_ci			 * all attrubute extents starting this one.
6024987da915Sopenharmony_ci			 */
6025987da915Sopenharmony_ci			first_lcn = ntfs_rl_vcn_to_lcn(na->rl, stop_vcn);
6026987da915Sopenharmony_ci			if (first_lcn == LCN_EINVAL) {
6027987da915Sopenharmony_ci				errno = EIO;
6028987da915Sopenharmony_ci				ntfs_log_perror("Bad runlist");
6029987da915Sopenharmony_ci				goto put_err_out;
6030987da915Sopenharmony_ci			}
6031987da915Sopenharmony_ci			if (first_lcn == LCN_ENOENT ||
6032987da915Sopenharmony_ci					first_lcn == LCN_RL_NOT_MAPPED)
6033987da915Sopenharmony_ci				finished_build = TRUE;
6034987da915Sopenharmony_ci		}
6035987da915Sopenharmony_ci
6036987da915Sopenharmony_ci		/*
6037987da915Sopenharmony_ci		 * Check whether we finished mapping pairs build, if so mark
6038987da915Sopenharmony_ci		 * extent as need to delete (by setting highest vcn to
6039987da915Sopenharmony_ci		 * NTFS_VCN_DELETE_MARK (-2), we shall check it later and
6040987da915Sopenharmony_ci		 * delete extent) and continue search.
6041987da915Sopenharmony_ci		 */
6042987da915Sopenharmony_ci		if (finished_build) {
6043987da915Sopenharmony_ci			ntfs_log_trace("Mark attr 0x%x for delete in inode "
6044987da915Sopenharmony_ci				"%lld.\n", (unsigned)le32_to_cpu(a->type),
6045987da915Sopenharmony_ci				(long long)ctx->ntfs_ino->mft_no);
6046987da915Sopenharmony_ci			a->highest_vcn = cpu_to_sle64(NTFS_VCN_DELETE_MARK);
6047987da915Sopenharmony_ci			ntfs_inode_mark_dirty(ctx->ntfs_ino);
6048987da915Sopenharmony_ci			continue;
6049987da915Sopenharmony_ci		}
6050987da915Sopenharmony_ci
6051987da915Sopenharmony_ci		switch (ntfs_attr_update_meta(a, na, m, holes, ctx)) {
6052987da915Sopenharmony_ci			case -1: return -1;
6053987da915Sopenharmony_ci			case -2: goto retry;
6054987da915Sopenharmony_ci			case -3: goto put_err_out;
6055987da915Sopenharmony_ci		}
6056987da915Sopenharmony_ci
6057987da915Sopenharmony_ci		/*
6058987da915Sopenharmony_ci		 * Determine maximum possible length of mapping pairs,
6059987da915Sopenharmony_ci		 * if we shall *not* expand space for mapping pairs.
6060987da915Sopenharmony_ci		 */
6061987da915Sopenharmony_ci		cur_max_mp_size = le32_to_cpu(a->length) -
6062987da915Sopenharmony_ci				le16_to_cpu(a->mapping_pairs_offset);
6063987da915Sopenharmony_ci		/*
6064987da915Sopenharmony_ci		 * Determine maximum possible length of mapping pairs in the
6065987da915Sopenharmony_ci		 * current mft record, if we shall expand space for mapping
6066987da915Sopenharmony_ci		 * pairs.
6067987da915Sopenharmony_ci		 */
6068987da915Sopenharmony_ci		exp_max_mp_size = le32_to_cpu(m->bytes_allocated) -
6069987da915Sopenharmony_ci				le32_to_cpu(m->bytes_in_use) + cur_max_mp_size;
6070987da915Sopenharmony_ci		/* Get the size for the rest of mapping pairs array. */
6071987da915Sopenharmony_ci		mp_size = ntfs_get_size_for_mapping_pairs(na->ni->vol, stop_rl,
6072987da915Sopenharmony_ci						stop_vcn, exp_max_mp_size);
6073987da915Sopenharmony_ci		if (mp_size <= 0) {
6074987da915Sopenharmony_ci			ntfs_log_perror("%s: get MP size failed", __FUNCTION__);
6075987da915Sopenharmony_ci			goto put_err_out;
6076987da915Sopenharmony_ci		}
6077987da915Sopenharmony_ci		/* Test mapping pairs for fitting in the current mft record. */
6078987da915Sopenharmony_ci		if (mp_size > exp_max_mp_size) {
6079987da915Sopenharmony_ci			/*
6080987da915Sopenharmony_ci			 * Mapping pairs of $ATTRIBUTE_LIST attribute must fit
6081987da915Sopenharmony_ci			 * in the base mft record. Try to move out other
6082987da915Sopenharmony_ci			 * attributes and try again.
6083987da915Sopenharmony_ci			 */
6084987da915Sopenharmony_ci			if (na->type == AT_ATTRIBUTE_LIST) {
6085987da915Sopenharmony_ci				ntfs_attr_put_search_ctx(ctx);
6086987da915Sopenharmony_ci				if (ntfs_inode_free_space(na->ni, mp_size -
6087987da915Sopenharmony_ci							cur_max_mp_size)) {
6088987da915Sopenharmony_ci					ntfs_log_perror("Attribute list is too "
6089987da915Sopenharmony_ci							"big. Defragment the "
6090987da915Sopenharmony_ci							"volume\n");
6091987da915Sopenharmony_ci					return -1;
6092987da915Sopenharmony_ci				}
6093987da915Sopenharmony_ci				goto retry;
6094987da915Sopenharmony_ci			}
6095987da915Sopenharmony_ci
6096987da915Sopenharmony_ci			/* Add attribute list if it isn't present, and retry. */
6097987da915Sopenharmony_ci			if (!NInoAttrList(base_ni)) {
6098987da915Sopenharmony_ci				ntfs_attr_put_search_ctx(ctx);
6099987da915Sopenharmony_ci				if (ntfs_inode_add_attrlist(base_ni)) {
6100987da915Sopenharmony_ci					ntfs_log_perror("Can not add attrlist");
6101987da915Sopenharmony_ci					return -1;
6102987da915Sopenharmony_ci				}
6103987da915Sopenharmony_ci				goto retry;
6104987da915Sopenharmony_ci			}
6105987da915Sopenharmony_ci
6106987da915Sopenharmony_ci			/*
6107987da915Sopenharmony_ci			 * Set mapping pairs size to maximum possible for this
6108987da915Sopenharmony_ci			 * mft record. We shall write the rest of mapping pairs
6109987da915Sopenharmony_ci			 * to another MFT records.
6110987da915Sopenharmony_ci			 */
6111987da915Sopenharmony_ci			mp_size = exp_max_mp_size;
6112987da915Sopenharmony_ci		}
6113987da915Sopenharmony_ci
6114987da915Sopenharmony_ci		/* Change space for mapping pairs if we need it. */
6115987da915Sopenharmony_ci		if (((mp_size + 7) & ~7) != cur_max_mp_size) {
6116987da915Sopenharmony_ci			if (ntfs_attr_record_resize(m, a,
6117987da915Sopenharmony_ci					le16_to_cpu(a->mapping_pairs_offset) +
6118987da915Sopenharmony_ci					mp_size)) {
6119987da915Sopenharmony_ci				errno = EIO;
6120987da915Sopenharmony_ci				ntfs_log_perror("Failed to resize attribute");
6121987da915Sopenharmony_ci				goto put_err_out;
6122987da915Sopenharmony_ci			}
6123987da915Sopenharmony_ci		}
6124987da915Sopenharmony_ci
6125987da915Sopenharmony_ci		/* Update lowest vcn. */
6126987da915Sopenharmony_ci		a->lowest_vcn = cpu_to_sle64(stop_vcn);
6127987da915Sopenharmony_ci		ntfs_inode_mark_dirty(ctx->ntfs_ino);
6128987da915Sopenharmony_ci		if ((ctx->ntfs_ino->nr_extents == -1 ||
6129987da915Sopenharmony_ci					NInoAttrList(ctx->ntfs_ino)) &&
6130987da915Sopenharmony_ci					ctx->attr->type != AT_ATTRIBUTE_LIST) {
6131987da915Sopenharmony_ci			ctx->al_entry->lowest_vcn = cpu_to_sle64(stop_vcn);
6132987da915Sopenharmony_ci			ntfs_attrlist_mark_dirty(ctx->ntfs_ino);
6133987da915Sopenharmony_ci		}
6134987da915Sopenharmony_ci
6135987da915Sopenharmony_ci		/*
6136987da915Sopenharmony_ci		 * Generate the new mapping pairs array directly into the
6137987da915Sopenharmony_ci		 * correct destination, i.e. the attribute record itself.
6138987da915Sopenharmony_ci		 */
6139987da915Sopenharmony_ci		if (!ntfs_mapping_pairs_build(na->ni->vol, (u8*)a + le16_to_cpu(
6140987da915Sopenharmony_ci				a->mapping_pairs_offset), mp_size, na->rl,
6141987da915Sopenharmony_ci				stop_vcn, &stop_rl))
6142987da915Sopenharmony_ci			finished_build = TRUE;
6143987da915Sopenharmony_ci		if (stop_rl)
6144987da915Sopenharmony_ci			stop_vcn = stop_rl->vcn;
6145987da915Sopenharmony_ci		else
6146987da915Sopenharmony_ci			stop_vcn = 0;
6147987da915Sopenharmony_ci		if (!finished_build && errno != ENOSPC) {
6148987da915Sopenharmony_ci			ntfs_log_perror("Failed to build mapping pairs");
6149987da915Sopenharmony_ci			goto put_err_out;
6150987da915Sopenharmony_ci		}
6151987da915Sopenharmony_ci		a->highest_vcn = cpu_to_sle64(stop_vcn - 1);
6152987da915Sopenharmony_ci	}
6153987da915Sopenharmony_ci	/* Check whether error occurred. */
6154987da915Sopenharmony_ci	if (errno != ENOENT) {
6155987da915Sopenharmony_ci		ntfs_log_perror("%s: Attribute lookup failed", __FUNCTION__);
6156987da915Sopenharmony_ci		goto put_err_out;
6157987da915Sopenharmony_ci	}
6158987da915Sopenharmony_ci		/*
6159987da915Sopenharmony_ci		 * If the base extent was skipped in the above process,
6160987da915Sopenharmony_ci		 * we still may have to update the sizes.
6161987da915Sopenharmony_ci		 */
6162987da915Sopenharmony_ci	if (!first_updated) {
6163987da915Sopenharmony_ci		le16 spcomp;
6164987da915Sopenharmony_ci
6165987da915Sopenharmony_ci		ntfs_attr_reinit_search_ctx(ctx);
6166987da915Sopenharmony_ci		if (!ntfs_attr_lookup(na->type, na->name, na->name_len,
6167987da915Sopenharmony_ci				CASE_SENSITIVE, 0, NULL, 0, ctx)) {
6168987da915Sopenharmony_ci			a = ctx->attr;
6169987da915Sopenharmony_ci			a->allocated_size = cpu_to_sle64(na->allocated_size);
6170987da915Sopenharmony_ci			spcomp = na->data_flags
6171987da915Sopenharmony_ci				& (ATTR_IS_COMPRESSED | ATTR_IS_SPARSE);
6172987da915Sopenharmony_ci			if (spcomp)
6173987da915Sopenharmony_ci				a->compressed_size = cpu_to_sle64(na->compressed_size);
6174987da915Sopenharmony_ci			/* Updating sizes taints the extent holding the attr */
6175987da915Sopenharmony_ci			if (ctx->ntfs_ino)
6176987da915Sopenharmony_ci				NInoSetDirty(ctx->ntfs_ino);
6177987da915Sopenharmony_ci			if ((na->type == AT_DATA) && (na->name == AT_UNNAMED)) {
6178987da915Sopenharmony_ci				na->ni->allocated_size
6179987da915Sopenharmony_ci					= (spcomp
6180987da915Sopenharmony_ci						? na->compressed_size
6181987da915Sopenharmony_ci						: na->allocated_size);
6182987da915Sopenharmony_ci				NInoFileNameSetDirty(na->ni);
6183987da915Sopenharmony_ci			}
6184987da915Sopenharmony_ci		} else {
6185987da915Sopenharmony_ci			ntfs_log_error("Failed to update sizes in base extent\n");
6186987da915Sopenharmony_ci			goto put_err_out;
6187987da915Sopenharmony_ci		}
6188987da915Sopenharmony_ci	}
6189987da915Sopenharmony_ci
6190987da915Sopenharmony_ci	/* Deallocate not used attribute extents and return with success. */
6191987da915Sopenharmony_ci	if (finished_build) {
6192987da915Sopenharmony_ci		ntfs_attr_reinit_search_ctx(ctx);
6193987da915Sopenharmony_ci		ntfs_log_trace("Deallocate marked extents.\n");
6194987da915Sopenharmony_ci		while (!ntfs_attr_lookup(na->type, na->name, na->name_len,
6195987da915Sopenharmony_ci				CASE_SENSITIVE, 0, NULL, 0, ctx)) {
6196987da915Sopenharmony_ci			if (sle64_to_cpu(ctx->attr->highest_vcn) !=
6197987da915Sopenharmony_ci							NTFS_VCN_DELETE_MARK)
6198987da915Sopenharmony_ci				continue;
6199987da915Sopenharmony_ci			/* Remove unused attribute record. */
6200987da915Sopenharmony_ci			if (ntfs_attr_record_rm(ctx)) {
6201987da915Sopenharmony_ci				ntfs_log_perror("Could not remove unused attr");
6202987da915Sopenharmony_ci				goto put_err_out;
6203987da915Sopenharmony_ci			}
6204987da915Sopenharmony_ci			ntfs_attr_reinit_search_ctx(ctx);
6205987da915Sopenharmony_ci		}
6206987da915Sopenharmony_ci		if (errno != ENOENT) {
6207987da915Sopenharmony_ci			ntfs_log_perror("%s: Attr lookup failed", __FUNCTION__);
6208987da915Sopenharmony_ci			goto put_err_out;
6209987da915Sopenharmony_ci		}
6210987da915Sopenharmony_ci		ntfs_log_trace("Deallocate done.\n");
6211987da915Sopenharmony_ci		ntfs_attr_put_search_ctx(ctx);
6212987da915Sopenharmony_ci		goto ok;
6213987da915Sopenharmony_ci	}
6214987da915Sopenharmony_ci	ntfs_attr_put_search_ctx(ctx);
6215987da915Sopenharmony_ci	ctx = NULL;
6216987da915Sopenharmony_ci
6217987da915Sopenharmony_ci	/* Allocate new MFT records for the rest of mapping pairs. */
6218987da915Sopenharmony_ci	while (1) {
6219987da915Sopenharmony_ci		/* Calculate size of rest mapping pairs. */
6220987da915Sopenharmony_ci		mp_size = ntfs_get_size_for_mapping_pairs(na->ni->vol,
6221987da915Sopenharmony_ci						na->rl, stop_vcn, INT_MAX);
6222987da915Sopenharmony_ci		if (mp_size <= 0) {
6223987da915Sopenharmony_ci			ntfs_log_perror("%s: get mp size failed", __FUNCTION__);
6224987da915Sopenharmony_ci			goto put_err_out;
6225987da915Sopenharmony_ci		}
6226987da915Sopenharmony_ci		/* Allocate new mft record, with special case for mft itself */
6227987da915Sopenharmony_ci		if (!na->ni->mft_no)
6228987da915Sopenharmony_ci			ni = ntfs_mft_rec_alloc(na->ni->vol,
6229987da915Sopenharmony_ci				na->type == AT_DATA);
6230987da915Sopenharmony_ci		else
6231987da915Sopenharmony_ci			ni = ntfs_mft_record_alloc(na->ni->vol, base_ni);
6232987da915Sopenharmony_ci		if (!ni) {
6233987da915Sopenharmony_ci			ntfs_log_perror("Could not allocate new MFT record");
6234987da915Sopenharmony_ci			goto put_err_out;
6235987da915Sopenharmony_ci		}
6236987da915Sopenharmony_ci		m = ni->mrec;
6237987da915Sopenharmony_ci		/*
6238987da915Sopenharmony_ci		 * If mapping size exceed available space, set them to
6239987da915Sopenharmony_ci		 * possible maximum.
6240987da915Sopenharmony_ci		 */
6241987da915Sopenharmony_ci		cur_max_mp_size = le32_to_cpu(m->bytes_allocated) -
6242987da915Sopenharmony_ci				le32_to_cpu(m->bytes_in_use) -
6243987da915Sopenharmony_ci				(offsetof(ATTR_RECORD, compressed_size) +
6244987da915Sopenharmony_ci				(((na->data_flags & ATTR_COMPRESSION_MASK)
6245987da915Sopenharmony_ci				    || NAttrSparse(na)) ?
6246987da915Sopenharmony_ci				sizeof(a->compressed_size) : 0)) -
6247987da915Sopenharmony_ci				((sizeof(ntfschar) * na->name_len + 7) & ~7);
6248987da915Sopenharmony_ci		if (mp_size > cur_max_mp_size)
6249987da915Sopenharmony_ci			mp_size = cur_max_mp_size;
6250987da915Sopenharmony_ci		/* Add attribute extent to new record. */
6251987da915Sopenharmony_ci		err = ntfs_non_resident_attr_record_add(ni, na->type,
6252987da915Sopenharmony_ci			na->name, na->name_len, stop_vcn, mp_size,
6253987da915Sopenharmony_ci			na->data_flags);
6254987da915Sopenharmony_ci		if (err == -1) {
6255987da915Sopenharmony_ci			err = errno;
6256987da915Sopenharmony_ci			ntfs_log_perror("Could not add attribute extent");
6257987da915Sopenharmony_ci			if (ntfs_mft_record_free(na->ni->vol, ni))
6258987da915Sopenharmony_ci				ntfs_log_perror("Could not free MFT record");
6259987da915Sopenharmony_ci			errno = err;
6260987da915Sopenharmony_ci			goto put_err_out;
6261987da915Sopenharmony_ci		}
6262987da915Sopenharmony_ci		a = (ATTR_RECORD*)((u8*)m + err);
6263987da915Sopenharmony_ci
6264987da915Sopenharmony_ci		err = ntfs_mapping_pairs_build(na->ni->vol, (u8*)a +
6265987da915Sopenharmony_ci			le16_to_cpu(a->mapping_pairs_offset), mp_size, na->rl,
6266987da915Sopenharmony_ci			stop_vcn, &stop_rl);
6267987da915Sopenharmony_ci		if (stop_rl)
6268987da915Sopenharmony_ci			stop_vcn = stop_rl->vcn;
6269987da915Sopenharmony_ci		else
6270987da915Sopenharmony_ci			stop_vcn = 0;
6271987da915Sopenharmony_ci		if (err < 0 && errno != ENOSPC) {
6272987da915Sopenharmony_ci			err = errno;
6273987da915Sopenharmony_ci			ntfs_log_perror("Failed to build MP");
6274987da915Sopenharmony_ci			if (ntfs_mft_record_free(na->ni->vol, ni))
6275987da915Sopenharmony_ci				ntfs_log_perror("Couldn't free MFT record");
6276987da915Sopenharmony_ci			errno = err;
6277987da915Sopenharmony_ci			goto put_err_out;
6278987da915Sopenharmony_ci		}
6279987da915Sopenharmony_ci		a->highest_vcn = cpu_to_sle64(stop_vcn - 1);
6280987da915Sopenharmony_ci		ntfs_inode_mark_dirty(ni);
6281987da915Sopenharmony_ci		/* All mapping pairs has been written. */
6282987da915Sopenharmony_ci		if (!err)
6283987da915Sopenharmony_ci			break;
6284987da915Sopenharmony_ci	}
6285987da915Sopenharmony_ciok:
6286987da915Sopenharmony_ci	NAttrClearRunlistDirty(na);
6287987da915Sopenharmony_ci	ret = 0;
6288987da915Sopenharmony_ciout:
6289987da915Sopenharmony_ci	return ret;
6290987da915Sopenharmony_ciput_err_out:
6291987da915Sopenharmony_ci	if (ctx)
6292987da915Sopenharmony_ci		ntfs_attr_put_search_ctx(ctx);
6293987da915Sopenharmony_ci	goto out;
6294987da915Sopenharmony_ci}
6295987da915Sopenharmony_ci#undef NTFS_VCN_DELETE_MARK
6296987da915Sopenharmony_ci
6297987da915Sopenharmony_ci/**
6298987da915Sopenharmony_ci * ntfs_attr_update_mapping_pairs - update mapping pairs for ntfs attribute
6299987da915Sopenharmony_ci * @na:		non-resident ntfs open attribute for which we need update
6300987da915Sopenharmony_ci * @from_vcn:	update runlist starting this VCN
6301987da915Sopenharmony_ci *
6302987da915Sopenharmony_ci * Build mapping pairs from @na->rl and write them to the disk. Also, this
6303987da915Sopenharmony_ci * function updates sparse bit, allocated and compressed size (allocates/frees
6304987da915Sopenharmony_ci * space for this field if required).
6305987da915Sopenharmony_ci *
6306987da915Sopenharmony_ci * @na->allocated_size should be set to correct value for the new runlist before
6307987da915Sopenharmony_ci * call to this function. Vice-versa @na->compressed_size will be calculated and
6308987da915Sopenharmony_ci * set to correct value during this function.
6309987da915Sopenharmony_ci *
6310987da915Sopenharmony_ci * FIXME: This function does not update sparse bit and compressed size correctly
6311987da915Sopenharmony_ci * if called with @from_vcn != 0.
6312987da915Sopenharmony_ci *
6313987da915Sopenharmony_ci * FIXME: Rewrite without using NTFS_VCN_DELETE_MARK define.
6314987da915Sopenharmony_ci *
6315987da915Sopenharmony_ci * On success return 0 and on error return -1 with errno set to the error code.
6316987da915Sopenharmony_ci * The following error codes are defined:
6317987da915Sopenharmony_ci *	EINVAL - Invalid arguments passed.
6318987da915Sopenharmony_ci *	ENOMEM - Not enough memory to complete operation.
6319987da915Sopenharmony_ci *	ENOSPC - There is no enough space in base mft to resize $ATTRIBUTE_LIST
6320987da915Sopenharmony_ci *		 or there is no free MFT records left to allocate.
6321987da915Sopenharmony_ci */
6322987da915Sopenharmony_ciint ntfs_attr_update_mapping_pairs(ntfs_attr *na, VCN from_vcn)
6323987da915Sopenharmony_ci{
6324987da915Sopenharmony_ci	int ret;
6325987da915Sopenharmony_ci
6326987da915Sopenharmony_ci	ntfs_log_enter("Entering\n");
6327987da915Sopenharmony_ci	ret = ntfs_attr_update_mapping_pairs_i(na, from_vcn, HOLES_OK);
6328987da915Sopenharmony_ci	ntfs_log_leave("\n");
6329987da915Sopenharmony_ci	return ret;
6330987da915Sopenharmony_ci}
6331987da915Sopenharmony_ci
6332987da915Sopenharmony_ci/**
6333987da915Sopenharmony_ci * ntfs_non_resident_attr_shrink - shrink a non-resident, open ntfs attribute
6334987da915Sopenharmony_ci * @na:		non-resident ntfs attribute to shrink
6335987da915Sopenharmony_ci * @newsize:	new size (in bytes) to which to shrink the attribute
6336987da915Sopenharmony_ci *
6337987da915Sopenharmony_ci * Reduce the size of a non-resident, open ntfs attribute @na to @newsize bytes.
6338987da915Sopenharmony_ci *
6339987da915Sopenharmony_ci * On success return 0 and on error return -1 with errno set to the error code.
6340987da915Sopenharmony_ci * The following error codes are defined:
6341987da915Sopenharmony_ci *	ENOMEM	- Not enough memory to complete operation.
6342987da915Sopenharmony_ci *	ERANGE	- @newsize is not valid for the attribute type of @na.
6343987da915Sopenharmony_ci */
6344987da915Sopenharmony_cistatic int ntfs_non_resident_attr_shrink(ntfs_attr *na, const s64 newsize)
6345987da915Sopenharmony_ci{
6346987da915Sopenharmony_ci	ntfs_volume *vol;
6347987da915Sopenharmony_ci	ntfs_attr_search_ctx *ctx;
6348987da915Sopenharmony_ci	VCN first_free_vcn;
6349987da915Sopenharmony_ci	s64 nr_freed_clusters;
6350987da915Sopenharmony_ci	int err;
6351987da915Sopenharmony_ci
6352987da915Sopenharmony_ci	ntfs_log_trace("Inode 0x%llx attr 0x%x new size %lld\n", (unsigned long long)
6353987da915Sopenharmony_ci		       na->ni->mft_no, le32_to_cpu(na->type), (long long)newsize);
6354987da915Sopenharmony_ci
6355987da915Sopenharmony_ci	vol = na->ni->vol;
6356987da915Sopenharmony_ci
6357987da915Sopenharmony_ci	/*
6358987da915Sopenharmony_ci	 * Check the attribute type and the corresponding minimum size
6359987da915Sopenharmony_ci	 * against @newsize and fail if @newsize is too small.
6360987da915Sopenharmony_ci	 */
6361987da915Sopenharmony_ci	if (ntfs_attr_size_bounds_check(vol, na->type, newsize) < 0) {
6362987da915Sopenharmony_ci		if (errno == ERANGE) {
6363987da915Sopenharmony_ci			ntfs_log_trace("Eeek! Size bounds check failed. "
6364987da915Sopenharmony_ci					"Aborting...\n");
6365987da915Sopenharmony_ci		} else if (errno == ENOENT)
6366987da915Sopenharmony_ci			errno = EIO;
6367987da915Sopenharmony_ci		return -1;
6368987da915Sopenharmony_ci	}
6369987da915Sopenharmony_ci
6370987da915Sopenharmony_ci	/* The first cluster outside the new allocation. */
6371987da915Sopenharmony_ci	if (na->data_flags & ATTR_COMPRESSION_MASK)
6372987da915Sopenharmony_ci		/*
6373987da915Sopenharmony_ci		 * For compressed files we must keep full compressions blocks,
6374987da915Sopenharmony_ci		 * but currently we do not decompress/recompress the last
6375987da915Sopenharmony_ci		 * block to truncate the data, so we may leave more allocated
6376987da915Sopenharmony_ci		 * clusters than really needed.
6377987da915Sopenharmony_ci		 */
6378987da915Sopenharmony_ci		first_free_vcn = (((newsize - 1)
6379987da915Sopenharmony_ci				 | (na->compression_block_size - 1)) + 1)
6380987da915Sopenharmony_ci				   >> vol->cluster_size_bits;
6381987da915Sopenharmony_ci	else
6382987da915Sopenharmony_ci		first_free_vcn = (newsize + vol->cluster_size - 1) >>
6383987da915Sopenharmony_ci				vol->cluster_size_bits;
6384987da915Sopenharmony_ci	/*
6385987da915Sopenharmony_ci	 * Compare the new allocation with the old one and only deallocate
6386987da915Sopenharmony_ci	 * clusters if there is a change.
6387987da915Sopenharmony_ci	 */
6388987da915Sopenharmony_ci	if ((na->allocated_size >> vol->cluster_size_bits) != first_free_vcn) {
6389987da915Sopenharmony_ci		if (ntfs_attr_map_whole_runlist(na)) {
6390987da915Sopenharmony_ci			ntfs_log_trace("Eeek! ntfs_attr_map_whole_runlist "
6391987da915Sopenharmony_ci					"failed.\n");
6392987da915Sopenharmony_ci			return -1;
6393987da915Sopenharmony_ci		}
6394987da915Sopenharmony_ci		/* Deallocate all clusters starting with the first free one. */
6395987da915Sopenharmony_ci		nr_freed_clusters = ntfs_cluster_free(vol, na, first_free_vcn,
6396987da915Sopenharmony_ci				-1);
6397987da915Sopenharmony_ci		if (nr_freed_clusters < 0) {
6398987da915Sopenharmony_ci			ntfs_log_trace("Eeek! Freeing of clusters failed. "
6399987da915Sopenharmony_ci					"Aborting...\n");
6400987da915Sopenharmony_ci			return -1;
6401987da915Sopenharmony_ci		}
6402987da915Sopenharmony_ci
6403987da915Sopenharmony_ci		/* Truncate the runlist itself. */
6404987da915Sopenharmony_ci		if (ntfs_rl_truncate(&na->rl, first_free_vcn)) {
6405987da915Sopenharmony_ci			/*
6406987da915Sopenharmony_ci			 * Failed to truncate the runlist, so just throw it
6407987da915Sopenharmony_ci			 * away, it will be mapped afresh on next use.
6408987da915Sopenharmony_ci			 */
6409987da915Sopenharmony_ci			free(na->rl);
6410987da915Sopenharmony_ci			na->rl = NULL;
6411987da915Sopenharmony_ci			ntfs_log_trace("Eeek! Run list truncation failed.\n");
6412987da915Sopenharmony_ci			return -1;
6413987da915Sopenharmony_ci		}
6414987da915Sopenharmony_ci		NAttrSetRunlistDirty(na);
6415987da915Sopenharmony_ci
6416987da915Sopenharmony_ci		/* Prepare to mapping pairs update. */
6417987da915Sopenharmony_ci		na->allocated_size = first_free_vcn << vol->cluster_size_bits;
6418987da915Sopenharmony_ci		/* Write mapping pairs for new runlist. */
6419987da915Sopenharmony_ci		if (ntfs_attr_update_mapping_pairs(na, 0 /*first_free_vcn*/)) {
6420987da915Sopenharmony_ci			ntfs_log_trace("Eeek! Mapping pairs update failed. "
6421987da915Sopenharmony_ci					"Leaving inconstant metadata. "
6422987da915Sopenharmony_ci					"Run chkdsk.\n");
6423987da915Sopenharmony_ci			return -1;
6424987da915Sopenharmony_ci		}
6425987da915Sopenharmony_ci	}
6426987da915Sopenharmony_ci
6427987da915Sopenharmony_ci	/* Get the first attribute record. */
6428987da915Sopenharmony_ci	ctx = ntfs_attr_get_search_ctx(na->ni, NULL);
6429987da915Sopenharmony_ci	if (!ctx)
6430987da915Sopenharmony_ci		return -1;
6431987da915Sopenharmony_ci
6432987da915Sopenharmony_ci	if (ntfs_attr_lookup(na->type, na->name, na->name_len, CASE_SENSITIVE,
6433987da915Sopenharmony_ci			0, NULL, 0, ctx)) {
6434987da915Sopenharmony_ci		err = errno;
6435987da915Sopenharmony_ci		if (err == ENOENT)
6436987da915Sopenharmony_ci			err = EIO;
6437987da915Sopenharmony_ci		ntfs_log_trace("Eeek! Lookup of first attribute extent failed. "
6438987da915Sopenharmony_ci				"Leaving inconstant metadata.\n");
6439987da915Sopenharmony_ci		goto put_err_out;
6440987da915Sopenharmony_ci	}
6441987da915Sopenharmony_ci
6442987da915Sopenharmony_ci	/* Update data and initialized size. */
6443987da915Sopenharmony_ci	na->data_size = newsize;
6444987da915Sopenharmony_ci	ctx->attr->data_size = cpu_to_sle64(newsize);
6445987da915Sopenharmony_ci	if (newsize < na->initialized_size) {
6446987da915Sopenharmony_ci		na->initialized_size = newsize;
6447987da915Sopenharmony_ci		ctx->attr->initialized_size = cpu_to_sle64(newsize);
6448987da915Sopenharmony_ci	}
6449987da915Sopenharmony_ci	/* Update data size in the index. */
6450987da915Sopenharmony_ci	if (na->ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) {
6451987da915Sopenharmony_ci		if (na->type == AT_INDEX_ROOT && na->name == NTFS_INDEX_I30) {
6452987da915Sopenharmony_ci			na->ni->data_size = na->data_size;
6453987da915Sopenharmony_ci			na->ni->allocated_size = na->allocated_size;
6454987da915Sopenharmony_ci			set_nino_flag(na->ni,KnownSize);
6455987da915Sopenharmony_ci		}
6456987da915Sopenharmony_ci	} else {
6457987da915Sopenharmony_ci		if (na->type == AT_DATA && na->name == AT_UNNAMED) {
6458987da915Sopenharmony_ci			na->ni->data_size = na->data_size;
6459987da915Sopenharmony_ci			NInoFileNameSetDirty(na->ni);
6460987da915Sopenharmony_ci		}
6461987da915Sopenharmony_ci	}
6462987da915Sopenharmony_ci
6463987da915Sopenharmony_ci	/* If the attribute now has zero size, make it resident. */
6464987da915Sopenharmony_ci	if (!newsize) {
6465987da915Sopenharmony_ci		if (!(na->data_flags & ATTR_IS_ENCRYPTED)
6466987da915Sopenharmony_ci		    && ntfs_attr_make_resident(na, ctx)) {
6467987da915Sopenharmony_ci			/* If couldn't make resident, just continue. */
6468987da915Sopenharmony_ci			if (errno != EPERM)
6469987da915Sopenharmony_ci				ntfs_log_error("Failed to make attribute "
6470987da915Sopenharmony_ci						"resident. Leaving as is...\n");
6471987da915Sopenharmony_ci		}
6472987da915Sopenharmony_ci	}
6473987da915Sopenharmony_ci
6474987da915Sopenharmony_ci	/* Set the inode dirty so it is written out later. */
6475987da915Sopenharmony_ci	ntfs_inode_mark_dirty(ctx->ntfs_ino);
6476987da915Sopenharmony_ci	/* Done! */
6477987da915Sopenharmony_ci	ntfs_attr_put_search_ctx(ctx);
6478987da915Sopenharmony_ci	return 0;
6479987da915Sopenharmony_ciput_err_out:
6480987da915Sopenharmony_ci	ntfs_attr_put_search_ctx(ctx);
6481987da915Sopenharmony_ci	errno = err;
6482987da915Sopenharmony_ci	return -1;
6483987da915Sopenharmony_ci}
6484987da915Sopenharmony_ci
6485987da915Sopenharmony_ci/**
6486987da915Sopenharmony_ci * ntfs_non_resident_attr_expand - expand a non-resident, open ntfs attribute
6487987da915Sopenharmony_ci * @na:		non-resident ntfs attribute to expand
6488987da915Sopenharmony_ci * @newsize:	new size (in bytes) to which to expand the attribute
6489987da915Sopenharmony_ci *
6490987da915Sopenharmony_ci * Expand the size of a non-resident, open ntfs attribute @na to @newsize bytes,
6491987da915Sopenharmony_ci * by allocating new clusters.
6492987da915Sopenharmony_ci *
6493987da915Sopenharmony_ci * On success return 0 and on error return -1 with errno set to the error code.
6494987da915Sopenharmony_ci * The following error codes are defined:
6495987da915Sopenharmony_ci *	ENOMEM - Not enough memory to complete operation.
6496987da915Sopenharmony_ci *	ERANGE - @newsize is not valid for the attribute type of @na.
6497987da915Sopenharmony_ci *	ENOSPC - There is no enough space in base mft to resize $ATTRIBUTE_LIST.
6498987da915Sopenharmony_ci */
6499987da915Sopenharmony_cistatic int ntfs_non_resident_attr_expand_i(ntfs_attr *na, const s64 newsize,
6500987da915Sopenharmony_ci					hole_type holes)
6501987da915Sopenharmony_ci{
6502987da915Sopenharmony_ci	LCN lcn_seek_from;
6503987da915Sopenharmony_ci	VCN first_free_vcn;
6504987da915Sopenharmony_ci	ntfs_volume *vol;
6505987da915Sopenharmony_ci	ntfs_attr_search_ctx *ctx;
6506987da915Sopenharmony_ci	runlist *rl, *rln;
6507987da915Sopenharmony_ci	s64 org_alloc_size;
6508987da915Sopenharmony_ci	int err;
6509987da915Sopenharmony_ci
6510987da915Sopenharmony_ci	ntfs_log_trace("Inode %lld, attr 0x%x, new size %lld old size %lld\n",
6511987da915Sopenharmony_ci			(unsigned long long)na->ni->mft_no, le32_to_cpu(na->type),
6512987da915Sopenharmony_ci			(long long)newsize, (long long)na->data_size);
6513987da915Sopenharmony_ci
6514987da915Sopenharmony_ci	vol = na->ni->vol;
6515987da915Sopenharmony_ci
6516987da915Sopenharmony_ci	/*
6517987da915Sopenharmony_ci	 * Check the attribute type and the corresponding maximum size
6518987da915Sopenharmony_ci	 * against @newsize and fail if @newsize is too big.
6519987da915Sopenharmony_ci	 */
6520987da915Sopenharmony_ci	if (ntfs_attr_size_bounds_check(vol, na->type, newsize) < 0) {
6521987da915Sopenharmony_ci		if (errno == ENOENT)
6522987da915Sopenharmony_ci			errno = EIO;
6523987da915Sopenharmony_ci		ntfs_log_perror("%s: bounds check failed", __FUNCTION__);
6524987da915Sopenharmony_ci		return -1;
6525987da915Sopenharmony_ci	}
6526987da915Sopenharmony_ci
6527987da915Sopenharmony_ci	if (na->type == AT_DATA)
6528987da915Sopenharmony_ci		NAttrSetDataAppending(na);
6529987da915Sopenharmony_ci	/* Save for future use. */
6530987da915Sopenharmony_ci	org_alloc_size = na->allocated_size;
6531987da915Sopenharmony_ci	/* The first cluster outside the new allocation. */
6532987da915Sopenharmony_ci	first_free_vcn = (newsize + vol->cluster_size - 1) >>
6533987da915Sopenharmony_ci			vol->cluster_size_bits;
6534987da915Sopenharmony_ci	/*
6535987da915Sopenharmony_ci	 * Compare the new allocation with the old one and only allocate
6536987da915Sopenharmony_ci	 * clusters if there is a change.
6537987da915Sopenharmony_ci	 */
6538987da915Sopenharmony_ci	if ((na->allocated_size >> vol->cluster_size_bits) < first_free_vcn) {
6539987da915Sopenharmony_ci#if PARTIAL_RUNLIST_UPDATING
6540987da915Sopenharmony_ci		s64 start_update;
6541987da915Sopenharmony_ci
6542987da915Sopenharmony_ci		/*
6543987da915Sopenharmony_ci		 * Update from the last previously allocated run,
6544987da915Sopenharmony_ci		 * as we may have to expand an existing hole.
6545987da915Sopenharmony_ci		 */
6546987da915Sopenharmony_ci		start_update = na->allocated_size >> vol->cluster_size_bits;
6547987da915Sopenharmony_ci		if (start_update)
6548987da915Sopenharmony_ci			start_update--;
6549987da915Sopenharmony_ci		if (ntfs_attr_map_partial_runlist(na, start_update)) {
6550987da915Sopenharmony_ci			ntfs_log_perror("failed to map partial runlist");
6551987da915Sopenharmony_ci			return -1;
6552987da915Sopenharmony_ci		}
6553987da915Sopenharmony_ci#else
6554987da915Sopenharmony_ci		if (ntfs_attr_map_whole_runlist(na)) {
6555987da915Sopenharmony_ci			ntfs_log_perror("ntfs_attr_map_whole_runlist failed");
6556987da915Sopenharmony_ci			return -1;
6557987da915Sopenharmony_ci		}
6558987da915Sopenharmony_ci#endif
6559987da915Sopenharmony_ci
6560987da915Sopenharmony_ci		/*
6561987da915Sopenharmony_ci		 * If we extend $DATA attribute on NTFS 3+ volume, we can add
6562987da915Sopenharmony_ci		 * sparse runs instead of real allocation of clusters.
6563987da915Sopenharmony_ci		 */
6564987da915Sopenharmony_ci		if ((na->type == AT_DATA) && (vol->major_ver >= 3)
6565987da915Sopenharmony_ci					 && (holes != HOLES_NO)) {
6566987da915Sopenharmony_ci			rl = ntfs_malloc(0x1000);
6567987da915Sopenharmony_ci			if (!rl)
6568987da915Sopenharmony_ci				return -1;
6569987da915Sopenharmony_ci
6570987da915Sopenharmony_ci			rl[0].vcn = (na->allocated_size >>
6571987da915Sopenharmony_ci					vol->cluster_size_bits);
6572987da915Sopenharmony_ci			rl[0].lcn = LCN_HOLE;
6573987da915Sopenharmony_ci			rl[0].length = first_free_vcn -
6574987da915Sopenharmony_ci				(na->allocated_size >> vol->cluster_size_bits);
6575987da915Sopenharmony_ci			rl[1].vcn = first_free_vcn;
6576987da915Sopenharmony_ci			rl[1].lcn = LCN_ENOENT;
6577987da915Sopenharmony_ci			rl[1].length = 0;
6578987da915Sopenharmony_ci		} else {
6579987da915Sopenharmony_ci			/*
6580987da915Sopenharmony_ci			 * Determine first after last LCN of attribute.
6581987da915Sopenharmony_ci			 * We will start seek clusters from this LCN to avoid
6582987da915Sopenharmony_ci			 * fragmentation.  If there are no valid LCNs in the
6583987da915Sopenharmony_ci			 * attribute let the cluster allocator choose the
6584987da915Sopenharmony_ci			 * starting LCN.
6585987da915Sopenharmony_ci			 */
6586987da915Sopenharmony_ci			lcn_seek_from = -1;
6587987da915Sopenharmony_ci			if (na->rl->length) {
6588987da915Sopenharmony_ci				/* Seek to the last run list element. */
6589987da915Sopenharmony_ci				for (rl = na->rl; (rl + 1)->length; rl++)
6590987da915Sopenharmony_ci					;
6591987da915Sopenharmony_ci				/*
6592987da915Sopenharmony_ci				 * If the last LCN is a hole or similar seek
6593987da915Sopenharmony_ci				 * back to last valid LCN.
6594987da915Sopenharmony_ci				 */
6595987da915Sopenharmony_ci				while (rl->lcn < 0 && rl != na->rl)
6596987da915Sopenharmony_ci					rl--;
6597987da915Sopenharmony_ci				/*
6598987da915Sopenharmony_ci				 * Only set lcn_seek_from it the LCN is valid.
6599987da915Sopenharmony_ci				 */
6600987da915Sopenharmony_ci				if (rl->lcn >= 0)
6601987da915Sopenharmony_ci					lcn_seek_from = rl->lcn + rl->length;
6602987da915Sopenharmony_ci			}
6603987da915Sopenharmony_ci
6604987da915Sopenharmony_ci			rl = ntfs_cluster_alloc(vol, na->allocated_size >>
6605987da915Sopenharmony_ci					vol->cluster_size_bits, first_free_vcn -
6606987da915Sopenharmony_ci					(na->allocated_size >>
6607987da915Sopenharmony_ci					vol->cluster_size_bits), lcn_seek_from,
6608987da915Sopenharmony_ci					DATA_ZONE);
6609987da915Sopenharmony_ci			if (!rl) {
6610987da915Sopenharmony_ci				ntfs_log_perror("Cluster allocation failed "
6611987da915Sopenharmony_ci						"(%lld)",
6612987da915Sopenharmony_ci						(long long)first_free_vcn -
6613987da915Sopenharmony_ci						((long long)na->allocated_size >>
6614987da915Sopenharmony_ci						 vol->cluster_size_bits));
6615987da915Sopenharmony_ci				return -1;
6616987da915Sopenharmony_ci			}
6617987da915Sopenharmony_ci		}
6618987da915Sopenharmony_ci
6619987da915Sopenharmony_ci		/* Append new clusters to attribute runlist. */
6620987da915Sopenharmony_ci		rln = ntfs_runlists_merge(na->rl, rl);
6621987da915Sopenharmony_ci		if (!rln) {
6622987da915Sopenharmony_ci			/* Failed, free just allocated clusters. */
6623987da915Sopenharmony_ci			err = errno;
6624987da915Sopenharmony_ci			ntfs_log_perror("Run list merge failed");
6625987da915Sopenharmony_ci			ntfs_cluster_free_from_rl(vol, rl);
6626987da915Sopenharmony_ci			free(rl);
6627987da915Sopenharmony_ci			errno = err;
6628987da915Sopenharmony_ci			return -1;
6629987da915Sopenharmony_ci		}
6630987da915Sopenharmony_ci		na->rl = rln;
6631987da915Sopenharmony_ci		NAttrSetRunlistDirty(na);
6632987da915Sopenharmony_ci
6633987da915Sopenharmony_ci		/* Prepare to mapping pairs update. */
6634987da915Sopenharmony_ci		na->allocated_size = first_free_vcn << vol->cluster_size_bits;
6635987da915Sopenharmony_ci#if PARTIAL_RUNLIST_UPDATING
6636987da915Sopenharmony_ci		/*
6637987da915Sopenharmony_ci		 * Write mapping pairs for new runlist, unless this is
6638987da915Sopenharmony_ci		 * a temporary state before appending data.
6639987da915Sopenharmony_ci		 * If the update is not done, we must be sure to do
6640987da915Sopenharmony_ci		 * it later, and to get to a clean state even on errors.
6641987da915Sopenharmony_ci		 */
6642987da915Sopenharmony_ci		if ((holes != HOLES_DELAY)
6643987da915Sopenharmony_ci		   && ntfs_attr_update_mapping_pairs_i(na, start_update,
6644987da915Sopenharmony_ci					holes)) {
6645987da915Sopenharmony_ci#else
6646987da915Sopenharmony_ci		/* Write mapping pairs for new runlist. */
6647987da915Sopenharmony_ci		if (ntfs_attr_update_mapping_pairs(na, 0)) {
6648987da915Sopenharmony_ci#endif
6649987da915Sopenharmony_ci			err = errno;
6650987da915Sopenharmony_ci			ntfs_log_perror("Mapping pairs update failed");
6651987da915Sopenharmony_ci			goto rollback;
6652987da915Sopenharmony_ci		}
6653987da915Sopenharmony_ci	}
6654987da915Sopenharmony_ci
6655987da915Sopenharmony_ci	ctx = ntfs_attr_get_search_ctx(na->ni, NULL);
6656987da915Sopenharmony_ci	if (!ctx) {
6657987da915Sopenharmony_ci		err = errno;
6658987da915Sopenharmony_ci		if (na->allocated_size == org_alloc_size) {
6659987da915Sopenharmony_ci			errno = err;
6660987da915Sopenharmony_ci			return -1;
6661987da915Sopenharmony_ci		} else
6662987da915Sopenharmony_ci			goto rollback;
6663987da915Sopenharmony_ci	}
6664987da915Sopenharmony_ci
6665987da915Sopenharmony_ci	if (ntfs_attr_lookup(na->type, na->name, na->name_len, CASE_SENSITIVE,
6666987da915Sopenharmony_ci			0, NULL, 0, ctx)) {
6667987da915Sopenharmony_ci		err = errno;
6668987da915Sopenharmony_ci		ntfs_log_perror("Lookup of first attribute extent failed");
6669987da915Sopenharmony_ci		if (err == ENOENT)
6670987da915Sopenharmony_ci			err = EIO;
6671987da915Sopenharmony_ci		if (na->allocated_size != org_alloc_size) {
6672987da915Sopenharmony_ci			ntfs_attr_put_search_ctx(ctx);
6673987da915Sopenharmony_ci			goto rollback;
6674987da915Sopenharmony_ci		} else
6675987da915Sopenharmony_ci			goto put_err_out;
6676987da915Sopenharmony_ci	}
6677987da915Sopenharmony_ci
6678987da915Sopenharmony_ci	/* Update data size. */
6679987da915Sopenharmony_ci	na->data_size = newsize;
6680987da915Sopenharmony_ci	ctx->attr->data_size = cpu_to_sle64(newsize);
6681987da915Sopenharmony_ci	/* Update data size in the index. */
6682987da915Sopenharmony_ci	if (na->ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) {
6683987da915Sopenharmony_ci		if (na->type == AT_INDEX_ROOT && na->name == NTFS_INDEX_I30) {
6684987da915Sopenharmony_ci			na->ni->data_size = na->data_size;
6685987da915Sopenharmony_ci			na->ni->allocated_size = na->allocated_size;
6686987da915Sopenharmony_ci			set_nino_flag(na->ni,KnownSize);
6687987da915Sopenharmony_ci		}
6688987da915Sopenharmony_ci	} else {
6689987da915Sopenharmony_ci		if (na->type == AT_DATA && na->name == AT_UNNAMED) {
6690987da915Sopenharmony_ci			na->ni->data_size = na->data_size;
6691987da915Sopenharmony_ci			NInoFileNameSetDirty(na->ni);
6692987da915Sopenharmony_ci		}
6693987da915Sopenharmony_ci	}
6694987da915Sopenharmony_ci	/* Set the inode dirty so it is written out later. */
6695987da915Sopenharmony_ci	ntfs_inode_mark_dirty(ctx->ntfs_ino);
6696987da915Sopenharmony_ci	/* Done! */
6697987da915Sopenharmony_ci	ntfs_attr_put_search_ctx(ctx);
6698987da915Sopenharmony_ci	return 0;
6699987da915Sopenharmony_cirollback:
6700987da915Sopenharmony_ci	/* Free allocated clusters. */
6701987da915Sopenharmony_ci	if (ntfs_cluster_free(vol, na, org_alloc_size >>
6702987da915Sopenharmony_ci			vol->cluster_size_bits, -1) < 0) {
6703987da915Sopenharmony_ci		err = EIO;
6704987da915Sopenharmony_ci		ntfs_log_perror("Leaking clusters");
6705987da915Sopenharmony_ci	}
6706987da915Sopenharmony_ci	/* Now, truncate the runlist itself. */
6707987da915Sopenharmony_ci	if (ntfs_rl_truncate(&na->rl, org_alloc_size >>
6708987da915Sopenharmony_ci			vol->cluster_size_bits)) {
6709987da915Sopenharmony_ci		/*
6710987da915Sopenharmony_ci		 * Failed to truncate the runlist, so just throw it away, it
6711987da915Sopenharmony_ci		 * will be mapped afresh on next use.
6712987da915Sopenharmony_ci		 */
6713987da915Sopenharmony_ci		free(na->rl);
6714987da915Sopenharmony_ci		na->rl = NULL;
6715987da915Sopenharmony_ci		ntfs_log_perror("Couldn't truncate runlist. Rollback failed");
6716987da915Sopenharmony_ci	} else {
6717987da915Sopenharmony_ci		NAttrSetRunlistDirty(na);
6718987da915Sopenharmony_ci		/* Prepare to mapping pairs update. */
6719987da915Sopenharmony_ci		na->allocated_size = org_alloc_size;
6720987da915Sopenharmony_ci		/* Restore mapping pairs. */
6721987da915Sopenharmony_ci		if (ntfs_attr_update_mapping_pairs(na, 0 /*na->allocated_size >>
6722987da915Sopenharmony_ci					vol->cluster_size_bits*/)) {
6723987da915Sopenharmony_ci			ntfs_log_perror("Failed to restore old mapping pairs");
6724987da915Sopenharmony_ci		}
6725987da915Sopenharmony_ci	}
6726987da915Sopenharmony_ci	errno = err;
6727987da915Sopenharmony_ci	return -1;
6728987da915Sopenharmony_ciput_err_out:
6729987da915Sopenharmony_ci	ntfs_attr_put_search_ctx(ctx);
6730987da915Sopenharmony_ci	errno = err;
6731987da915Sopenharmony_ci	return -1;
6732987da915Sopenharmony_ci}
6733987da915Sopenharmony_ci
6734987da915Sopenharmony_ci
6735987da915Sopenharmony_cistatic int ntfs_non_resident_attr_expand(ntfs_attr *na, const s64 newsize,
6736987da915Sopenharmony_ci				hole_type holes)
6737987da915Sopenharmony_ci{
6738987da915Sopenharmony_ci	int ret;
6739987da915Sopenharmony_ci
6740987da915Sopenharmony_ci	ntfs_log_enter("Entering\n");
6741987da915Sopenharmony_ci	ret = ntfs_non_resident_attr_expand_i(na, newsize, holes);
6742987da915Sopenharmony_ci	ntfs_log_leave("\n");
6743987da915Sopenharmony_ci	return ret;
6744987da915Sopenharmony_ci}
6745987da915Sopenharmony_ci
6746987da915Sopenharmony_ci/**
6747987da915Sopenharmony_ci * ntfs_attr_truncate - resize an ntfs attribute
6748987da915Sopenharmony_ci * @na:		open ntfs attribute to resize
6749987da915Sopenharmony_ci * @newsize:	new size (in bytes) to which to resize the attribute
6750987da915Sopenharmony_ci * @holes:	how to create a hole if expanding
6751987da915Sopenharmony_ci *
6752987da915Sopenharmony_ci * Change the size of an open ntfs attribute @na to @newsize bytes. If the
6753987da915Sopenharmony_ci * attribute is made bigger and the attribute is resident the newly
6754987da915Sopenharmony_ci * "allocated" space is cleared and if the attribute is non-resident the
6755987da915Sopenharmony_ci * newly allocated space is marked as not initialised and no real allocation
6756987da915Sopenharmony_ci * on disk is performed.
6757987da915Sopenharmony_ci *
6758987da915Sopenharmony_ci * On success return 0.
6759987da915Sopenharmony_ci * On error return values are:
6760987da915Sopenharmony_ci * 	STATUS_RESIDENT_ATTRIBUTE_FILLED_MFT
6761987da915Sopenharmony_ci * 	STATUS_ERROR - otherwise
6762987da915Sopenharmony_ci * The following error codes are defined:
6763987da915Sopenharmony_ci *	EINVAL	   - Invalid arguments were passed to the function.
6764987da915Sopenharmony_ci *	EOPNOTSUPP - The desired resize is not implemented yet.
6765987da915Sopenharmony_ci * 	EACCES     - Encrypted attribute.
6766987da915Sopenharmony_ci */
6767987da915Sopenharmony_cistatic int ntfs_attr_truncate_i(ntfs_attr *na, const s64 newsize,
6768987da915Sopenharmony_ci					hole_type holes)
6769987da915Sopenharmony_ci{
6770987da915Sopenharmony_ci	int ret = STATUS_ERROR;
6771987da915Sopenharmony_ci	s64 fullsize;
6772987da915Sopenharmony_ci	BOOL compressed;
6773987da915Sopenharmony_ci
6774987da915Sopenharmony_ci	if (!na || newsize < 0 ||
6775987da915Sopenharmony_ci			(na->ni->mft_no == FILE_MFT && na->type == AT_DATA)) {
6776987da915Sopenharmony_ci		ntfs_log_trace("Invalid arguments passed.\n");
6777987da915Sopenharmony_ci		errno = EINVAL;
6778987da915Sopenharmony_ci		return STATUS_ERROR;
6779987da915Sopenharmony_ci	}
6780987da915Sopenharmony_ci
6781987da915Sopenharmony_ci	ntfs_log_enter("Entering for inode %lld, attr 0x%x, size %lld\n",
6782987da915Sopenharmony_ci		       (unsigned long long)na->ni->mft_no, le32_to_cpu(na->type),
6783987da915Sopenharmony_ci		       (long long)newsize);
6784987da915Sopenharmony_ci
6785987da915Sopenharmony_ci	if (na->data_size == newsize) {
6786987da915Sopenharmony_ci		ntfs_log_trace("Size is already ok\n");
6787987da915Sopenharmony_ci		ret = STATUS_OK;
6788987da915Sopenharmony_ci		goto out;
6789987da915Sopenharmony_ci	}
6790987da915Sopenharmony_ci	/*
6791987da915Sopenharmony_ci	 * Encrypted attributes are not supported. We return access denied,
6792987da915Sopenharmony_ci	 * which is what Windows NT4 does, too.
6793987da915Sopenharmony_ci	 */
6794987da915Sopenharmony_ci	if ((na->data_flags & ATTR_IS_ENCRYPTED) && !na->ni->vol->efs_raw) {
6795987da915Sopenharmony_ci		errno = EACCES;
6796987da915Sopenharmony_ci		ntfs_log_trace("Cannot truncate encrypted attribute\n");
6797987da915Sopenharmony_ci		goto out;
6798987da915Sopenharmony_ci	}
6799987da915Sopenharmony_ci	/*
6800987da915Sopenharmony_ci	 * TODO: Implement making handling of compressed attributes.
6801987da915Sopenharmony_ci	 * Currently we can only expand the attribute or delete it,
6802987da915Sopenharmony_ci	 * and only for ATTR_IS_COMPRESSED. This is however possible
6803987da915Sopenharmony_ci	 * for resident attributes when there is no open fuse context
6804987da915Sopenharmony_ci	 * (important case : $INDEX_ROOT:$I30)
6805987da915Sopenharmony_ci	 */
6806987da915Sopenharmony_ci	compressed = (na->data_flags & ATTR_COMPRESSION_MASK)
6807987da915Sopenharmony_ci			 != const_cpu_to_le16(0);
6808987da915Sopenharmony_ci	if (compressed
6809987da915Sopenharmony_ci	   && NAttrNonResident(na)
6810987da915Sopenharmony_ci	   && ((na->data_flags & ATTR_COMPRESSION_MASK) != ATTR_IS_COMPRESSED)) {
6811987da915Sopenharmony_ci		errno = EOPNOTSUPP;
6812987da915Sopenharmony_ci		ntfs_log_perror("Failed to truncate compressed attribute");
6813987da915Sopenharmony_ci		goto out;
6814987da915Sopenharmony_ci	}
6815987da915Sopenharmony_ci	if (NAttrNonResident(na)) {
6816987da915Sopenharmony_ci		/*
6817987da915Sopenharmony_ci		 * For compressed data, the last block must be fully
6818987da915Sopenharmony_ci		 * allocated, and we do not know the size of compression
6819987da915Sopenharmony_ci		 * block until the attribute has been made non-resident.
6820987da915Sopenharmony_ci		 * Moreover we can only process a single compression
6821987da915Sopenharmony_ci		 * block at a time (from where we are about to write),
6822987da915Sopenharmony_ci		 * so we silently do not allocate more.
6823987da915Sopenharmony_ci		 *
6824987da915Sopenharmony_ci		 * Note : do not request upsizing of compressed files
6825987da915Sopenharmony_ci		 * unless being able to face the consequences !
6826987da915Sopenharmony_ci		 */
6827987da915Sopenharmony_ci		if (compressed && newsize && (newsize > na->data_size))
6828987da915Sopenharmony_ci			fullsize = (na->initialized_size
6829987da915Sopenharmony_ci				 | (na->compression_block_size - 1)) + 1;
6830987da915Sopenharmony_ci		else
6831987da915Sopenharmony_ci			fullsize = newsize;
6832987da915Sopenharmony_ci		if (fullsize > na->data_size)
6833987da915Sopenharmony_ci			ret = ntfs_non_resident_attr_expand(na, fullsize,
6834987da915Sopenharmony_ci								holes);
6835987da915Sopenharmony_ci		else
6836987da915Sopenharmony_ci			ret = ntfs_non_resident_attr_shrink(na, fullsize);
6837987da915Sopenharmony_ci	} else
6838987da915Sopenharmony_ci		ret = ntfs_resident_attr_resize_i(na, newsize, holes);
6839987da915Sopenharmony_ciout:
6840987da915Sopenharmony_ci	ntfs_log_leave("Return status %d\n", ret);
6841987da915Sopenharmony_ci	return ret;
6842987da915Sopenharmony_ci}
6843987da915Sopenharmony_ci
6844987da915Sopenharmony_ci/*
6845987da915Sopenharmony_ci *		Resize an attribute, creating a hole if relevant
6846987da915Sopenharmony_ci */
6847987da915Sopenharmony_ci
6848987da915Sopenharmony_ciint ntfs_attr_truncate(ntfs_attr *na, const s64 newsize)
6849987da915Sopenharmony_ci{
6850987da915Sopenharmony_ci	int r;
6851987da915Sopenharmony_ci
6852987da915Sopenharmony_ci	r = ntfs_attr_truncate_i(na, newsize, HOLES_OK);
6853987da915Sopenharmony_ci	NAttrClearDataAppending(na);
6854987da915Sopenharmony_ci	NAttrClearBeingNonResident(na);
6855987da915Sopenharmony_ci	return (r);
6856987da915Sopenharmony_ci}
6857987da915Sopenharmony_ci
6858987da915Sopenharmony_ci/*
6859987da915Sopenharmony_ci *		Resize an attribute, avoiding hole creation
6860987da915Sopenharmony_ci */
6861987da915Sopenharmony_ci
6862987da915Sopenharmony_ciint ntfs_attr_truncate_solid(ntfs_attr *na, const s64 newsize)
6863987da915Sopenharmony_ci{
6864987da915Sopenharmony_ci	return (ntfs_attr_truncate_i(na, newsize, HOLES_NO));
6865987da915Sopenharmony_ci}
6866987da915Sopenharmony_ci
6867987da915Sopenharmony_ci/*
6868987da915Sopenharmony_ci *		Stuff a hole in a compressed file
6869987da915Sopenharmony_ci *
6870987da915Sopenharmony_ci *	An unallocated hole must be aligned on compression block size.
6871987da915Sopenharmony_ci *	If needed current block and target block are stuffed with zeroes.
6872987da915Sopenharmony_ci *
6873987da915Sopenharmony_ci *	Returns 0 if succeeded,
6874987da915Sopenharmony_ci *		-1 if it failed (as explained in errno)
6875987da915Sopenharmony_ci */
6876987da915Sopenharmony_ci
6877987da915Sopenharmony_cistatic int stuff_hole(ntfs_attr *na, const s64 pos)
6878987da915Sopenharmony_ci{
6879987da915Sopenharmony_ci	s64 size;
6880987da915Sopenharmony_ci	s64 begin_size;
6881987da915Sopenharmony_ci	s64 end_size;
6882987da915Sopenharmony_ci	char *buf;
6883987da915Sopenharmony_ci	int ret;
6884987da915Sopenharmony_ci
6885987da915Sopenharmony_ci	ret = 0;
6886987da915Sopenharmony_ci		/*
6887987da915Sopenharmony_ci		 * If the attribute is resident, the compression block size
6888987da915Sopenharmony_ci		 * is not defined yet and we can make no decision.
6889987da915Sopenharmony_ci		 * So we first try resizing to the target and if the
6890987da915Sopenharmony_ci		 * attribute is still resident, we're done
6891987da915Sopenharmony_ci		 */
6892987da915Sopenharmony_ci	if (!NAttrNonResident(na)) {
6893987da915Sopenharmony_ci		ret = ntfs_resident_attr_resize(na, pos);
6894987da915Sopenharmony_ci		if (!ret && !NAttrNonResident(na))
6895987da915Sopenharmony_ci			na->initialized_size = na->data_size = pos;
6896987da915Sopenharmony_ci	}
6897987da915Sopenharmony_ci	if (!ret && NAttrNonResident(na)) {
6898987da915Sopenharmony_ci			/* does the hole span over several compression block ? */
6899987da915Sopenharmony_ci		if ((pos ^ na->initialized_size)
6900987da915Sopenharmony_ci				& ~(na->compression_block_size - 1)) {
6901987da915Sopenharmony_ci			begin_size = ((na->initialized_size - 1)
6902987da915Sopenharmony_ci					| (na->compression_block_size - 1))
6903987da915Sopenharmony_ci					+ 1 - na->initialized_size;
6904987da915Sopenharmony_ci			end_size = pos & (na->compression_block_size - 1);
6905987da915Sopenharmony_ci			size = (begin_size > end_size ? begin_size : end_size);
6906987da915Sopenharmony_ci		} else {
6907987da915Sopenharmony_ci			/* short stuffing in a single compression block */
6908987da915Sopenharmony_ci			begin_size = size = pos - na->initialized_size;
6909987da915Sopenharmony_ci			end_size = 0;
6910987da915Sopenharmony_ci		}
6911987da915Sopenharmony_ci		if (size)
6912987da915Sopenharmony_ci			buf = (char*)ntfs_malloc(size);
6913987da915Sopenharmony_ci		else
6914987da915Sopenharmony_ci			buf = (char*)NULL;
6915987da915Sopenharmony_ci		if (buf || !size) {
6916987da915Sopenharmony_ci			memset(buf,0,size);
6917987da915Sopenharmony_ci				/* stuff into current block */
6918987da915Sopenharmony_ci			if (begin_size
6919987da915Sopenharmony_ci			    && (ntfs_attr_pwrite(na,
6920987da915Sopenharmony_ci				na->initialized_size, begin_size, buf)
6921987da915Sopenharmony_ci				   != begin_size))
6922987da915Sopenharmony_ci				ret = -1;
6923987da915Sopenharmony_ci				/* create an unstuffed hole */
6924987da915Sopenharmony_ci			if (!ret
6925987da915Sopenharmony_ci			    && ((na->initialized_size + end_size) < pos)
6926987da915Sopenharmony_ci			    && ntfs_non_resident_attr_expand(na,
6927987da915Sopenharmony_ci					pos - end_size, HOLES_OK))
6928987da915Sopenharmony_ci				ret = -1;
6929987da915Sopenharmony_ci			else
6930987da915Sopenharmony_ci				na->initialized_size
6931987da915Sopenharmony_ci				    = na->data_size = pos - end_size;
6932987da915Sopenharmony_ci				/* stuff into the target block */
6933987da915Sopenharmony_ci			if (!ret && end_size
6934987da915Sopenharmony_ci			    && (ntfs_attr_pwrite(na,
6935987da915Sopenharmony_ci				na->initialized_size, end_size, buf)
6936987da915Sopenharmony_ci				    != end_size))
6937987da915Sopenharmony_ci				ret = -1;
6938987da915Sopenharmony_ci			if (buf)
6939987da915Sopenharmony_ci				free(buf);
6940987da915Sopenharmony_ci		} else
6941987da915Sopenharmony_ci			ret = -1;
6942987da915Sopenharmony_ci	}
6943987da915Sopenharmony_ci		/* make absolutely sure we have reached the target */
6944987da915Sopenharmony_ci	if (!ret && (na->initialized_size != pos)) {
6945987da915Sopenharmony_ci		ntfs_log_error("Failed to stuff a compressed file"
6946987da915Sopenharmony_ci			"target %lld reached %lld\n",
6947987da915Sopenharmony_ci			(long long)pos, (long long)na->initialized_size);
6948987da915Sopenharmony_ci		errno = EIO;
6949987da915Sopenharmony_ci		ret = -1;
6950987da915Sopenharmony_ci	}
6951987da915Sopenharmony_ci	return (ret);
6952987da915Sopenharmony_ci}
6953987da915Sopenharmony_ci
6954987da915Sopenharmony_ci/**
6955987da915Sopenharmony_ci * ntfs_attr_readall - read the entire data from an ntfs attribute
6956987da915Sopenharmony_ci * @ni:		open ntfs inode in which the ntfs attribute resides
6957987da915Sopenharmony_ci * @type:	attribute type
6958987da915Sopenharmony_ci * @name:	attribute name in little endian Unicode or AT_UNNAMED or NULL
6959987da915Sopenharmony_ci * @name_len:	length of attribute @name in Unicode characters (if @name given)
6960987da915Sopenharmony_ci * @data_size:	if non-NULL then store here the data size
6961987da915Sopenharmony_ci *
6962987da915Sopenharmony_ci * This function will read the entire content of an ntfs attribute.
6963987da915Sopenharmony_ci * If @name is AT_UNNAMED then look specifically for an unnamed attribute.
6964987da915Sopenharmony_ci * If @name is NULL then the attribute could be either named or not.
6965987da915Sopenharmony_ci * In both those cases @name_len is not used at all.
6966987da915Sopenharmony_ci *
6967987da915Sopenharmony_ci * On success a buffer is allocated with the content of the attribute
6968987da915Sopenharmony_ci * and which needs to be freed when it's not needed anymore. If the
6969987da915Sopenharmony_ci * @data_size parameter is non-NULL then the data size is set there.
6970987da915Sopenharmony_ci *
6971987da915Sopenharmony_ci * On error NULL is returned with errno set to the error code.
6972987da915Sopenharmony_ci */
6973987da915Sopenharmony_civoid *ntfs_attr_readall(ntfs_inode *ni, const ATTR_TYPES type,
6974987da915Sopenharmony_ci			ntfschar *name, u32 name_len, s64 *data_size)
6975987da915Sopenharmony_ci{
6976987da915Sopenharmony_ci	ntfs_attr *na;
6977987da915Sopenharmony_ci	void *data, *ret = NULL;
6978987da915Sopenharmony_ci	s64 size;
6979987da915Sopenharmony_ci
6980987da915Sopenharmony_ci	ntfs_log_enter("Entering\n");
6981987da915Sopenharmony_ci
6982987da915Sopenharmony_ci	na = ntfs_attr_open(ni, type, name, name_len);
6983987da915Sopenharmony_ci	if (!na) {
6984987da915Sopenharmony_ci		ntfs_log_perror("ntfs_attr_open failed, inode %lld attr 0x%lx",
6985987da915Sopenharmony_ci				(long long)ni->mft_no,(long)le32_to_cpu(type));
6986987da915Sopenharmony_ci		goto err_exit;
6987987da915Sopenharmony_ci	}
6988987da915Sopenharmony_ci		/*
6989987da915Sopenharmony_ci		 * Consistency check : restrict to 65536 bytes.
6990987da915Sopenharmony_ci		 *   index bitmaps may need more, but still limited by
6991987da915Sopenharmony_ci		 *   the number of clusters.
6992987da915Sopenharmony_ci		 */
6993987da915Sopenharmony_ci	if (((u64)na->data_size > 65536)
6994987da915Sopenharmony_ci	    && ((type != AT_BITMAP)
6995987da915Sopenharmony_ci		|| ((u64)na->data_size >
6996987da915Sopenharmony_ci			(u64)((ni->vol->nr_clusters + 7) >> 3)))) {
6997987da915Sopenharmony_ci		ntfs_log_error("Corrupt attribute 0x%lx in inode %lld\n",
6998987da915Sopenharmony_ci				(long)le32_to_cpu(type),(long long)ni->mft_no);
6999987da915Sopenharmony_ci		errno = EOVERFLOW;
7000987da915Sopenharmony_ci		goto out;
7001987da915Sopenharmony_ci	}
7002987da915Sopenharmony_ci	data = ntfs_malloc(na->data_size);
7003987da915Sopenharmony_ci	if (!data)
7004987da915Sopenharmony_ci		goto out;
7005987da915Sopenharmony_ci
7006987da915Sopenharmony_ci	size = ntfs_attr_pread(na, 0, na->data_size, data);
7007987da915Sopenharmony_ci	if (size != na->data_size) {
7008987da915Sopenharmony_ci		ntfs_log_perror("ntfs_attr_pread failed");
7009987da915Sopenharmony_ci		free(data);
7010987da915Sopenharmony_ci		goto out;
7011987da915Sopenharmony_ci	}
7012987da915Sopenharmony_ci	ret = data;
7013987da915Sopenharmony_ci	if (data_size)
7014987da915Sopenharmony_ci		*data_size = size;
7015987da915Sopenharmony_ciout:
7016987da915Sopenharmony_ci	ntfs_attr_close(na);
7017987da915Sopenharmony_cierr_exit:
7018987da915Sopenharmony_ci	ntfs_log_leave("\n");
7019987da915Sopenharmony_ci	return ret;
7020987da915Sopenharmony_ci}
7021987da915Sopenharmony_ci
7022987da915Sopenharmony_ci/*
7023987da915Sopenharmony_ci *		Read some data from a data attribute
7024987da915Sopenharmony_ci *
7025987da915Sopenharmony_ci *	Returns the amount of data read, negative if there was an error
7026987da915Sopenharmony_ci */
7027987da915Sopenharmony_ci
7028987da915Sopenharmony_ciint ntfs_attr_data_read(ntfs_inode *ni,
7029987da915Sopenharmony_ci		ntfschar *stream_name, int stream_name_len,
7030987da915Sopenharmony_ci		char *buf, size_t size, off_t offset)
7031987da915Sopenharmony_ci{
7032987da915Sopenharmony_ci	ntfs_attr *na = NULL;
7033987da915Sopenharmony_ci	int res, total = 0;
7034987da915Sopenharmony_ci
7035987da915Sopenharmony_ci	na = ntfs_attr_open(ni, AT_DATA, stream_name, stream_name_len);
7036987da915Sopenharmony_ci	if (!na) {
7037987da915Sopenharmony_ci		res = -errno;
7038987da915Sopenharmony_ci		goto exit;
7039987da915Sopenharmony_ci	}
7040987da915Sopenharmony_ci	if ((size_t)offset < (size_t)na->data_size) {
7041987da915Sopenharmony_ci		if (offset + size > (size_t)na->data_size)
7042987da915Sopenharmony_ci			size = na->data_size - offset;
7043987da915Sopenharmony_ci		while (size) {
7044987da915Sopenharmony_ci			res = ntfs_attr_pread(na, offset, size, buf + total);
7045987da915Sopenharmony_ci			if ((off_t)res < (off_t)size)
7046987da915Sopenharmony_ci				ntfs_log_perror("ntfs_attr_pread partial read "
7047987da915Sopenharmony_ci					"(%lld : %lld <> %d)",
7048987da915Sopenharmony_ci					(long long)offset,
7049987da915Sopenharmony_ci					(long long)size, res);
7050987da915Sopenharmony_ci			if (res <= 0) {
7051987da915Sopenharmony_ci				res = -errno;
7052987da915Sopenharmony_ci				goto exit;
7053987da915Sopenharmony_ci			}
7054987da915Sopenharmony_ci			size -= res;
7055987da915Sopenharmony_ci			offset += res;
7056987da915Sopenharmony_ci			total += res;
7057987da915Sopenharmony_ci		}
7058987da915Sopenharmony_ci	}
7059987da915Sopenharmony_ci	res = total;
7060987da915Sopenharmony_ciexit:
7061987da915Sopenharmony_ci	if (na)
7062987da915Sopenharmony_ci		ntfs_attr_close(na);
7063987da915Sopenharmony_ci	return res;
7064987da915Sopenharmony_ci}
7065987da915Sopenharmony_ci
7066987da915Sopenharmony_ci
7067987da915Sopenharmony_ci/*
7068987da915Sopenharmony_ci *		Write some data into a data attribute
7069987da915Sopenharmony_ci *
7070987da915Sopenharmony_ci *	Returns the amount of data written, negative if there was an error
7071987da915Sopenharmony_ci */
7072987da915Sopenharmony_ci
7073987da915Sopenharmony_ciint ntfs_attr_data_write(ntfs_inode *ni, ntfschar *stream_name,
7074987da915Sopenharmony_ci		int stream_name_len, const char *buf, size_t size, off_t offset)
7075987da915Sopenharmony_ci{
7076987da915Sopenharmony_ci	ntfs_attr *na = NULL;
7077987da915Sopenharmony_ci	int res, total = 0;
7078987da915Sopenharmony_ci
7079987da915Sopenharmony_ci	na = ntfs_attr_open(ni, AT_DATA, stream_name, stream_name_len);
7080987da915Sopenharmony_ci	if (!na) {
7081987da915Sopenharmony_ci		res = -errno;
7082987da915Sopenharmony_ci		goto exit;
7083987da915Sopenharmony_ci	}
7084987da915Sopenharmony_ci	while (size) {
7085987da915Sopenharmony_ci		res = ntfs_attr_pwrite(na, offset, size, buf + total);
7086987da915Sopenharmony_ci		if (res < (s64)size)
7087987da915Sopenharmony_ci			ntfs_log_perror("ntfs_attr_pwrite partial write (%lld: "
7088987da915Sopenharmony_ci				"%lld <> %d)", (long long)offset,
7089987da915Sopenharmony_ci				(long long)size, res);
7090987da915Sopenharmony_ci		if (res <= 0) {
7091987da915Sopenharmony_ci			res = -errno;
7092987da915Sopenharmony_ci			goto exit;
7093987da915Sopenharmony_ci		}
7094987da915Sopenharmony_ci		size -= res;
7095987da915Sopenharmony_ci		offset += res;
7096987da915Sopenharmony_ci		total += res;
7097987da915Sopenharmony_ci	}
7098987da915Sopenharmony_ci	res = total;
7099987da915Sopenharmony_ciexit:
7100987da915Sopenharmony_ci	if (na)
7101987da915Sopenharmony_ci		ntfs_attr_close(na);
7102987da915Sopenharmony_ci	return res;
7103987da915Sopenharmony_ci}
7104987da915Sopenharmony_ci
7105987da915Sopenharmony_ci/*
7106987da915Sopenharmony_ci *		Shrink the size of a data attribute if needed
7107987da915Sopenharmony_ci *
7108987da915Sopenharmony_ci *	For non-resident attributes only.
7109987da915Sopenharmony_ci *	The space remains allocated.
7110987da915Sopenharmony_ci *
7111987da915Sopenharmony_ci *	Returns 0 if successful
7112987da915Sopenharmony_ci *		-1 if failed, with errno telling why
7113987da915Sopenharmony_ci */
7114987da915Sopenharmony_ci
7115987da915Sopenharmony_ci
7116987da915Sopenharmony_ciint ntfs_attr_shrink_size(ntfs_inode *ni, ntfschar *stream_name,
7117987da915Sopenharmony_ci		int stream_name_len, off_t offset)
7118987da915Sopenharmony_ci{
7119987da915Sopenharmony_ci	ntfs_attr_search_ctx *ctx;
7120987da915Sopenharmony_ci	ATTR_RECORD *a;
7121987da915Sopenharmony_ci	int res;
7122987da915Sopenharmony_ci
7123987da915Sopenharmony_ci	res = -1;
7124987da915Sopenharmony_ci	ctx = ntfs_attr_get_search_ctx(ni, NULL);
7125987da915Sopenharmony_ci	if (ctx) {
7126987da915Sopenharmony_ci		if (!ntfs_attr_lookup(AT_DATA, stream_name, stream_name_len,
7127987da915Sopenharmony_ci			CASE_SENSITIVE, 0, NULL, 0, ctx)) {
7128987da915Sopenharmony_ci			a = ctx->attr;
7129987da915Sopenharmony_ci
7130987da915Sopenharmony_ci			if (a->non_resident
7131987da915Sopenharmony_ci			    && (sle64_to_cpu(a->initialized_size) > offset)) {
7132987da915Sopenharmony_ci				a->initialized_size = cpu_to_sle64(offset);
7133987da915Sopenharmony_ci				a->data_size = a->initialized_size;
7134987da915Sopenharmony_ci			}
7135987da915Sopenharmony_ci			res = 0;
7136987da915Sopenharmony_ci		}
7137987da915Sopenharmony_ci		ntfs_attr_put_search_ctx(ctx);
7138987da915Sopenharmony_ci	}
7139987da915Sopenharmony_ci	return (res);
7140987da915Sopenharmony_ci}
7141987da915Sopenharmony_ci
7142987da915Sopenharmony_ciint ntfs_attr_exist(ntfs_inode *ni, const ATTR_TYPES type, const ntfschar *name,
7143987da915Sopenharmony_ci		    u32 name_len)
7144987da915Sopenharmony_ci{
7145987da915Sopenharmony_ci	ntfs_attr_search_ctx *ctx;
7146987da915Sopenharmony_ci	int ret;
7147987da915Sopenharmony_ci
7148987da915Sopenharmony_ci	ntfs_log_trace("Entering\n");
7149987da915Sopenharmony_ci
7150987da915Sopenharmony_ci	ctx = ntfs_attr_get_search_ctx(ni, NULL);
7151987da915Sopenharmony_ci	if (!ctx)
7152987da915Sopenharmony_ci		return 0;
7153987da915Sopenharmony_ci
7154987da915Sopenharmony_ci	ret = ntfs_attr_lookup(type, name, name_len, CASE_SENSITIVE, 0, NULL, 0,
7155987da915Sopenharmony_ci			       ctx);
7156987da915Sopenharmony_ci
7157987da915Sopenharmony_ci	ntfs_attr_put_search_ctx(ctx);
7158987da915Sopenharmony_ci
7159987da915Sopenharmony_ci	return !ret;
7160987da915Sopenharmony_ci}
7161987da915Sopenharmony_ci
7162987da915Sopenharmony_ciint ntfs_attr_remove(ntfs_inode *ni, const ATTR_TYPES type, ntfschar *name,
7163987da915Sopenharmony_ci		     u32 name_len)
7164987da915Sopenharmony_ci{
7165987da915Sopenharmony_ci	ntfs_attr *na;
7166987da915Sopenharmony_ci	int ret;
7167987da915Sopenharmony_ci
7168987da915Sopenharmony_ci	ntfs_log_trace("Entering\n");
7169987da915Sopenharmony_ci
7170987da915Sopenharmony_ci	if (!ni) {
7171987da915Sopenharmony_ci		ntfs_log_error("%s: NULL inode pointer", __FUNCTION__);
7172987da915Sopenharmony_ci		errno = EINVAL;
7173987da915Sopenharmony_ci		return -1;
7174987da915Sopenharmony_ci	}
7175987da915Sopenharmony_ci
7176987da915Sopenharmony_ci	na = ntfs_attr_open(ni, type, name, name_len);
7177987da915Sopenharmony_ci	if (!na) {
7178987da915Sopenharmony_ci			/* do not log removal of non-existent stream */
7179987da915Sopenharmony_ci		if (type != AT_DATA) {
7180987da915Sopenharmony_ci			ntfs_log_perror("Failed to open attribute 0x%02x of inode "
7181987da915Sopenharmony_ci				"0x%llx", le32_to_cpu(type), (unsigned long long)ni->mft_no);
7182987da915Sopenharmony_ci		}
7183987da915Sopenharmony_ci		return -1;
7184987da915Sopenharmony_ci	}
7185987da915Sopenharmony_ci
7186987da915Sopenharmony_ci	ret = ntfs_attr_rm(na);
7187987da915Sopenharmony_ci	if (ret)
7188987da915Sopenharmony_ci		ntfs_log_perror("Failed to remove attribute 0x%02x of inode "
7189987da915Sopenharmony_ci				"0x%llx", le32_to_cpu(type), (unsigned long long)ni->mft_no);
7190987da915Sopenharmony_ci	ntfs_attr_close(na);
7191987da915Sopenharmony_ci
7192987da915Sopenharmony_ci	return ret;
7193987da915Sopenharmony_ci}
7194987da915Sopenharmony_ci
7195987da915Sopenharmony_ci/* Below macros are 32-bit ready. */
7196987da915Sopenharmony_ci#define BCX(x) ((x) - (((x) >> 1) & 0x77777777) - \
7197987da915Sopenharmony_ci		      (((x) >> 2) & 0x33333333) - \
7198987da915Sopenharmony_ci		      (((x) >> 3) & 0x11111111))
7199987da915Sopenharmony_ci#define BITCOUNT(x) (((BCX(x) + (BCX(x) >> 4)) & 0x0F0F0F0F) % 255)
7200987da915Sopenharmony_ci
7201987da915Sopenharmony_cistatic u8 *ntfs_init_lut256(void)
7202987da915Sopenharmony_ci{
7203987da915Sopenharmony_ci	int i;
7204987da915Sopenharmony_ci	u8 *lut;
7205987da915Sopenharmony_ci
7206987da915Sopenharmony_ci	lut = ntfs_malloc(256);
7207987da915Sopenharmony_ci	if (lut)
7208987da915Sopenharmony_ci		for(i = 0; i < 256; i++)
7209987da915Sopenharmony_ci			*(lut + i) = 8 - BITCOUNT(i);
7210987da915Sopenharmony_ci	return lut;
7211987da915Sopenharmony_ci}
7212987da915Sopenharmony_ci
7213987da915Sopenharmony_cis64 ntfs_attr_get_free_bits(ntfs_attr *na)
7214987da915Sopenharmony_ci{
7215987da915Sopenharmony_ci	u8 *buf, *lut;
7216987da915Sopenharmony_ci	s64 br      = 0;
7217987da915Sopenharmony_ci	s64 total   = 0;
7218987da915Sopenharmony_ci	s64 nr_free = 0;
7219987da915Sopenharmony_ci
7220987da915Sopenharmony_ci	lut = ntfs_init_lut256();
7221987da915Sopenharmony_ci	if (!lut)
7222987da915Sopenharmony_ci		return -1;
7223987da915Sopenharmony_ci
7224987da915Sopenharmony_ci	buf = ntfs_malloc(65536);
7225987da915Sopenharmony_ci	if (!buf)
7226987da915Sopenharmony_ci		goto out;
7227987da915Sopenharmony_ci
7228987da915Sopenharmony_ci	while (1) {
7229987da915Sopenharmony_ci		u32 *p;
7230987da915Sopenharmony_ci		br = ntfs_attr_pread(na, total, 65536, buf);
7231987da915Sopenharmony_ci		if (br <= 0)
7232987da915Sopenharmony_ci			break;
7233987da915Sopenharmony_ci		total += br;
7234987da915Sopenharmony_ci		p = (u32 *)buf + br / 4 - 1;
7235987da915Sopenharmony_ci		for (; (u8 *)p >= buf; p--) {
7236987da915Sopenharmony_ci			nr_free += lut[ *p        & 255] +
7237987da915Sopenharmony_ci			           lut[(*p >>  8) & 255] +
7238987da915Sopenharmony_ci			           lut[(*p >> 16) & 255] +
7239987da915Sopenharmony_ci			           lut[(*p >> 24)      ];
7240987da915Sopenharmony_ci		}
7241987da915Sopenharmony_ci		switch (br % 4) {
7242987da915Sopenharmony_ci			case 3:  nr_free += lut[*(buf + br - 3)];
7243987da915Sopenharmony_ci			/* FALLTHRU */
7244987da915Sopenharmony_ci			case 2:  nr_free += lut[*(buf + br - 2)];
7245987da915Sopenharmony_ci			/* FALLTHRU */
7246987da915Sopenharmony_ci			case 1:  nr_free += lut[*(buf + br - 1)];
7247987da915Sopenharmony_ci		}
7248987da915Sopenharmony_ci	}
7249987da915Sopenharmony_ci	free(buf);
7250987da915Sopenharmony_ciout:
7251987da915Sopenharmony_ci	free(lut);
7252987da915Sopenharmony_ci	if (!total || br < 0)
7253987da915Sopenharmony_ci		return -1;
7254987da915Sopenharmony_ci	return nr_free;
7255987da915Sopenharmony_ci}
7256