blob: 6f3fa0604adbbf1d559797bbbf600e114beeb1b3
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 | int count; |
441 | |
442 | item.inum = MREF(mref); |
443 | item.ni = (ntfs_inode*)NULL; |
444 | item.pathname = (const char*)NULL; |
445 | item.varsize = 0; |
446 | count = ntfs_invalidate_cache(vol->nidata_cache, |
447 | GENERIC(&item),idata_cache_compare,CACHE_FREE); |
448 | } |
449 | |
450 | #endif |
451 | |
452 | /* |
453 | * Open an inode |
454 | * |
455 | * When possible, an entry recorded in the cache is reused |
456 | * |
457 | * **NEVER REOPEN** an inode, this can lead to a duplicated |
458 | * cache entry (hard to detect), and to an obsolete one being |
459 | * reused. System files are however protected from being cached. |
460 | */ |
461 | |
462 | ntfs_inode *ntfs_inode_open(ntfs_volume *vol, const MFT_REF mref) |
463 | { |
464 | ntfs_inode *ni; |
465 | #if CACHE_NIDATA_SIZE |
466 | struct CACHED_NIDATA item; |
467 | struct CACHED_NIDATA *cached; |
468 | |
469 | /* fetch idata from cache */ |
470 | item.inum = MREF(mref); |
471 | debug_double_inode(item.inum,1); |
472 | item.pathname = (const char*)NULL; |
473 | item.varsize = 0; |
474 | cached = (struct CACHED_NIDATA*)ntfs_fetch_cache(vol->nidata_cache, |
475 | GENERIC(&item),idata_cache_compare); |
476 | if (cached) { |
477 | ni = cached->ni; |
478 | /* do not keep open entries in cache */ |
479 | ntfs_remove_cache(vol->nidata_cache, |
480 | (struct CACHED_GENERIC*)cached,0); |
481 | } else { |
482 | ni = ntfs_inode_real_open(vol, mref); |
483 | } |
484 | #else |
485 | ni = ntfs_inode_real_open(vol, mref); |
486 | #endif |
487 | return (ni); |
488 | } |
489 | |
490 | /* |
491 | * Close an inode entry |
492 | * |
493 | * If cacheing is in use, the entry is synced and kept available |
494 | * in cache for further use. |
495 | * |
496 | * System files (inode < 16 or having the IS_4 flag) are protected |
497 | * against being cached. |
498 | */ |
499 | |
500 | int ntfs_inode_close(ntfs_inode *ni) |
501 | { |
502 | int res; |
503 | #if CACHE_NIDATA_SIZE |
504 | BOOL dirty; |
505 | struct CACHED_NIDATA item; |
506 | |
507 | if (ni) { |
508 | debug_double_inode(ni->mft_no,0); |
509 | /* do not cache system files : could lead to double entries */ |
510 | if (ni->vol && ni->vol->nidata_cache |
511 | && ((ni->mft_no == FILE_root) |
512 | || ((ni->mft_no >= FILE_first_user) |
513 | && !(ni->mrec->flags & MFT_RECORD_IS_4)))) { |
514 | /* If we have dirty metadata, write it out. */ |
515 | dirty = NInoDirty(ni) || NInoAttrListDirty(ni); |
516 | if (dirty) { |
517 | res = ntfs_inode_sync(ni); |
518 | /* do a real close if sync failed */ |
519 | if (res) |
520 | ntfs_inode_real_close(ni); |
521 | } else |
522 | res = 0; |
523 | |
524 | if (!res) { |
525 | /* feed idata into cache */ |
526 | item.inum = ni->mft_no; |
527 | item.ni = ni; |
528 | item.pathname = (const char*)NULL; |
529 | item.varsize = 0; |
530 | debug_cached_inode(ni); |
531 | ntfs_enter_cache(ni->vol->nidata_cache, |
532 | GENERIC(&item), idata_cache_compare); |
533 | } |
534 | } else { |
535 | /* cache not ready or system file, really close */ |
536 | res = ntfs_inode_real_close(ni); |
537 | } |
538 | } else |
539 | res = 0; |
540 | #else |
541 | res = ntfs_inode_real_close(ni); |
542 | #endif |
543 | return (res); |
544 | } |
545 | |
546 | /** |
547 | * ntfs_extent_inode_open - load an extent inode and attach it to its base |
548 | * @base_ni: base ntfs inode |
549 | * @mref: mft reference of the extent inode to load (in little endian) |
550 | * |
551 | * First check if the extent inode @mref is already attached to the base ntfs |
552 | * inode @base_ni, and if so, return a pointer to the attached extent inode. |
553 | * |
554 | * If the extent inode is not already attached to the base inode, allocate an |
555 | * ntfs_inode structure and initialize it for the given inode @mref. @mref |
556 | * specifies the inode number / mft record to read, including the sequence |
557 | * number, which can be 0 if no sequence number checking is to be performed. |
558 | * |
559 | * Then, allocate a buffer for the mft record, read the mft record from the |
560 | * volume @base_ni->vol, and attach it to the ntfs_inode structure (->mrec). |
561 | * The mft record is mst deprotected and sanity checked for validity and we |
562 | * abort if deprotection or checks fail. |
563 | * |
564 | * Finally attach the ntfs inode to its base inode @base_ni and return a |
565 | * pointer to the ntfs_inode structure on success or NULL on error, with errno |
566 | * set to the error code. |
567 | * |
568 | * Note, extent inodes are never closed directly. They are automatically |
569 | * disposed off by the closing of the base inode. |
570 | */ |
571 | ntfs_inode *ntfs_extent_inode_open(ntfs_inode *base_ni, const MFT_REF mref) |
572 | { |
573 | u64 mft_no = MREF_LE(mref); |
574 | ntfs_inode *ni = NULL; |
575 | ntfs_inode **extent_nis; |
576 | int i; |
577 | |
578 | if (!base_ni) { |
579 | errno = EINVAL; |
580 | ntfs_log_perror("%s", __FUNCTION__); |
581 | return NULL; |
582 | } |
583 | |
584 | ntfs_log_enter("Opening extent inode %lld (base mft record %lld).\n", |
585 | (unsigned long long)mft_no, |
586 | (unsigned long long)base_ni->mft_no); |
587 | |
588 | /* Is the extent inode already open and attached to the base inode? */ |
589 | if (base_ni->nr_extents > 0) { |
590 | extent_nis = base_ni->extent_nis; |
591 | for (i = 0; i < base_ni->nr_extents; i++) { |
592 | u16 seq_no; |
593 | |
594 | ni = extent_nis[i]; |
595 | if (mft_no != ni->mft_no) |
596 | continue; |
597 | /* Verify the sequence number if given. */ |
598 | seq_no = MSEQNO_LE(mref); |
599 | if (seq_no && seq_no != le16_to_cpu( |
600 | ni->mrec->sequence_number)) { |
601 | errno = EIO; |
602 | ntfs_log_perror("Found stale extent mft " |
603 | "reference mft=%lld", |
604 | (long long)ni->mft_no); |
605 | goto out; |
606 | } |
607 | goto out; |
608 | } |
609 | } |
610 | /* Wasn't there, we need to load the extent inode. */ |
611 | ni = __ntfs_inode_allocate(base_ni->vol); |
612 | if (!ni) |
613 | goto out; |
614 | if (ntfs_file_record_read(base_ni->vol, le64_to_cpu(mref), &ni->mrec, NULL)) |
615 | goto err_out; |
616 | ni->mft_no = mft_no; |
617 | ni->nr_extents = -1; |
618 | ni->base_ni = base_ni; |
619 | /* Attach extent inode to base inode, reallocating memory if needed. */ |
620 | if (!(base_ni->nr_extents & 3)) { |
621 | i = (base_ni->nr_extents + 4) * sizeof(ntfs_inode *); |
622 | |
623 | extent_nis = ntfs_malloc(i); |
624 | if (!extent_nis) |
625 | goto err_out; |
626 | if (base_ni->nr_extents) { |
627 | memcpy(extent_nis, base_ni->extent_nis, |
628 | i - 4 * sizeof(ntfs_inode *)); |
629 | free(base_ni->extent_nis); |
630 | } |
631 | base_ni->extent_nis = extent_nis; |
632 | } |
633 | base_ni->extent_nis[base_ni->nr_extents++] = ni; |
634 | out: |
635 | ntfs_log_leave("\n"); |
636 | return ni; |
637 | err_out: |
638 | __ntfs_inode_release(ni); |
639 | ni = NULL; |
640 | goto out; |
641 | } |
642 | |
643 | /** |
644 | * ntfs_inode_attach_all_extents - attach all extents for target inode |
645 | * @ni: opened ntfs inode for which perform attach |
646 | * |
647 | * Return 0 on success and -1 on error with errno set to the error code. |
648 | */ |
649 | int ntfs_inode_attach_all_extents(ntfs_inode *ni) |
650 | { |
651 | ATTR_LIST_ENTRY *ale; |
652 | u64 prev_attached = 0; |
653 | |
654 | if (!ni) { |
655 | ntfs_log_trace("Invalid arguments.\n"); |
656 | errno = EINVAL; |
657 | return -1; |
658 | } |
659 | |
660 | if (ni->nr_extents == -1) |
661 | ni = ni->base_ni; |
662 | |
663 | ntfs_log_trace("Entering for inode 0x%llx.\n", (long long) ni->mft_no); |
664 | |
665 | /* Inode haven't got attribute list, thus nothing to attach. */ |
666 | if (!NInoAttrList(ni)) |
667 | return 0; |
668 | |
669 | if (!ni->attr_list) { |
670 | ntfs_log_trace("Corrupt in-memory struct.\n"); |
671 | errno = EINVAL; |
672 | return -1; |
673 | } |
674 | |
675 | /* Walk through attribute list and attach all extents. */ |
676 | errno = 0; |
677 | ale = (ATTR_LIST_ENTRY *)ni->attr_list; |
678 | while ((u8*)ale < ni->attr_list + ni->attr_list_size) { |
679 | if (ni->mft_no != MREF_LE(ale->mft_reference) && |
680 | prev_attached != MREF_LE(ale->mft_reference)) { |
681 | if (!ntfs_extent_inode_open(ni, ale->mft_reference)) { |
682 | ntfs_log_trace("Couldn't attach extent inode.\n"); |
683 | return -1; |
684 | } |
685 | prev_attached = MREF_LE(ale->mft_reference); |
686 | } |
687 | ale = (ATTR_LIST_ENTRY *)((u8*)ale + le16_to_cpu(ale->length)); |
688 | } |
689 | return 0; |
690 | } |
691 | |
692 | /** |
693 | * ntfs_inode_sync_standard_information - update standard information attribute |
694 | * @ni: ntfs inode to update standard information |
695 | * |
696 | * Return 0 on success or -1 on error with errno set to the error code. |
697 | */ |
698 | static int ntfs_inode_sync_standard_information(ntfs_inode *ni) |
699 | { |
700 | ntfs_attr_search_ctx *ctx; |
701 | STANDARD_INFORMATION *std_info; |
702 | u32 lth; |
703 | le32 lthle; |
704 | |
705 | ntfs_log_trace("Entering for inode %lld\n", (long long)ni->mft_no); |
706 | |
707 | ctx = ntfs_attr_get_search_ctx(ni, NULL); |
708 | if (!ctx) |
709 | return -1; |
710 | if (ntfs_attr_lookup(AT_STANDARD_INFORMATION, AT_UNNAMED, |
711 | 0, CASE_SENSITIVE, 0, NULL, 0, ctx)) { |
712 | ntfs_log_perror("Failed to sync standard info (inode %lld)", |
713 | (long long)ni->mft_no); |
714 | ntfs_attr_put_search_ctx(ctx); |
715 | return -1; |
716 | } |
717 | std_info = (STANDARD_INFORMATION *)((u8 *)ctx->attr + |
718 | le16_to_cpu(ctx->attr->value_offset)); |
719 | std_info->file_attributes = ni->flags; |
720 | if (!test_nino_flag(ni, TimesSet)) { |
721 | std_info->creation_time = ni->creation_time; |
722 | std_info->last_data_change_time = ni->last_data_change_time; |
723 | std_info->last_mft_change_time = ni->last_mft_change_time; |
724 | std_info->last_access_time = ni->last_access_time; |
725 | } |
726 | |
727 | /* JPA update v3.x extensions, ensuring consistency */ |
728 | |
729 | lthle = ctx->attr->length; |
730 | lth = le32_to_cpu(lthle); |
731 | if (test_nino_flag(ni, v3_Extensions) |
732 | && (lth <= sizeof(STANDARD_INFORMATION))) |
733 | ntfs_log_error("bad sync of standard information\n"); |
734 | |
735 | if (lth > sizeof(STANDARD_INFORMATION)) { |
736 | std_info->owner_id = ni->owner_id; |
737 | std_info->security_id = ni->security_id; |
738 | std_info->quota_charged = ni->quota_charged; |
739 | std_info->usn = ni->usn; |
740 | } |
741 | ntfs_inode_mark_dirty(ctx->ntfs_ino); |
742 | ntfs_attr_put_search_ctx(ctx); |
743 | return 0; |
744 | } |
745 | |
746 | /** |
747 | * ntfs_inode_sync_file_name - update FILE_NAME attributes |
748 | * @ni: ntfs inode to update FILE_NAME attributes |
749 | * |
750 | * Update all FILE_NAME attributes for inode @ni in the index. |
751 | * |
752 | * Return 0 on success or -1 on error with errno set to the error code. |
753 | */ |
754 | static int ntfs_inode_sync_file_name(ntfs_inode *ni, ntfs_inode *dir_ni) |
755 | { |
756 | ntfs_attr_search_ctx *ctx = NULL; |
757 | ntfs_index_context *ictx; |
758 | ntfs_inode *index_ni; |
759 | FILE_NAME_ATTR *fn; |
760 | FILE_NAME_ATTR *fnx; |
761 | REPARSE_POINT *rpp; |
762 | le32 reparse_tag; |
763 | int err = 0; |
764 | |
765 | ntfs_log_trace("Entering for inode %lld\n", (long long)ni->mft_no); |
766 | |
767 | ctx = ntfs_attr_get_search_ctx(ni, NULL); |
768 | if (!ctx) { |
769 | err = errno; |
770 | goto err_out; |
771 | } |
772 | /* Collect the reparse tag, if any */ |
773 | reparse_tag = cpu_to_le32(0); |
774 | if (ni->flags & FILE_ATTR_REPARSE_POINT) { |
775 | if (!ntfs_attr_lookup(AT_REPARSE_POINT, NULL, |
776 | 0, CASE_SENSITIVE, 0, NULL, 0, ctx)) { |
777 | rpp = (REPARSE_POINT*)((u8 *)ctx->attr + |
778 | le16_to_cpu(ctx->attr->value_offset)); |
779 | reparse_tag = rpp->reparse_tag; |
780 | } |
781 | ntfs_attr_reinit_search_ctx(ctx); |
782 | } |
783 | /* Walk through all FILE_NAME attributes and update them. */ |
784 | while (!ntfs_attr_lookup(AT_FILE_NAME, NULL, 0, 0, 0, NULL, 0, ctx)) { |
785 | fn = (FILE_NAME_ATTR *)((u8 *)ctx->attr + |
786 | le16_to_cpu(ctx->attr->value_offset)); |
787 | if (MREF_LE(fn->parent_directory) == ni->mft_no) { |
788 | /* |
789 | * WARNING: We cheat here and obtain 2 attribute |
790 | * search contexts for one inode (first we obtained |
791 | * above, second will be obtained inside |
792 | * ntfs_index_lookup), it's acceptable for library, |
793 | * but will deadlock in the kernel. |
794 | */ |
795 | index_ni = ni; |
796 | } else |
797 | if (dir_ni) |
798 | index_ni = dir_ni; |
799 | else |
800 | index_ni = ntfs_inode_open(ni->vol, |
801 | le64_to_cpu(fn->parent_directory)); |
802 | if (!index_ni) { |
803 | if (!err) |
804 | err = errno; |
805 | ntfs_log_perror("Failed to open inode %lld with index", |
806 | (long long)le64_to_cpu(fn->parent_directory)); |
807 | continue; |
808 | } |
809 | ictx = ntfs_index_ctx_get(index_ni, NTFS_INDEX_I30, 4); |
810 | if (!ictx) { |
811 | if (!err) |
812 | err = errno; |
813 | ntfs_log_perror("Failed to get index ctx, inode %lld", |
814 | (long long)index_ni->mft_no); |
815 | if ((ni != index_ni) && !dir_ni |
816 | && ntfs_inode_close(index_ni) && !err) |
817 | err = errno; |
818 | continue; |
819 | } |
820 | if (ntfs_index_lookup(fn, sizeof(FILE_NAME_ATTR), ictx)) { |
821 | if (!err) { |
822 | if (errno == ENOENT) |
823 | err = EIO; |
824 | else |
825 | err = errno; |
826 | } |
827 | ntfs_log_perror("Index lookup failed, inode %lld", |
828 | (long long)index_ni->mft_no); |
829 | ntfs_index_ctx_put(ictx); |
830 | if (ni != index_ni && ntfs_inode_close(index_ni) && !err) |
831 | err = errno; |
832 | continue; |
833 | } |
834 | /* Update flags and file size. */ |
835 | fnx = (FILE_NAME_ATTR *)ictx->data; |
836 | fnx->file_attributes = |
837 | (fnx->file_attributes & ~FILE_ATTR_VALID_FLAGS) | |
838 | (ni->flags & FILE_ATTR_VALID_FLAGS); |
839 | if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) |
840 | fnx->data_size = fnx->allocated_size |
841 | = const_cpu_to_le64(0); |
842 | else { |
843 | fnx->allocated_size = cpu_to_sle64(ni->allocated_size); |
844 | fnx->data_size = cpu_to_sle64(ni->data_size); |
845 | } |
846 | /* update or clear the reparse tag in the index */ |
847 | fnx->reparse_point_tag = reparse_tag; |
848 | if (!test_nino_flag(ni, TimesSet)) { |
849 | fnx->creation_time = ni->creation_time; |
850 | fnx->last_data_change_time = ni->last_data_change_time; |
851 | fnx->last_mft_change_time = ni->last_mft_change_time; |
852 | fnx->last_access_time = ni->last_access_time; |
853 | } else { |
854 | fnx->creation_time = fn->creation_time; |
855 | fnx->last_data_change_time = fn->last_data_change_time; |
856 | fnx->last_mft_change_time = fn->last_mft_change_time; |
857 | fnx->last_access_time = fn->last_access_time; |
858 | } |
859 | ntfs_index_entry_mark_dirty(ictx); |
860 | ntfs_index_ctx_put(ictx); |
861 | if ((ni != index_ni) && !dir_ni |
862 | && ntfs_inode_close(index_ni) && !err) |
863 | err = errno; |
864 | } |
865 | /* Check for real error occurred. */ |
866 | if (errno != ENOENT) { |
867 | err = errno; |
868 | ntfs_log_perror("Attribute lookup failed, inode %lld", |
869 | (long long)ni->mft_no); |
870 | goto err_out; |
871 | } |
872 | ntfs_attr_put_search_ctx(ctx); |
873 | if (err) { |
874 | errno = err; |
875 | return -1; |
876 | } |
877 | return 0; |
878 | err_out: |
879 | if (ctx) |
880 | ntfs_attr_put_search_ctx(ctx); |
881 | errno = err; |
882 | return -1; |
883 | } |
884 | |
885 | /** |
886 | * ntfs_inode_sync - write the inode (and its dirty extents) to disk |
887 | * @ni: ntfs inode to write |
888 | * |
889 | * Write the inode @ni to disk as well as its dirty extent inodes if such |
890 | * exist and @ni is a base inode. If @ni is an extent inode, only @ni is |
891 | * written completely disregarding its base inode and any other extent inodes. |
892 | * |
893 | * For a base inode with dirty extent inodes if any writes fail for whatever |
894 | * reason, the failing inode is skipped and the sync process is continued. At |
895 | * the end the error condition that brought about the failure is returned. Thus |
896 | * the smallest amount of data loss possible occurs. |
897 | * |
898 | * Return 0 on success or -1 on error with errno set to the error code. |
899 | * The following error codes are defined: |
900 | * EINVAL - Invalid arguments were passed to the function. |
901 | * EBUSY - Inode and/or one of its extents is busy, try again later. |
902 | * EIO - I/O error while writing the inode (or one of its extents). |
903 | */ |
904 | static int ntfs_inode_sync_in_dir(ntfs_inode *ni, ntfs_inode *dir_ni) |
905 | { |
906 | int ret = 0; |
907 | int err = 0; |
908 | if (!ni) { |
909 | errno = EINVAL; |
910 | ntfs_log_error("Failed to sync NULL inode\n"); |
911 | return -1; |
912 | } |
913 | |
914 | ntfs_log_enter("Entering for inode %lld\n", (long long)ni->mft_no); |
915 | |
916 | /* Update STANDARD_INFORMATION. */ |
917 | if ((ni->mrec->flags & MFT_RECORD_IN_USE) && ni->nr_extents != -1 && |
918 | ntfs_inode_sync_standard_information(ni)) { |
919 | if (!err || errno == EIO) { |
920 | err = errno; |
921 | if (err != EIO) |
922 | err = EBUSY; |
923 | } |
924 | } |
925 | |
926 | /* Update FILE_NAME's in the index. */ |
927 | if ((ni->mrec->flags & MFT_RECORD_IN_USE) && ni->nr_extents != -1 && |
928 | NInoFileNameTestAndClearDirty(ni) && |
929 | ntfs_inode_sync_file_name(ni, dir_ni)) { |
930 | if (!err || errno == EIO) { |
931 | err = errno; |
932 | if (err != EIO) |
933 | err = EBUSY; |
934 | } |
935 | ntfs_log_perror("Failed to sync FILE_NAME (inode %lld)", |
936 | (long long)ni->mft_no); |
937 | NInoFileNameSetDirty(ni); |
938 | } |
939 | |
940 | /* Write out attribute list from cache to disk. */ |
941 | if ((ni->mrec->flags & MFT_RECORD_IN_USE) && ni->nr_extents != -1 && |
942 | NInoAttrList(ni) && NInoAttrListTestAndClearDirty(ni)) { |
943 | ntfs_attr *na; |
944 | |
945 | na = ntfs_attr_open(ni, AT_ATTRIBUTE_LIST, AT_UNNAMED, 0); |
946 | if (!na) { |
947 | if (!err || errno == EIO) { |
948 | err = errno; |
949 | if (err != EIO) |
950 | err = EBUSY; |
951 | ntfs_log_perror("Attribute list sync failed " |
952 | "(open, inode %lld)", |
953 | (long long)ni->mft_no); |
954 | } |
955 | NInoAttrListSetDirty(ni); |
956 | goto sync_inode; |
957 | } |
958 | |
959 | if (na->data_size == ni->attr_list_size) { |
960 | if (ntfs_attr_pwrite(na, 0, ni->attr_list_size, |
961 | ni->attr_list) != ni->attr_list_size) { |
962 | if (!err || errno == EIO) { |
963 | err = errno; |
964 | if (err != EIO) |
965 | err = EBUSY; |
966 | ntfs_log_perror("Attribute list sync " |
967 | "failed (write, inode %lld)", |
968 | (long long)ni->mft_no); |
969 | } |
970 | NInoAttrListSetDirty(ni); |
971 | } |
972 | } else { |
973 | err = EIO; |
974 | ntfs_log_error("Attribute list sync failed (bad size, " |
975 | "inode %lld)\n", (long long)ni->mft_no); |
976 | NInoAttrListSetDirty(ni); |
977 | } |
978 | ntfs_attr_close(na); |
979 | } |
980 | |
981 | sync_inode: |
982 | /* Write this inode out to the $MFT (and $MFTMirr if applicable). */ |
983 | if (NInoTestAndClearDirty(ni)) { |
984 | if (ntfs_mft_record_write(ni->vol, ni->mft_no, ni->mrec)) { |
985 | if (!err || errno == EIO) { |
986 | err = errno; |
987 | if (err != EIO) |
988 | err = EBUSY; |
989 | } |
990 | NInoSetDirty(ni); |
991 | ntfs_log_perror("MFT record sync failed, inode %lld", |
992 | (long long)ni->mft_no); |
993 | } |
994 | } |
995 | |
996 | /* If this is a base inode with extents write all dirty extents, too. */ |
997 | if (ni->nr_extents > 0) { |
998 | s32 i; |
999 | |
1000 | for (i = 0; i < ni->nr_extents; ++i) { |
1001 | ntfs_inode *eni; |
1002 | |
1003 | eni = ni->extent_nis[i]; |
1004 | if (!NInoTestAndClearDirty(eni)) |
1005 | continue; |
1006 | |
1007 | if (ntfs_mft_record_write(eni->vol, eni->mft_no, |
1008 | eni->mrec)) { |
1009 | if (!err || errno == EIO) { |
1010 | err = errno; |
1011 | if (err != EIO) |
1012 | err = EBUSY; |
1013 | } |
1014 | NInoSetDirty(eni); |
1015 | ntfs_log_perror("Extent MFT record sync failed," |
1016 | " inode %lld/%lld", |
1017 | (long long)ni->mft_no, |
1018 | (long long)eni->mft_no); |
1019 | } |
1020 | } |
1021 | } |
1022 | |
1023 | if (err) { |
1024 | errno = err; |
1025 | ret = -1; |
1026 | } |
1027 | |
1028 | ntfs_log_leave("\n"); |
1029 | return ret; |
1030 | } |
1031 | |
1032 | int ntfs_inode_sync(ntfs_inode *ni) |
1033 | { |
1034 | return (ntfs_inode_sync_in_dir(ni, (ntfs_inode*)NULL)); |
1035 | } |
1036 | |
1037 | /* |
1038 | * Close an inode with an open parent inode |
1039 | */ |
1040 | |
1041 | int ntfs_inode_close_in_dir(ntfs_inode *ni, ntfs_inode *dir_ni) |
1042 | { |
1043 | int res; |
1044 | |
1045 | res = ntfs_inode_sync_in_dir(ni, dir_ni); |
1046 | if (res) { |
1047 | if (errno != EIO) |
1048 | errno = EBUSY; |
1049 | } else |
1050 | res = ntfs_inode_close(ni); |
1051 | return (res); |
1052 | } |
1053 | |
1054 | /** |
1055 | * ntfs_inode_add_attrlist - add attribute list to inode and fill it |
1056 | * @ni: opened ntfs inode to which add attribute list |
1057 | * |
1058 | * Return 0 on success or -1 on error with errno set to the error code. |
1059 | * The following error codes are defined: |
1060 | * EINVAL - Invalid arguments were passed to the function. |
1061 | * EEXIST - Attribute list already exist. |
1062 | * EIO - Input/Ouput error occurred. |
1063 | * ENOMEM - Not enough memory to perform add. |
1064 | */ |
1065 | int ntfs_inode_add_attrlist(ntfs_inode *ni) |
1066 | { |
1067 | int err; |
1068 | ntfs_attr_search_ctx *ctx; |
1069 | u8 *al = NULL, *aln; |
1070 | int al_len = 0; |
1071 | ATTR_LIST_ENTRY *ale = NULL; |
1072 | ntfs_attr *na; |
1073 | |
1074 | if (!ni) { |
1075 | errno = EINVAL; |
1076 | ntfs_log_perror("%s", __FUNCTION__); |
1077 | return -1; |
1078 | } |
1079 | |
1080 | ntfs_log_trace("inode %llu\n", (unsigned long long) ni->mft_no); |
1081 | |
1082 | if (NInoAttrList(ni) || ni->nr_extents) { |
1083 | errno = EEXIST; |
1084 | ntfs_log_perror("Inode already has attribute list"); |
1085 | return -1; |
1086 | } |
1087 | |
1088 | /* Form attribute list. */ |
1089 | ctx = ntfs_attr_get_search_ctx(ni, NULL); |
1090 | if (!ctx) { |
1091 | err = errno; |
1092 | goto err_out; |
1093 | } |
1094 | /* Walk through all attributes. */ |
1095 | while (!ntfs_attr_lookup(AT_UNUSED, NULL, 0, 0, 0, NULL, 0, ctx)) { |
1096 | |
1097 | int ale_size; |
1098 | |
1099 | if (ctx->attr->type == AT_ATTRIBUTE_LIST) { |
1100 | err = EIO; |
1101 | ntfs_log_perror("Attribute list already present"); |
1102 | goto put_err_out; |
1103 | } |
1104 | |
1105 | ale_size = (sizeof(ATTR_LIST_ENTRY) + sizeof(ntfschar) * |
1106 | ctx->attr->name_length + 7) & ~7; |
1107 | al_len += ale_size; |
1108 | |
1109 | aln = realloc(al, al_len); |
1110 | if (!aln) { |
1111 | err = errno; |
1112 | ntfs_log_perror("Failed to realloc %d bytes", al_len); |
1113 | goto put_err_out; |
1114 | } |
1115 | ale = (ATTR_LIST_ENTRY *)(aln + ((u8 *)ale - al)); |
1116 | al = aln; |
1117 | |
1118 | memset(ale, 0, ale_size); |
1119 | |
1120 | /* Add attribute to attribute list. */ |
1121 | ale->type = ctx->attr->type; |
1122 | ale->length = cpu_to_le16((sizeof(ATTR_LIST_ENTRY) + |
1123 | sizeof(ntfschar) * ctx->attr->name_length + 7) & ~7); |
1124 | ale->name_length = ctx->attr->name_length; |
1125 | ale->name_offset = (u8 *)ale->name - (u8 *)ale; |
1126 | if (ctx->attr->non_resident) |
1127 | ale->lowest_vcn = ctx->attr->lowest_vcn; |
1128 | else |
1129 | ale->lowest_vcn = 0; |
1130 | ale->mft_reference = MK_LE_MREF(ni->mft_no, |
1131 | le16_to_cpu(ni->mrec->sequence_number)); |
1132 | ale->instance = ctx->attr->instance; |
1133 | memcpy(ale->name, (u8 *)ctx->attr + |
1134 | le16_to_cpu(ctx->attr->name_offset), |
1135 | ctx->attr->name_length * sizeof(ntfschar)); |
1136 | ale = (ATTR_LIST_ENTRY *)(al + al_len); |
1137 | } |
1138 | /* Check for real error occurred. */ |
1139 | if (errno != ENOENT) { |
1140 | err = errno; |
1141 | ntfs_log_perror("%s: Attribute lookup failed, inode %lld", |
1142 | __FUNCTION__, (long long)ni->mft_no); |
1143 | goto put_err_out; |
1144 | } |
1145 | |
1146 | /* Set in-memory attribute list. */ |
1147 | ni->attr_list = al; |
1148 | ni->attr_list_size = al_len; |
1149 | NInoSetAttrList(ni); |
1150 | NInoAttrListSetDirty(ni); |
1151 | |
1152 | /* Free space if there is not enough it for $ATTRIBUTE_LIST. */ |
1153 | if (le32_to_cpu(ni->mrec->bytes_allocated) - |
1154 | le32_to_cpu(ni->mrec->bytes_in_use) < |
1155 | offsetof(ATTR_RECORD, resident_end)) { |
1156 | if (ntfs_inode_free_space(ni, |
1157 | offsetof(ATTR_RECORD, resident_end))) { |
1158 | /* Failed to free space. */ |
1159 | err = errno; |
1160 | ntfs_log_perror("Failed to free space for attrlist"); |
1161 | goto rollback; |
1162 | } |
1163 | } |
1164 | |
1165 | /* Add $ATTRIBUTE_LIST to mft record. */ |
1166 | if (ntfs_resident_attr_record_add(ni, |
1167 | AT_ATTRIBUTE_LIST, NULL, 0, NULL, 0, 0) < 0) { |
1168 | err = errno; |
1169 | ntfs_log_perror("Couldn't add $ATTRIBUTE_LIST to MFT"); |
1170 | goto rollback; |
1171 | } |
1172 | |
1173 | /* Resize it. */ |
1174 | na = ntfs_attr_open(ni, AT_ATTRIBUTE_LIST, AT_UNNAMED, 0); |
1175 | if (!na) { |
1176 | err = errno; |
1177 | ntfs_log_perror("Failed to open just added $ATTRIBUTE_LIST"); |
1178 | goto remove_attrlist_record; |
1179 | } |
1180 | if (ntfs_attr_truncate(na, al_len)) { |
1181 | err = errno; |
1182 | ntfs_log_perror("Failed to resize just added $ATTRIBUTE_LIST"); |
1183 | ntfs_attr_close(na); |
1184 | goto remove_attrlist_record;; |
1185 | } |
1186 | |
1187 | ntfs_attr_put_search_ctx(ctx); |
1188 | ntfs_attr_close(na); |
1189 | return 0; |
1190 | |
1191 | remove_attrlist_record: |
1192 | /* Prevent ntfs_attr_recorm_rm from freeing attribute list. */ |
1193 | ni->attr_list = NULL; |
1194 | NInoClearAttrList(ni); |
1195 | /* Remove $ATTRIBUTE_LIST record. */ |
1196 | ntfs_attr_reinit_search_ctx(ctx); |
1197 | if (!ntfs_attr_lookup(AT_ATTRIBUTE_LIST, NULL, 0, |
1198 | CASE_SENSITIVE, 0, NULL, 0, ctx)) { |
1199 | if (ntfs_attr_record_rm(ctx)) |
1200 | ntfs_log_perror("Rollback failed to remove attrlist"); |
1201 | } else |
1202 | ntfs_log_perror("Rollback failed to find attrlist"); |
1203 | /* Setup back in-memory runlist. */ |
1204 | ni->attr_list = al; |
1205 | ni->attr_list_size = al_len; |
1206 | NInoSetAttrList(ni); |
1207 | rollback: |
1208 | /* |
1209 | * Scan attribute list for attributes that placed not in the base MFT |
1210 | * record and move them to it. |
1211 | */ |
1212 | ntfs_attr_reinit_search_ctx(ctx); |
1213 | ale = (ATTR_LIST_ENTRY*)al; |
1214 | while ((u8*)ale < al + al_len) { |
1215 | if (MREF_LE(ale->mft_reference) != ni->mft_no) { |
1216 | if (!ntfs_attr_lookup(ale->type, ale->name, |
1217 | ale->name_length, |
1218 | CASE_SENSITIVE, |
1219 | sle64_to_cpu(ale->lowest_vcn), |
1220 | NULL, 0, ctx)) { |
1221 | if (ntfs_attr_record_move_to(ctx, ni)) |
1222 | ntfs_log_perror("Rollback failed to " |
1223 | "move attribute"); |
1224 | } else |
1225 | ntfs_log_perror("Rollback failed to find attr"); |
1226 | ntfs_attr_reinit_search_ctx(ctx); |
1227 | } |
1228 | ale = (ATTR_LIST_ENTRY*)((u8*)ale + le16_to_cpu(ale->length)); |
1229 | } |
1230 | /* Remove in-memory attribute list. */ |
1231 | ni->attr_list = NULL; |
1232 | ni->attr_list_size = 0; |
1233 | NInoClearAttrList(ni); |
1234 | NInoAttrListClearDirty(ni); |
1235 | put_err_out: |
1236 | ntfs_attr_put_search_ctx(ctx); |
1237 | err_out: |
1238 | free(al); |
1239 | errno = err; |
1240 | return -1; |
1241 | } |
1242 | |
1243 | /** |
1244 | * ntfs_inode_free_space - free space in the MFT record of an inode |
1245 | * @ni: ntfs inode in which MFT record needs more free space |
1246 | * @size: amount of space needed to free |
1247 | * |
1248 | * Return 0 on success or -1 on error with errno set to the error code. |
1249 | */ |
1250 | int ntfs_inode_free_space(ntfs_inode *ni, int size) |
1251 | { |
1252 | ntfs_attr_search_ctx *ctx; |
1253 | int freed; |
1254 | |
1255 | if (!ni || size < 0) { |
1256 | errno = EINVAL; |
1257 | ntfs_log_perror("%s: ni=%p size=%d", __FUNCTION__, ni, size); |
1258 | return -1; |
1259 | } |
1260 | |
1261 | ntfs_log_trace("Entering for inode %lld, size %d\n", |
1262 | (unsigned long long)ni->mft_no, size); |
1263 | |
1264 | freed = (le32_to_cpu(ni->mrec->bytes_allocated) - |
1265 | le32_to_cpu(ni->mrec->bytes_in_use)); |
1266 | |
1267 | if (size <= freed) |
1268 | return 0; |
1269 | |
1270 | ctx = ntfs_attr_get_search_ctx(ni, NULL); |
1271 | if (!ctx) |
1272 | return -1; |
1273 | /* |
1274 | * $STANDARD_INFORMATION and $ATTRIBUTE_LIST must stay in the base MFT |
1275 | * record, so position search context on the first attribute after them. |
1276 | */ |
1277 | if (ntfs_attr_position(AT_FILE_NAME, ctx)) |
1278 | goto put_err_out; |
1279 | |
1280 | while (1) { |
1281 | int record_size; |
1282 | /* |
1283 | * Check whether attribute is from different MFT record. If so, |
1284 | * find next, because we don't need such. |
1285 | */ |
1286 | while (ctx->ntfs_ino->mft_no != ni->mft_no) { |
1287 | retry: |
1288 | if (ntfs_attr_position(AT_UNUSED, ctx)) |
1289 | goto put_err_out; |
1290 | } |
1291 | |
1292 | if (ntfs_inode_base(ctx->ntfs_ino)->mft_no == FILE_MFT && |
1293 | ctx->attr->type == AT_DATA) |
1294 | goto retry; |
1295 | |
1296 | if (ctx->attr->type == AT_INDEX_ROOT) |
1297 | goto retry; |
1298 | |
1299 | record_size = le32_to_cpu(ctx->attr->length); |
1300 | |
1301 | if (ntfs_attr_record_move_away(ctx, 0)) { |
1302 | ntfs_log_perror("Failed to move out attribute #2"); |
1303 | break; |
1304 | } |
1305 | freed += record_size; |
1306 | |
1307 | /* Check whether we are done. */ |
1308 | if (size <= freed) { |
1309 | ntfs_attr_put_search_ctx(ctx); |
1310 | return 0; |
1311 | } |
1312 | /* |
1313 | * Reposition to first attribute after $STANDARD_INFORMATION |
1314 | * and $ATTRIBUTE_LIST instead of simply skipping this attribute |
1315 | * because in the case when we have got only in-memory attribute |
1316 | * list then ntfs_attr_lookup will fail when it tries to find |
1317 | * $ATTRIBUTE_LIST. |
1318 | */ |
1319 | ntfs_attr_reinit_search_ctx(ctx); |
1320 | if (ntfs_attr_position(AT_FILE_NAME, ctx)) |
1321 | break; |
1322 | } |
1323 | put_err_out: |
1324 | ntfs_attr_put_search_ctx(ctx); |
1325 | if (errno == ENOSPC) |
1326 | ntfs_log_trace("No attributes left that could be moved out.\n"); |
1327 | return -1; |
1328 | } |
1329 | |
1330 | /** |
1331 | * ntfs_inode_update_times - update selected time fields for ntfs inode |
1332 | * @ni: ntfs inode for which update time fields |
1333 | * @mask: select which time fields should be updated |
1334 | * |
1335 | * This function updates time fields to current time. Fields to update are |
1336 | * selected using @mask (see enum @ntfs_time_update_flags for posssible values). |
1337 | */ |
1338 | void ntfs_inode_update_times(ntfs_inode *ni, ntfs_time_update_flags mask) |
1339 | { |
1340 | ntfs_time now; |
1341 | |
1342 | if (!ni) { |
1343 | ntfs_log_error("%s(): Invalid arguments.\n", __FUNCTION__); |
1344 | return; |
1345 | } |
1346 | |
1347 | if ((ni->mft_no < FILE_first_user && ni->mft_no != FILE_root) || |
1348 | NVolReadOnly(ni->vol) || !mask) |
1349 | return; |
1350 | |
1351 | now = ntfs_current_time(); |
1352 | if (mask & NTFS_UPDATE_ATIME) |
1353 | ni->last_access_time = now; |
1354 | if (mask & NTFS_UPDATE_MTIME) |
1355 | ni->last_data_change_time = now; |
1356 | if (mask & NTFS_UPDATE_CTIME) |
1357 | ni->last_mft_change_time = now; |
1358 | |
1359 | NInoFileNameSetDirty(ni); |
1360 | NInoSetDirty(ni); |
1361 | } |
1362 | |
1363 | /** |
1364 | * ntfs_inode_badclus_bad - check for $Badclus:$Bad data attribute |
1365 | * @mft_no: mft record number where @attr is present |
1366 | * @attr: attribute record used to check for the $Bad attribute |
1367 | * |
1368 | * Check if the mft record given by @mft_no and @attr contains the bad sector |
1369 | * list. Please note that mft record numbers describing $Badclus extent inodes |
1370 | * will not match the current $Badclus:$Bad check. |
1371 | * |
1372 | * On success return 1 if the file is $Badclus:$Bad, otherwise return 0. |
1373 | * On error return -1 with errno set to the error code. |
1374 | */ |
1375 | int ntfs_inode_badclus_bad(u64 mft_no, ATTR_RECORD *attr) |
1376 | { |
1377 | int len, ret = 0; |
1378 | ntfschar *ustr; |
1379 | |
1380 | if (!attr) { |
1381 | ntfs_log_error("Invalid argument.\n"); |
1382 | errno = EINVAL; |
1383 | return -1; |
1384 | } |
1385 | |
1386 | if (mft_no != FILE_BadClus) |
1387 | return 0; |
1388 | |
1389 | if (attr->type != AT_DATA) |
1390 | return 0; |
1391 | |
1392 | if ((ustr = ntfs_str2ucs("$Bad", &len)) == NULL) { |
1393 | ntfs_log_perror("Couldn't convert '$Bad' to Unicode"); |
1394 | return -1; |
1395 | } |
1396 | |
1397 | if (ustr && ntfs_names_are_equal(ustr, len, |
1398 | (ntfschar *)((u8 *)attr + le16_to_cpu(attr->name_offset)), |
1399 | attr->name_length, 0, NULL, 0)) |
1400 | ret = 1; |
1401 | |
1402 | ntfs_ucsfree(ustr); |
1403 | |
1404 | return ret; |
1405 | } |
1406 | |
1407 | #ifdef HAVE_SETXATTR /* extended attributes interface required */ |
1408 | |
1409 | /* |
1410 | * Get high precision NTFS times |
1411 | * |
1412 | * They are returned in following order : create, update, access, change |
1413 | * provided they fit in requested size. |
1414 | * |
1415 | * Returns the modified size if successfull (or 32 if buffer size is null) |
1416 | * -errno if failed |
1417 | */ |
1418 | |
1419 | int ntfs_inode_get_times(ntfs_inode *ni, char *value, size_t size) |
1420 | { |
1421 | ntfs_attr_search_ctx *ctx; |
1422 | STANDARD_INFORMATION *std_info; |
1423 | u64 *times; |
1424 | int ret; |
1425 | |
1426 | ret = 0; |
1427 | ctx = ntfs_attr_get_search_ctx(ni, NULL); |
1428 | if (ctx) { |
1429 | if (ntfs_attr_lookup(AT_STANDARD_INFORMATION, AT_UNNAMED, |
1430 | 0, CASE_SENSITIVE, 0, NULL, 0, ctx)) { |
1431 | ntfs_log_perror("Failed to get standard info (inode %lld)", |
1432 | (long long)ni->mft_no); |
1433 | } else { |
1434 | std_info = (STANDARD_INFORMATION *)((u8 *)ctx->attr + |
1435 | le16_to_cpu(ctx->attr->value_offset)); |
1436 | if (value && (size >= 8)) { |
1437 | times = (u64*)value; |
1438 | times[0] = le64_to_cpu(std_info->creation_time); |
1439 | ret = 8; |
1440 | if (size >= 16) { |
1441 | times[1] = le64_to_cpu(std_info->last_data_change_time); |
1442 | ret = 16; |
1443 | } |
1444 | if (size >= 24) { |
1445 | times[2] = le64_to_cpu(std_info->last_access_time); |
1446 | ret = 24; |
1447 | } |
1448 | if (size >= 32) { |
1449 | times[3] = le64_to_cpu(std_info->last_mft_change_time); |
1450 | ret = 32; |
1451 | } |
1452 | } else |
1453 | if (!size) |
1454 | ret = 32; |
1455 | else |
1456 | ret = -ERANGE; |
1457 | } |
1458 | ntfs_attr_put_search_ctx(ctx); |
1459 | } |
1460 | return (ret ? ret : -errno); |
1461 | } |
1462 | |
1463 | /* |
1464 | * Set high precision NTFS times |
1465 | * |
1466 | * They are expected in this order : create, update, access |
1467 | * provided they are present in input. The change time is set to |
1468 | * current time. |
1469 | * |
1470 | * The times are inserted directly in the standard_information and |
1471 | * file names attributes to avoid manipulating low precision times |
1472 | * |
1473 | * Returns 0 if success |
1474 | * -1 if there were an error (described by errno) |
1475 | */ |
1476 | |
1477 | int ntfs_inode_set_times(ntfs_inode *ni, const char *value, size_t size, |
1478 | int flags) |
1479 | { |
1480 | ntfs_attr_search_ctx *ctx; |
1481 | STANDARD_INFORMATION *std_info; |
1482 | FILE_NAME_ATTR *fn; |
1483 | const u64 *times; |
1484 | ntfs_time now; |
1485 | int cnt; |
1486 | int ret; |
1487 | |
1488 | ret = -1; |
1489 | if ((size >= 8) && !(flags & XATTR_CREATE)) { |
1490 | times = (const u64*)value; |
1491 | now = ntfs_current_time(); |
1492 | /* update the standard information attribute */ |
1493 | ctx = ntfs_attr_get_search_ctx(ni, NULL); |
1494 | if (ctx) { |
1495 | if (ntfs_attr_lookup(AT_STANDARD_INFORMATION, |
1496 | AT_UNNAMED, 0, CASE_SENSITIVE, |
1497 | 0, NULL, 0, ctx)) { |
1498 | ntfs_log_perror("Failed to get standard info (inode %lld)", |
1499 | (long long)ni->mft_no); |
1500 | } else { |
1501 | std_info = (STANDARD_INFORMATION *)((u8 *)ctx->attr + |
1502 | le16_to_cpu(ctx->attr->value_offset)); |
1503 | /* |
1504 | * Mark times set to avoid overwriting |
1505 | * them when the inode is closed. |
1506 | * The inode structure must also be updated |
1507 | * (with loss of precision) because of cacheing. |
1508 | * TODO : use NTFS precision in inode, and |
1509 | * return sub-second times in getattr() |
1510 | */ |
1511 | set_nino_flag(ni, TimesSet); |
1512 | std_info->creation_time = cpu_to_le64(times[0]); |
1513 | ni->creation_time |
1514 | = std_info->creation_time; |
1515 | if (size >= 16) { |
1516 | std_info->last_data_change_time = cpu_to_le64(times[1]); |
1517 | ni->last_data_change_time |
1518 | = std_info->last_data_change_time; |
1519 | } |
1520 | if (size >= 24) { |
1521 | std_info->last_access_time = cpu_to_le64(times[2]); |
1522 | ni->last_access_time |
1523 | = std_info->last_access_time; |
1524 | } |
1525 | std_info->last_mft_change_time = now; |
1526 | ni->last_mft_change_time = now; |
1527 | ntfs_inode_mark_dirty(ctx->ntfs_ino); |
1528 | NInoFileNameSetDirty(ni); |
1529 | |
1530 | /* update the file names attributes */ |
1531 | ntfs_attr_reinit_search_ctx(ctx); |
1532 | cnt = 0; |
1533 | while (!ntfs_attr_lookup(AT_FILE_NAME, |
1534 | AT_UNNAMED, 0, CASE_SENSITIVE, |
1535 | 0, NULL, 0, ctx)) { |
1536 | fn = (FILE_NAME_ATTR*)((u8 *)ctx->attr + |
1537 | le16_to_cpu(ctx->attr->value_offset)); |
1538 | fn->creation_time |
1539 | = cpu_to_le64(times[0]); |
1540 | if (size >= 16) |
1541 | fn->last_data_change_time |
1542 | = cpu_to_le64(times[1]); |
1543 | if (size >= 24) |
1544 | fn->last_access_time |
1545 | = cpu_to_le64(times[2]); |
1546 | fn->last_mft_change_time = now; |
1547 | cnt++; |
1548 | } |
1549 | if (cnt) |
1550 | ret = 0; |
1551 | else { |
1552 | ntfs_log_perror("Failed to get file names (inode %lld)", |
1553 | (long long)ni->mft_no); |
1554 | } |
1555 | } |
1556 | ntfs_attr_put_search_ctx(ctx); |
1557 | } |
1558 | } else |
1559 | if (size < 8) |
1560 | errno = ERANGE; |
1561 | else |
1562 | errno = EEXIST; |
1563 | return (ret); |
1564 | } |
1565 | |
1566 | #endif /* HAVE_SETXATTR */ |
1567 |