blob: a4a01348be2620072ee6a6f5e9b78cc43ac177a6
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-2008 Szabolcs Szakacsits |
6 | * Copyright (c) 2004-2007 Yura Pakhuchiy |
7 | * Copyright (c) 2004-2005 Richard Russon |
8 | * Copyright (c) 2009-2010 Jean-Pierre Andre |
9 | * |
10 | * This program/include file is free software; you can redistribute it and/or |
11 | * modify it under the terms of the GNU General Public License as published |
12 | * by the Free Software Foundation; either version 2 of the License, or |
13 | * (at your option) any later version. |
14 | * |
15 | * This program/include file is distributed in the hope that it will be |
16 | * useful, but WITHOUT ANY WARRANTY; without even the implied warranty |
17 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
18 | * GNU General Public License for more details. |
19 | * |
20 | * You should have received a copy of the GNU General Public License |
21 | * along with this program (in the main directory of the NTFS-3G |
22 | * distribution in the file COPYING); if not, write to the Free Software |
23 | * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
24 | */ |
25 | |
26 | #ifdef HAVE_CONFIG_H |
27 | #include "config.h" |
28 | #endif |
29 | |
30 | #ifdef HAVE_STDLIB_H |
31 | #include <stdlib.h> |
32 | #endif |
33 | #ifdef HAVE_STRING_H |
34 | #include <string.h> |
35 | #endif |
36 | #ifdef HAVE_ERRNO_H |
37 | #include <errno.h> |
38 | #endif |
39 | #ifdef HAVE_SETXATTR |
40 | #include <sys/xattr.h> |
41 | #endif |
42 | |
43 | #include "param.h" |
44 | #include "compat.h" |
45 | #include "types.h" |
46 | #include "volume.h" |
47 | #include "cache.h" |
48 | #include "inode.h" |
49 | #include "attrib.h" |
50 | #include "debug.h" |
51 | #include "mft.h" |
52 | #include "attrlist.h" |
53 | #include "runlist.h" |
54 | #include "lcnalloc.h" |
55 | #include "index.h" |
56 | #include "dir.h" |
57 | #include "ntfstime.h" |
58 | #include "logging.h" |
59 | #include "misc.h" |
60 | |
61 | ntfs_inode *ntfs_inode_base(ntfs_inode *ni) |
62 | { |
63 | if (ni->nr_extents == -1) |
64 | return ni->base_ni; |
65 | return ni; |
66 | } |
67 | |
68 | /** |
69 | * ntfs_inode_mark_dirty - set the inode (and its base inode if it exists) dirty |
70 | * @ni: ntfs inode to set dirty |
71 | * |
72 | * Set the inode @ni dirty so it is written out later (at the latest at |
73 | * ntfs_inode_close() time). If @ni is an extent inode, set the base inode |
74 | * dirty, too. |
75 | * |
76 | * This function cannot fail. |
77 | */ |
78 | void ntfs_inode_mark_dirty(ntfs_inode *ni) |
79 | { |
80 | NInoSetDirty(ni); |
81 | if (ni->nr_extents == -1) |
82 | NInoSetDirty(ni->base_ni); |
83 | } |
84 | |
85 | /** |
86 | * __ntfs_inode_allocate - Create and initialise an NTFS inode object |
87 | * @vol: |
88 | * |
89 | * Description... |
90 | * |
91 | * Returns: |
92 | */ |
93 | static ntfs_inode *__ntfs_inode_allocate(ntfs_volume *vol) |
94 | { |
95 | ntfs_inode *ni; |
96 | |
97 | ni = (ntfs_inode*)ntfs_calloc(sizeof(ntfs_inode)); |
98 | if (ni) |
99 | ni->vol = vol; |
100 | return ni; |
101 | } |
102 | |
103 | /** |
104 | * ntfs_inode_allocate - Create an NTFS inode object |
105 | * @vol: |
106 | * |
107 | * Description... |
108 | * |
109 | * Returns: |
110 | */ |
111 | ntfs_inode *ntfs_inode_allocate(ntfs_volume *vol) |
112 | { |
113 | return __ntfs_inode_allocate(vol); |
114 | } |
115 | |
116 | /** |
117 | * __ntfs_inode_release - Destroy an NTFS inode object |
118 | * @ni: |
119 | * |
120 | * Description... |
121 | * |
122 | * Returns: |
123 | */ |
124 | static void __ntfs_inode_release(ntfs_inode *ni) |
125 | { |
126 | if (NInoDirty(ni)) |
127 | ntfs_log_error("Releasing dirty inode %lld!\n", |
128 | (long long)ni->mft_no); |
129 | if (NInoAttrList(ni) && ni->attr_list) |
130 | free(ni->attr_list); |
131 | free(ni->mrec); |
132 | free(ni); |
133 | return; |
134 | } |
135 | |
136 | /** |
137 | * ntfs_inode_open - open an inode ready for access |
138 | * @vol: volume to get the inode from |
139 | * @mref: inode number / mft record number to open |
140 | * |
141 | * Allocate an ntfs_inode structure and initialize it for the given inode |
142 | * specified by @mref. @mref specifies the inode number / mft record to read, |
143 | * including the sequence number, which can be 0 if no sequence number checking |
144 | * is to be performed. |
145 | * |
146 | * Then, allocate a buffer for the mft record, read the mft record from the |
147 | * volume @vol, and attach it to the ntfs_inode structure (->mrec). The |
148 | * mft record is mst deprotected and sanity checked for validity and we abort |
149 | * if deprotection or checks fail. |
150 | * |
151 | * Finally, search for an attribute list attribute in the mft record and if one |
152 | * is found, load the attribute list attribute value and attach it to the |
153 | * ntfs_inode structure (->attr_list). Also set the NI_AttrList bit to indicate |
154 | * this. |
155 | * |
156 | * Return a pointer to the ntfs_inode structure on success or NULL on error, |
157 | * with errno set to the error code. |
158 | */ |
159 | static ntfs_inode *ntfs_inode_real_open(ntfs_volume *vol, const MFT_REF mref) |
160 | { |
161 | s64 l; |
162 | ntfs_inode *ni = NULL; |
163 | ntfs_attr_search_ctx *ctx; |
164 | STANDARD_INFORMATION *std_info; |
165 | le32 lthle; |
166 | int olderrno; |
167 | |
168 | ntfs_log_enter("Entering for inode %lld\n", (long long)MREF(mref)); |
169 | if (!vol) { |
170 | errno = EINVAL; |
171 | goto out; |
172 | } |
173 | ni = __ntfs_inode_allocate(vol); |
174 | if (!ni) |
175 | goto out; |
176 | if (ntfs_file_record_read(vol, mref, &ni->mrec, NULL)) |
177 | goto err_out; |
178 | if (!(ni->mrec->flags & MFT_RECORD_IN_USE)) { |
179 | errno = ENOENT; |
180 | goto err_out; |
181 | } |
182 | ni->mft_no = MREF(mref); |
183 | ctx = ntfs_attr_get_search_ctx(ni, NULL); |
184 | if (!ctx) |
185 | goto err_out; |
186 | /* Receive some basic information about inode. */ |
187 | if (ntfs_attr_lookup(AT_STANDARD_INFORMATION, AT_UNNAMED, |
188 | 0, CASE_SENSITIVE, 0, NULL, 0, ctx)) { |
189 | if (!ni->mrec->base_mft_record) |
190 | ntfs_log_perror("No STANDARD_INFORMATION in base record" |
191 | " %lld", (long long)MREF(mref)); |
192 | goto put_err_out; |
193 | } |
194 | std_info = (STANDARD_INFORMATION *)((u8 *)ctx->attr + |
195 | le16_to_cpu(ctx->attr->value_offset)); |
196 | ni->flags = std_info->file_attributes; |
197 | ni->creation_time = std_info->creation_time; |
198 | ni->last_data_change_time = std_info->last_data_change_time; |
199 | ni->last_mft_change_time = std_info->last_mft_change_time; |
200 | ni->last_access_time = std_info->last_access_time; |
201 | /* JPA insert v3 extensions if present */ |
202 | /* length may be seen as 72 (v1.x) or 96 (v3.x) */ |
203 | lthle = ctx->attr->length; |
204 | if (le32_to_cpu(lthle) > sizeof(STANDARD_INFORMATION)) { |
205 | set_nino_flag(ni, v3_Extensions); |
206 | ni->owner_id = std_info->owner_id; |
207 | ni->security_id = std_info->security_id; |
208 | ni->quota_charged = std_info->quota_charged; |
209 | ni->usn = std_info->usn; |
210 | } else { |
211 | clear_nino_flag(ni, v3_Extensions); |
212 | ni->owner_id = const_cpu_to_le32(0); |
213 | ni->security_id = const_cpu_to_le32(0); |
214 | } |
215 | /* Set attribute list information. */ |
216 | olderrno = errno; |
217 | if (ntfs_attr_lookup(AT_ATTRIBUTE_LIST, AT_UNNAMED, 0, |
218 | CASE_SENSITIVE, 0, NULL, 0, ctx)) { |
219 | if (errno != ENOENT) |
220 | goto put_err_out; |
221 | /* Attribute list attribute does not present. */ |
222 | /* restore previous errno to avoid misinterpretation */ |
223 | errno = olderrno; |
224 | goto get_size; |
225 | } |
226 | NInoSetAttrList(ni); |
227 | l = ntfs_get_attribute_value_length(ctx->attr); |
228 | if (!l) |
229 | goto put_err_out; |
230 | if (l > 0x40000) { |
231 | errno = EIO; |
232 | ntfs_log_perror("Too large attrlist attribute (%lld), inode " |
233 | "%lld", (long long)l, (long long)MREF(mref)); |
234 | goto put_err_out; |
235 | } |
236 | ni->attr_list_size = l; |
237 | ni->attr_list = ntfs_malloc(ni->attr_list_size); |
238 | if (!ni->attr_list) |
239 | goto put_err_out; |
240 | l = ntfs_get_attribute_value(vol, ctx->attr, ni->attr_list); |
241 | if (!l) |
242 | goto put_err_out; |
243 | if (l != ni->attr_list_size) { |
244 | errno = EIO; |
245 | ntfs_log_perror("Unexpected attrlist size (%lld <> %u), inode " |
246 | "%lld", (long long)l, ni->attr_list_size, |
247 | (long long)MREF(mref)); |
248 | goto put_err_out; |
249 | } |
250 | get_size: |
251 | olderrno = errno; |
252 | if (ntfs_attr_lookup(AT_DATA, AT_UNNAMED, 0, 0, 0, NULL, 0, ctx)) { |
253 | if (errno != ENOENT) |
254 | goto put_err_out; |
255 | /* Directory or special file. */ |
256 | /* restore previous errno to avoid misinterpretation */ |
257 | errno = olderrno; |
258 | ni->data_size = ni->allocated_size = 0; |
259 | } else { |
260 | if (ctx->attr->non_resident) { |
261 | ni->data_size = sle64_to_cpu(ctx->attr->data_size); |
262 | if (ctx->attr->flags & |
263 | (ATTR_IS_COMPRESSED | ATTR_IS_SPARSE)) |
264 | ni->allocated_size = sle64_to_cpu( |
265 | ctx->attr->compressed_size); |
266 | else |
267 | ni->allocated_size = sle64_to_cpu( |
268 | ctx->attr->allocated_size); |
269 | } else { |
270 | ni->data_size = le32_to_cpu(ctx->attr->value_length); |
271 | ni->allocated_size = (ni->data_size + 7) & ~7; |
272 | } |
273 | set_nino_flag(ni,KnownSize); |
274 | } |
275 | ntfs_attr_put_search_ctx(ctx); |
276 | out: |
277 | ntfs_log_leave("\n"); |
278 | return ni; |
279 | |
280 | put_err_out: |
281 | ntfs_attr_put_search_ctx(ctx); |
282 | err_out: |
283 | __ntfs_inode_release(ni); |
284 | ni = NULL; |
285 | goto out; |
286 | } |
287 | |
288 | /** |
289 | * ntfs_inode_close - close an ntfs inode and free all associated memory |
290 | * @ni: ntfs inode to close |
291 | * |
292 | * Make sure the ntfs inode @ni is clean. |
293 | * |
294 | * If the ntfs inode @ni is a base inode, close all associated extent inodes, |
295 | * then deallocate all memory attached to it, and finally free the ntfs inode |
296 | * structure itself. |
297 | * |
298 | * If it is an extent inode, we disconnect it from its base inode before we |
299 | * destroy it. |
300 | * |
301 | * It is OK to pass NULL to this function, it is just noop in this case. |
302 | * |
303 | * Return 0 on success or -1 on error with errno set to the error code. On |
304 | * error, @ni has not been freed. The user should attempt to handle the error |
305 | * and call ntfs_inode_close() again. The following error codes are defined: |
306 | * |
307 | * EBUSY @ni and/or its attribute list runlist is/are dirty and the |
308 | * attempt to write it/them to disk failed. |
309 | * EINVAL @ni is invalid (probably it is an extent inode). |
310 | * EIO I/O error while trying to write inode to disk. |
311 | */ |
312 | |
313 | int ntfs_inode_real_close(ntfs_inode *ni) |
314 | { |
315 | int ret = -1; |
316 | |
317 | if (!ni) |
318 | return 0; |
319 | |
320 | ntfs_log_enter("Entering for inode %lld\n", (long long)ni->mft_no); |
321 | |
322 | /* If we have dirty metadata, write it out. */ |
323 | if (NInoDirty(ni) || NInoAttrListDirty(ni)) { |
324 | if (ntfs_inode_sync(ni)) { |
325 | if (errno != EIO) |
326 | errno = EBUSY; |
327 | goto err; |
328 | } |
329 | } |
330 | /* Is this a base inode with mapped extent inodes? */ |
331 | if (ni->nr_extents > 0) { |
332 | while (ni->nr_extents > 0) { |
333 | if (ntfs_inode_real_close(ni->extent_nis[0])) { |
334 | if (errno != EIO) |
335 | errno = EBUSY; |
336 | goto err; |
337 | } |
338 | } |
339 | } else if (ni->nr_extents == -1) { |
340 | ntfs_inode **tmp_nis; |
341 | ntfs_inode *base_ni; |
342 | s32 i; |
343 | |
344 | /* |
345 | * If the inode is an extent inode, disconnect it from the |
346 | * base inode before destroying it. |
347 | */ |
348 | base_ni = ni->base_ni; |
349 | for (i = 0; i < base_ni->nr_extents; ++i) { |
350 | tmp_nis = base_ni->extent_nis; |
351 | if (tmp_nis[i] != ni) |
352 | continue; |
353 | /* Found it. Disconnect. */ |
354 | memmove(tmp_nis + i, tmp_nis + i + 1, |
355 | (base_ni->nr_extents - i - 1) * |
356 | sizeof(ntfs_inode *)); |
357 | /* Buffer should be for multiple of four extents. */ |
358 | if ((--base_ni->nr_extents) & 3) { |
359 | i = -1; |
360 | break; |
361 | } |
362 | /* |
363 | * ElectricFence is unhappy with realloc(x,0) as free(x) |
364 | * thus we explicitly separate these two cases. |
365 | */ |
366 | if (base_ni->nr_extents) { |
367 | /* Resize the memory buffer. */ |
368 | tmp_nis = realloc(tmp_nis, base_ni->nr_extents * |
369 | sizeof(ntfs_inode *)); |
370 | /* Ignore errors, they don't really matter. */ |
371 | if (tmp_nis) |
372 | base_ni->extent_nis = tmp_nis; |
373 | } else if (tmp_nis) { |
374 | free(tmp_nis); |
375 | base_ni->extent_nis = (ntfs_inode**)NULL; |
376 | } |
377 | /* Allow for error checking. */ |
378 | i = -1; |
379 | break; |
380 | } |
381 | |
382 | /* |
383 | * We could successfully sync, so only log this error |
384 | * and try to sync other inode extents too. |
385 | */ |
386 | if (i != -1) |
387 | ntfs_log_error("Extent inode %lld was not found\n", |
388 | (long long)ni->mft_no); |
389 | } |
390 | |
391 | __ntfs_inode_release(ni); |
392 | ret = 0; |
393 | err: |
394 | ntfs_log_leave("\n"); |
395 | return ret; |
396 | } |
397 | |
398 | #if CACHE_NIDATA_SIZE |
399 | |
400 | /* |
401 | * Free an inode structure when there is not more space |
402 | * in the cache |
403 | */ |
404 | |
405 | void ntfs_inode_nidata_free(const struct CACHED_GENERIC *cached) |
406 | { |
407 | ntfs_inode_real_close(((const struct CACHED_NIDATA*)cached)->ni); |
408 | } |
409 | |
410 | /* |
411 | * Compute a hash value for an inode entry |
412 | */ |
413 | |
414 | int ntfs_inode_nidata_hash(const struct CACHED_GENERIC *item) |
415 | { |
416 | return (((const struct CACHED_NIDATA*)item)->inum |
417 | % (2*CACHE_NIDATA_SIZE)); |
418 | } |
419 | |
420 | /* |
421 | * inum comparing for entering/fetching from cache |
422 | */ |
423 | |
424 | static int idata_cache_compare(const struct CACHED_GENERIC *cached, |
425 | const struct CACHED_GENERIC *wanted) |
426 | { |
427 | return (((const struct CACHED_NIDATA*)cached)->inum |
428 | != ((const struct CACHED_NIDATA*)wanted)->inum); |
429 | } |
430 | |
431 | /* |
432 | * Invalidate an inode entry when not needed anymore. |
433 | * The entry should have been synced, it may be reused later, |
434 | * if it is requested before it is dropped from cache. |
435 | */ |
436 | |
437 | void ntfs_inode_invalidate(ntfs_volume *vol, const MFT_REF mref) |
438 | { |
439 | struct CACHED_NIDATA item; |
440 | |
441 | item.inum = MREF(mref); |
442 | item.ni = (ntfs_inode*)NULL; |
443 | item.pathname = (const char*)NULL; |
444 | item.varsize = 0; |
445 | ntfs_invalidate_cache(vol->nidata_cache, |
446 | GENERIC(&item),idata_cache_compare,CACHE_FREE); |
447 | } |
448 | |
449 | #endif |
450 | |
451 | /* |
452 | * Open an inode |
453 | * |
454 | * When possible, an entry recorded in the cache is reused |
455 | * |
456 | * **NEVER REOPEN** an inode, this can lead to a duplicated |
457 | * cache entry (hard to detect), and to an obsolete one being |
458 | * reused. System files are however protected from being cached. |
459 | */ |
460 | |
461 | ntfs_inode *ntfs_inode_open(ntfs_volume *vol, const MFT_REF mref) |
462 | { |
463 | ntfs_inode *ni; |
464 | #if CACHE_NIDATA_SIZE |
465 | struct CACHED_NIDATA item; |
466 | struct CACHED_NIDATA *cached; |
467 | |
468 | /* fetch idata from cache */ |
469 | item.inum = MREF(mref); |
470 | debug_double_inode(item.inum,1); |
471 | item.pathname = (const char*)NULL; |
472 | item.varsize = 0; |
473 | cached = (struct CACHED_NIDATA*)ntfs_fetch_cache(vol->nidata_cache, |
474 | GENERIC(&item),idata_cache_compare); |
475 | if (cached) { |
476 | ni = cached->ni; |
477 | /* do not keep open entries in cache */ |
478 | ntfs_remove_cache(vol->nidata_cache, |
479 | (struct CACHED_GENERIC*)cached,0); |
480 | } else { |
481 | ni = ntfs_inode_real_open(vol, mref); |
482 | } |
483 | if (!ni) { |
484 | debug_double_inode(item.inum, 0); |
485 | } |
486 | #else |
487 | ni = ntfs_inode_real_open(vol, mref); |
488 | #endif |
489 | return (ni); |
490 | } |
491 | |
492 | /* |
493 | * Close an inode entry |
494 | * |
495 | * If cacheing is in use, the entry is synced and kept available |
496 | * in cache for further use. |
497 | * |
498 | * System files (inode < 16 or having the IS_4 flag) are protected |
499 | * against being cached. |
500 | */ |
501 | |
502 | int ntfs_inode_close(ntfs_inode *ni) |
503 | { |
504 | int res; |
505 | #if CACHE_NIDATA_SIZE |
506 | BOOL dirty; |
507 | struct CACHED_NIDATA item; |
508 | |
509 | if (ni) { |
510 | debug_double_inode(ni->mft_no,0); |
511 | /* do not cache system files : could lead to double entries */ |
512 | if (ni->vol && ni->vol->nidata_cache |
513 | && ((ni->mft_no == FILE_root) |
514 | || ((ni->mft_no >= FILE_first_user) |
515 | && !(ni->mrec->flags & MFT_RECORD_IS_4)))) { |
516 | /* If we have dirty metadata, write it out. */ |
517 | dirty = NInoDirty(ni) || NInoAttrListDirty(ni); |
518 | if (dirty) { |
519 | res = ntfs_inode_sync(ni); |
520 | /* do a real close if sync failed */ |
521 | if (res) |
522 | ntfs_inode_real_close(ni); |
523 | } else |
524 | res = 0; |
525 | |
526 | if (!res) { |
527 | /* feed idata into cache */ |
528 | item.inum = ni->mft_no; |
529 | item.ni = ni; |
530 | item.pathname = (const char*)NULL; |
531 | item.varsize = 0; |
532 | debug_cached_inode(ni); |
533 | ntfs_enter_cache(ni->vol->nidata_cache, |
534 | GENERIC(&item), idata_cache_compare); |
535 | } |
536 | } else { |
537 | /* cache not ready or system file, really close */ |
538 | res = ntfs_inode_real_close(ni); |
539 | } |
540 | } else |
541 | res = 0; |
542 | #else |
543 | res = ntfs_inode_real_close(ni); |
544 | #endif |
545 | return (res); |
546 | } |
547 | |
548 | /** |
549 | * ntfs_extent_inode_open - load an extent inode and attach it to its base |
550 | * @base_ni: base ntfs inode |
551 | * @mref: mft reference of the extent inode to load (in little endian) |
552 | * |
553 | * First check if the extent inode @mref is already attached to the base ntfs |
554 | * inode @base_ni, and if so, return a pointer to the attached extent inode. |
555 | * |
556 | * If the extent inode is not already attached to the base inode, allocate an |
557 | * ntfs_inode structure and initialize it for the given inode @mref. @mref |
558 | * specifies the inode number / mft record to read, including the sequence |
559 | * number, which can be 0 if no sequence number checking is to be performed. |
560 | * |
561 | * Then, allocate a buffer for the mft record, read the mft record from the |
562 | * volume @base_ni->vol, and attach it to the ntfs_inode structure (->mrec). |
563 | * The mft record is mst deprotected and sanity checked for validity and we |
564 | * abort if deprotection or checks fail. |
565 | * |
566 | * Finally attach the ntfs inode to its base inode @base_ni and return a |
567 | * pointer to the ntfs_inode structure on success or NULL on error, with errno |
568 | * set to the error code. |
569 | * |
570 | * Note, extent inodes are never closed directly. They are automatically |
571 | * disposed off by the closing of the base inode. |
572 | */ |
573 | ntfs_inode *ntfs_extent_inode_open(ntfs_inode *base_ni, const MFT_REF mref) |
574 | { |
575 | u64 mft_no = MREF_LE(mref); |
576 | VCN extent_vcn; |
577 | runlist_element *rl; |
578 | ntfs_volume *vol; |
579 | ntfs_inode *ni = NULL; |
580 | ntfs_inode **extent_nis; |
581 | int i; |
582 | |
583 | if (!base_ni) { |
584 | errno = EINVAL; |
585 | ntfs_log_perror("%s", __FUNCTION__); |
586 | return NULL; |
587 | } |
588 | |
589 | ntfs_log_enter("Opening extent inode %lld (base mft record %lld).\n", |
590 | (unsigned long long)mft_no, |
591 | (unsigned long long)base_ni->mft_no); |
592 | |
593 | if (!base_ni->mft_no) { |
594 | /* |
595 | * When getting extents of MFT, we must be sure |
596 | * they are in the MFT part which has already |
597 | * been mapped, otherwise we fall into an endless |
598 | * recursion. |
599 | * Situations have been met where extents locations |
600 | * are described in themselves. |
601 | * This is a severe error which chkdsk cannot fix. |
602 | */ |
603 | vol = base_ni->vol; |
604 | extent_vcn = mft_no << vol->mft_record_size_bits |
605 | >> vol->cluster_size_bits; |
606 | rl = vol->mft_na->rl; |
607 | if (rl) { |
608 | while (rl->length |
609 | && ((rl->vcn + rl->length) <= extent_vcn)) |
610 | rl++; |
611 | } |
612 | if (!rl || (rl->lcn < 0)) { |
613 | ntfs_log_error("MFT is corrupt, cannot read" |
614 | " its unmapped extent record %lld\n", |
615 | (long long)mft_no); |
616 | ntfs_log_error("Note : chkdsk cannot fix this," |
617 | " try ntfsfix\n"); |
618 | errno = EIO; |
619 | ni = (ntfs_inode*)NULL; |
620 | goto out; |
621 | } |
622 | } |
623 | |
624 | /* Is the extent inode already open and attached to the base inode? */ |
625 | if (base_ni->nr_extents > 0) { |
626 | extent_nis = base_ni->extent_nis; |
627 | for (i = 0; i < base_ni->nr_extents; i++) { |
628 | u16 seq_no; |
629 | |
630 | ni = extent_nis[i]; |
631 | if (mft_no != ni->mft_no) |
632 | continue; |
633 | /* Verify the sequence number if given. */ |
634 | seq_no = MSEQNO_LE(mref); |
635 | if (seq_no && seq_no != le16_to_cpu( |
636 | ni->mrec->sequence_number)) { |
637 | errno = EIO; |
638 | ntfs_log_perror("Found stale extent mft " |
639 | "reference mft=%lld", |
640 | (long long)ni->mft_no); |
641 | goto out; |
642 | } |
643 | goto out; |
644 | } |
645 | } |
646 | /* Wasn't there, we need to load the extent inode. */ |
647 | ni = __ntfs_inode_allocate(base_ni->vol); |
648 | if (!ni) |
649 | goto out; |
650 | if (ntfs_file_record_read(base_ni->vol, le64_to_cpu(mref), &ni->mrec, NULL)) |
651 | goto err_out; |
652 | ni->mft_no = mft_no; |
653 | ni->nr_extents = -1; |
654 | ni->base_ni = base_ni; |
655 | /* Attach extent inode to base inode, reallocating memory if needed. */ |
656 | if (!(base_ni->nr_extents & 3)) { |
657 | i = (base_ni->nr_extents + 4) * sizeof(ntfs_inode *); |
658 | |
659 | extent_nis = ntfs_malloc(i); |
660 | if (!extent_nis) |
661 | goto err_out; |
662 | if (base_ni->nr_extents) { |
663 | memcpy(extent_nis, base_ni->extent_nis, |
664 | i - 4 * sizeof(ntfs_inode *)); |
665 | free(base_ni->extent_nis); |
666 | } |
667 | base_ni->extent_nis = extent_nis; |
668 | } |
669 | base_ni->extent_nis[base_ni->nr_extents++] = ni; |
670 | out: |
671 | ntfs_log_leave("\n"); |
672 | return ni; |
673 | err_out: |
674 | __ntfs_inode_release(ni); |
675 | ni = NULL; |
676 | goto out; |
677 | } |
678 | |
679 | /** |
680 | * ntfs_inode_attach_all_extents - attach all extents for target inode |
681 | * @ni: opened ntfs inode for which perform attach |
682 | * |
683 | * Return 0 on success and -1 on error with errno set to the error code. |
684 | */ |
685 | int ntfs_inode_attach_all_extents(ntfs_inode *ni) |
686 | { |
687 | ATTR_LIST_ENTRY *ale; |
688 | u64 prev_attached = 0; |
689 | |
690 | if (!ni) { |
691 | ntfs_log_trace("Invalid arguments.\n"); |
692 | errno = EINVAL; |
693 | return -1; |
694 | } |
695 | |
696 | if (ni->nr_extents == -1) |
697 | ni = ni->base_ni; |
698 | |
699 | ntfs_log_trace("Entering for inode 0x%llx.\n", (long long) ni->mft_no); |
700 | |
701 | /* Inode haven't got attribute list, thus nothing to attach. */ |
702 | if (!NInoAttrList(ni)) |
703 | return 0; |
704 | |
705 | if (!ni->attr_list) { |
706 | ntfs_log_trace("Corrupt in-memory struct.\n"); |
707 | errno = EINVAL; |
708 | return -1; |
709 | } |
710 | |
711 | /* Walk through attribute list and attach all extents. */ |
712 | errno = 0; |
713 | ale = (ATTR_LIST_ENTRY *)ni->attr_list; |
714 | while ((u8*)ale < ni->attr_list + ni->attr_list_size) { |
715 | if (ni->mft_no != MREF_LE(ale->mft_reference) && |
716 | prev_attached != MREF_LE(ale->mft_reference)) { |
717 | if (!ntfs_extent_inode_open(ni, ale->mft_reference)) { |
718 | ntfs_log_trace("Couldn't attach extent inode.\n"); |
719 | return -1; |
720 | } |
721 | prev_attached = MREF_LE(ale->mft_reference); |
722 | } |
723 | ale = (ATTR_LIST_ENTRY *)((u8*)ale + le16_to_cpu(ale->length)); |
724 | } |
725 | return 0; |
726 | } |
727 | |
728 | /** |
729 | * ntfs_inode_sync_standard_information - update standard information attribute |
730 | * @ni: ntfs inode to update standard information |
731 | * |
732 | * Return 0 on success or -1 on error with errno set to the error code. |
733 | */ |
734 | static int ntfs_inode_sync_standard_information(ntfs_inode *ni) |
735 | { |
736 | ntfs_attr_search_ctx *ctx; |
737 | STANDARD_INFORMATION *std_info; |
738 | u32 lth; |
739 | le32 lthle; |
740 | |
741 | ntfs_log_trace("Entering for inode %lld\n", (long long)ni->mft_no); |
742 | |
743 | ctx = ntfs_attr_get_search_ctx(ni, NULL); |
744 | if (!ctx) |
745 | return -1; |
746 | if (ntfs_attr_lookup(AT_STANDARD_INFORMATION, AT_UNNAMED, |
747 | 0, CASE_SENSITIVE, 0, NULL, 0, ctx)) { |
748 | ntfs_log_perror("Failed to sync standard info (inode %lld)", |
749 | (long long)ni->mft_no); |
750 | ntfs_attr_put_search_ctx(ctx); |
751 | return -1; |
752 | } |
753 | std_info = (STANDARD_INFORMATION *)((u8 *)ctx->attr + |
754 | le16_to_cpu(ctx->attr->value_offset)); |
755 | std_info->file_attributes = ni->flags; |
756 | if (!test_nino_flag(ni, TimesSet)) { |
757 | std_info->creation_time = ni->creation_time; |
758 | std_info->last_data_change_time = ni->last_data_change_time; |
759 | std_info->last_mft_change_time = ni->last_mft_change_time; |
760 | std_info->last_access_time = ni->last_access_time; |
761 | } |
762 | |
763 | /* JPA update v3.x extensions, ensuring consistency */ |
764 | |
765 | lthle = ctx->attr->length; |
766 | lth = le32_to_cpu(lthle); |
767 | if (test_nino_flag(ni, v3_Extensions) |
768 | && (lth <= sizeof(STANDARD_INFORMATION))) |
769 | ntfs_log_error("bad sync of standard information\n"); |
770 | |
771 | if (lth > sizeof(STANDARD_INFORMATION)) { |
772 | std_info->owner_id = ni->owner_id; |
773 | std_info->security_id = ni->security_id; |
774 | std_info->quota_charged = ni->quota_charged; |
775 | std_info->usn = ni->usn; |
776 | } |
777 | ntfs_inode_mark_dirty(ctx->ntfs_ino); |
778 | ntfs_attr_put_search_ctx(ctx); |
779 | return 0; |
780 | } |
781 | |
782 | /** |
783 | * ntfs_inode_sync_file_name - update FILE_NAME attributes |
784 | * @ni: ntfs inode to update FILE_NAME attributes |
785 | * |
786 | * Update all FILE_NAME attributes for inode @ni in the index. |
787 | * |
788 | * Return 0 on success or -1 on error with errno set to the error code. |
789 | */ |
790 | static int ntfs_inode_sync_file_name(ntfs_inode *ni, ntfs_inode *dir_ni) |
791 | { |
792 | ntfs_attr_search_ctx *ctx = NULL; |
793 | ntfs_index_context *ictx; |
794 | ntfs_inode *index_ni; |
795 | FILE_NAME_ATTR *fn; |
796 | FILE_NAME_ATTR *fnx; |
797 | REPARSE_POINT *rpp; |
798 | le32 reparse_tag; |
799 | int err = 0; |
800 | |
801 | ntfs_log_trace("Entering for inode %lld\n", (long long)ni->mft_no); |
802 | |
803 | ctx = ntfs_attr_get_search_ctx(ni, NULL); |
804 | if (!ctx) { |
805 | err = errno; |
806 | goto err_out; |
807 | } |
808 | /* Collect the reparse tag, if any */ |
809 | reparse_tag = cpu_to_le32(0); |
810 | if (ni->flags & FILE_ATTR_REPARSE_POINT) { |
811 | if (!ntfs_attr_lookup(AT_REPARSE_POINT, NULL, |
812 | 0, CASE_SENSITIVE, 0, NULL, 0, ctx)) { |
813 | rpp = (REPARSE_POINT*)((u8 *)ctx->attr + |
814 | le16_to_cpu(ctx->attr->value_offset)); |
815 | reparse_tag = rpp->reparse_tag; |
816 | } |
817 | ntfs_attr_reinit_search_ctx(ctx); |
818 | } |
819 | /* Walk through all FILE_NAME attributes and update them. */ |
820 | while (!ntfs_attr_lookup(AT_FILE_NAME, NULL, 0, 0, 0, NULL, 0, ctx)) { |
821 | fn = (FILE_NAME_ATTR *)((u8 *)ctx->attr + |
822 | le16_to_cpu(ctx->attr->value_offset)); |
823 | if (MREF_LE(fn->parent_directory) == ni->mft_no) { |
824 | /* |
825 | * WARNING: We cheat here and obtain 2 attribute |
826 | * search contexts for one inode (first we obtained |
827 | * above, second will be obtained inside |
828 | * ntfs_index_lookup), it's acceptable for library, |
829 | * but will deadlock in the kernel. |
830 | */ |
831 | index_ni = ni; |
832 | } else |
833 | if (dir_ni) |
834 | index_ni = dir_ni; |
835 | else |
836 | index_ni = ntfs_inode_open(ni->vol, |
837 | le64_to_cpu(fn->parent_directory)); |
838 | if (!index_ni) { |
839 | if (!err) |
840 | err = errno; |
841 | ntfs_log_perror("Failed to open inode %lld with index", |
842 | (long long)le64_to_cpu(fn->parent_directory)); |
843 | continue; |
844 | } |
845 | ictx = ntfs_index_ctx_get(index_ni, NTFS_INDEX_I30, 4); |
846 | if (!ictx) { |
847 | if (!err) |
848 | err = errno; |
849 | ntfs_log_perror("Failed to get index ctx, inode %lld", |
850 | (long long)index_ni->mft_no); |
851 | if ((ni != index_ni) && !dir_ni |
852 | && ntfs_inode_close(index_ni) && !err) |
853 | err = errno; |
854 | continue; |
855 | } |
856 | if (ntfs_index_lookup(fn, sizeof(FILE_NAME_ATTR), ictx)) { |
857 | if (!err) { |
858 | if (errno == ENOENT) |
859 | err = EIO; |
860 | else |
861 | err = errno; |
862 | } |
863 | ntfs_log_perror("Index lookup failed, inode %lld", |
864 | (long long)index_ni->mft_no); |
865 | ntfs_index_ctx_put(ictx); |
866 | if (ni != index_ni && ntfs_inode_close(index_ni) && !err) |
867 | err = errno; |
868 | continue; |
869 | } |
870 | /* Update flags and file size. */ |
871 | fnx = (FILE_NAME_ATTR *)ictx->data; |
872 | fnx->file_attributes = |
873 | (fnx->file_attributes & ~FILE_ATTR_VALID_FLAGS) | |
874 | (ni->flags & FILE_ATTR_VALID_FLAGS); |
875 | if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) |
876 | fnx->data_size = fnx->allocated_size |
877 | = const_cpu_to_le64(0); |
878 | else { |
879 | fnx->allocated_size = cpu_to_sle64(ni->allocated_size); |
880 | fnx->data_size = cpu_to_sle64(ni->data_size); |
881 | /* |
882 | * The file name record has also to be fixed if some |
883 | * attribute update implied the unnamed data to be |
884 | * made non-resident |
885 | */ |
886 | fn->allocated_size = fnx->allocated_size; |
887 | } |
888 | /* update or clear the reparse tag in the index */ |
889 | fnx->reparse_point_tag = reparse_tag; |
890 | if (!test_nino_flag(ni, TimesSet)) { |
891 | fnx->creation_time = ni->creation_time; |
892 | fnx->last_data_change_time = ni->last_data_change_time; |
893 | fnx->last_mft_change_time = ni->last_mft_change_time; |
894 | fnx->last_access_time = ni->last_access_time; |
895 | } else { |
896 | fnx->creation_time = fn->creation_time; |
897 | fnx->last_data_change_time = fn->last_data_change_time; |
898 | fnx->last_mft_change_time = fn->last_mft_change_time; |
899 | fnx->last_access_time = fn->last_access_time; |
900 | } |
901 | ntfs_index_entry_mark_dirty(ictx); |
902 | ntfs_index_ctx_put(ictx); |
903 | if ((ni != index_ni) && !dir_ni |
904 | && ntfs_inode_close(index_ni) && !err) |
905 | err = errno; |
906 | } |
907 | /* Check for real error occurred. */ |
908 | if (errno != ENOENT) { |
909 | err = errno; |
910 | ntfs_log_perror("Attribute lookup failed, inode %lld", |
911 | (long long)ni->mft_no); |
912 | goto err_out; |
913 | } |
914 | ntfs_attr_put_search_ctx(ctx); |
915 | if (err) { |
916 | errno = err; |
917 | return -1; |
918 | } |
919 | return 0; |
920 | err_out: |
921 | if (ctx) |
922 | ntfs_attr_put_search_ctx(ctx); |
923 | errno = err; |
924 | return -1; |
925 | } |
926 | |
927 | /** |
928 | * ntfs_inode_sync - write the inode (and its dirty extents) to disk |
929 | * @ni: ntfs inode to write |
930 | * |
931 | * Write the inode @ni to disk as well as its dirty extent inodes if such |
932 | * exist and @ni is a base inode. If @ni is an extent inode, only @ni is |
933 | * written completely disregarding its base inode and any other extent inodes. |
934 | * |
935 | * For a base inode with dirty extent inodes if any writes fail for whatever |
936 | * reason, the failing inode is skipped and the sync process is continued. At |
937 | * the end the error condition that brought about the failure is returned. Thus |
938 | * the smallest amount of data loss possible occurs. |
939 | * |
940 | * Return 0 on success or -1 on error with errno set to the error code. |
941 | * The following error codes are defined: |
942 | * EINVAL - Invalid arguments were passed to the function. |
943 | * EBUSY - Inode and/or one of its extents is busy, try again later. |
944 | * EIO - I/O error while writing the inode (or one of its extents). |
945 | */ |
946 | static int ntfs_inode_sync_in_dir(ntfs_inode *ni, ntfs_inode *dir_ni) |
947 | { |
948 | int ret = 0; |
949 | int err = 0; |
950 | if (!ni) { |
951 | errno = EINVAL; |
952 | ntfs_log_error("Failed to sync NULL inode\n"); |
953 | return -1; |
954 | } |
955 | |
956 | ntfs_log_enter("Entering for inode %lld\n", (long long)ni->mft_no); |
957 | |
958 | /* Update STANDARD_INFORMATION. */ |
959 | if ((ni->mrec->flags & MFT_RECORD_IN_USE) && ni->nr_extents != -1 && |
960 | ntfs_inode_sync_standard_information(ni)) { |
961 | if (!err || errno == EIO) { |
962 | err = errno; |
963 | if (err != EIO) |
964 | err = EBUSY; |
965 | } |
966 | } |
967 | |
968 | /* Update FILE_NAME's in the index. */ |
969 | if ((ni->mrec->flags & MFT_RECORD_IN_USE) && ni->nr_extents != -1 && |
970 | NInoFileNameTestAndClearDirty(ni) && |
971 | ntfs_inode_sync_file_name(ni, dir_ni)) { |
972 | if (!err || errno == EIO) { |
973 | err = errno; |
974 | if (err != EIO) |
975 | err = EBUSY; |
976 | } |
977 | ntfs_log_perror("Failed to sync FILE_NAME (inode %lld)", |
978 | (long long)ni->mft_no); |
979 | NInoFileNameSetDirty(ni); |
980 | } |
981 | |
982 | /* Write out attribute list from cache to disk. */ |
983 | if ((ni->mrec->flags & MFT_RECORD_IN_USE) && ni->nr_extents != -1 && |
984 | NInoAttrList(ni) && NInoAttrListTestAndClearDirty(ni)) { |
985 | ntfs_attr *na; |
986 | |
987 | na = ntfs_attr_open(ni, AT_ATTRIBUTE_LIST, AT_UNNAMED, 0); |
988 | if (!na) { |
989 | if (!err || errno == EIO) { |
990 | err = errno; |
991 | if (err != EIO) |
992 | err = EBUSY; |
993 | ntfs_log_perror("Attribute list sync failed " |
994 | "(open, inode %lld)", |
995 | (long long)ni->mft_no); |
996 | } |
997 | NInoAttrListSetDirty(ni); |
998 | goto sync_inode; |
999 | } |
1000 | |
1001 | if (na->data_size == ni->attr_list_size) { |
1002 | if (ntfs_attr_pwrite(na, 0, ni->attr_list_size, |
1003 | ni->attr_list) != ni->attr_list_size) { |
1004 | if (!err || errno == EIO) { |
1005 | err = errno; |
1006 | if (err != EIO) |
1007 | err = EBUSY; |
1008 | ntfs_log_perror("Attribute list sync " |
1009 | "failed (write, inode %lld)", |
1010 | (long long)ni->mft_no); |
1011 | } |
1012 | NInoAttrListSetDirty(ni); |
1013 | } |
1014 | } else { |
1015 | err = EIO; |
1016 | ntfs_log_error("Attribute list sync failed (bad size, " |
1017 | "inode %lld)\n", (long long)ni->mft_no); |
1018 | NInoAttrListSetDirty(ni); |
1019 | } |
1020 | ntfs_attr_close(na); |
1021 | } |
1022 | |
1023 | sync_inode: |
1024 | /* Write this inode out to the $MFT (and $MFTMirr if applicable). */ |
1025 | if (NInoTestAndClearDirty(ni)) { |
1026 | if (ntfs_mft_record_write(ni->vol, ni->mft_no, ni->mrec)) { |
1027 | if (!err || errno == EIO) { |
1028 | err = errno; |
1029 | if (err != EIO) |
1030 | err = EBUSY; |
1031 | } |
1032 | NInoSetDirty(ni); |
1033 | ntfs_log_perror("MFT record sync failed, inode %lld", |
1034 | (long long)ni->mft_no); |
1035 | } |
1036 | } |
1037 | |
1038 | /* If this is a base inode with extents write all dirty extents, too. */ |
1039 | if (ni->nr_extents > 0) { |
1040 | s32 i; |
1041 | |
1042 | for (i = 0; i < ni->nr_extents; ++i) { |
1043 | ntfs_inode *eni; |
1044 | |
1045 | eni = ni->extent_nis[i]; |
1046 | if (!NInoTestAndClearDirty(eni)) |
1047 | continue; |
1048 | |
1049 | if (ntfs_mft_record_write(eni->vol, eni->mft_no, |
1050 | eni->mrec)) { |
1051 | if (!err || errno == EIO) { |
1052 | err = errno; |
1053 | if (err != EIO) |
1054 | err = EBUSY; |
1055 | } |
1056 | NInoSetDirty(eni); |
1057 | ntfs_log_perror("Extent MFT record sync failed," |
1058 | " inode %lld/%lld", |
1059 | (long long)ni->mft_no, |
1060 | (long long)eni->mft_no); |
1061 | } |
1062 | } |
1063 | } |
1064 | |
1065 | if (err) { |
1066 | errno = err; |
1067 | ret = -1; |
1068 | } |
1069 | |
1070 | ntfs_log_leave("\n"); |
1071 | return ret; |
1072 | } |
1073 | |
1074 | int ntfs_inode_sync(ntfs_inode *ni) |
1075 | { |
1076 | return (ntfs_inode_sync_in_dir(ni, (ntfs_inode*)NULL)); |
1077 | } |
1078 | |
1079 | /* |
1080 | * Close an inode with an open parent inode |
1081 | */ |
1082 | |
1083 | int ntfs_inode_close_in_dir(ntfs_inode *ni, ntfs_inode *dir_ni) |
1084 | { |
1085 | int res; |
1086 | |
1087 | res = ntfs_inode_sync_in_dir(ni, dir_ni); |
1088 | if (res) { |
1089 | if (errno != EIO) |
1090 | errno = EBUSY; |
1091 | } else |
1092 | res = ntfs_inode_close(ni); |
1093 | return (res); |
1094 | } |
1095 | |
1096 | /** |
1097 | * ntfs_inode_add_attrlist - add attribute list to inode and fill it |
1098 | * @ni: opened ntfs inode to which add attribute list |
1099 | * |
1100 | * Return 0 on success or -1 on error with errno set to the error code. |
1101 | * The following error codes are defined: |
1102 | * EINVAL - Invalid arguments were passed to the function. |
1103 | * EEXIST - Attribute list already exist. |
1104 | * EIO - Input/Ouput error occurred. |
1105 | * ENOMEM - Not enough memory to perform add. |
1106 | */ |
1107 | int ntfs_inode_add_attrlist(ntfs_inode *ni) |
1108 | { |
1109 | int err; |
1110 | ntfs_attr_search_ctx *ctx; |
1111 | u8 *al = NULL, *aln; |
1112 | int al_len = 0; |
1113 | ATTR_LIST_ENTRY *ale = NULL; |
1114 | ntfs_attr *na; |
1115 | |
1116 | if (!ni) { |
1117 | errno = EINVAL; |
1118 | ntfs_log_perror("%s", __FUNCTION__); |
1119 | return -1; |
1120 | } |
1121 | |
1122 | ntfs_log_trace("inode %llu\n", (unsigned long long) ni->mft_no); |
1123 | |
1124 | if (NInoAttrList(ni) || ni->nr_extents) { |
1125 | errno = EEXIST; |
1126 | ntfs_log_perror("Inode already has attribute list"); |
1127 | return -1; |
1128 | } |
1129 | |
1130 | /* Form attribute list. */ |
1131 | ctx = ntfs_attr_get_search_ctx(ni, NULL); |
1132 | if (!ctx) { |
1133 | err = errno; |
1134 | goto err_out; |
1135 | } |
1136 | /* Walk through all attributes. */ |
1137 | while (!ntfs_attr_lookup(AT_UNUSED, NULL, 0, 0, 0, NULL, 0, ctx)) { |
1138 | |
1139 | int ale_size; |
1140 | |
1141 | if (ctx->attr->type == AT_ATTRIBUTE_LIST) { |
1142 | err = EIO; |
1143 | ntfs_log_perror("Attribute list already present"); |
1144 | goto put_err_out; |
1145 | } |
1146 | |
1147 | ale_size = (sizeof(ATTR_LIST_ENTRY) + sizeof(ntfschar) * |
1148 | ctx->attr->name_length + 7) & ~7; |
1149 | al_len += ale_size; |
1150 | |
1151 | aln = realloc(al, al_len); |
1152 | if (!aln) { |
1153 | err = errno; |
1154 | ntfs_log_perror("Failed to realloc %d bytes", al_len); |
1155 | goto put_err_out; |
1156 | } |
1157 | ale = (ATTR_LIST_ENTRY *)(aln + ((u8 *)ale - al)); |
1158 | al = aln; |
1159 | |
1160 | memset(ale, 0, ale_size); |
1161 | |
1162 | /* Add attribute to attribute list. */ |
1163 | ale->type = ctx->attr->type; |
1164 | ale->length = cpu_to_le16((sizeof(ATTR_LIST_ENTRY) + |
1165 | sizeof(ntfschar) * ctx->attr->name_length + 7) & ~7); |
1166 | ale->name_length = ctx->attr->name_length; |
1167 | ale->name_offset = (u8 *)ale->name - (u8 *)ale; |
1168 | if (ctx->attr->non_resident) |
1169 | ale->lowest_vcn = ctx->attr->lowest_vcn; |
1170 | else |
1171 | ale->lowest_vcn = 0; |
1172 | ale->mft_reference = MK_LE_MREF(ni->mft_no, |
1173 | le16_to_cpu(ni->mrec->sequence_number)); |
1174 | ale->instance = ctx->attr->instance; |
1175 | memcpy(ale->name, (u8 *)ctx->attr + |
1176 | le16_to_cpu(ctx->attr->name_offset), |
1177 | ctx->attr->name_length * sizeof(ntfschar)); |
1178 | ale = (ATTR_LIST_ENTRY *)(al + al_len); |
1179 | } |
1180 | /* Check for real error occurred. */ |
1181 | if (errno != ENOENT) { |
1182 | err = errno; |
1183 | ntfs_log_perror("%s: Attribute lookup failed, inode %lld", |
1184 | __FUNCTION__, (long long)ni->mft_no); |
1185 | goto put_err_out; |
1186 | } |
1187 | |
1188 | /* Set in-memory attribute list. */ |
1189 | ni->attr_list = al; |
1190 | ni->attr_list_size = al_len; |
1191 | NInoSetAttrList(ni); |
1192 | NInoAttrListSetDirty(ni); |
1193 | |
1194 | /* Free space if there is not enough it for $ATTRIBUTE_LIST. */ |
1195 | if (le32_to_cpu(ni->mrec->bytes_allocated) - |
1196 | le32_to_cpu(ni->mrec->bytes_in_use) < |
1197 | offsetof(ATTR_RECORD, resident_end)) { |
1198 | if (ntfs_inode_free_space(ni, |
1199 | offsetof(ATTR_RECORD, resident_end))) { |
1200 | /* Failed to free space. */ |
1201 | err = errno; |
1202 | ntfs_log_perror("Failed to free space for attrlist"); |
1203 | goto rollback; |
1204 | } |
1205 | } |
1206 | |
1207 | /* Add $ATTRIBUTE_LIST to mft record. */ |
1208 | if (ntfs_resident_attr_record_add(ni, |
1209 | AT_ATTRIBUTE_LIST, NULL, 0, NULL, 0, 0) < 0) { |
1210 | err = errno; |
1211 | ntfs_log_perror("Couldn't add $ATTRIBUTE_LIST to MFT"); |
1212 | goto rollback; |
1213 | } |
1214 | |
1215 | /* Resize it. */ |
1216 | na = ntfs_attr_open(ni, AT_ATTRIBUTE_LIST, AT_UNNAMED, 0); |
1217 | if (!na) { |
1218 | err = errno; |
1219 | ntfs_log_perror("Failed to open just added $ATTRIBUTE_LIST"); |
1220 | goto remove_attrlist_record; |
1221 | } |
1222 | if (ntfs_attr_truncate(na, al_len)) { |
1223 | err = errno; |
1224 | ntfs_log_perror("Failed to resize just added $ATTRIBUTE_LIST"); |
1225 | ntfs_attr_close(na); |
1226 | goto remove_attrlist_record;; |
1227 | } |
1228 | |
1229 | ntfs_attr_put_search_ctx(ctx); |
1230 | ntfs_attr_close(na); |
1231 | return 0; |
1232 | |
1233 | remove_attrlist_record: |
1234 | /* Prevent ntfs_attr_recorm_rm from freeing attribute list. */ |
1235 | ni->attr_list = NULL; |
1236 | NInoClearAttrList(ni); |
1237 | /* Remove $ATTRIBUTE_LIST record. */ |
1238 | ntfs_attr_reinit_search_ctx(ctx); |
1239 | if (!ntfs_attr_lookup(AT_ATTRIBUTE_LIST, NULL, 0, |
1240 | CASE_SENSITIVE, 0, NULL, 0, ctx)) { |
1241 | if (ntfs_attr_record_rm(ctx)) |
1242 | ntfs_log_perror("Rollback failed to remove attrlist"); |
1243 | } else |
1244 | ntfs_log_perror("Rollback failed to find attrlist"); |
1245 | /* Setup back in-memory runlist. */ |
1246 | ni->attr_list = al; |
1247 | ni->attr_list_size = al_len; |
1248 | NInoSetAttrList(ni); |
1249 | rollback: |
1250 | /* |
1251 | * Scan attribute list for attributes that placed not in the base MFT |
1252 | * record and move them to it. |
1253 | */ |
1254 | ntfs_attr_reinit_search_ctx(ctx); |
1255 | ale = (ATTR_LIST_ENTRY*)al; |
1256 | while ((u8*)ale < al + al_len) { |
1257 | if (MREF_LE(ale->mft_reference) != ni->mft_no) { |
1258 | if (!ntfs_attr_lookup(ale->type, ale->name, |
1259 | ale->name_length, |
1260 | CASE_SENSITIVE, |
1261 | sle64_to_cpu(ale->lowest_vcn), |
1262 | NULL, 0, ctx)) { |
1263 | if (ntfs_attr_record_move_to(ctx, ni)) |
1264 | ntfs_log_perror("Rollback failed to " |
1265 | "move attribute"); |
1266 | } else |
1267 | ntfs_log_perror("Rollback failed to find attr"); |
1268 | ntfs_attr_reinit_search_ctx(ctx); |
1269 | } |
1270 | ale = (ATTR_LIST_ENTRY*)((u8*)ale + le16_to_cpu(ale->length)); |
1271 | } |
1272 | /* Remove in-memory attribute list. */ |
1273 | ni->attr_list = NULL; |
1274 | ni->attr_list_size = 0; |
1275 | NInoClearAttrList(ni); |
1276 | NInoAttrListClearDirty(ni); |
1277 | put_err_out: |
1278 | ntfs_attr_put_search_ctx(ctx); |
1279 | err_out: |
1280 | free(al); |
1281 | errno = err; |
1282 | return -1; |
1283 | } |
1284 | |
1285 | /** |
1286 | * ntfs_inode_free_space - free space in the MFT record of an inode |
1287 | * @ni: ntfs inode in which MFT record needs more free space |
1288 | * @size: amount of space needed to free |
1289 | * |
1290 | * Return 0 on success or -1 on error with errno set to the error code. |
1291 | */ |
1292 | int ntfs_inode_free_space(ntfs_inode *ni, int size) |
1293 | { |
1294 | ntfs_attr_search_ctx *ctx; |
1295 | int freed; |
1296 | |
1297 | if (!ni || size < 0) { |
1298 | errno = EINVAL; |
1299 | ntfs_log_perror("%s: ni=%p size=%d", __FUNCTION__, ni, size); |
1300 | return -1; |
1301 | } |
1302 | |
1303 | ntfs_log_trace("Entering for inode %lld, size %d\n", |
1304 | (unsigned long long)ni->mft_no, size); |
1305 | |
1306 | freed = (le32_to_cpu(ni->mrec->bytes_allocated) - |
1307 | le32_to_cpu(ni->mrec->bytes_in_use)); |
1308 | |
1309 | if (size <= freed) |
1310 | return 0; |
1311 | |
1312 | ctx = ntfs_attr_get_search_ctx(ni, NULL); |
1313 | if (!ctx) |
1314 | return -1; |
1315 | /* |
1316 | * $STANDARD_INFORMATION and $ATTRIBUTE_LIST must stay in the base MFT |
1317 | * record, so position search context on the first attribute after them. |
1318 | */ |
1319 | if (ntfs_attr_position(AT_FILE_NAME, ctx)) |
1320 | goto put_err_out; |
1321 | |
1322 | while (1) { |
1323 | int record_size; |
1324 | /* |
1325 | * Check whether attribute is from different MFT record. If so, |
1326 | * find next, because we don't need such. |
1327 | */ |
1328 | while (ctx->ntfs_ino->mft_no != ni->mft_no) { |
1329 | retry: |
1330 | if (ntfs_attr_position(AT_UNUSED, ctx)) |
1331 | goto put_err_out; |
1332 | } |
1333 | |
1334 | if (ntfs_inode_base(ctx->ntfs_ino)->mft_no == FILE_MFT && |
1335 | ctx->attr->type == AT_DATA) |
1336 | goto retry; |
1337 | |
1338 | if (ctx->attr->type == AT_INDEX_ROOT) |
1339 | goto retry; |
1340 | |
1341 | record_size = le32_to_cpu(ctx->attr->length); |
1342 | |
1343 | if (ntfs_attr_record_move_away(ctx, 0)) { |
1344 | ntfs_log_perror("Failed to move out attribute #2"); |
1345 | break; |
1346 | } |
1347 | freed += record_size; |
1348 | |
1349 | /* Check whether we are done. */ |
1350 | if (size <= freed) { |
1351 | ntfs_attr_put_search_ctx(ctx); |
1352 | return 0; |
1353 | } |
1354 | /* |
1355 | * Reposition to first attribute after $STANDARD_INFORMATION |
1356 | * and $ATTRIBUTE_LIST instead of simply skipping this attribute |
1357 | * because in the case when we have got only in-memory attribute |
1358 | * list then ntfs_attr_lookup will fail when it tries to find |
1359 | * $ATTRIBUTE_LIST. |
1360 | */ |
1361 | ntfs_attr_reinit_search_ctx(ctx); |
1362 | if (ntfs_attr_position(AT_FILE_NAME, ctx)) |
1363 | break; |
1364 | } |
1365 | put_err_out: |
1366 | ntfs_attr_put_search_ctx(ctx); |
1367 | if (errno == ENOSPC) |
1368 | ntfs_log_trace("No attributes left that could be moved out.\n"); |
1369 | return -1; |
1370 | } |
1371 | |
1372 | /** |
1373 | * ntfs_inode_update_times - update selected time fields for ntfs inode |
1374 | * @ni: ntfs inode for which update time fields |
1375 | * @mask: select which time fields should be updated |
1376 | * |
1377 | * This function updates time fields to current time. Fields to update are |
1378 | * selected using @mask (see enum @ntfs_time_update_flags for posssible values). |
1379 | */ |
1380 | void ntfs_inode_update_times(ntfs_inode *ni, ntfs_time_update_flags mask) |
1381 | { |
1382 | ntfs_time now; |
1383 | |
1384 | if (!ni) { |
1385 | ntfs_log_error("%s(): Invalid arguments.\n", __FUNCTION__); |
1386 | return; |
1387 | } |
1388 | |
1389 | if ((ni->mft_no < FILE_first_user && ni->mft_no != FILE_root) || |
1390 | NVolReadOnly(ni->vol) || !mask) |
1391 | return; |
1392 | |
1393 | now = ntfs_current_time(); |
1394 | if (mask & NTFS_UPDATE_ATIME) |
1395 | ni->last_access_time = now; |
1396 | if (mask & NTFS_UPDATE_MTIME) |
1397 | ni->last_data_change_time = now; |
1398 | if (mask & NTFS_UPDATE_CTIME) |
1399 | ni->last_mft_change_time = now; |
1400 | |
1401 | NInoFileNameSetDirty(ni); |
1402 | NInoSetDirty(ni); |
1403 | } |
1404 | |
1405 | /** |
1406 | * ntfs_inode_badclus_bad - check for $Badclus:$Bad data attribute |
1407 | * @mft_no: mft record number where @attr is present |
1408 | * @attr: attribute record used to check for the $Bad attribute |
1409 | * |
1410 | * Check if the mft record given by @mft_no and @attr contains the bad sector |
1411 | * list. Please note that mft record numbers describing $Badclus extent inodes |
1412 | * will not match the current $Badclus:$Bad check. |
1413 | * |
1414 | * On success return 1 if the file is $Badclus:$Bad, otherwise return 0. |
1415 | * On error return -1 with errno set to the error code. |
1416 | */ |
1417 | int ntfs_inode_badclus_bad(u64 mft_no, ATTR_RECORD *attr) |
1418 | { |
1419 | int len, ret = 0; |
1420 | ntfschar *ustr; |
1421 | |
1422 | if (!attr) { |
1423 | ntfs_log_error("Invalid argument.\n"); |
1424 | errno = EINVAL; |
1425 | return -1; |
1426 | } |
1427 | |
1428 | if (mft_no != FILE_BadClus) |
1429 | return 0; |
1430 | |
1431 | if (attr->type != AT_DATA) |
1432 | return 0; |
1433 | |
1434 | if ((ustr = ntfs_str2ucs("$Bad", &len)) == NULL) { |
1435 | ntfs_log_perror("Couldn't convert '$Bad' to Unicode"); |
1436 | return -1; |
1437 | } |
1438 | |
1439 | if (ustr && ntfs_names_are_equal(ustr, len, |
1440 | (ntfschar *)((u8 *)attr + le16_to_cpu(attr->name_offset)), |
1441 | attr->name_length, 0, NULL, 0)) |
1442 | ret = 1; |
1443 | |
1444 | ntfs_ucsfree(ustr); |
1445 | |
1446 | return ret; |
1447 | } |
1448 | |
1449 | #ifdef HAVE_SETXATTR /* extended attributes interface required */ |
1450 | |
1451 | /* |
1452 | * Get high precision NTFS times |
1453 | * |
1454 | * They are returned in following order : create, update, access, change |
1455 | * provided they fit in requested size. |
1456 | * |
1457 | * Returns the modified size if successfull (or 32 if buffer size is null) |
1458 | * -errno if failed |
1459 | */ |
1460 | |
1461 | int ntfs_inode_get_times(ntfs_inode *ni, char *value, size_t size) |
1462 | { |
1463 | ntfs_attr_search_ctx *ctx; |
1464 | STANDARD_INFORMATION *std_info; |
1465 | u64 *times; |
1466 | int ret; |
1467 | |
1468 | ret = 0; |
1469 | ctx = ntfs_attr_get_search_ctx(ni, NULL); |
1470 | if (ctx) { |
1471 | if (ntfs_attr_lookup(AT_STANDARD_INFORMATION, AT_UNNAMED, |
1472 | 0, CASE_SENSITIVE, 0, NULL, 0, ctx)) { |
1473 | ntfs_log_perror("Failed to get standard info (inode %lld)", |
1474 | (long long)ni->mft_no); |
1475 | } else { |
1476 | std_info = (STANDARD_INFORMATION *)((u8 *)ctx->attr + |
1477 | le16_to_cpu(ctx->attr->value_offset)); |
1478 | if (value && (size >= 8)) { |
1479 | times = (u64*)value; |
1480 | times[0] = le64_to_cpu(std_info->creation_time); |
1481 | ret = 8; |
1482 | if (size >= 16) { |
1483 | times[1] = le64_to_cpu(std_info->last_data_change_time); |
1484 | ret = 16; |
1485 | } |
1486 | if (size >= 24) { |
1487 | times[2] = le64_to_cpu(std_info->last_access_time); |
1488 | ret = 24; |
1489 | } |
1490 | if (size >= 32) { |
1491 | times[3] = le64_to_cpu(std_info->last_mft_change_time); |
1492 | ret = 32; |
1493 | } |
1494 | } else |
1495 | if (!size) |
1496 | ret = 32; |
1497 | else |
1498 | ret = -ERANGE; |
1499 | } |
1500 | ntfs_attr_put_search_ctx(ctx); |
1501 | } |
1502 | return (ret ? ret : -errno); |
1503 | } |
1504 | |
1505 | /* |
1506 | * Set high precision NTFS times |
1507 | * |
1508 | * They are expected in this order : create, update, access |
1509 | * provided they are present in input. The change time is set to |
1510 | * current time. |
1511 | * |
1512 | * The times are inserted directly in the standard_information and |
1513 | * file names attributes to avoid manipulating low precision times |
1514 | * |
1515 | * Returns 0 if success |
1516 | * -1 if there were an error (described by errno) |
1517 | */ |
1518 | |
1519 | int ntfs_inode_set_times(ntfs_inode *ni, const char *value, size_t size, |
1520 | int flags) |
1521 | { |
1522 | ntfs_attr_search_ctx *ctx; |
1523 | STANDARD_INFORMATION *std_info; |
1524 | FILE_NAME_ATTR *fn; |
1525 | const u64 *times; |
1526 | ntfs_time now; |
1527 | int cnt; |
1528 | int ret; |
1529 | |
1530 | ret = -1; |
1531 | if ((size >= 8) && !(flags & XATTR_CREATE)) { |
1532 | times = (const u64*)value; |
1533 | now = ntfs_current_time(); |
1534 | /* update the standard information attribute */ |
1535 | ctx = ntfs_attr_get_search_ctx(ni, NULL); |
1536 | if (ctx) { |
1537 | if (ntfs_attr_lookup(AT_STANDARD_INFORMATION, |
1538 | AT_UNNAMED, 0, CASE_SENSITIVE, |
1539 | 0, NULL, 0, ctx)) { |
1540 | ntfs_log_perror("Failed to get standard info (inode %lld)", |
1541 | (long long)ni->mft_no); |
1542 | } else { |
1543 | std_info = (STANDARD_INFORMATION *)((u8 *)ctx->attr + |
1544 | le16_to_cpu(ctx->attr->value_offset)); |
1545 | /* |
1546 | * Mark times set to avoid overwriting |
1547 | * them when the inode is closed. |
1548 | * The inode structure must also be updated |
1549 | * (with loss of precision) because of cacheing. |
1550 | * TODO : use NTFS precision in inode, and |
1551 | * return sub-second times in getattr() |
1552 | */ |
1553 | set_nino_flag(ni, TimesSet); |
1554 | std_info->creation_time = cpu_to_le64(times[0]); |
1555 | ni->creation_time |
1556 | = std_info->creation_time; |
1557 | if (size >= 16) { |
1558 | std_info->last_data_change_time = cpu_to_le64(times[1]); |
1559 | ni->last_data_change_time |
1560 | = std_info->last_data_change_time; |
1561 | } |
1562 | if (size >= 24) { |
1563 | std_info->last_access_time = cpu_to_le64(times[2]); |
1564 | ni->last_access_time |
1565 | = std_info->last_access_time; |
1566 | } |
1567 | std_info->last_mft_change_time = now; |
1568 | ni->last_mft_change_time = now; |
1569 | ntfs_inode_mark_dirty(ctx->ntfs_ino); |
1570 | NInoFileNameSetDirty(ni); |
1571 | |
1572 | /* update the file names attributes */ |
1573 | ntfs_attr_reinit_search_ctx(ctx); |
1574 | cnt = 0; |
1575 | while (!ntfs_attr_lookup(AT_FILE_NAME, |
1576 | AT_UNNAMED, 0, CASE_SENSITIVE, |
1577 | 0, NULL, 0, ctx)) { |
1578 | fn = (FILE_NAME_ATTR*)((u8 *)ctx->attr + |
1579 | le16_to_cpu(ctx->attr->value_offset)); |
1580 | fn->creation_time |
1581 | = cpu_to_le64(times[0]); |
1582 | if (size >= 16) |
1583 | fn->last_data_change_time |
1584 | = cpu_to_le64(times[1]); |
1585 | if (size >= 24) |
1586 | fn->last_access_time |
1587 | = cpu_to_le64(times[2]); |
1588 | fn->last_mft_change_time = now; |
1589 | cnt++; |
1590 | } |
1591 | if (cnt) |
1592 | ret = 0; |
1593 | else { |
1594 | ntfs_log_perror("Failed to get file names (inode %lld)", |
1595 | (long long)ni->mft_no); |
1596 | } |
1597 | } |
1598 | ntfs_attr_put_search_ctx(ctx); |
1599 | } |
1600 | } else |
1601 | if (size < 8) |
1602 | errno = ERANGE; |
1603 | else |
1604 | errno = EEXIST; |
1605 | return (ret); |
1606 | } |
1607 | |
1608 | #endif /* HAVE_SETXATTR */ |
1609 |