xref: /haiku/src/add-ons/kernel/file_systems/ntfs/libntfs/inode.c (revision 0c93c0a807b27096abbfad677436afb7d1712d4a)
1 /**
2  * inode.c - Inode handling code. Originated from the Linux-NTFS project.
3  *
4  * Copyright (c) 2002-2005 Anton Altaparmakov
5  * Copyright (c) 2002-2006 Szabolcs Szakacsits
6  * Copyright (c) 2004-2005 Yura Pakhuchiy
7  * Copyright (c) 2004-2005 Richard Russon
8  *
9  * This program/include file is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License as published
11  * by the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program/include file is distributed in the hope that it will be
15  * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
16  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program (in the main directory of the NTFS-3G
21  * distribution in the file COPYING); if not, write to the Free Software
22  * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23  */
24 
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
28 
29 #ifdef HAVE_STDLIB_H
30 #include <stdlib.h>
31 #endif
32 #ifdef HAVE_STRING_H
33 #include <string.h>
34 #endif
35 #ifdef HAVE_ERRNO_H
36 #include <errno.h>
37 #endif
38 
39 #include "compat.h"
40 #include "types.h"
41 #include "attrib.h"
42 #include "inode.h"
43 #include "debug.h"
44 #include "mft.h"
45 #include "attrlist.h"
46 #include "runlist.h"
47 #include "lcnalloc.h"
48 #include "index.h"
49 #include "dir.h"
50 #include "ntfstime.h"
51 #include "logging.h"
52 #include "misc.h"
53 
54 /**
55  * ntfs_inode_mark_dirty - set the inode (and its base inode if it exists) dirty
56  * @ni:		ntfs inode to set dirty
57  *
58  * Set the inode @ni dirty so it is written out later (at the latest at
59  * ntfs_inode_close() time). If @ni is an extent inode, set the base inode
60  * dirty, too.
61  *
62  * This function cannot fail.
63  */
64 void ntfs_inode_mark_dirty(ntfs_inode *ni)
65 {
66 	NInoSetDirty(ni);
67 	if (ni->nr_extents == -1)
68 		NInoSetDirty(ni->base_ni);
69 }
70 
71 /**
72  * __ntfs_inode_allocate - Create and initialise an NTFS inode object
73  * @vol:
74  *
75  * Description...
76  *
77  * Returns:
78  */
79 static ntfs_inode *__ntfs_inode_allocate(ntfs_volume *vol)
80 {
81 	ntfs_inode *ni;
82 
83 	ni = (ntfs_inode*)calloc(1, sizeof(ntfs_inode));
84 	if (ni)
85 		ni->vol = vol;
86 	return ni;
87 }
88 
89 /**
90  * ntfs_inode_allocate - Create an NTFS inode object
91  * @vol:
92  *
93  * Description...
94  *
95  * Returns:
96  */
97 ntfs_inode *ntfs_inode_allocate(ntfs_volume *vol)
98 {
99 	return __ntfs_inode_allocate(vol);
100 }
101 
102 /**
103  * __ntfs_inode_release - Destroy an NTFS inode object
104  * @ni:
105  *
106  * Description...
107  *
108  * Returns:
109  */
110 static int __ntfs_inode_release(ntfs_inode *ni)
111 {
112 	if (NInoDirty(ni))
113 		ntfs_log_debug("Eeek. Discarding dirty inode!\n");
114 	if (NInoAttrList(ni) && ni->attr_list)
115 		free(ni->attr_list);
116 	free(ni->mrec);
117 	free(ni);
118 	return 0;
119 }
120 
121 /**
122  * ntfs_inode_open - open an inode ready for access
123  * @vol:	volume to get the inode from
124  * @mref:	inode number / mft record number to open
125  *
126  * Allocate an ntfs_inode structure and initialize it for the given inode
127  * specified by @mref. @mref specifies the inode number / mft record to read,
128  * including the sequence number, which can be 0 if no sequence number checking
129  * is to be performed.
130  *
131  * Then, allocate a buffer for the mft record, read the mft record from the
132  * volume @vol, and attach it to the ntfs_inode structure (->mrec). The
133  * mft record is mst deprotected and sanity checked for validity and we abort
134  * if deprotection or checks fail.
135  *
136  * Finally, search for an attribute list attribute in the mft record and if one
137  * is found, load the attribute list attribute value and attach it to the
138  * ntfs_inode structure (->attr_list). Also set the NI_AttrList bit to indicate
139  * this.
140  *
141  * Return a pointer to the ntfs_inode structure on success or NULL on error,
142  * with errno set to the error code.
143  */
144 ntfs_inode *ntfs_inode_open(ntfs_volume *vol, const MFT_REF mref)
145 {
146 	s64 l;
147 	ntfs_inode *ni;
148 	ntfs_attr_search_ctx *ctx;
149 	int err = 0;
150 	STANDARD_INFORMATION *std_info;
151 
152 	ntfs_log_trace("Entering for inode 0x%llx.\n", MREF(mref));
153 	if (!vol) {
154 		errno = EINVAL;
155 		return NULL;
156 	}
157 	ni = __ntfs_inode_allocate(vol);
158 	if (!ni)
159 		return NULL;
160 	if (ntfs_file_record_read(vol, mref, &ni->mrec, NULL))
161 		goto err_out;
162 	if (!(ni->mrec->flags & MFT_RECORD_IN_USE)) {
163 		err = ENOENT;
164 		goto err_out;
165 	}
166 	ni->mft_no = MREF(mref);
167 	ctx = ntfs_attr_get_search_ctx(ni, NULL);
168 	if (!ctx)
169 		goto err_out;
170 	/* Receive some basic information about inode. */
171 	if (ntfs_attr_lookup(AT_STANDARD_INFORMATION, AT_UNNAMED,
172 				0, CASE_SENSITIVE, 0, NULL, 0, ctx)) {
173 		err = errno;
174 		ntfs_log_trace("Failed to receive STANDARD_INFORMATION "
175 				"attribute.\n");
176 		goto put_err_out;
177 	}
178 	std_info = (STANDARD_INFORMATION *)((u8 *)ctx->attr +
179 			le16_to_cpu(ctx->attr->value_offset));
180 	ni->flags = std_info->file_attributes;
181 	ni->creation_time = ntfs2utc(std_info->creation_time);
182 	ni->last_data_change_time = ntfs2utc(std_info->last_data_change_time);
183 	ni->last_mft_change_time = ntfs2utc(std_info->last_mft_change_time);
184 	ni->last_access_time = ntfs2utc(std_info->last_access_time);
185 	/* Set attribute list information. */
186 	if (ntfs_attr_lookup(AT_ATTRIBUTE_LIST, AT_UNNAMED, 0, 0, 0, NULL, 0,
187 			ctx)) {
188 		if (errno != ENOENT)
189 			goto put_err_out;
190 		/* Attribute list attribute does not present. */
191 		goto get_size;
192 	}
193 	NInoSetAttrList(ni);
194 	l = ntfs_get_attribute_value_length(ctx->attr);
195 	if (!l)
196 		goto put_err_out;
197 	if (l > 0x40000) {
198 		err = EIO;
199 		goto put_err_out;
200 	}
201 	ni->attr_list_size = l;
202 	ni->attr_list = ntfs_malloc(ni->attr_list_size);
203 	if (!ni->attr_list)
204 		goto put_err_out;
205 	l = ntfs_get_attribute_value(vol, ctx->attr, ni->attr_list);
206 	if (!l)
207 		goto put_err_out;
208 	if (l != ni->attr_list_size) {
209 		err = EIO;
210 		goto put_err_out;
211 	}
212 get_size:
213 	if (ntfs_attr_lookup(AT_DATA, AT_UNNAMED, 0, 0, 0, NULL, 0, ctx)) {
214 		if (errno != ENOENT)
215 			goto put_err_out;
216 		/* Directory or special file. */
217 		ni->data_size = ni->allocated_size = 0;
218 	} else {
219 		if (ctx->attr->non_resident) {
220 			ni->data_size = sle64_to_cpu(ctx->attr->data_size);
221 			if (ctx->attr->flags &
222 					(ATTR_IS_COMPRESSED | ATTR_IS_SPARSE))
223 				ni->allocated_size = sle64_to_cpu(
224 						ctx->attr->compressed_size);
225 			else
226 				ni->allocated_size = sle64_to_cpu(
227 						ctx->attr->allocated_size);
228 		} else {
229 			ni->data_size = le32_to_cpu(ctx->attr->value_length);
230 			ni->allocated_size = (ni->data_size + 7) & ~7;
231 		}
232 	}
233 	ntfs_attr_put_search_ctx(ctx);
234 	return ni;
235 put_err_out:
236 	if (!err)
237 		err = errno;
238 	ntfs_attr_put_search_ctx(ctx);
239 err_out:
240 	if (!err)
241 		err = errno;
242 	__ntfs_inode_release(ni);
243 	errno = err;
244 	return NULL;
245 }
246 
247 /**
248  * ntfs_inode_close - close an ntfs inode and free all associated memory
249  * @ni:		ntfs inode to close
250  *
251  * Make sure the ntfs inode @ni is clean.
252  *
253  * If the ntfs inode @ni is a base inode, close all associated extent inodes,
254  * then deallocate all memory attached to it, and finally free the ntfs inode
255  * structure itself.
256  *
257  * If it is an extent inode, we disconnect it from its base inode before we
258  * destroy it.
259  *
260  * Return 0 on success or -1 on error with errno set to the error code. On
261  * error, @ni has not been freed. The user should attempt to handle the error
262  * and call ntfs_inode_close() again. The following error codes are defined:
263  *
264  *	EBUSY	@ni and/or its attribute list runlist is/are dirty and the
265  *		attempt to write it/them to disk failed.
266  *	EINVAL	@ni is invalid (probably it is an extent inode).
267  *	EIO	I/O error while trying to write inode to disk.
268  */
269 int ntfs_inode_close(ntfs_inode *ni)
270 {
271 	if (!ni)
272 		return 0;
273 
274 	ntfs_log_trace("Entering for inode 0x%llx.\n", (long long) ni->mft_no);
275 
276 	/* If we have dirty metadata, write it out. */
277 	if (NInoDirty(ni) || NInoAttrListDirty(ni)) {
278 		if (ntfs_inode_sync(ni)) {
279 			if (errno != EIO)
280 				errno = EBUSY;
281 			return -1;
282 		}
283 	}
284 	/* Is this a base inode with mapped extent inodes? */
285 	if (ni->nr_extents > 0) {
286 		while (ni->nr_extents > 0) {
287 			if (ntfs_inode_close(ni->extent_nis[0])) {
288 				if (errno != EIO)
289 					errno = EBUSY;
290 				return -1;
291 			}
292 		}
293 	} else if (ni->nr_extents == -1) {
294 		ntfs_inode **tmp_nis;
295 		ntfs_inode *base_ni;
296 		s32 i;
297 
298 		/*
299 		 * If the inode is an extent inode, disconnect it from the
300 		 * base inode before destroying it.
301 		 */
302 		base_ni = ni->base_ni;
303 		for (i = 0; i < base_ni->nr_extents; ++i) {
304 			tmp_nis = base_ni->extent_nis;
305 			if (tmp_nis[i] != ni)
306 				continue;
307 			/* Found it. Disconnect. */
308 			memmove(tmp_nis + i, tmp_nis + i + 1,
309 					(base_ni->nr_extents - i - 1) *
310 					sizeof(ntfs_inode *));
311 			/* Buffer should be for multiple of four extents. */
312 			if ((--base_ni->nr_extents) & 3) {
313 				i = -1;
314 				break;
315 			}
316 			/*
317 			 * ElectricFence is unhappy with realloc(x,0) as free(x)
318 			 * thus we explicitly separate these two cases.
319 			 */
320 			if (base_ni->nr_extents) {
321 				/* Resize the memory buffer. */
322 				tmp_nis = realloc(tmp_nis, base_ni->nr_extents *
323 						  sizeof(ntfs_inode *));
324 				/* Ignore errors, they don't really matter. */
325 				if (tmp_nis)
326 					base_ni->extent_nis = tmp_nis;
327 			} else if (tmp_nis)
328 				free(tmp_nis);
329 			/* Allow for error checking. */
330 			i = -1;
331 			break;
332 		}
333 		if (i != -1)
334 			ntfs_log_debug("Extent inode was not attached to base inode! "
335 					"Weird! Continuing regardless.\n");
336 	}
337 	return __ntfs_inode_release(ni);
338 }
339 
340 /**
341  * ntfs_extent_inode_open - load an extent inode and attach it to its base
342  * @base_ni:	base ntfs inode
343  * @mref:	mft reference of the extent inode to load (in little endian)
344  *
345  * First check if the extent inode @mref is already attached to the base ntfs
346  * inode @base_ni, and if so, return a pointer to the attached extent inode.
347  *
348  * If the extent inode is not already attached to the base inode, allocate an
349  * ntfs_inode structure and initialize it for the given inode @mref. @mref
350  * specifies the inode number / mft record to read, including the sequence
351  * number, which can be 0 if no sequence number checking is to be performed.
352  *
353  * Then, allocate a buffer for the mft record, read the mft record from the
354  * volume @base_ni->vol, and attach it to the ntfs_inode structure (->mrec).
355  * The mft record is mst deprotected and sanity checked for validity and we
356  * abort if deprotection or checks fail.
357  *
358  * Finally attach the ntfs inode to its base inode @base_ni and return a
359  * pointer to the ntfs_inode structure on success or NULL on error, with errno
360  * set to the error code.
361  *
362  * Note, extent inodes are never closed directly. They are automatically
363  * disposed off by the closing of the base inode.
364  */
365 ntfs_inode *ntfs_extent_inode_open(ntfs_inode *base_ni, const MFT_REF mref)
366 {
367 	u64 mft_no = MREF_LE(mref);
368 	ntfs_inode *ni;
369 	ntfs_inode **extent_nis;
370 	int i;
371 
372 	if (!base_ni) {
373 		errno = EINVAL;
374 		return NULL;
375 	}
376 	ntfs_log_trace("Opening extent inode 0x%llx (base mft record 0x%llx).\n",
377 			(unsigned long long)mft_no,
378 			(unsigned long long)base_ni->mft_no);
379 	/* Is the extent inode already open and attached to the base inode? */
380 	if (base_ni->nr_extents > 0) {
381 		extent_nis = base_ni->extent_nis;
382 		for (i = 0; i < base_ni->nr_extents; i++) {
383 			u16 seq_no;
384 
385 			ni = extent_nis[i];
386 			if (mft_no != ni->mft_no)
387 				continue;
388 			/* Verify the sequence number if given. */
389 			seq_no = MSEQNO_LE(mref);
390 			if (seq_no && seq_no != le16_to_cpu(
391 					ni->mrec->sequence_number)) {
392 				ntfs_log_debug("Found stale extent mft reference! "
393 					"Corrupt file system. Run chkdsk.\n");
394 				errno = EIO;
395 				return NULL;
396 			}
397 			/* We are done, return the extent inode. */
398 			return ni;
399 		}
400 	}
401 	/* Wasn't there, we need to load the extent inode. */
402 	ni = __ntfs_inode_allocate(base_ni->vol);
403 	if (!ni)
404 		return NULL;
405 	if (ntfs_file_record_read(base_ni->vol, le64_to_cpu(mref), &ni->mrec,
406 			NULL))
407 		goto err_out;
408 	ni->mft_no = mft_no;
409 	ni->nr_extents = -1;
410 	ni->base_ni = base_ni;
411 	/* Attach extent inode to base inode, reallocating memory if needed. */
412 	if (!(base_ni->nr_extents & 3)) {
413 		i = (base_ni->nr_extents + 4) * sizeof(ntfs_inode *);
414 
415 		extent_nis = ntfs_malloc(i);
416 		if (!extent_nis)
417 			goto err_out;
418 		if (base_ni->nr_extents) {
419 			memcpy(extent_nis, base_ni->extent_nis,
420 					i - 4 * sizeof(ntfs_inode *));
421 			free(base_ni->extent_nis);
422 		}
423 		base_ni->extent_nis = extent_nis;
424 	}
425 	base_ni->extent_nis[base_ni->nr_extents++] = ni;
426 	return ni;
427 err_out:
428 	i = errno;
429 	__ntfs_inode_release(ni);
430 	errno = i;
431 	ntfs_log_perror("Failed to open extent inode");
432 	return NULL;
433 }
434 
435 /**
436  * ntfs_inode_attach_all_extents - attach all extents for target inode
437  * @ni:		opened ntfs inode for which perform attach
438  *
439  * Return 0 on success and -1 on error with errno set to the error code.
440  */
441 int ntfs_inode_attach_all_extents(ntfs_inode *ni)
442 {
443 	ATTR_LIST_ENTRY *ale;
444 	u64 prev_attached = 0;
445 
446 	if (!ni) {
447 		ntfs_log_trace("Invalid arguments.\n");
448 		errno = EINVAL;
449 		return -1;
450 	}
451 
452 	if (ni->nr_extents == -1)
453 		ni = ni->base_ni;
454 
455 	ntfs_log_trace("Entering for inode 0x%llx.\n", (long long) ni->mft_no);
456 
457 	/* Inode haven't got attribute list, thus nothing to attach. */
458 	if (!NInoAttrList(ni))
459 		return 0;
460 
461 	if (!ni->attr_list) {
462 		ntfs_log_trace("Corrupt in-memory struct.\n");
463 		errno = EINVAL;
464 		return -1;
465 	}
466 
467 	/* Walk through attribute list and attach all extents. */
468 	errno = 0;
469 	ale = (ATTR_LIST_ENTRY *)ni->attr_list;
470 	while ((u8*)ale < ni->attr_list + ni->attr_list_size) {
471 		if (ni->mft_no != MREF_LE(ale->mft_reference) &&
472 				prev_attached != MREF_LE(ale->mft_reference)) {
473 			if (!ntfs_extent_inode_open(ni,
474 					MREF_LE(ale->mft_reference))) {
475 				ntfs_log_trace("Couldn't attach extent inode.\n");
476 				return -1;
477 			}
478 			prev_attached = MREF_LE(ale->mft_reference);
479 		}
480 		ale = (ATTR_LIST_ENTRY *)((u8*)ale + le16_to_cpu(ale->length));
481 	}
482 	return 0;
483 }
484 
485 /**
486  * ntfs_inode_sync_standard_information - update standard information attribute
487  * @ni:		ntfs inode to update standard information
488  *
489  * Return 0 on success or -1 on error with errno set to the error code.
490  */
491 static int ntfs_inode_sync_standard_information(ntfs_inode *ni)
492 {
493 	ntfs_attr_search_ctx *ctx;
494 	STANDARD_INFORMATION *std_info;
495 	int err;
496 
497 	ntfs_log_trace("Entering for inode 0x%llx.\n", (long long) ni->mft_no);
498 
499 	ctx = ntfs_attr_get_search_ctx(ni, NULL);
500 	if (!ctx)
501 		return -1;
502 	if (ntfs_attr_lookup(AT_STANDARD_INFORMATION, AT_UNNAMED,
503 				0, CASE_SENSITIVE, 0, NULL, 0, ctx)) {
504 		err = errno;
505 		ntfs_log_trace("Failed to receive STANDARD_INFORMATION "
506 				"attribute.\n");
507 		ntfs_attr_put_search_ctx(ctx);
508 		errno = err;
509 		return -1;
510 	}
511 	std_info = (STANDARD_INFORMATION *)((u8 *)ctx->attr +
512 			le16_to_cpu(ctx->attr->value_offset));
513 	std_info->file_attributes = ni->flags;
514 	std_info->creation_time = utc2ntfs(ni->creation_time);
515 	std_info->last_data_change_time = utc2ntfs(ni->last_data_change_time);
516 	std_info->last_mft_change_time = utc2ntfs(ni->last_mft_change_time);
517 	std_info->last_access_time = utc2ntfs(ni->last_access_time);
518 	ntfs_inode_mark_dirty(ctx->ntfs_ino);
519 	ntfs_attr_put_search_ctx(ctx);
520 	return 0;
521 }
522 
523 /**
524  * ntfs_inode_sync_file_name - update FILE_NAME attributes
525  * @ni:		ntfs inode to update FILE_NAME attributes
526  *
527  * Update all FILE_NAME attributes for inode @ni in the index.
528  *
529  * Return 0 on success or -1 on error with errno set to the error code.
530  */
531 static int ntfs_inode_sync_file_name(ntfs_inode *ni)
532 {
533 	ntfs_attr_search_ctx *ctx = NULL;
534 	ntfs_index_context *ictx;
535 	ntfs_inode *index_ni;
536 	FILE_NAME_ATTR *fn;
537 	int err = 0;
538 
539 	ntfs_log_trace("Entering for inode 0x%llx.\n", (long long) ni->mft_no);
540 
541 	ctx = ntfs_attr_get_search_ctx(ni, NULL);
542 	if (!ctx) {
543 		err = errno;
544 		ntfs_log_trace("Failed to get attribute search context.\n");
545 		goto err_out;
546 	}
547 	/* Walk through all FILE_NAME attributes and update them. */
548 	while (!ntfs_attr_lookup(AT_FILE_NAME, NULL, 0, 0, 0, NULL, 0, ctx)) {
549 		fn = (FILE_NAME_ATTR *)((u8 *)ctx->attr +
550 				le16_to_cpu(ctx->attr->value_offset));
551 		if (MREF_LE(fn->parent_directory) == ni->mft_no) {
552 			/*
553 			 * WARNING: We cheater here and obtain 2 attribute
554 			 * search contexts for one inode (first we obtained
555 			 * above, second will be obtained inside
556 			 * ntfs_index_lookup), it's acceptable for library,
557 			 * but will lock kernel.
558 			 */
559 			index_ni = ni;
560 		} else
561 			index_ni = ntfs_inode_open(ni->vol,
562 				le64_to_cpu(fn->parent_directory));
563 		if (!index_ni) {
564 			if (!err)
565 				err = errno;
566 			ntfs_log_trace("Failed to open inode with index.\n");
567 			continue;
568 		}
569 		ictx = ntfs_index_ctx_get(index_ni, NTFS_INDEX_I30, 4);
570 		if (!ictx) {
571 			if (!err)
572 				err = errno;
573 			ntfs_log_trace("Failed to get index context.\n");
574 			ntfs_inode_close(index_ni);
575 			continue;
576 		}
577 		if (ntfs_index_lookup(fn, sizeof(FILE_NAME_ATTR), ictx)) {
578 			if (!err) {
579 				if (errno == ENOENT)
580 					err = EIO;
581 				else
582 					err = errno;
583 			}
584 			ntfs_log_trace("Index lookup failed.\n");
585 			ntfs_index_ctx_put(ictx);
586 			ntfs_inode_close(index_ni);
587 			continue;
588 		}
589 		/* Update flags and file size. */
590 		fn = (FILE_NAME_ATTR *)ictx->data;
591 		fn->file_attributes =
592 				(fn->file_attributes & ~FILE_ATTR_VALID_FLAGS) |
593 				(ni->flags & FILE_ATTR_VALID_FLAGS);
594 		fn->allocated_size = cpu_to_sle64(ni->allocated_size);
595 		fn->data_size = cpu_to_sle64(ni->data_size);
596 		fn->creation_time = utc2ntfs(ni->creation_time);
597 		fn->last_data_change_time = utc2ntfs(ni->last_data_change_time);
598 		fn->last_mft_change_time = utc2ntfs(ni->last_mft_change_time);
599 		fn->last_access_time = utc2ntfs(ni->last_access_time);
600 		ntfs_index_entry_mark_dirty(ictx);
601 		ntfs_index_ctx_put(ictx);
602 		if (ni != index_ni)
603 			ntfs_inode_close(index_ni);
604 	}
605 	/* Check for real error occurred. */
606 	if (errno != ENOENT) {
607 		err = errno;
608 		ntfs_log_trace("Attribute lookup failed.\n");
609 		goto err_out;
610 	}
611 	ntfs_attr_put_search_ctx(ctx);
612 	if (err) {
613 		errno = err;
614 		return -1;
615 	}
616 	return 0;
617 err_out:
618 	if (ctx)
619 		ntfs_attr_put_search_ctx(ctx);
620 	errno = err;
621 	return -1;
622 }
623 
624 /**
625  * ntfs_inode_sync - write the inode (and its dirty extents) to disk
626  * @ni:		ntfs inode to write
627  *
628  * Write the inode @ni to disk as well as its dirty extent inodes if such
629  * exist and @ni is a base inode. If @ni is an extent inode, only @ni is
630  * written completely disregarding its base inode and any other extent inodes.
631  *
632  * For a base inode with dirty extent inodes if any writes fail for whatever
633  * reason, the failing inode is skipped and the sync process is continued. At
634  * the end the error condition that brought about the failure is returned. Thus
635  * the smallest amount of data loss possible occurs.
636  *
637  * Return 0 on success or -1 on error with errno set to the error code.
638  * The following error codes are defined:
639  *	EINVAL	- Invalid arguments were passed to the function.
640  *	EBUSY	- Inode and/or one of its extents is busy, try again later.
641  *	EIO	- I/O error while writing the inode (or one of its extents).
642  */
643 int ntfs_inode_sync(ntfs_inode *ni)
644 {
645 	int err = 0;
646 
647 	if (!ni) {
648 		errno = EINVAL;
649 		return -1;
650 	}
651 
652 	ntfs_log_trace("Entering for inode 0x%llx.\n", (long long) ni->mft_no);
653 
654 	/* Update STANDARD_INFORMATION. */
655 	if ((ni->mrec->flags & MFT_RECORD_IN_USE) && ni->nr_extents != -1 &&
656 			ntfs_inode_sync_standard_information(ni)) {
657 		if (!err || errno == EIO) {
658 			err = errno;
659 			if (err != EIO)
660 				err = EBUSY;
661 		}
662 		ntfs_log_trace("Failed to sync standard information.\n");
663 	}
664 
665 	/* Update FILE_NAME's in the index. */
666 	if ((ni->mrec->flags & MFT_RECORD_IN_USE) && ni->nr_extents != -1 &&
667 			NInoFileNameTestAndClearDirty(ni) &&
668 			ntfs_inode_sync_file_name(ni)) {
669 		if (!err || errno == EIO) {
670 			err = errno;
671 			if (err != EIO)
672 				err = EBUSY;
673 		}
674 		ntfs_log_trace("Failed to sync FILE_NAME attributes.\n");
675 		NInoFileNameSetDirty(ni);
676 	}
677 
678 	/* Write out attribute list from cache to disk. */
679 	if ((ni->mrec->flags & MFT_RECORD_IN_USE) && ni->nr_extents != -1 &&
680 			NInoAttrList(ni) && NInoAttrListTestAndClearDirty(ni)) {
681 		ntfs_attr *na;
682 
683 		na = ntfs_attr_open(ni, AT_ATTRIBUTE_LIST, AT_UNNAMED, 0);
684 		if (!na) {
685 			if (!err || errno == EIO) {
686 				err = errno;
687 				if (err != EIO)
688 					err = EBUSY;
689 				ntfs_log_trace("Attribute list sync failed (open "
690 						"failed).\n");
691 			}
692 			NInoAttrListSetDirty(ni);
693 		} else {
694 			if (na->data_size == ni->attr_list_size) {
695 				if (ntfs_attr_pwrite(na, 0, ni->attr_list_size,
696 							ni->attr_list) !=
697 							ni->attr_list_size) {
698 					if (!err || errno == EIO) {
699 						err = errno;
700 						if (err != EIO)
701 							err = EBUSY;
702 						ntfs_log_trace("Attribute list sync "
703 							"failed (write failed).\n");
704 					}
705 					NInoAttrListSetDirty(ni);
706 				}
707 			} else {
708 				err = EIO;
709 				ntfs_log_trace("Attribute list sync failed (invalid size).\n");
710 				NInoAttrListSetDirty(ni);
711 			}
712 			ntfs_attr_close(na);
713 		}
714 	}
715 
716 	/* Write this inode out to the $MFT (and $MFTMirr if applicable). */
717 	if (NInoTestAndClearDirty(ni)) {
718 		if (ntfs_mft_record_write(ni->vol, ni->mft_no, ni->mrec)) {
719 			if (!err || errno == EIO) {
720 				err = errno;
721 				if (err != EIO)
722 					err = EBUSY;
723 			}
724 			NInoSetDirty(ni);
725 			ntfs_log_trace("Base MFT record sync failed.\n");
726 		}
727 	}
728 
729 	/* If this is a base inode with extents write all dirty extents, too. */
730 	if (ni->nr_extents > 0) {
731 		s32 i;
732 
733 		for (i = 0; i < ni->nr_extents; ++i) {
734 			ntfs_inode *eni;
735 
736 			eni = ni->extent_nis[i];
737 			if (NInoTestAndClearDirty(eni)) {
738 				if (ntfs_mft_record_write(eni->vol, eni->mft_no,
739 						eni->mrec)) {
740 					if (!err || errno == EIO) {
741 						err = errno;
742 						if (err != EIO)
743 							err = EBUSY;
744 					}
745 					NInoSetDirty(eni);
746 					ntfs_log_trace("Extent MFT record sync "
747 							"failed.\n");
748 				}
749 			}
750 		}
751 	}
752 
753 	if (!err)
754 		return 0;
755 	errno = err;
756 	return -1;
757 }
758 
759 /**
760  * ntfs_inode_add_attrlist - add attribute list to inode and fill it
761  * @ni: opened ntfs inode to which add attribute list
762  *
763  * Return 0 on success or -1 on error with errno set to the error code.
764  * The following error codes are defined:
765  *	EINVAL	- Invalid arguments were passed to the function.
766  *	EEXIST	- Attribute list already exist.
767  *	EIO	- Input/Ouput error occurred.
768  *	ENOMEM	- Not enough memory to perform add.
769  */
770 int ntfs_inode_add_attrlist(ntfs_inode *ni)
771 {
772 	int err;
773 	ntfs_attr_search_ctx *ctx;
774 	u8 *al = NULL, *aln;
775 	int al_len = 0;
776 	ATTR_LIST_ENTRY *ale = NULL;
777 	ntfs_attr *na;
778 
779 	if (!ni) {
780 		ntfs_log_trace("Invalid arguments.\n");
781 		errno = EINVAL;
782 		return -1;
783 	}
784 
785 	ntfs_log_trace("Entering for inode 0x%llx.\n", (long long) ni->mft_no);
786 
787 	if (NInoAttrList(ni) || ni->nr_extents) {
788 		ntfs_log_trace("Inode already has got attribute list.\n");
789 		errno = EEXIST;
790 		return -1;
791 	}
792 
793 	/* Form attribute list. */
794 	ctx = ntfs_attr_get_search_ctx(ni, NULL);
795 	if (!ctx) {
796 		err = errno;
797 		ntfs_log_trace("Couldn't get search context.\n");
798 		goto err_out;
799 	}
800 	/* Walk through all attributes. */
801 	while (!ntfs_attr_lookup(AT_UNUSED, NULL, 0, 0, 0, NULL, 0, ctx)) {
802 
803 		int ale_size;
804 
805 		if (ctx->attr->type == AT_ATTRIBUTE_LIST) {
806 			err = EIO;
807 			ntfs_log_trace("Eeek! Attribute list already present.\n");
808 			goto put_err_out;
809 		}
810 
811 		ale_size = (sizeof(ATTR_LIST_ENTRY) + sizeof(ntfschar) *
812 					ctx->attr->name_length + 7) & ~7;
813 		al_len += ale_size;
814 
815 		aln = realloc(al, al_len);
816 		if (!aln) {
817 			err = errno;
818 			ntfs_log_perror("Failed to realloc %d bytes", al_len);
819 			goto put_err_out;
820 		}
821 		ale = (ATTR_LIST_ENTRY *)(aln + ((u8 *)ale - al));
822 		al = aln;
823 
824 		memset(ale, 0, ale_size);
825 
826 		/* Add attribute to attribute list. */
827 		ale->type = ctx->attr->type;
828 		ale->length = cpu_to_le16((sizeof(ATTR_LIST_ENTRY) +
829 			sizeof(ntfschar) * ctx->attr->name_length + 7) & ~7);
830 		ale->name_length = ctx->attr->name_length;
831 		ale->name_offset = (u8 *)ale->name - (u8 *)ale;
832 		if (ctx->attr->non_resident)
833 			ale->lowest_vcn = ctx->attr->lowest_vcn;
834 		else
835 			ale->lowest_vcn = 0;
836 		ale->mft_reference = MK_LE_MREF(ni->mft_no,
837 			le16_to_cpu(ni->mrec->sequence_number));
838 		ale->instance = ctx->attr->instance;
839 		memcpy(ale->name, (u8 *)ctx->attr +
840 				le16_to_cpu(ctx->attr->name_offset),
841 				ctx->attr->name_length * sizeof(ntfschar));
842 		ale = (ATTR_LIST_ENTRY *)(al + al_len);
843 	}
844 	/* Check for real error occurred. */
845 	if (errno != ENOENT) {
846 		err = errno;
847 		ntfs_log_trace("Attribute lookup failed.\n");
848 		goto put_err_out;
849 	}
850 
851 	/* Set in-memory attribute list. */
852 	ni->attr_list = al;
853 	ni->attr_list_size = al_len;
854 	NInoSetAttrList(ni);
855 	NInoAttrListSetDirty(ni);
856 
857 	/* Free space if there is not enough it for $ATTRIBUTE_LIST. */
858 	if (le32_to_cpu(ni->mrec->bytes_allocated) -
859 			le32_to_cpu(ni->mrec->bytes_in_use) <
860 			offsetof(ATTR_RECORD, resident_end)) {
861 		if (ntfs_inode_free_space(ni,
862 				offsetof(ATTR_RECORD, resident_end))) {
863 			/* Failed to free space. */
864 			err = errno;
865 			ntfs_log_trace("Failed to free space for "
866 					"$ATTRIBUTE_LIST.\n");
867 			goto rollback;
868 		}
869 	}
870 
871 	/* Add $ATTRIBUTE_LIST to mft record. */
872 	if (ntfs_resident_attr_record_add(ni,
873 				AT_ATTRIBUTE_LIST, NULL, 0, NULL, 0, 0) < 0) {
874 		err = errno;
875 		ntfs_log_trace("Couldn't add $ATTRIBUTE_LIST to MFT record.\n");
876 		goto rollback;
877 	}
878 
879 	/* Resize it. */
880 	na = ntfs_attr_open(ni, AT_ATTRIBUTE_LIST, AT_UNNAMED, 0);
881 	if (!na) {
882 		err = errno;
883 		ntfs_log_trace("Failed to open just added $ATTRIBUTE_LIST.\n");
884 		goto remove_attrlist_record;
885 	}
886 	if (ntfs_attr_truncate(na, al_len)) {
887 		err = errno;
888 		ntfs_log_trace("Failed to resize just added $ATTRIBUTE_LIST.\n");
889 		ntfs_attr_close(na);
890 		goto remove_attrlist_record;;
891 	}
892 
893 	ntfs_attr_put_search_ctx(ctx);
894 	ntfs_attr_close(na);
895 	return 0;
896 
897 remove_attrlist_record:
898 	/* Prevent ntfs_attr_recorm_rm from freeing attribute list. */
899 	ni->attr_list = NULL;
900 	NInoClearAttrList(ni);
901 	/* Remove $ATTRIBUTE_LIST record. */
902 	ntfs_attr_reinit_search_ctx(ctx);
903 	if (!ntfs_attr_lookup(AT_ATTRIBUTE_LIST, NULL, 0,
904 				CASE_SENSITIVE, 0, NULL, 0, ctx)) {
905 		if (ntfs_attr_record_rm(ctx))
906 			ntfs_log_trace("Rollback failed. Failed to remove attribute "
907 					"list record.\n");
908 	} else
909 		ntfs_log_trace("Rollback failed. Couldn't find attribute list "
910 				"record.\n");
911 	/* Setup back in-memory runlist. */
912 	ni->attr_list = al;
913 	ni->attr_list_size = al_len;
914 	NInoSetAttrList(ni);
915 rollback:
916 	/*
917 	 * Scan attribute list for attributes that placed not in the base MFT
918 	 * record and move them to it.
919 	 */
920 	ntfs_attr_reinit_search_ctx(ctx);
921 	ale = (ATTR_LIST_ENTRY*)al;
922 	while ((u8*)ale < al + al_len) {
923 		if (MREF_LE(ale->mft_reference) != ni->mft_no) {
924 			if (!ntfs_attr_lookup(ale->type, ale->name,
925 						ale->name_length,
926 						CASE_SENSITIVE,
927 						sle64_to_cpu(ale->lowest_vcn),
928 						NULL, 0, ctx)) {
929 				if (ntfs_attr_record_move_to(ctx, ni))
930 					ntfs_log_trace("Rollback failed. Couldn't "
931 						"back attribute to base MFT record.\n");
932 			} else
933 				ntfs_log_trace("Rollback failed. ntfs_attr_lookup "
934 						"failed.\n");
935 			ntfs_attr_reinit_search_ctx(ctx);
936 		}
937 		ale = (ATTR_LIST_ENTRY*)((u8*)ale + le16_to_cpu(ale->length));
938 	}
939 	/* Remove in-memory attribute list. */
940 	ni->attr_list = NULL;
941 	ni->attr_list_size = 0;
942 	NInoClearAttrList(ni);
943 	NInoAttrListClearDirty(ni);
944 put_err_out:
945 	ntfs_attr_put_search_ctx(ctx);
946 err_out:
947 	free(al);
948 	errno = err;
949 	return -1;
950 }
951 
952 /**
953  * ntfs_inode_free_space - free space in the MFT record of inode
954  * @ni:		ntfs inode in which MFT record free space
955  * @size:	amount of space needed to free
956  *
957  * Return 0 on success or -1 on error with errno set to the error code.
958  */
959 int ntfs_inode_free_space(ntfs_inode *ni, int size)
960 {
961 	ntfs_attr_search_ctx *ctx;
962 	int freed, err;
963 
964 	if (!ni || size < 0) {
965 		ntfs_log_trace("Invalid arguments.\n");
966 		errno = EINVAL;
967 		return -1;
968 	}
969 
970 	ntfs_log_trace("Entering for inode 0x%llx, size %d.\n",
971 			(long long) ni->mft_no, size);
972 
973 	freed = (le32_to_cpu(ni->mrec->bytes_allocated) -
974 				le32_to_cpu(ni->mrec->bytes_in_use));
975 
976 	if (size <= freed)
977 		return 0;
978 
979 	ctx = ntfs_attr_get_search_ctx(ni, NULL);
980 	if (!ctx) {
981 		err = errno;
982 		ntfs_log_trace("Failed to get attribute search context.\n");
983 		errno = err;
984 		return -1;
985 	}
986 
987 	/*
988 	 * Chkdsk complain if $STANDARD_INFORMATION is not in the base MFT
989 	 * record. FIXME: I'm not sure in this, need to recheck. For now simply
990 	 * do not move $STANDARD_INFORMATION at all.
991 	 *
992 	 * Also we can't move $ATTRIBUTE_LIST from base MFT_RECORD, so position
993 	 * search context on first attribute after $STANDARD_INFORMATION and
994 	 * $ATTRIBUTE_LIST.
995 	 *
996 	 * Why we reposition instead of simply skip this attributes during
997 	 * enumeration? Because in case we have got only in-memory attribute
998 	 * list ntfs_attr_lookup will fail when it will try to find
999 	 * $ATTRIBUTE_LIST.
1000 	 */
1001 	if (ntfs_attr_lookup(AT_FILE_NAME, NULL, 0, CASE_SENSITIVE, 0, NULL,
1002 				0, ctx)) {
1003 		if (errno != ENOENT) {
1004 			err = errno;
1005 			ntfs_log_trace("Attribute lookup failed.\n");
1006 			goto put_err_out;
1007 		}
1008 		if (ctx->attr->type == AT_END) {
1009 			err = ENOSPC;
1010 			goto put_err_out;
1011 		}
1012 	}
1013 
1014 	while (1) {
1015 		int record_size;
1016 
1017 		/*
1018 		 * Check whether attribute is from different MFT record. If so,
1019 		 * find next, because we don't need such.
1020 		 */
1021 		while (ctx->ntfs_ino->mft_no != ni->mft_no) {
1022 			if (ntfs_attr_lookup(AT_UNUSED, NULL, 0, CASE_SENSITIVE,
1023 						0, NULL, 0, ctx)) {
1024 				err = errno;
1025 				if (errno != ENOENT) {
1026 					ntfs_log_trace("Attribute lookup failed.\n");
1027 				} else
1028 					err = ENOSPC;
1029 				goto put_err_out;
1030 			}
1031 		}
1032 
1033 		record_size = le32_to_cpu(ctx->attr->length);
1034 
1035 		/* Move away attribute. */
1036 		if (ntfs_attr_record_move_away(ctx, 0)) {
1037 			err = errno;
1038 			ntfs_log_trace("Failed to move out attribute.\n");
1039 			break;
1040 		}
1041 		freed += record_size;
1042 
1043 		/* Check whether we done. */
1044 		if (size <= freed) {
1045 			ntfs_attr_put_search_ctx(ctx);
1046 			return 0;
1047 		}
1048 
1049 		/*
1050 		 * Reposition to first attribute after $STANDARD_INFORMATION and
1051 		 * $ATTRIBUTE_LIST (see comments upwards).
1052 		 */
1053 		ntfs_attr_reinit_search_ctx(ctx);
1054 		if (ntfs_attr_lookup(AT_FILE_NAME, NULL, 0, CASE_SENSITIVE, 0,
1055 				NULL, 0, ctx)) {
1056 			if (errno != ENOENT) {
1057 				err = errno;
1058 				ntfs_log_trace("Attribute lookup failed.\n");
1059 				break;
1060 			}
1061 			if (ctx->attr->type == AT_END) {
1062 				err = ENOSPC;
1063 				break;
1064 			}
1065 		}
1066 	}
1067 put_err_out:
1068 	ntfs_attr_put_search_ctx(ctx);
1069 	if (err == ENOSPC)
1070 		ntfs_log_trace("No attributes left that can be moved out.\n");
1071 	errno = err;
1072 	return -1;
1073 }
1074 
1075 /**
1076  * ntfs_inode_update_atime - update access time for ntfs inode
1077  * @ni:		ntfs inode for which update access time
1078  *
1079  * This function usually get called when user read not metadata from inode.
1080  * Do not update time for system files.
1081  */
1082 void ntfs_inode_update_atime(ntfs_inode *ni)
1083 {
1084 	if (!NVolReadOnly(ni->vol) && !NVolNoATime(ni->vol) && (ni->mft_no >=
1085 			FILE_first_user || ni->mft_no == FILE_root)) {
1086 		ni->last_access_time = time(NULL);
1087 		NInoFileNameSetDirty(ni);
1088 		NInoSetDirty(ni);
1089 	}
1090 }
1091 
1092 /**
1093  * ntfs_inode_update_time - update all times for ntfs inode
1094  * @ni:		ntfs inode for which update times
1095  *
1096  * This function updates last access, mft and data change times. Usually
1097  * get called when user write not metadata to inode. Do not update time for
1098  * system files.
1099  */
1100 void ntfs_inode_update_time(ntfs_inode *ni)
1101 {
1102 	if (!NVolReadOnly(ni->vol) &&
1103 	    (ni->mft_no >= FILE_first_user || ni->mft_no == FILE_root)) {
1104 		time_t now;
1105 
1106 		now = time(NULL);
1107 		ni->last_data_change_time = now;
1108 		ni->last_mft_change_time = now;
1109 		NInoFileNameSetDirty(ni);
1110 		NInoSetDirty(ni);
1111 	}
1112 }
1113 
1114 /**
1115  * ntfs_inode_badclus_bad - check for $Badclus:$Bad data attribute
1116  * @mft_no:		mft record number where @attr is present
1117  * @attr:		attribute record used to check for the $Bad attribute
1118  *
1119  * Check if the mft record given by @mft_no and @attr contains the bad sector
1120  * list. Please note that mft record numbers describing $Badclus extent inodes
1121  * will not match the current $Badclus:$Bad check.
1122  *
1123  * On success return 1 if the file is $Badclus:$Bad, otherwise return 0.
1124  * On error return -1 with errno set to the error code.
1125  */
1126 int ntfs_inode_badclus_bad(u64 mft_no, ATTR_RECORD *attr)
1127 {
1128 	int len, ret = 0;
1129 	ntfschar *ustr;
1130 
1131 	if (!attr) {
1132 		ntfs_log_error("Invalid argument.\n");
1133 		errno = EINVAL;
1134 		return -1;
1135 	}
1136 
1137 	if (mft_no != FILE_BadClus)
1138 	       	return 0;
1139 
1140 	if (attr->type != AT_DATA)
1141 	       	return 0;
1142 
1143 	if ((ustr = ntfs_str2ucs("$Bad", &len)) == NULL) {
1144 		ntfs_log_perror("Couldn't convert '$Bad' to Unicode");
1145 		return -1;
1146 	}
1147 
1148 	if (ustr && ntfs_names_are_equal(ustr, len,
1149 			(ntfschar *)((u8 *)attr + le16_to_cpu(attr->name_offset)),
1150 			attr->name_length, 0, NULL, 0))
1151 		ret = 1;
1152 
1153 	ntfs_ucsfree(ustr);
1154 
1155 	return ret;
1156 }
1157