1987da915Sopenharmony_ci/**
2987da915Sopenharmony_ci * efs.c - Limited processing of encrypted files
3987da915Sopenharmony_ci *
4987da915Sopenharmony_ci *	This module is part of ntfs-3g library
5987da915Sopenharmony_ci *
6987da915Sopenharmony_ci * Copyright (c)      2009 Martin Bene
7987da915Sopenharmony_ci * Copyright (c)      2009-2010 Jean-Pierre Andre
8987da915Sopenharmony_ci *
9987da915Sopenharmony_ci * This program/include file is free software; you can redistribute it and/or
10987da915Sopenharmony_ci * modify it under the terms of the GNU General Public License as published
11987da915Sopenharmony_ci * by the Free Software Foundation; either version 2 of the License, or
12987da915Sopenharmony_ci * (at your option) any later version.
13987da915Sopenharmony_ci *
14987da915Sopenharmony_ci * This program/include file is distributed in the hope that it will be
15987da915Sopenharmony_ci * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
16987da915Sopenharmony_ci * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17987da915Sopenharmony_ci * GNU General Public License for more details.
18987da915Sopenharmony_ci *
19987da915Sopenharmony_ci * You should have received a copy of the GNU General Public License
20987da915Sopenharmony_ci * along with this program (in the main directory of the NTFS-3G
21987da915Sopenharmony_ci * distribution in the file COPYING); if not, write to the Free Software
22987da915Sopenharmony_ci * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23987da915Sopenharmony_ci */
24987da915Sopenharmony_ci
25987da915Sopenharmony_ci#ifdef HAVE_CONFIG_H
26987da915Sopenharmony_ci#include "config.h"
27987da915Sopenharmony_ci#endif
28987da915Sopenharmony_ci
29987da915Sopenharmony_ci#ifdef HAVE_STDLIB_H
30987da915Sopenharmony_ci#include <stdlib.h>
31987da915Sopenharmony_ci#endif
32987da915Sopenharmony_ci#ifdef HAVE_ERRNO_H
33987da915Sopenharmony_ci#include <errno.h>
34987da915Sopenharmony_ci#endif
35987da915Sopenharmony_ci#ifdef HAVE_STRING_H
36987da915Sopenharmony_ci#include <string.h>
37987da915Sopenharmony_ci#endif
38987da915Sopenharmony_ci#ifdef HAVE_SYS_STAT_H
39987da915Sopenharmony_ci#include <sys/stat.h>
40987da915Sopenharmony_ci#endif
41987da915Sopenharmony_ci
42987da915Sopenharmony_ci#ifdef HAVE_SYS_SYSMACROS_H
43987da915Sopenharmony_ci#include <sys/sysmacros.h>
44987da915Sopenharmony_ci#endif
45987da915Sopenharmony_ci
46987da915Sopenharmony_ci#include "types.h"
47987da915Sopenharmony_ci#include "debug.h"
48987da915Sopenharmony_ci#include "attrib.h"
49987da915Sopenharmony_ci#include "inode.h"
50987da915Sopenharmony_ci#include "dir.h"
51987da915Sopenharmony_ci#include "efs.h"
52987da915Sopenharmony_ci#include "index.h"
53987da915Sopenharmony_ci#include "logging.h"
54987da915Sopenharmony_ci#include "misc.h"
55987da915Sopenharmony_ci#include "efs.h"
56987da915Sopenharmony_ci#include "xattrs.h"
57987da915Sopenharmony_ci
58987da915Sopenharmony_cistatic ntfschar logged_utility_stream_name[] = {
59987da915Sopenharmony_ci	const_cpu_to_le16('$'),
60987da915Sopenharmony_ci	const_cpu_to_le16('E'),
61987da915Sopenharmony_ci	const_cpu_to_le16('F'),
62987da915Sopenharmony_ci	const_cpu_to_le16('S'),
63987da915Sopenharmony_ci	const_cpu_to_le16(0)
64987da915Sopenharmony_ci} ;
65987da915Sopenharmony_ci
66987da915Sopenharmony_ci
67987da915Sopenharmony_ci/*
68987da915Sopenharmony_ci *		Get the ntfs EFS info into an extended attribute
69987da915Sopenharmony_ci */
70987da915Sopenharmony_ci
71987da915Sopenharmony_ciint ntfs_get_efs_info(ntfs_inode *ni, char *value, size_t size)
72987da915Sopenharmony_ci{
73987da915Sopenharmony_ci	EFS_ATTR_HEADER *efs_info;
74987da915Sopenharmony_ci	s64 attr_size = 0;
75987da915Sopenharmony_ci
76987da915Sopenharmony_ci	if (ni) {
77987da915Sopenharmony_ci		if (ni->flags & FILE_ATTR_ENCRYPTED) {
78987da915Sopenharmony_ci			efs_info = (EFS_ATTR_HEADER*)ntfs_attr_readall(ni,
79987da915Sopenharmony_ci				AT_LOGGED_UTILITY_STREAM,(ntfschar*)NULL, 0,
80987da915Sopenharmony_ci				&attr_size);
81987da915Sopenharmony_ci			if (efs_info
82987da915Sopenharmony_ci			    && (le32_to_cpu(efs_info->length) == attr_size)) {
83987da915Sopenharmony_ci				if (attr_size <= (s64)size) {
84987da915Sopenharmony_ci					if (value)
85987da915Sopenharmony_ci						memcpy(value,efs_info,attr_size);
86987da915Sopenharmony_ci					else {
87987da915Sopenharmony_ci						errno = EFAULT;
88987da915Sopenharmony_ci						attr_size = 0;
89987da915Sopenharmony_ci					}
90987da915Sopenharmony_ci				} else
91987da915Sopenharmony_ci					if (size) {
92987da915Sopenharmony_ci						errno = ERANGE;
93987da915Sopenharmony_ci						attr_size = 0;
94987da915Sopenharmony_ci					}
95987da915Sopenharmony_ci				free (efs_info);
96987da915Sopenharmony_ci			} else {
97987da915Sopenharmony_ci				if (efs_info) {
98987da915Sopenharmony_ci					free(efs_info);
99987da915Sopenharmony_ci					ntfs_log_error("Bad efs_info for inode %lld\n",
100987da915Sopenharmony_ci						(long long)ni->mft_no);
101987da915Sopenharmony_ci				} else {
102987da915Sopenharmony_ci					ntfs_log_error("Could not get efsinfo"
103987da915Sopenharmony_ci						" for inode %lld\n",
104987da915Sopenharmony_ci						(long long)ni->mft_no);
105987da915Sopenharmony_ci				}
106987da915Sopenharmony_ci				errno = EIO;
107987da915Sopenharmony_ci				attr_size = 0;
108987da915Sopenharmony_ci			}
109987da915Sopenharmony_ci		} else {
110987da915Sopenharmony_ci			errno = ENODATA;
111987da915Sopenharmony_ci			ntfs_log_trace("Inode %lld is not encrypted\n",
112987da915Sopenharmony_ci				(long long)ni->mft_no);
113987da915Sopenharmony_ci		}
114987da915Sopenharmony_ci	}
115987da915Sopenharmony_ci	return (attr_size ? (int)attr_size : -errno);
116987da915Sopenharmony_ci}
117987da915Sopenharmony_ci
118987da915Sopenharmony_ci/*
119987da915Sopenharmony_ci *		Fix all encrypted AT_DATA attributes of an inode
120987da915Sopenharmony_ci *
121987da915Sopenharmony_ci *	The fix may require making an attribute non resident, which
122987da915Sopenharmony_ci *	requires more space in the MFT record, and may cause some
123987da915Sopenharmony_ci *	attribute to be expelled and the full record to be reorganized.
124987da915Sopenharmony_ci *	When this happens, the search for data attributes has to be
125987da915Sopenharmony_ci *	reinitialized.
126987da915Sopenharmony_ci *
127987da915Sopenharmony_ci *	Returns zero if successful.
128987da915Sopenharmony_ci *		-1 if there is a problem.
129987da915Sopenharmony_ci */
130987da915Sopenharmony_ci
131987da915Sopenharmony_cistatic int fixup_loop(ntfs_inode *ni)
132987da915Sopenharmony_ci{
133987da915Sopenharmony_ci	ntfs_attr_search_ctx *ctx;
134987da915Sopenharmony_ci	ntfs_attr *na;
135987da915Sopenharmony_ci	ATTR_RECORD *a;
136987da915Sopenharmony_ci	BOOL restart;
137987da915Sopenharmony_ci	int cnt;
138987da915Sopenharmony_ci	int maxcnt;
139987da915Sopenharmony_ci	int res = 0;
140987da915Sopenharmony_ci
141987da915Sopenharmony_ci	maxcnt = 0;
142987da915Sopenharmony_ci	do {
143987da915Sopenharmony_ci		restart = FALSE;
144987da915Sopenharmony_ci		ctx = ntfs_attr_get_search_ctx(ni, NULL);
145987da915Sopenharmony_ci		if (!ctx) {
146987da915Sopenharmony_ci			ntfs_log_error("Failed to get ctx for efs\n");
147987da915Sopenharmony_ci			res = -1;
148987da915Sopenharmony_ci		}
149987da915Sopenharmony_ci		cnt = 0;
150987da915Sopenharmony_ci		while (!restart && !res
151987da915Sopenharmony_ci			&& !ntfs_attr_lookup(AT_DATA, NULL, 0,
152987da915Sopenharmony_ci				   CASE_SENSITIVE, 0, NULL, 0, ctx)) {
153987da915Sopenharmony_ci			cnt++;
154987da915Sopenharmony_ci			a = ctx->attr;
155987da915Sopenharmony_ci			na = ntfs_attr_open(ctx->ntfs_ino, AT_DATA,
156987da915Sopenharmony_ci				(ntfschar*)((u8*)a + le16_to_cpu(a->name_offset)),
157987da915Sopenharmony_ci				a->name_length);
158987da915Sopenharmony_ci			if (!na) {
159987da915Sopenharmony_ci				ntfs_log_error("can't open DATA Attribute\n");
160987da915Sopenharmony_ci				res = -1;
161987da915Sopenharmony_ci			}
162987da915Sopenharmony_ci			if (na && !(ctx->attr->flags & ATTR_IS_ENCRYPTED)) {
163987da915Sopenharmony_ci				if (!NAttrNonResident(na)
164987da915Sopenharmony_ci				   && ntfs_attr_make_non_resident(na, ctx)) {
165987da915Sopenharmony_ci				/*
166987da915Sopenharmony_ci				 * ntfs_attr_make_non_resident fails if there
167987da915Sopenharmony_ci				 * is not enough space in the MFT record.
168987da915Sopenharmony_ci				 * When this happens, force making non-resident
169987da915Sopenharmony_ci				 * so that some other attribute is expelled.
170987da915Sopenharmony_ci				 */
171987da915Sopenharmony_ci					if (ntfs_attr_force_non_resident(na)) {
172987da915Sopenharmony_ci						res = -1;
173987da915Sopenharmony_ci					} else {
174987da915Sopenharmony_ci					/* make sure there is some progress */
175987da915Sopenharmony_ci						if (cnt <= maxcnt) {
176987da915Sopenharmony_ci							errno = EIO;
177987da915Sopenharmony_ci							ntfs_log_error("Multiple failure"
178987da915Sopenharmony_ci								" making non resident\n");
179987da915Sopenharmony_ci							res = -1;
180987da915Sopenharmony_ci						} else {
181987da915Sopenharmony_ci							ntfs_attr_put_search_ctx(ctx);
182987da915Sopenharmony_ci							ctx = (ntfs_attr_search_ctx*)NULL;
183987da915Sopenharmony_ci							restart = TRUE;
184987da915Sopenharmony_ci							maxcnt = cnt;
185987da915Sopenharmony_ci						}
186987da915Sopenharmony_ci					}
187987da915Sopenharmony_ci				}
188987da915Sopenharmony_ci				if (!restart && !res
189987da915Sopenharmony_ci				    && ntfs_efs_fixup_attribute(ctx, na)) {
190987da915Sopenharmony_ci					ntfs_log_error("Error in efs fixup of AT_DATA Attribute\n");
191987da915Sopenharmony_ci					res = -1;
192987da915Sopenharmony_ci				}
193987da915Sopenharmony_ci			}
194987da915Sopenharmony_ci		if (na)
195987da915Sopenharmony_ci			ntfs_attr_close(na);
196987da915Sopenharmony_ci		}
197987da915Sopenharmony_ci	} while (restart && !res);
198987da915Sopenharmony_ci	if (ctx)
199987da915Sopenharmony_ci		ntfs_attr_put_search_ctx(ctx);
200987da915Sopenharmony_ci	return (res);
201987da915Sopenharmony_ci}
202987da915Sopenharmony_ci
203987da915Sopenharmony_ci/*
204987da915Sopenharmony_ci *		Set the efs data from an extended attribute
205987da915Sopenharmony_ci *	Warning : the new data is not checked
206987da915Sopenharmony_ci *	Returns 0, or -1 if there is a problem
207987da915Sopenharmony_ci */
208987da915Sopenharmony_ci
209987da915Sopenharmony_ciint ntfs_set_efs_info(ntfs_inode *ni, const char *value, size_t size,
210987da915Sopenharmony_ci			int flags)
211987da915Sopenharmony_ci
212987da915Sopenharmony_ci{
213987da915Sopenharmony_ci	int res;
214987da915Sopenharmony_ci	int written;
215987da915Sopenharmony_ci	ntfs_attr *na;
216987da915Sopenharmony_ci	const EFS_ATTR_HEADER *info_header;
217987da915Sopenharmony_ci
218987da915Sopenharmony_ci	res = 0;
219987da915Sopenharmony_ci	if (ni && value && size) {
220987da915Sopenharmony_ci		if (ni->flags & (FILE_ATTR_ENCRYPTED | FILE_ATTR_COMPRESSED)) {
221987da915Sopenharmony_ci			if (ni->flags & FILE_ATTR_ENCRYPTED) {
222987da915Sopenharmony_ci				ntfs_log_trace("Inode %lld already encrypted\n",
223987da915Sopenharmony_ci						(long long)ni->mft_no);
224987da915Sopenharmony_ci				errno = EEXIST;
225987da915Sopenharmony_ci			} else {
226987da915Sopenharmony_ci				/*
227987da915Sopenharmony_ci				 * Possible problem : if encrypted file was
228987da915Sopenharmony_ci				 * restored in a compressed directory, it was
229987da915Sopenharmony_ci				 * restored as compressed.
230987da915Sopenharmony_ci				 * TODO : decompress first.
231987da915Sopenharmony_ci				 */
232987da915Sopenharmony_ci				ntfs_log_error("Inode %lld cannot be encrypted and compressed\n",
233987da915Sopenharmony_ci					(long long)ni->mft_no);
234987da915Sopenharmony_ci				errno = EIO;
235987da915Sopenharmony_ci			}
236987da915Sopenharmony_ci			return -1;
237987da915Sopenharmony_ci		}
238987da915Sopenharmony_ci		info_header = (const EFS_ATTR_HEADER*)value;
239987da915Sopenharmony_ci			/* make sure we get a likely efsinfo */
240987da915Sopenharmony_ci		if (le32_to_cpu(info_header->length) != size) {
241987da915Sopenharmony_ci			errno = EINVAL;
242987da915Sopenharmony_ci			return (-1);
243987da915Sopenharmony_ci		}
244987da915Sopenharmony_ci		if (!ntfs_attr_exist(ni,AT_LOGGED_UTILITY_STREAM,
245987da915Sopenharmony_ci				(ntfschar*)NULL,0)) {
246987da915Sopenharmony_ci			if (!(flags & XATTR_REPLACE)) {
247987da915Sopenharmony_ci			/*
248987da915Sopenharmony_ci			 * no logged_utility_stream attribute : add one,
249987da915Sopenharmony_ci			 * apparently, this does not feed the new value in
250987da915Sopenharmony_ci			 */
251987da915Sopenharmony_ci				res = ntfs_attr_add(ni,AT_LOGGED_UTILITY_STREAM,
252987da915Sopenharmony_ci					logged_utility_stream_name,4,
253987da915Sopenharmony_ci					(u8*)NULL,(s64)size);
254987da915Sopenharmony_ci			} else {
255987da915Sopenharmony_ci				errno = ENODATA;
256987da915Sopenharmony_ci				res = -1;
257987da915Sopenharmony_ci			}
258987da915Sopenharmony_ci		} else {
259987da915Sopenharmony_ci			errno = EEXIST;
260987da915Sopenharmony_ci			res = -1;
261987da915Sopenharmony_ci		}
262987da915Sopenharmony_ci		if (!res) {
263987da915Sopenharmony_ci			/*
264987da915Sopenharmony_ci			 * open and update the existing efs data
265987da915Sopenharmony_ci			 */
266987da915Sopenharmony_ci			na = ntfs_attr_open(ni, AT_LOGGED_UTILITY_STREAM,
267987da915Sopenharmony_ci				logged_utility_stream_name, 4);
268987da915Sopenharmony_ci			if (na) {
269987da915Sopenharmony_ci				/* resize attribute */
270987da915Sopenharmony_ci				res = ntfs_attr_truncate(na, (s64)size);
271987da915Sopenharmony_ci				/* overwrite value if any */
272987da915Sopenharmony_ci				if (!res && value) {
273987da915Sopenharmony_ci					written = (int)ntfs_attr_pwrite(na,
274987da915Sopenharmony_ci						 (s64)0, (s64)size, value);
275987da915Sopenharmony_ci					if (written != (s64)size) {
276987da915Sopenharmony_ci						ntfs_log_error("Failed to "
277987da915Sopenharmony_ci							"update efs data\n");
278987da915Sopenharmony_ci						errno = EIO;
279987da915Sopenharmony_ci						res = -1;
280987da915Sopenharmony_ci					}
281987da915Sopenharmony_ci				}
282987da915Sopenharmony_ci				ntfs_attr_close(na);
283987da915Sopenharmony_ci			} else
284987da915Sopenharmony_ci				res = -1;
285987da915Sopenharmony_ci		}
286987da915Sopenharmony_ci		if (!res) {
287987da915Sopenharmony_ci			/* Don't handle AT_DATA Attribute(s) if inode is a directory */
288987da915Sopenharmony_ci			if (!(ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)) {
289987da915Sopenharmony_ci				/* iterate over AT_DATA attributes */
290987da915Sopenharmony_ci                        	/* set encrypted flag, truncate attribute to match padding bytes */
291987da915Sopenharmony_ci
292987da915Sopenharmony_ci			if (fixup_loop(ni))
293987da915Sopenharmony_ci				return -1;
294987da915Sopenharmony_ci			}
295987da915Sopenharmony_ci			ni->flags |= FILE_ATTR_ENCRYPTED;
296987da915Sopenharmony_ci			NInoSetDirty(ni);
297987da915Sopenharmony_ci			NInoFileNameSetDirty(ni);
298987da915Sopenharmony_ci		}
299987da915Sopenharmony_ci	} else {
300987da915Sopenharmony_ci		errno = EINVAL;
301987da915Sopenharmony_ci		res = -1;
302987da915Sopenharmony_ci	}
303987da915Sopenharmony_ci	return (res ? -1 : 0);
304987da915Sopenharmony_ci}
305987da915Sopenharmony_ci
306987da915Sopenharmony_ci/*
307987da915Sopenharmony_ci *              Fixup raw encrypted AT_DATA Attribute
308987da915Sopenharmony_ci *     read padding length from last two bytes
309987da915Sopenharmony_ci *     truncate attribute, make non-resident,
310987da915Sopenharmony_ci *     set data size to match padding length
311987da915Sopenharmony_ci *     set ATTR_IS_ENCRYPTED flag on attribute
312987da915Sopenharmony_ci *
313987da915Sopenharmony_ci *	Return 0 if successful
314987da915Sopenharmony_ci *		-1 if failed (errno tells why)
315987da915Sopenharmony_ci */
316987da915Sopenharmony_ci
317987da915Sopenharmony_ciint ntfs_efs_fixup_attribute(ntfs_attr_search_ctx *ctx, ntfs_attr *na)
318987da915Sopenharmony_ci{
319987da915Sopenharmony_ci	s64 newsize;
320987da915Sopenharmony_ci	s64 oldsize;
321987da915Sopenharmony_ci	le16 appended_bytes;
322987da915Sopenharmony_ci	u16 padding_length;
323987da915Sopenharmony_ci	ntfs_inode *ni;
324987da915Sopenharmony_ci	BOOL close_ctx = FALSE;
325987da915Sopenharmony_ci
326987da915Sopenharmony_ci	if (!na) {
327987da915Sopenharmony_ci		ntfs_log_error("no na specified for efs_fixup_attribute\n");
328987da915Sopenharmony_ci		goto err_out;
329987da915Sopenharmony_ci	}
330987da915Sopenharmony_ci	if (!ctx) {
331987da915Sopenharmony_ci		ctx = ntfs_attr_get_search_ctx(na->ni, NULL);
332987da915Sopenharmony_ci		if (!ctx) {
333987da915Sopenharmony_ci			ntfs_log_error("Failed to get ctx for efs\n");
334987da915Sopenharmony_ci			goto err_out;
335987da915Sopenharmony_ci		}
336987da915Sopenharmony_ci		close_ctx = TRUE;
337987da915Sopenharmony_ci		if (ntfs_attr_lookup(AT_DATA, na->name, na->name_len,
338987da915Sopenharmony_ci				CASE_SENSITIVE, 0, NULL, 0, ctx)) {
339987da915Sopenharmony_ci			ntfs_log_error("attr lookup for AT_DATA attribute failed in efs fixup\n");
340987da915Sopenharmony_ci			goto err_out;
341987da915Sopenharmony_ci		}
342987da915Sopenharmony_ci	} else {
343987da915Sopenharmony_ci		if (!NAttrNonResident(na)) {
344987da915Sopenharmony_ci			ntfs_log_error("Cannot make non resident"
345987da915Sopenharmony_ci				" when a context has been allocated\n");
346987da915Sopenharmony_ci			goto err_out;
347987da915Sopenharmony_ci		}
348987da915Sopenharmony_ci	}
349987da915Sopenharmony_ci
350987da915Sopenharmony_ci		/* no extra bytes are added to void attributes */
351987da915Sopenharmony_ci	oldsize = na->data_size;
352987da915Sopenharmony_ci	if (oldsize) {
353987da915Sopenharmony_ci		/* make sure size is valid for a raw encrypted stream */
354987da915Sopenharmony_ci		if ((oldsize & 511) != 2) {
355987da915Sopenharmony_ci			ntfs_log_error("Bad raw encrypted stream\n");
356987da915Sopenharmony_ci			goto err_out;
357987da915Sopenharmony_ci		}
358987da915Sopenharmony_ci		/* read padding length from last two bytes of attribute */
359987da915Sopenharmony_ci		if (ntfs_attr_pread(na, oldsize - 2, 2, &appended_bytes) != 2) {
360987da915Sopenharmony_ci			ntfs_log_error("Error reading padding length\n");
361987da915Sopenharmony_ci			goto err_out;
362987da915Sopenharmony_ci		}
363987da915Sopenharmony_ci		padding_length = le16_to_cpu(appended_bytes);
364987da915Sopenharmony_ci		if (padding_length > 511 || padding_length > na->data_size-2) {
365987da915Sopenharmony_ci			errno = EINVAL;
366987da915Sopenharmony_ci			ntfs_log_error("invalid padding length %d for data_size %lld\n",
367987da915Sopenharmony_ci				 padding_length, (long long)oldsize);
368987da915Sopenharmony_ci			goto err_out;
369987da915Sopenharmony_ci		}
370987da915Sopenharmony_ci		newsize = oldsize - padding_length - 2;
371987da915Sopenharmony_ci		/*
372987da915Sopenharmony_ci		 * truncate attribute to possibly free clusters allocated
373987da915Sopenharmony_ci		 * for the last two bytes, but do not truncate to new size
374987da915Sopenharmony_ci		 * to avoid losing useful data
375987da915Sopenharmony_ci		 */
376987da915Sopenharmony_ci		if (ntfs_attr_truncate(na, oldsize - 2)) {
377987da915Sopenharmony_ci			ntfs_log_error("Error truncating attribute\n");
378987da915Sopenharmony_ci			goto err_out;
379987da915Sopenharmony_ci		}
380987da915Sopenharmony_ci	} else
381987da915Sopenharmony_ci		newsize = 0;
382987da915Sopenharmony_ci
383987da915Sopenharmony_ci	/*
384987da915Sopenharmony_ci	 * Encrypted AT_DATA Attributes MUST be non-resident
385987da915Sopenharmony_ci	 * This has to be done after the attribute is resized, as
386987da915Sopenharmony_ci	 * resizing down to zero may cause the attribute to be made
387987da915Sopenharmony_ci	 * resident.
388987da915Sopenharmony_ci	 */
389987da915Sopenharmony_ci	if (!NAttrNonResident(na)
390987da915Sopenharmony_ci	    && ntfs_attr_make_non_resident(na, ctx)) {
391987da915Sopenharmony_ci		if (!close_ctx
392987da915Sopenharmony_ci		    || ntfs_attr_force_non_resident(na)) {
393987da915Sopenharmony_ci			ntfs_log_error("Error making DATA attribute non-resident\n");
394987da915Sopenharmony_ci			goto err_out;
395987da915Sopenharmony_ci		} else {
396987da915Sopenharmony_ci			/*
397987da915Sopenharmony_ci			 * must reinitialize context after forcing
398987da915Sopenharmony_ci			 * non-resident. We need a context for updating
399987da915Sopenharmony_ci			 * the state, and at this point, we are sure
400987da915Sopenharmony_ci			 * the context is not used elsewhere.
401987da915Sopenharmony_ci			 */
402987da915Sopenharmony_ci			ntfs_attr_reinit_search_ctx(ctx);
403987da915Sopenharmony_ci			if (ntfs_attr_lookup(AT_DATA, na->name, na->name_len,
404987da915Sopenharmony_ci					CASE_SENSITIVE, 0, NULL, 0, ctx)) {
405987da915Sopenharmony_ci				ntfs_log_error("attr lookup for AT_DATA attribute failed in efs fixup\n");
406987da915Sopenharmony_ci				goto err_out;
407987da915Sopenharmony_ci			}
408987da915Sopenharmony_ci		}
409987da915Sopenharmony_ci	}
410987da915Sopenharmony_ci	ni = na->ni;
411987da915Sopenharmony_ci	if (!na->name_len) {
412987da915Sopenharmony_ci		ni->data_size = newsize;
413987da915Sopenharmony_ci		ni->allocated_size = na->allocated_size;
414987da915Sopenharmony_ci	}
415987da915Sopenharmony_ci	NInoSetDirty(ni);
416987da915Sopenharmony_ci	NInoFileNameSetDirty(ni);
417987da915Sopenharmony_ci
418987da915Sopenharmony_ci	ctx->attr->data_size = cpu_to_sle64(newsize);
419987da915Sopenharmony_ci	if (sle64_to_cpu(ctx->attr->initialized_size) > newsize)
420987da915Sopenharmony_ci		ctx->attr->initialized_size = ctx->attr->data_size;
421987da915Sopenharmony_ci	ctx->attr->flags |= ATTR_IS_ENCRYPTED;
422987da915Sopenharmony_ci	if (close_ctx)
423987da915Sopenharmony_ci		ntfs_attr_put_search_ctx(ctx);
424987da915Sopenharmony_ci
425987da915Sopenharmony_ci	return (0);
426987da915Sopenharmony_cierr_out:
427987da915Sopenharmony_ci	if (close_ctx && ctx)
428987da915Sopenharmony_ci		ntfs_attr_put_search_ctx(ctx);
429987da915Sopenharmony_ci	return (-1);
430987da915Sopenharmony_ci}
431