blob: 12ea369edca294e0cc04c8acd4348da65ccc40e1
1 | /** |
2 | * attrib.c - Attribute handling code. Originated from the Linux-NTFS project. |
3 | * |
4 | * Copyright (c) 2000-2010 Anton Altaparmakov |
5 | * Copyright (c) 2002-2005 Richard Russon |
6 | * Copyright (c) 2002-2008 Szabolcs Szakacsits |
7 | * Copyright (c) 2004-2007 Yura Pakhuchiy |
8 | * Copyright (c) 2007-2010 Jean-Pierre Andre |
9 | * Copyright (c) 2010 Erik Larsson |
10 | * |
11 | * This program/include file is free software; you can redistribute it and/or |
12 | * modify it under the terms of the GNU General Public License as published |
13 | * by the Free Software Foundation; either version 2 of the License, or |
14 | * (at your option) any later version. |
15 | * |
16 | * This program/include file is distributed in the hope that it will be |
17 | * useful, but WITHOUT ANY WARRANTY; without even the implied warranty |
18 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
19 | * GNU General Public License for more details. |
20 | * |
21 | * You should have received a copy of the GNU General Public License |
22 | * along with this program (in the main directory of the NTFS-3G |
23 | * distribution in the file COPYING); if not, write to the Free Software |
24 | * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
25 | */ |
26 | |
27 | #ifdef HAVE_CONFIG_H |
28 | #include "config.h" |
29 | #endif |
30 | |
31 | #ifdef HAVE_STDIO_H |
32 | #include <stdio.h> |
33 | #endif |
34 | #ifdef HAVE_STRING_H |
35 | #include <string.h> |
36 | #endif |
37 | #ifdef HAVE_STDLIB_H |
38 | #include <stdlib.h> |
39 | #endif |
40 | #ifdef HAVE_ERRNO_H |
41 | #include <errno.h> |
42 | #endif |
43 | #ifdef HAVE_LIMITS_H |
44 | #include <limits.h> |
45 | #endif |
46 | |
47 | #include "param.h" |
48 | #include "compat.h" |
49 | #include "attrib.h" |
50 | #include "attrlist.h" |
51 | #include "device.h" |
52 | #include "mft.h" |
53 | #include "debug.h" |
54 | #include "mst.h" |
55 | #include "volume.h" |
56 | #include "types.h" |
57 | #include "layout.h" |
58 | #include "inode.h" |
59 | #include "runlist.h" |
60 | #include "lcnalloc.h" |
61 | #include "dir.h" |
62 | #include "compress.h" |
63 | #include "bitmap.h" |
64 | #include "logging.h" |
65 | #include "misc.h" |
66 | #include "efs.h" |
67 | |
68 | #define STANDARD_COMPRESSION_UNIT 4 |
69 | #define MAX_COMPRESSION_CLUSTER_SIZE 4096 |
70 | |
71 | ntfschar AT_UNNAMED[] = { const_cpu_to_le16('\0') }; |
72 | ntfschar STREAM_SDS[] = { const_cpu_to_le16('$'), |
73 | const_cpu_to_le16('S'), |
74 | const_cpu_to_le16('D'), |
75 | const_cpu_to_le16('S'), |
76 | const_cpu_to_le16('\0') }; |
77 | |
78 | ntfschar TXF_DATA[] = { const_cpu_to_le16('$'), |
79 | const_cpu_to_le16('T'), |
80 | const_cpu_to_le16('X'), |
81 | const_cpu_to_le16('F'), |
82 | const_cpu_to_le16('_'), |
83 | const_cpu_to_le16('D'), |
84 | const_cpu_to_le16('A'), |
85 | const_cpu_to_le16('T'), |
86 | const_cpu_to_le16('A'), |
87 | const_cpu_to_le16('\0') }; |
88 | |
89 | static int NAttrFlag(ntfs_attr *na, FILE_ATTR_FLAGS flag) |
90 | { |
91 | if (na->type == AT_DATA && na->name == AT_UNNAMED) |
92 | return (na->ni->flags & flag); |
93 | return 0; |
94 | } |
95 | |
96 | static void NAttrSetFlag(ntfs_attr *na, FILE_ATTR_FLAGS flag) |
97 | { |
98 | if (na->type == AT_DATA && na->name == AT_UNNAMED) |
99 | na->ni->flags |= flag; |
100 | else |
101 | ntfs_log_trace("Denied setting flag %d for not unnamed data " |
102 | "attribute\n", flag); |
103 | } |
104 | |
105 | static void NAttrClearFlag(ntfs_attr *na, FILE_ATTR_FLAGS flag) |
106 | { |
107 | if (na->type == AT_DATA && na->name == AT_UNNAMED) |
108 | na->ni->flags &= ~flag; |
109 | } |
110 | |
111 | #define GenNAttrIno(func_name, flag) \ |
112 | int NAttr##func_name(ntfs_attr *na) { return NAttrFlag (na, flag); } \ |
113 | void NAttrSet##func_name(ntfs_attr *na) { NAttrSetFlag (na, flag); } \ |
114 | void NAttrClear##func_name(ntfs_attr *na){ NAttrClearFlag(na, flag); } |
115 | |
116 | GenNAttrIno(Compressed, FILE_ATTR_COMPRESSED) |
117 | GenNAttrIno(Encrypted, FILE_ATTR_ENCRYPTED) |
118 | GenNAttrIno(Sparse, FILE_ATTR_SPARSE_FILE) |
119 | |
120 | /** |
121 | * ntfs_get_attribute_value_length - Find the length of an attribute |
122 | * @a: |
123 | * |
124 | * Description... |
125 | * |
126 | * Returns: |
127 | */ |
128 | s64 ntfs_get_attribute_value_length(const ATTR_RECORD *a) |
129 | { |
130 | if (!a) { |
131 | errno = EINVAL; |
132 | return 0; |
133 | } |
134 | errno = 0; |
135 | if (a->non_resident) |
136 | return sle64_to_cpu(a->data_size); |
137 | |
138 | return (s64)le32_to_cpu(a->value_length); |
139 | } |
140 | |
141 | /** |
142 | * ntfs_get_attribute_value - Get a copy of an attribute |
143 | * @vol: |
144 | * @a: |
145 | * @b: |
146 | * |
147 | * Description... |
148 | * |
149 | * Returns: |
150 | */ |
151 | s64 ntfs_get_attribute_value(const ntfs_volume *vol, |
152 | const ATTR_RECORD *a, u8 *b) |
153 | { |
154 | runlist *rl; |
155 | s64 total, r; |
156 | int i; |
157 | |
158 | /* Sanity checks. */ |
159 | if (!vol || !a || !b) { |
160 | errno = EINVAL; |
161 | return 0; |
162 | } |
163 | /* Complex attribute? */ |
164 | /* |
165 | * Ignore the flags in case they are not zero for an attribute list |
166 | * attribute. Windows does not complain about invalid flags and chkdsk |
167 | * does not detect or fix them so we need to cope with it, too. |
168 | */ |
169 | if (a->type != AT_ATTRIBUTE_LIST && a->flags) { |
170 | ntfs_log_error("Non-zero (%04x) attribute flags. Cannot handle " |
171 | "this yet.\n", le16_to_cpu(a->flags)); |
172 | errno = EOPNOTSUPP; |
173 | return 0; |
174 | } |
175 | if (!a->non_resident) { |
176 | /* Attribute is resident. */ |
177 | |
178 | /* Sanity check. */ |
179 | if (le32_to_cpu(a->value_length) + le16_to_cpu(a->value_offset) |
180 | > le32_to_cpu(a->length)) { |
181 | return 0; |
182 | } |
183 | |
184 | memcpy(b, (const char*)a + le16_to_cpu(a->value_offset), |
185 | le32_to_cpu(a->value_length)); |
186 | errno = 0; |
187 | return (s64)le32_to_cpu(a->value_length); |
188 | } |
189 | |
190 | /* Attribute is not resident. */ |
191 | |
192 | /* If no data, return 0. */ |
193 | if (!(a->data_size)) { |
194 | errno = 0; |
195 | return 0; |
196 | } |
197 | /* |
198 | * FIXME: What about attribute lists?!? (AIA) |
199 | */ |
200 | /* Decompress the mapping pairs array into a runlist. */ |
201 | rl = ntfs_mapping_pairs_decompress(vol, a, NULL); |
202 | if (!rl) { |
203 | errno = EINVAL; |
204 | return 0; |
205 | } |
206 | /* |
207 | * FIXED: We were overflowing here in a nasty fashion when we |
208 | * reach the last cluster in the runlist as the buffer will |
209 | * only be big enough to hold data_size bytes while we are |
210 | * reading in allocated_size bytes which is usually larger |
211 | * than data_size, since the actual data is unlikely to have a |
212 | * size equal to a multiple of the cluster size! |
213 | * FIXED2: We were also overflowing here in the same fashion |
214 | * when the data_size was more than one run smaller than the |
215 | * allocated size which happens with Windows XP sometimes. |
216 | */ |
217 | /* Now load all clusters in the runlist into b. */ |
218 | for (i = 0, total = 0; rl[i].length; i++) { |
219 | if (total + (rl[i].length << vol->cluster_size_bits) >= |
220 | sle64_to_cpu(a->data_size)) { |
221 | unsigned char *intbuf = NULL; |
222 | /* |
223 | * We have reached the last run so we were going to |
224 | * overflow when executing the ntfs_pread() which is |
225 | * BAAAAAAAD! |
226 | * Temporary fix: |
227 | * Allocate a new buffer with size: |
228 | * rl[i].length << vol->cluster_size_bits, do the |
229 | * read into our buffer, then memcpy the correct |
230 | * amount of data into the caller supplied buffer, |
231 | * free our buffer, and continue. |
232 | * We have reached the end of data size so we were |
233 | * going to overflow in the same fashion. |
234 | * Temporary fix: same as above. |
235 | */ |
236 | intbuf = ntfs_malloc(rl[i].length << vol->cluster_size_bits); |
237 | if (!intbuf) { |
238 | free(rl); |
239 | return 0; |
240 | } |
241 | /* |
242 | * FIXME: If compressed file: Only read if lcn != -1. |
243 | * Otherwise, we are dealing with a sparse run and we |
244 | * just memset the user buffer to 0 for the length of |
245 | * the run, which should be 16 (= compression unit |
246 | * size). |
247 | * FIXME: Really only when file is compressed, or can |
248 | * we have sparse runs in uncompressed files as well? |
249 | * - Yes we can, in sparse files! But not necessarily |
250 | * size of 16, just run length. |
251 | */ |
252 | r = ntfs_pread(vol->dev, rl[i].lcn << |
253 | vol->cluster_size_bits, rl[i].length << |
254 | vol->cluster_size_bits, intbuf); |
255 | if (r != rl[i].length << vol->cluster_size_bits) { |
256 | #define ESTR "Error reading attribute value" |
257 | if (r == -1) |
258 | ntfs_log_perror(ESTR); |
259 | else if (r < rl[i].length << |
260 | vol->cluster_size_bits) { |
261 | ntfs_log_debug(ESTR ": Ran out of input data.\n"); |
262 | errno = EIO; |
263 | } else { |
264 | ntfs_log_debug(ESTR ": unknown error\n"); |
265 | errno = EIO; |
266 | } |
267 | #undef ESTR |
268 | free(rl); |
269 | free(intbuf); |
270 | return 0; |
271 | } |
272 | memcpy(b + total, intbuf, sle64_to_cpu(a->data_size) - |
273 | total); |
274 | free(intbuf); |
275 | total = sle64_to_cpu(a->data_size); |
276 | break; |
277 | } |
278 | /* |
279 | * FIXME: If compressed file: Only read if lcn != -1. |
280 | * Otherwise, we are dealing with a sparse run and we just |
281 | * memset the user buffer to 0 for the length of the run, which |
282 | * should be 16 (= compression unit size). |
283 | * FIXME: Really only when file is compressed, or can |
284 | * we have sparse runs in uncompressed files as well? |
285 | * - Yes we can, in sparse files! But not necessarily size of |
286 | * 16, just run length. |
287 | */ |
288 | r = ntfs_pread(vol->dev, rl[i].lcn << vol->cluster_size_bits, |
289 | rl[i].length << vol->cluster_size_bits, |
290 | b + total); |
291 | if (r != rl[i].length << vol->cluster_size_bits) { |
292 | #define ESTR "Error reading attribute value" |
293 | if (r == -1) |
294 | ntfs_log_perror(ESTR); |
295 | else if (r < rl[i].length << vol->cluster_size_bits) { |
296 | ntfs_log_debug(ESTR ": Ran out of input data.\n"); |
297 | errno = EIO; |
298 | } else { |
299 | ntfs_log_debug(ESTR ": unknown error\n"); |
300 | errno = EIO; |
301 | } |
302 | #undef ESTR |
303 | free(rl); |
304 | return 0; |
305 | } |
306 | total += r; |
307 | } |
308 | free(rl); |
309 | return total; |
310 | } |
311 | |
312 | /* Already cleaned up code below, but still look for FIXME:... */ |
313 | |
314 | /** |
315 | * __ntfs_attr_init - primary initialization of an ntfs attribute structure |
316 | * @na: ntfs attribute to initialize |
317 | * @ni: ntfs inode with which to initialize the ntfs attribute |
318 | * @type: attribute type |
319 | * @name: attribute name in little endian Unicode or NULL |
320 | * @name_len: length of attribute @name in Unicode characters (if @name given) |
321 | * |
322 | * Initialize the ntfs attribute @na with @ni, @type, @name, and @name_len. |
323 | */ |
324 | static void __ntfs_attr_init(ntfs_attr *na, ntfs_inode *ni, |
325 | const ATTR_TYPES type, ntfschar *name, const u32 name_len) |
326 | { |
327 | na->rl = NULL; |
328 | na->ni = ni; |
329 | na->type = type; |
330 | na->name = name; |
331 | if (name) |
332 | na->name_len = name_len; |
333 | else |
334 | na->name_len = 0; |
335 | } |
336 | |
337 | /** |
338 | * ntfs_attr_init - initialize an ntfs_attr with data sizes and status |
339 | * @na: |
340 | * @non_resident: |
341 | * @compressed: |
342 | * @encrypted: |
343 | * @sparse: |
344 | * @allocated_size: |
345 | * @data_size: |
346 | * @initialized_size: |
347 | * @compressed_size: |
348 | * @compression_unit: |
349 | * |
350 | * Final initialization for an ntfs attribute. |
351 | */ |
352 | void ntfs_attr_init(ntfs_attr *na, const BOOL non_resident, |
353 | const ATTR_FLAGS data_flags, |
354 | const BOOL encrypted, const BOOL sparse, |
355 | const s64 allocated_size, const s64 data_size, |
356 | const s64 initialized_size, const s64 compressed_size, |
357 | const u8 compression_unit) |
358 | { |
359 | if (!NAttrInitialized(na)) { |
360 | na->data_flags = data_flags; |
361 | if (non_resident) |
362 | NAttrSetNonResident(na); |
363 | if (data_flags & ATTR_COMPRESSION_MASK) |
364 | NAttrSetCompressed(na); |
365 | if (encrypted) |
366 | NAttrSetEncrypted(na); |
367 | if (sparse) |
368 | NAttrSetSparse(na); |
369 | na->allocated_size = allocated_size; |
370 | na->data_size = data_size; |
371 | na->initialized_size = initialized_size; |
372 | if ((data_flags & ATTR_COMPRESSION_MASK) || sparse) { |
373 | ntfs_volume *vol = na->ni->vol; |
374 | |
375 | na->compressed_size = compressed_size; |
376 | na->compression_block_clusters = 1 << compression_unit; |
377 | na->compression_block_size = 1 << (compression_unit + |
378 | vol->cluster_size_bits); |
379 | na->compression_block_size_bits = ffs( |
380 | na->compression_block_size) - 1; |
381 | } |
382 | NAttrSetInitialized(na); |
383 | } |
384 | } |
385 | |
386 | /** |
387 | * ntfs_attr_open - open an ntfs attribute for access |
388 | * @ni: open ntfs inode in which the ntfs attribute resides |
389 | * @type: attribute type |
390 | * @name: attribute name in little endian Unicode or AT_UNNAMED or NULL |
391 | * @name_len: length of attribute @name in Unicode characters (if @name given) |
392 | * |
393 | * Allocate a new ntfs attribute structure, initialize it with @ni, @type, |
394 | * @name, and @name_len, then return it. Return NULL on error with |
395 | * errno set to the error code. |
396 | * |
397 | * If @name is AT_UNNAMED look specifically for an unnamed attribute. If you |
398 | * do not care whether the attribute is named or not set @name to NULL. In |
399 | * both those cases @name_len is not used at all. |
400 | */ |
401 | ntfs_attr *ntfs_attr_open(ntfs_inode *ni, const ATTR_TYPES type, |
402 | ntfschar *name, u32 name_len) |
403 | { |
404 | ntfs_attr_search_ctx *ctx; |
405 | ntfs_attr *na = NULL; |
406 | ntfschar *newname = NULL; |
407 | ATTR_RECORD *a; |
408 | BOOL cs; |
409 | |
410 | ntfs_log_enter("Entering for inode %lld, attr 0x%x.\n", |
411 | (unsigned long long)ni->mft_no, type); |
412 | |
413 | if (!ni || !ni->vol || !ni->mrec) { |
414 | errno = EINVAL; |
415 | goto out; |
416 | } |
417 | na = ntfs_calloc(sizeof(ntfs_attr)); |
418 | if (!na) |
419 | goto out; |
420 | if (name && name != AT_UNNAMED && name != NTFS_INDEX_I30) { |
421 | name = ntfs_ucsndup(name, name_len); |
422 | if (!name) |
423 | goto err_out; |
424 | newname = name; |
425 | } |
426 | |
427 | ctx = ntfs_attr_get_search_ctx(ni, NULL); |
428 | if (!ctx) |
429 | goto err_out; |
430 | |
431 | if (ntfs_attr_lookup(type, name, name_len, 0, 0, NULL, 0, ctx)) |
432 | goto put_err_out; |
433 | |
434 | a = ctx->attr; |
435 | |
436 | if (!name) { |
437 | if (a->name_length) { |
438 | name = ntfs_ucsndup((ntfschar*)((u8*)a + le16_to_cpu( |
439 | a->name_offset)), a->name_length); |
440 | if (!name) |
441 | goto put_err_out; |
442 | newname = name; |
443 | name_len = a->name_length; |
444 | } else { |
445 | name = AT_UNNAMED; |
446 | name_len = 0; |
447 | } |
448 | } |
449 | |
450 | __ntfs_attr_init(na, ni, type, name, name_len); |
451 | |
452 | /* |
453 | * Wipe the flags in case they are not zero for an attribute list |
454 | * attribute. Windows does not complain about invalid flags and chkdsk |
455 | * does not detect or fix them so we need to cope with it, too. |
456 | */ |
457 | if (type == AT_ATTRIBUTE_LIST) |
458 | a->flags = 0; |
459 | |
460 | if ((type == AT_DATA) && !a->initialized_size) { |
461 | /* |
462 | * Define/redefine the compression state if stream is |
463 | * empty, based on the compression mark on parent |
464 | * directory (for unnamed data streams) or on current |
465 | * inode (for named data streams). The compression mark |
466 | * may change any time, the compression state can only |
467 | * change when stream is wiped out. |
468 | */ |
469 | a->flags &= ~ATTR_COMPRESSION_MASK; |
470 | if ((na->ni->flags & FILE_ATTR_COMPRESSED) |
471 | && (ni->vol->cluster_size <= MAX_COMPRESSION_CLUSTER_SIZE)) |
472 | a->flags |= ATTR_IS_COMPRESSED; |
473 | } |
474 | |
475 | cs = a->flags & (ATTR_IS_COMPRESSED | ATTR_IS_SPARSE); |
476 | |
477 | if (na->type == AT_DATA && na->name == AT_UNNAMED && |
478 | ((!(a->flags & ATTR_IS_SPARSE) != !NAttrSparse(na)) || |
479 | (!(a->flags & ATTR_IS_ENCRYPTED) != !NAttrEncrypted(na)))) { |
480 | errno = EIO; |
481 | ntfs_log_perror("Inode %lld has corrupt attribute flags " |
482 | "(0x%x <> 0x%x)",(unsigned long long)ni->mft_no, |
483 | a->flags, na->ni->flags); |
484 | goto put_err_out; |
485 | } |
486 | |
487 | if (a->non_resident) { |
488 | if ((a->flags & ATTR_COMPRESSION_MASK) |
489 | && !a->compression_unit) { |
490 | errno = EIO; |
491 | ntfs_log_perror("Compressed inode %lld attr 0x%x has " |
492 | "no compression unit", |
493 | (unsigned long long)ni->mft_no, type); |
494 | goto put_err_out; |
495 | } |
496 | ntfs_attr_init(na, TRUE, a->flags, |
497 | a->flags & ATTR_IS_ENCRYPTED, |
498 | a->flags & ATTR_IS_SPARSE, |
499 | sle64_to_cpu(a->allocated_size), |
500 | sle64_to_cpu(a->data_size), |
501 | sle64_to_cpu(a->initialized_size), |
502 | cs ? sle64_to_cpu(a->compressed_size) : 0, |
503 | cs ? a->compression_unit : 0); |
504 | } else { |
505 | s64 l = le32_to_cpu(a->value_length); |
506 | ntfs_attr_init(na, FALSE, a->flags, |
507 | a->flags & ATTR_IS_ENCRYPTED, |
508 | a->flags & ATTR_IS_SPARSE, (l + 7) & ~7, l, l, |
509 | cs ? (l + 7) & ~7 : 0, 0); |
510 | } |
511 | ntfs_attr_put_search_ctx(ctx); |
512 | out: |
513 | ntfs_log_leave("\n"); |
514 | return na; |
515 | |
516 | put_err_out: |
517 | ntfs_attr_put_search_ctx(ctx); |
518 | err_out: |
519 | free(newname); |
520 | free(na); |
521 | na = NULL; |
522 | goto out; |
523 | } |
524 | |
525 | /** |
526 | * ntfs_attr_close - free an ntfs attribute structure |
527 | * @na: ntfs attribute structure to free |
528 | * |
529 | * Release all memory associated with the ntfs attribute @na and then release |
530 | * @na itself. |
531 | */ |
532 | void ntfs_attr_close(ntfs_attr *na) |
533 | { |
534 | if (!na) |
535 | return; |
536 | if (NAttrNonResident(na) && na->rl) |
537 | free(na->rl); |
538 | /* Don't release if using an internal constant. */ |
539 | if (na->name != AT_UNNAMED && na->name != NTFS_INDEX_I30 |
540 | && na->name != STREAM_SDS) |
541 | free(na->name); |
542 | free(na); |
543 | } |
544 | |
545 | /** |
546 | * ntfs_attr_map_runlist - map (a part of) a runlist of an ntfs attribute |
547 | * @na: ntfs attribute for which to map (part of) a runlist |
548 | * @vcn: map runlist part containing this vcn |
549 | * |
550 | * Map the part of a runlist containing the @vcn of the ntfs attribute @na. |
551 | * |
552 | * Return 0 on success and -1 on error with errno set to the error code. |
553 | */ |
554 | int ntfs_attr_map_runlist(ntfs_attr *na, VCN vcn) |
555 | { |
556 | LCN lcn; |
557 | ntfs_attr_search_ctx *ctx; |
558 | |
559 | ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x, vcn 0x%llx.\n", |
560 | (unsigned long long)na->ni->mft_no, na->type, (long long)vcn); |
561 | |
562 | lcn = ntfs_rl_vcn_to_lcn(na->rl, vcn); |
563 | if (lcn >= 0 || lcn == LCN_HOLE || lcn == LCN_ENOENT) |
564 | return 0; |
565 | |
566 | ctx = ntfs_attr_get_search_ctx(na->ni, NULL); |
567 | if (!ctx) |
568 | return -1; |
569 | |
570 | /* Find the attribute in the mft record. */ |
571 | if (!ntfs_attr_lookup(na->type, na->name, na->name_len, CASE_SENSITIVE, |
572 | vcn, NULL, 0, ctx)) { |
573 | runlist_element *rl; |
574 | |
575 | /* Decode the runlist. */ |
576 | rl = ntfs_mapping_pairs_decompress(na->ni->vol, ctx->attr, |
577 | na->rl); |
578 | if (rl) { |
579 | na->rl = rl; |
580 | ntfs_attr_put_search_ctx(ctx); |
581 | return 0; |
582 | } |
583 | } |
584 | |
585 | ntfs_attr_put_search_ctx(ctx); |
586 | return -1; |
587 | } |
588 | |
589 | /** |
590 | * ntfs_attr_map_whole_runlist - map the whole runlist of an ntfs attribute |
591 | * @na: ntfs attribute for which to map the runlist |
592 | * |
593 | * Map the whole runlist of the ntfs attribute @na. For an attribute made up |
594 | * of only one attribute extent this is the same as calling |
595 | * ntfs_attr_map_runlist(na, 0) but for an attribute with multiple extents this |
596 | * will map the runlist fragments from each of the extents thus giving access |
597 | * to the entirety of the disk allocation of an attribute. |
598 | * |
599 | * Return 0 on success and -1 on error with errno set to the error code. |
600 | */ |
601 | int ntfs_attr_map_whole_runlist(ntfs_attr *na) |
602 | { |
603 | VCN next_vcn, last_vcn, highest_vcn; |
604 | ntfs_attr_search_ctx *ctx; |
605 | ntfs_volume *vol = na->ni->vol; |
606 | ATTR_RECORD *a; |
607 | int ret = -1; |
608 | |
609 | ntfs_log_enter("Entering for inode %llu, attr 0x%x.\n", |
610 | (unsigned long long)na->ni->mft_no, na->type); |
611 | |
612 | ctx = ntfs_attr_get_search_ctx(na->ni, NULL); |
613 | if (!ctx) |
614 | goto out; |
615 | |
616 | /* Map all attribute extents one by one. */ |
617 | next_vcn = last_vcn = highest_vcn = 0; |
618 | a = NULL; |
619 | while (1) { |
620 | runlist_element *rl; |
621 | |
622 | int not_mapped = 0; |
623 | if (ntfs_rl_vcn_to_lcn(na->rl, next_vcn) == LCN_RL_NOT_MAPPED) |
624 | not_mapped = 1; |
625 | |
626 | if (ntfs_attr_lookup(na->type, na->name, na->name_len, |
627 | CASE_SENSITIVE, next_vcn, NULL, 0, ctx)) |
628 | break; |
629 | |
630 | a = ctx->attr; |
631 | |
632 | if (not_mapped) { |
633 | /* Decode the runlist. */ |
634 | rl = ntfs_mapping_pairs_decompress(na->ni->vol, |
635 | a, na->rl); |
636 | if (!rl) |
637 | goto err_out; |
638 | na->rl = rl; |
639 | } |
640 | |
641 | /* Are we in the first extent? */ |
642 | if (!next_vcn) { |
643 | if (a->lowest_vcn) { |
644 | errno = EIO; |
645 | ntfs_log_perror("First extent of inode %llu " |
646 | "attribute has non-zero lowest_vcn", |
647 | (unsigned long long)na->ni->mft_no); |
648 | goto err_out; |
649 | } |
650 | /* Get the last vcn in the attribute. */ |
651 | last_vcn = sle64_to_cpu(a->allocated_size) >> |
652 | vol->cluster_size_bits; |
653 | } |
654 | |
655 | /* Get the lowest vcn for the next extent. */ |
656 | highest_vcn = sle64_to_cpu(a->highest_vcn); |
657 | next_vcn = highest_vcn + 1; |
658 | |
659 | /* Only one extent or error, which we catch below. */ |
660 | if (next_vcn <= 0) { |
661 | errno = ENOENT; |
662 | break; |
663 | } |
664 | |
665 | /* Avoid endless loops due to corruption. */ |
666 | if (next_vcn < sle64_to_cpu(a->lowest_vcn)) { |
667 | errno = EIO; |
668 | ntfs_log_perror("Inode %llu has corrupt attribute list", |
669 | (unsigned long long)na->ni->mft_no); |
670 | goto err_out; |
671 | } |
672 | } |
673 | if (!a) { |
674 | ntfs_log_perror("Couldn't find attribute for runlist mapping"); |
675 | goto err_out; |
676 | } |
677 | if (highest_vcn && highest_vcn != last_vcn - 1) { |
678 | errno = EIO; |
679 | ntfs_log_perror("Failed to load full runlist: inode: %llu " |
680 | "highest_vcn: 0x%llx last_vcn: 0x%llx", |
681 | (unsigned long long)na->ni->mft_no, |
682 | (long long)highest_vcn, (long long)last_vcn); |
683 | goto err_out; |
684 | } |
685 | if (errno == ENOENT) |
686 | ret = 0; |
687 | err_out: |
688 | ntfs_attr_put_search_ctx(ctx); |
689 | out: |
690 | ntfs_log_leave("\n"); |
691 | return ret; |
692 | } |
693 | |
694 | /** |
695 | * ntfs_attr_vcn_to_lcn - convert a vcn into a lcn given an ntfs attribute |
696 | * @na: ntfs attribute whose runlist to use for conversion |
697 | * @vcn: vcn to convert |
698 | * |
699 | * Convert the virtual cluster number @vcn of an attribute into a logical |
700 | * cluster number (lcn) of a device using the runlist @na->rl to map vcns to |
701 | * their corresponding lcns. |
702 | * |
703 | * If the @vcn is not mapped yet, attempt to map the attribute extent |
704 | * containing the @vcn and retry the vcn to lcn conversion. |
705 | * |
706 | * Since lcns must be >= 0, we use negative return values with special meaning: |
707 | * |
708 | * Return value Meaning / Description |
709 | * ========================================== |
710 | * -1 = LCN_HOLE Hole / not allocated on disk. |
711 | * -3 = LCN_ENOENT There is no such vcn in the attribute. |
712 | * -4 = LCN_EINVAL Input parameter error. |
713 | * -5 = LCN_EIO Corrupt fs, disk i/o error, or not enough memory. |
714 | */ |
715 | LCN ntfs_attr_vcn_to_lcn(ntfs_attr *na, const VCN vcn) |
716 | { |
717 | LCN lcn; |
718 | BOOL is_retry = FALSE; |
719 | |
720 | if (!na || !NAttrNonResident(na) || vcn < 0) |
721 | return (LCN)LCN_EINVAL; |
722 | |
723 | ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x.\n", (unsigned long |
724 | long)na->ni->mft_no, na->type); |
725 | retry: |
726 | /* Convert vcn to lcn. If that fails map the runlist and retry once. */ |
727 | lcn = ntfs_rl_vcn_to_lcn(na->rl, vcn); |
728 | if (lcn >= 0) |
729 | return lcn; |
730 | if (!is_retry && !ntfs_attr_map_runlist(na, vcn)) { |
731 | is_retry = TRUE; |
732 | goto retry; |
733 | } |
734 | /* |
735 | * If the attempt to map the runlist failed, or we are getting |
736 | * LCN_RL_NOT_MAPPED despite having mapped the attribute extent |
737 | * successfully, something is really badly wrong... |
738 | */ |
739 | if (!is_retry || lcn == (LCN)LCN_RL_NOT_MAPPED) |
740 | return (LCN)LCN_EIO; |
741 | /* lcn contains the appropriate error code. */ |
742 | return lcn; |
743 | } |
744 | |
745 | /** |
746 | * ntfs_attr_find_vcn - find a vcn in the runlist of an ntfs attribute |
747 | * @na: ntfs attribute whose runlist to search |
748 | * @vcn: vcn to find |
749 | * |
750 | * Find the virtual cluster number @vcn in the runlist of the ntfs attribute |
751 | * @na and return the the address of the runlist element containing the @vcn. |
752 | * |
753 | * Note you need to distinguish between the lcn of the returned runlist |
754 | * element being >= 0 and LCN_HOLE. In the later case you have to return zeroes |
755 | * on read and allocate clusters on write. You need to update the runlist, the |
756 | * attribute itself as well as write the modified mft record to disk. |
757 | * |
758 | * If there is an error return NULL with errno set to the error code. The |
759 | * following error codes are defined: |
760 | * EINVAL Input parameter error. |
761 | * ENOENT There is no such vcn in the runlist. |
762 | * ENOMEM Not enough memory. |
763 | * EIO I/O error or corrupt metadata. |
764 | */ |
765 | runlist_element *ntfs_attr_find_vcn(ntfs_attr *na, const VCN vcn) |
766 | { |
767 | runlist_element *rl; |
768 | BOOL is_retry = FALSE; |
769 | |
770 | if (!na || !NAttrNonResident(na) || vcn < 0) { |
771 | errno = EINVAL; |
772 | return NULL; |
773 | } |
774 | |
775 | ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x, vcn %llx\n", |
776 | (unsigned long long)na->ni->mft_no, na->type, |
777 | (long long)vcn); |
778 | retry: |
779 | rl = na->rl; |
780 | if (!rl) |
781 | goto map_rl; |
782 | if (vcn < rl[0].vcn) |
783 | goto map_rl; |
784 | while (rl->length) { |
785 | if (vcn < rl[1].vcn) { |
786 | if (rl->lcn >= (LCN)LCN_HOLE) |
787 | return rl; |
788 | break; |
789 | } |
790 | rl++; |
791 | } |
792 | switch (rl->lcn) { |
793 | case (LCN)LCN_RL_NOT_MAPPED: |
794 | goto map_rl; |
795 | case (LCN)LCN_ENOENT: |
796 | errno = ENOENT; |
797 | break; |
798 | case (LCN)LCN_EINVAL: |
799 | errno = EINVAL; |
800 | break; |
801 | default: |
802 | errno = EIO; |
803 | break; |
804 | } |
805 | return NULL; |
806 | map_rl: |
807 | /* The @vcn is in an unmapped region, map the runlist and retry. */ |
808 | if (!is_retry && !ntfs_attr_map_runlist(na, vcn)) { |
809 | is_retry = TRUE; |
810 | goto retry; |
811 | } |
812 | /* |
813 | * If we already retried or the mapping attempt failed something has |
814 | * gone badly wrong. EINVAL and ENOENT coming from a failed mapping |
815 | * attempt are equivalent to errors for us as they should not happen |
816 | * in our code paths. |
817 | */ |
818 | if (is_retry || errno == EINVAL || errno == ENOENT) |
819 | errno = EIO; |
820 | return NULL; |
821 | } |
822 | |
823 | /** |
824 | * ntfs_attr_pread_i - see description at ntfs_attr_pread() |
825 | */ |
826 | static s64 ntfs_attr_pread_i(ntfs_attr *na, const s64 pos, s64 count, void *b) |
827 | { |
828 | s64 br, to_read, ofs, total, total2, max_read, max_init; |
829 | ntfs_volume *vol; |
830 | runlist_element *rl; |
831 | u16 efs_padding_length; |
832 | |
833 | /* Sanity checking arguments is done in ntfs_attr_pread(). */ |
834 | |
835 | if ((na->data_flags & ATTR_COMPRESSION_MASK) && NAttrNonResident(na)) { |
836 | if ((na->data_flags & ATTR_COMPRESSION_MASK) |
837 | == ATTR_IS_COMPRESSED) |
838 | return ntfs_compressed_attr_pread(na, pos, count, b); |
839 | else { |
840 | /* compression mode not supported */ |
841 | errno = EOPNOTSUPP; |
842 | return -1; |
843 | } |
844 | } |
845 | /* |
846 | * Encrypted non-resident attributes are not supported. We return |
847 | * access denied, which is what Windows NT4 does, too. |
848 | * However, allow if mounted with efs_raw option |
849 | */ |
850 | vol = na->ni->vol; |
851 | if (!vol->efs_raw && NAttrEncrypted(na) && NAttrNonResident(na)) { |
852 | errno = EACCES; |
853 | return -1; |
854 | } |
855 | |
856 | if (!count) |
857 | return 0; |
858 | /* |
859 | * Truncate reads beyond end of attribute, |
860 | * but round to next 512 byte boundary for encrypted |
861 | * attributes with efs_raw mount option |
862 | */ |
863 | max_read = na->data_size; |
864 | max_init = na->initialized_size; |
865 | if (na->ni->vol->efs_raw |
866 | && (na->data_flags & ATTR_IS_ENCRYPTED) |
867 | && NAttrNonResident(na)) { |
868 | if (na->data_size != na->initialized_size) { |
869 | ntfs_log_error("uninitialized encrypted file not supported\n"); |
870 | errno = EINVAL; |
871 | return -1; |
872 | } |
873 | max_init = max_read = ((na->data_size + 511) & ~511) + 2; |
874 | } |
875 | if (pos + count > max_read) { |
876 | if (pos >= max_read) |
877 | return 0; |
878 | count = max_read - pos; |
879 | } |
880 | /* If it is a resident attribute, get the value from the mft record. */ |
881 | if (!NAttrNonResident(na)) { |
882 | ntfs_attr_search_ctx *ctx; |
883 | char *val; |
884 | |
885 | ctx = ntfs_attr_get_search_ctx(na->ni, NULL); |
886 | if (!ctx) |
887 | return -1; |
888 | if (ntfs_attr_lookup(na->type, na->name, na->name_len, 0, |
889 | 0, NULL, 0, ctx)) { |
890 | res_err_out: |
891 | ntfs_attr_put_search_ctx(ctx); |
892 | return -1; |
893 | } |
894 | val = (char*)ctx->attr + le16_to_cpu(ctx->attr->value_offset); |
895 | if (val < (char*)ctx->attr || val + |
896 | le32_to_cpu(ctx->attr->value_length) > |
897 | (char*)ctx->mrec + vol->mft_record_size) { |
898 | errno = EIO; |
899 | ntfs_log_perror("%s: Sanity check failed", __FUNCTION__); |
900 | goto res_err_out; |
901 | } |
902 | memcpy(b, val + pos, count); |
903 | ntfs_attr_put_search_ctx(ctx); |
904 | return count; |
905 | } |
906 | total = total2 = 0; |
907 | /* Zero out reads beyond initialized size. */ |
908 | if (pos + count > max_init) { |
909 | if (pos >= max_init) { |
910 | memset(b, 0, count); |
911 | return count; |
912 | } |
913 | total2 = pos + count - max_init; |
914 | count -= total2; |
915 | memset((u8*)b + count, 0, total2); |
916 | } |
917 | /* |
918 | * for encrypted non-resident attributes with efs_raw set |
919 | * the last two bytes aren't read from disk but contain |
920 | * the number of padding bytes so original size can be |
921 | * restored |
922 | */ |
923 | if (na->ni->vol->efs_raw && |
924 | (na->data_flags & ATTR_IS_ENCRYPTED) && |
925 | ((pos + count) > max_init-2)) { |
926 | efs_padding_length = 511 - ((na->data_size - 1) & 511); |
927 | if (pos+count == max_init) { |
928 | if (count == 1) { |
929 | *((u8*)b+count-1) = (u8)(efs_padding_length >> 8); |
930 | count--; |
931 | total2++; |
932 | } else { |
933 | *(u16*)((u8*)b+count-2) = cpu_to_le16(efs_padding_length); |
934 | count -= 2; |
935 | total2 +=2; |
936 | } |
937 | } else { |
938 | *((u8*)b+count-1) = (u8)(efs_padding_length & 0xff); |
939 | count--; |
940 | total2++; |
941 | } |
942 | } |
943 | |
944 | /* Find the runlist element containing the vcn. */ |
945 | rl = ntfs_attr_find_vcn(na, pos >> vol->cluster_size_bits); |
946 | if (!rl) { |
947 | /* |
948 | * If the vcn is not present it is an out of bounds read. |
949 | * However, we already truncated the read to the data_size, |
950 | * so getting this here is an error. |
951 | */ |
952 | if (errno == ENOENT) { |
953 | errno = EIO; |
954 | ntfs_log_perror("%s: Failed to find VCN #1", __FUNCTION__); |
955 | } |
956 | return -1; |
957 | } |
958 | /* |
959 | * Gather the requested data into the linear destination buffer. Note, |
960 | * a partial final vcn is taken care of by the @count capping of read |
961 | * length. |
962 | */ |
963 | ofs = pos - (rl->vcn << vol->cluster_size_bits); |
964 | for (; count; rl++, ofs = 0) { |
965 | if (rl->lcn == LCN_RL_NOT_MAPPED) { |
966 | rl = ntfs_attr_find_vcn(na, rl->vcn); |
967 | if (!rl) { |
968 | if (errno == ENOENT) { |
969 | errno = EIO; |
970 | ntfs_log_perror("%s: Failed to find VCN #2", |
971 | __FUNCTION__); |
972 | } |
973 | goto rl_err_out; |
974 | } |
975 | /* Needed for case when runs merged. */ |
976 | ofs = pos + total - (rl->vcn << vol->cluster_size_bits); |
977 | } |
978 | if (!rl->length) { |
979 | errno = EIO; |
980 | ntfs_log_perror("%s: Zero run length", __FUNCTION__); |
981 | goto rl_err_out; |
982 | } |
983 | if (rl->lcn < (LCN)0) { |
984 | if (rl->lcn != (LCN)LCN_HOLE) { |
985 | ntfs_log_perror("%s: Bad run (%lld)", |
986 | __FUNCTION__, |
987 | (long long)rl->lcn); |
988 | goto rl_err_out; |
989 | } |
990 | /* It is a hole, just zero the matching @b range. */ |
991 | to_read = min(count, (rl->length << |
992 | vol->cluster_size_bits) - ofs); |
993 | memset(b, 0, to_read); |
994 | /* Update progress counters. */ |
995 | total += to_read; |
996 | count -= to_read; |
997 | b = (u8*)b + to_read; |
998 | continue; |
999 | } |
1000 | /* It is a real lcn, read it into @dst. */ |
1001 | to_read = min(count, (rl->length << vol->cluster_size_bits) - |
1002 | ofs); |
1003 | retry: |
1004 | ntfs_log_trace("Reading %lld bytes from vcn %lld, lcn %lld, ofs" |
1005 | " %lld.\n", (long long)to_read, (long long)rl->vcn, |
1006 | (long long )rl->lcn, (long long)ofs); |
1007 | br = ntfs_pread(vol->dev, (rl->lcn << vol->cluster_size_bits) + |
1008 | ofs, to_read, b); |
1009 | /* If everything ok, update progress counters and continue. */ |
1010 | if (br > 0) { |
1011 | total += br; |
1012 | count -= br; |
1013 | b = (u8*)b + br; |
1014 | } |
1015 | if (br == to_read) |
1016 | continue; |
1017 | /* If the syscall was interrupted, try again. */ |
1018 | if (br == (s64)-1 && errno == EINTR) |
1019 | goto retry; |
1020 | if (total) |
1021 | return total; |
1022 | if (!br) |
1023 | errno = EIO; |
1024 | ntfs_log_perror("%s: ntfs_pread failed", __FUNCTION__); |
1025 | return -1; |
1026 | } |
1027 | /* Finally, return the number of bytes read. */ |
1028 | return total + total2; |
1029 | rl_err_out: |
1030 | if (total) |
1031 | return total; |
1032 | errno = EIO; |
1033 | return -1; |
1034 | } |
1035 | |
1036 | /** |
1037 | * ntfs_attr_pread - read from an attribute specified by an ntfs_attr structure |
1038 | * @na: ntfs attribute to read from |
1039 | * @pos: byte position in the attribute to begin reading from |
1040 | * @count: number of bytes to read |
1041 | * @b: output data buffer |
1042 | * |
1043 | * This function will read @count bytes starting at offset @pos from the ntfs |
1044 | * attribute @na into the data buffer @b. |
1045 | * |
1046 | * On success, return the number of successfully read bytes. If this number is |
1047 | * lower than @count this means that the read reached end of file or that an |
1048 | * error was encountered during the read so that the read is partial. 0 means |
1049 | * end of file or nothing was read (also return 0 when @count is 0). |
1050 | * |
1051 | * On error and nothing has been read, return -1 with errno set appropriately |
1052 | * to the return code of ntfs_pread(), or to EINVAL in case of invalid |
1053 | * arguments. |
1054 | */ |
1055 | s64 ntfs_attr_pread(ntfs_attr *na, const s64 pos, s64 count, void *b) |
1056 | { |
1057 | s64 ret; |
1058 | |
1059 | if (!na || !na->ni || !na->ni->vol || !b || pos < 0 || count < 0) { |
1060 | errno = EINVAL; |
1061 | ntfs_log_perror("%s: na=%p b=%p pos=%lld count=%lld", |
1062 | __FUNCTION__, na, b, (long long)pos, |
1063 | (long long)count); |
1064 | return -1; |
1065 | } |
1066 | |
1067 | ntfs_log_enter("Entering for inode %lld attr 0x%x pos %lld count " |
1068 | "%lld\n", (unsigned long long)na->ni->mft_no, |
1069 | na->type, (long long)pos, (long long)count); |
1070 | |
1071 | ret = ntfs_attr_pread_i(na, pos, count, b); |
1072 | |
1073 | ntfs_log_leave("\n"); |
1074 | return ret; |
1075 | } |
1076 | |
1077 | static int ntfs_attr_fill_zero(ntfs_attr *na, s64 pos, s64 count) |
1078 | { |
1079 | char *buf; |
1080 | s64 written, size, end = pos + count; |
1081 | s64 ofsi; |
1082 | const runlist_element *rli; |
1083 | ntfs_volume *vol; |
1084 | int ret = -1; |
1085 | |
1086 | ntfs_log_trace("pos %lld, count %lld\n", (long long)pos, |
1087 | (long long)count); |
1088 | |
1089 | if (!na || pos < 0 || count < 0) { |
1090 | errno = EINVAL; |
1091 | goto err_out; |
1092 | } |
1093 | |
1094 | buf = ntfs_calloc(NTFS_BUF_SIZE); |
1095 | if (!buf) |
1096 | goto err_out; |
1097 | |
1098 | rli = na->rl; |
1099 | ofsi = 0; |
1100 | vol = na->ni->vol; |
1101 | while (pos < end) { |
1102 | while (rli->length && (ofsi + (rli->length << |
1103 | vol->cluster_size_bits) <= pos)) { |
1104 | ofsi += (rli->length << vol->cluster_size_bits); |
1105 | rli++; |
1106 | } |
1107 | size = min(end - pos, NTFS_BUF_SIZE); |
1108 | written = ntfs_rl_pwrite(vol, rli, ofsi, pos, size, buf); |
1109 | if (written <= 0) { |
1110 | ntfs_log_perror("Failed to zero space"); |
1111 | goto err_free; |
1112 | } |
1113 | pos += written; |
1114 | } |
1115 | |
1116 | ret = 0; |
1117 | err_free: |
1118 | free(buf); |
1119 | err_out: |
1120 | return ret; |
1121 | } |
1122 | |
1123 | static int ntfs_attr_fill_hole(ntfs_attr *na, s64 count, s64 *ofs, |
1124 | runlist_element **rl, VCN *update_from) |
1125 | { |
1126 | s64 to_write; |
1127 | s64 need; |
1128 | ntfs_volume *vol = na->ni->vol; |
1129 | int eo, ret = -1; |
1130 | runlist *rlc; |
1131 | LCN lcn_seek_from = -1; |
1132 | VCN cur_vcn, from_vcn; |
1133 | |
1134 | to_write = min(count, ((*rl)->length << vol->cluster_size_bits) - *ofs); |
1135 | |
1136 | cur_vcn = (*rl)->vcn; |
1137 | from_vcn = (*rl)->vcn + (*ofs >> vol->cluster_size_bits); |
1138 | |
1139 | ntfs_log_trace("count: %lld, cur_vcn: %lld, from: %lld, to: %lld, ofs: " |
1140 | "%lld\n", (long long)count, (long long)cur_vcn, |
1141 | (long long)from_vcn, (long long)to_write, (long long)*ofs); |
1142 | |
1143 | /* Map whole runlist to be able update mapping pairs later. */ |
1144 | if (ntfs_attr_map_whole_runlist(na)) |
1145 | goto err_out; |
1146 | |
1147 | /* Restore @*rl, it probably get lost during runlist mapping. */ |
1148 | *rl = ntfs_attr_find_vcn(na, cur_vcn); |
1149 | if (!*rl) { |
1150 | ntfs_log_error("Failed to find run after mapping runlist. " |
1151 | "Please report to %s.\n", NTFS_DEV_LIST); |
1152 | errno = EIO; |
1153 | goto err_out; |
1154 | } |
1155 | |
1156 | /* Search backwards to find the best lcn to start seek from. */ |
1157 | rlc = *rl; |
1158 | while (rlc->vcn) { |
1159 | rlc--; |
1160 | if (rlc->lcn >= 0) { |
1161 | /* |
1162 | * avoid fragmenting a compressed file |
1163 | * Windows does not do that, and that may |
1164 | * not be desirable for files which can |
1165 | * be updated |
1166 | */ |
1167 | if (na->data_flags & ATTR_COMPRESSION_MASK) |
1168 | lcn_seek_from = rlc->lcn + rlc->length; |
1169 | else |
1170 | lcn_seek_from = rlc->lcn + (from_vcn - rlc->vcn); |
1171 | break; |
1172 | } |
1173 | } |
1174 | if (lcn_seek_from == -1) { |
1175 | /* Backwards search failed, search forwards. */ |
1176 | rlc = *rl; |
1177 | while (rlc->length) { |
1178 | rlc++; |
1179 | if (rlc->lcn >= 0) { |
1180 | lcn_seek_from = rlc->lcn - (rlc->vcn - from_vcn); |
1181 | if (lcn_seek_from < -1) |
1182 | lcn_seek_from = -1; |
1183 | break; |
1184 | } |
1185 | } |
1186 | } |
1187 | |
1188 | need = ((*ofs + to_write - 1) >> vol->cluster_size_bits) |
1189 | + 1 + (*rl)->vcn - from_vcn; |
1190 | if ((na->data_flags & ATTR_COMPRESSION_MASK) |
1191 | && (need < na->compression_block_clusters)) { |
1192 | /* |
1193 | * for a compressed file, be sure to allocate the full hole. |
1194 | * We may need space to decompress existing compressed data. |
1195 | */ |
1196 | rlc = ntfs_cluster_alloc(vol, (*rl)->vcn, (*rl)->length, |
1197 | lcn_seek_from, DATA_ZONE); |
1198 | } else |
1199 | rlc = ntfs_cluster_alloc(vol, from_vcn, need, |
1200 | lcn_seek_from, DATA_ZONE); |
1201 | if (!rlc) |
1202 | goto err_out; |
1203 | |
1204 | *rl = ntfs_runlists_merge(na->rl, rlc); |
1205 | /* |
1206 | * For a compressed attribute, we must be sure there is an |
1207 | * available entry, so reserve it before it gets too late. |
1208 | */ |
1209 | if (*rl && (na->data_flags & ATTR_COMPRESSION_MASK)) |
1210 | *rl = ntfs_rl_extend(*rl,1); |
1211 | if (!*rl) { |
1212 | eo = errno; |
1213 | ntfs_log_perror("Failed to merge runlists"); |
1214 | if (ntfs_cluster_free_from_rl(vol, rlc)) { |
1215 | ntfs_log_perror("Failed to free hot clusters. " |
1216 | "Please run chkdsk /f"); |
1217 | } |
1218 | errno = eo; |
1219 | goto err_out; |
1220 | } |
1221 | na->rl = *rl; |
1222 | if (*update_from == -1) |
1223 | *update_from = from_vcn; |
1224 | *rl = ntfs_attr_find_vcn(na, cur_vcn); |
1225 | if (!*rl) { |
1226 | /* |
1227 | * It's definitely a BUG, if we failed to find @cur_vcn, because |
1228 | * we missed it during instantiating of the hole. |
1229 | */ |
1230 | ntfs_log_error("Failed to find run after hole instantiation. " |
1231 | "Please report to %s.\n", NTFS_DEV_LIST); |
1232 | errno = EIO; |
1233 | goto err_out; |
1234 | } |
1235 | /* If leaved part of the hole go to the next run. */ |
1236 | if ((*rl)->lcn < 0) |
1237 | (*rl)++; |
1238 | /* Now LCN shoudn't be less than 0. */ |
1239 | if ((*rl)->lcn < 0) { |
1240 | ntfs_log_error("BUG! LCN is lesser than 0. " |
1241 | "Please report to the %s.\n", NTFS_DEV_LIST); |
1242 | errno = EIO; |
1243 | goto err_out; |
1244 | } |
1245 | if (*ofs) { |
1246 | /* Clear non-sparse region from @cur_vcn to @*ofs. */ |
1247 | if (ntfs_attr_fill_zero(na, cur_vcn << vol->cluster_size_bits, |
1248 | *ofs)) |
1249 | goto err_out; |
1250 | } |
1251 | if ((*rl)->vcn < cur_vcn) { |
1252 | /* |
1253 | * Clusters that replaced hole are merged with |
1254 | * previous run, so we need to update offset. |
1255 | */ |
1256 | *ofs += (cur_vcn - (*rl)->vcn) << vol->cluster_size_bits; |
1257 | } |
1258 | if ((*rl)->vcn > cur_vcn) { |
1259 | /* |
1260 | * We left part of the hole, so we need to update offset |
1261 | */ |
1262 | *ofs -= ((*rl)->vcn - cur_vcn) << vol->cluster_size_bits; |
1263 | } |
1264 | |
1265 | ret = 0; |
1266 | err_out: |
1267 | return ret; |
1268 | } |
1269 | |
1270 | static int stuff_hole(ntfs_attr *na, const s64 pos); |
1271 | |
1272 | /** |
1273 | * ntfs_attr_pwrite - positioned write to an ntfs attribute |
1274 | * @na: ntfs attribute to write to |
1275 | * @pos: position in the attribute to write to |
1276 | * @count: number of bytes to write |
1277 | * @b: data buffer to write to disk |
1278 | * |
1279 | * This function will write @count bytes from data buffer @b to ntfs attribute |
1280 | * @na at position @pos. |
1281 | * |
1282 | * On success, return the number of successfully written bytes. If this number |
1283 | * is lower than @count this means that an error was encountered during the |
1284 | * write so that the write is partial. 0 means nothing was written (also return |
1285 | * 0 when @count is 0). |
1286 | * |
1287 | * On error and nothing has been written, return -1 with errno set |
1288 | * appropriately to the return code of ntfs_pwrite(), or to EINVAL in case of |
1289 | * invalid arguments. |
1290 | */ |
1291 | s64 ntfs_attr_pwrite(ntfs_attr *na, const s64 pos, s64 count, const void *b) |
1292 | { |
1293 | s64 written, to_write, ofs, old_initialized_size, old_data_size; |
1294 | s64 total = 0; |
1295 | VCN update_from = -1; |
1296 | ntfs_volume *vol; |
1297 | s64 fullcount; |
1298 | ntfs_attr_search_ctx *ctx = NULL; |
1299 | runlist_element *rl; |
1300 | s64 hole_end; |
1301 | int eo; |
1302 | int compressed_part; |
1303 | struct { |
1304 | unsigned int undo_initialized_size : 1; |
1305 | unsigned int undo_data_size : 1; |
1306 | } need_to = { 0, 0 }; |
1307 | BOOL makingnonresident = FALSE; |
1308 | BOOL wasnonresident = FALSE; |
1309 | BOOL compressed; |
1310 | |
1311 | ntfs_log_enter("Entering for inode %lld, attr 0x%x, pos 0x%llx, count " |
1312 | "0x%llx.\n", (long long)na->ni->mft_no, na->type, |
1313 | (long long)pos, (long long)count); |
1314 | |
1315 | if (!na || !na->ni || !na->ni->vol || !b || pos < 0 || count < 0) { |
1316 | errno = EINVAL; |
1317 | ntfs_log_perror("%s", __FUNCTION__); |
1318 | goto errno_set; |
1319 | } |
1320 | vol = na->ni->vol; |
1321 | compressed = (na->data_flags & ATTR_COMPRESSION_MASK) |
1322 | != const_cpu_to_le16(0); |
1323 | /* |
1324 | * Encrypted attributes are only supported in raw mode. We return |
1325 | * access denied, which is what Windows NT4 does, too. |
1326 | * Moreover a file cannot be both encrypted and compressed. |
1327 | */ |
1328 | if ((na->data_flags & ATTR_IS_ENCRYPTED) |
1329 | && (compressed || !vol->efs_raw)) { |
1330 | errno = EACCES; |
1331 | goto errno_set; |
1332 | } |
1333 | /* |
1334 | * Fill the gap, when writing beyond the end of a compressed |
1335 | * file. This will make recursive calls |
1336 | */ |
1337 | if (compressed |
1338 | && (na->type == AT_DATA) |
1339 | && (pos > na->initialized_size) |
1340 | && stuff_hole(na,pos)) |
1341 | goto errno_set; |
1342 | /* If this is a compressed attribute it needs special treatment. */ |
1343 | wasnonresident = NAttrNonResident(na) != 0; |
1344 | makingnonresident = wasnonresident /* yes : already changed */ |
1345 | && !pos && (count == na->initialized_size); |
1346 | /* |
1347 | * Writing to compressed files is currently restricted |
1348 | * to appending data. However we have to accept |
1349 | * recursive write calls to make the attribute non resident. |
1350 | * These are writing at position 0 up to initialized_size. |
1351 | * Compression is also restricted to data streams. |
1352 | * Only ATTR_IS_COMPRESSED compression mode is supported. |
1353 | */ |
1354 | if (compressed |
1355 | && ((na->type != AT_DATA) |
1356 | || ((na->data_flags & ATTR_COMPRESSION_MASK) |
1357 | != ATTR_IS_COMPRESSED) |
1358 | || ((pos != na->initialized_size) |
1359 | && (pos || (count != na->initialized_size))))) { |
1360 | // TODO: Implement writing compressed attributes! (AIA) |
1361 | errno = EOPNOTSUPP; |
1362 | goto errno_set; |
1363 | } |
1364 | |
1365 | if (!count) |
1366 | goto out; |
1367 | /* for a compressed file, get prepared to reserve a full block */ |
1368 | fullcount = count; |
1369 | /* If the write reaches beyond the end, extend the attribute. */ |
1370 | old_data_size = na->data_size; |
1371 | if (pos + count > na->data_size) { |
1372 | if (ntfs_attr_truncate(na, pos + count)) { |
1373 | ntfs_log_perror("Failed to enlarge attribute"); |
1374 | goto errno_set; |
1375 | } |
1376 | /* resizing may change the compression mode */ |
1377 | compressed = (na->data_flags & ATTR_COMPRESSION_MASK) |
1378 | != const_cpu_to_le16(0); |
1379 | need_to.undo_data_size = 1; |
1380 | } |
1381 | /* |
1382 | * For compressed data, a single full block was allocated |
1383 | * to deal with compression, possibly in a previous call. |
1384 | * We are not able to process several blocks because |
1385 | * some clusters are freed after compression and |
1386 | * new allocations have to be done before proceeding, |
1387 | * so truncate the requested count if needed (big buffers). |
1388 | */ |
1389 | if (compressed) { |
1390 | fullcount = na->data_size - pos; |
1391 | if (count > fullcount) |
1392 | count = fullcount; |
1393 | } |
1394 | old_initialized_size = na->initialized_size; |
1395 | /* If it is a resident attribute, write the data to the mft record. */ |
1396 | if (!NAttrNonResident(na)) { |
1397 | char *val; |
1398 | |
1399 | ctx = ntfs_attr_get_search_ctx(na->ni, NULL); |
1400 | if (!ctx) |
1401 | goto err_out; |
1402 | if (ntfs_attr_lookup(na->type, na->name, na->name_len, 0, |
1403 | 0, NULL, 0, ctx)) { |
1404 | ntfs_log_perror("%s: lookup failed", __FUNCTION__); |
1405 | goto err_out; |
1406 | } |
1407 | val = (char*)ctx->attr + le16_to_cpu(ctx->attr->value_offset); |
1408 | if (val < (char*)ctx->attr || val + |
1409 | le32_to_cpu(ctx->attr->value_length) > |
1410 | (char*)ctx->mrec + vol->mft_record_size) { |
1411 | errno = EIO; |
1412 | ntfs_log_perror("%s: Sanity check failed", __FUNCTION__); |
1413 | goto err_out; |
1414 | } |
1415 | memcpy(val + pos, b, count); |
1416 | if (ntfs_mft_record_write(vol, ctx->ntfs_ino->mft_no, |
1417 | ctx->mrec)) { |
1418 | /* |
1419 | * NOTE: We are in a bad state at this moment. We have |
1420 | * dirtied the mft record but we failed to commit it to |
1421 | * disk. Since we have read the mft record ok before, |
1422 | * it is unlikely to fail writing it, so is ok to just |
1423 | * return error here... (AIA) |
1424 | */ |
1425 | ntfs_log_perror("%s: failed to write mft record", __FUNCTION__); |
1426 | goto err_out; |
1427 | } |
1428 | ntfs_attr_put_search_ctx(ctx); |
1429 | total = count; |
1430 | goto out; |
1431 | } |
1432 | |
1433 | /* Handle writes beyond initialized_size. */ |
1434 | if (pos + count > na->initialized_size) { |
1435 | if (ntfs_attr_map_whole_runlist(na)) |
1436 | goto err_out; |
1437 | /* |
1438 | * For a compressed attribute, we must be sure there is an |
1439 | * available entry, and, when reopening a compressed file, |
1440 | * we may need to split a hole. So reserve the entries |
1441 | * before it gets too late. |
1442 | */ |
1443 | if (compressed) { |
1444 | na->rl = ntfs_rl_extend(na->rl,2); |
1445 | if (!na->rl) |
1446 | goto err_out; |
1447 | } |
1448 | /* Set initialized_size to @pos + @count. */ |
1449 | ctx = ntfs_attr_get_search_ctx(na->ni, NULL); |
1450 | if (!ctx) |
1451 | goto err_out; |
1452 | if (ntfs_attr_lookup(na->type, na->name, na->name_len, 0, |
1453 | 0, NULL, 0, ctx)) |
1454 | goto err_out; |
1455 | |
1456 | /* If write starts beyond initialized_size, zero the gap. */ |
1457 | if (pos > na->initialized_size) |
1458 | if (ntfs_attr_fill_zero(na, na->initialized_size, |
1459 | pos - na->initialized_size)) |
1460 | goto err_out; |
1461 | |
1462 | ctx->attr->initialized_size = cpu_to_sle64(pos + count); |
1463 | /* fix data_size for compressed files */ |
1464 | if (compressed) |
1465 | ctx->attr->data_size = ctx->attr->initialized_size; |
1466 | if (ntfs_mft_record_write(vol, ctx->ntfs_ino->mft_no, |
1467 | ctx->mrec)) { |
1468 | /* |
1469 | * Undo the change in the in-memory copy and send it |
1470 | * back for writing. |
1471 | */ |
1472 | ctx->attr->initialized_size = |
1473 | cpu_to_sle64(old_initialized_size); |
1474 | ntfs_mft_record_write(vol, ctx->ntfs_ino->mft_no, |
1475 | ctx->mrec); |
1476 | goto err_out; |
1477 | } |
1478 | na->initialized_size = pos + count; |
1479 | #if CACHE_NIDATA_SIZE |
1480 | if (na->ni->mrec->flags & MFT_RECORD_IS_DIRECTORY |
1481 | ? na->type == AT_INDEX_ROOT && na->name == NTFS_INDEX_I30 |
1482 | : na->type == AT_DATA && na->name == AT_UNNAMED) { |
1483 | na->ni->data_size = na->data_size; |
1484 | na->ni->allocated_size = na->allocated_size; |
1485 | set_nino_flag(na->ni,KnownSize); |
1486 | } |
1487 | #endif |
1488 | ntfs_attr_put_search_ctx(ctx); |
1489 | ctx = NULL; |
1490 | /* |
1491 | * NOTE: At this point the initialized_size in the mft record |
1492 | * has been updated BUT there is random data on disk thus if |
1493 | * we decide to abort, we MUST change the initialized_size |
1494 | * again. |
1495 | */ |
1496 | need_to.undo_initialized_size = 1; |
1497 | } |
1498 | /* Find the runlist element containing the vcn. */ |
1499 | rl = ntfs_attr_find_vcn(na, pos >> vol->cluster_size_bits); |
1500 | if (!rl) { |
1501 | /* |
1502 | * If the vcn is not present it is an out of bounds write. |
1503 | * However, we already extended the size of the attribute, |
1504 | * so getting this here must be an error of some kind. |
1505 | */ |
1506 | if (errno == ENOENT) { |
1507 | errno = EIO; |
1508 | ntfs_log_perror("%s: Failed to find VCN #3", __FUNCTION__); |
1509 | } |
1510 | goto err_out; |
1511 | } |
1512 | ofs = pos - (rl->vcn << vol->cluster_size_bits); |
1513 | /* |
1514 | * Determine if there is compressed data in the current |
1515 | * compression block (when appending to an existing file). |
1516 | * If so, decompression will be needed, and the full block |
1517 | * must be allocated to be identified as uncompressed. |
1518 | * This comes in two variants, depending on whether |
1519 | * compression has saved at least one cluster. |
1520 | * The compressed size can never be over full size by |
1521 | * more than 485 (maximum for 15 compression blocks |
1522 | * compressed to 4098 and the last 3640 bytes compressed |
1523 | * to 3640 + 3640/8 = 4095, with 15*2 + 4095 - 3640 = 485) |
1524 | * This is less than the smallest cluster, so the hole is |
1525 | * is never beyond the cluster next to the position of |
1526 | * the first uncompressed byte to write. |
1527 | */ |
1528 | compressed_part = 0; |
1529 | if (compressed) { |
1530 | if ((rl->lcn == (LCN)LCN_HOLE) |
1531 | && wasnonresident) { |
1532 | if (rl->length < na->compression_block_clusters) |
1533 | compressed_part |
1534 | = na->compression_block_clusters |
1535 | - rl->length; |
1536 | else { |
1537 | compressed_part |
1538 | = na->compression_block_clusters; |
1539 | if (rl->length > na->compression_block_clusters) { |
1540 | rl[2].lcn = rl[1].lcn; |
1541 | rl[2].vcn = rl[1].vcn; |
1542 | rl[2].length = rl[1].length; |
1543 | rl[1].vcn -= compressed_part; |
1544 | rl[1].lcn = LCN_HOLE; |
1545 | rl[1].length = compressed_part; |
1546 | rl[0].length -= compressed_part; |
1547 | ofs -= rl->length << vol->cluster_size_bits; |
1548 | rl++; |
1549 | } |
1550 | } |
1551 | /* normal hole filling will do later */ |
1552 | } else |
1553 | if ((rl->lcn >= 0) && (rl[1].lcn == (LCN)LCN_HOLE)) { |
1554 | s64 xofs; |
1555 | |
1556 | if (wasnonresident) |
1557 | compressed_part = na->compression_block_clusters |
1558 | - rl[1].length; |
1559 | rl++; |
1560 | xofs = 0; |
1561 | if (ntfs_attr_fill_hole(na, |
1562 | rl->length << vol->cluster_size_bits, |
1563 | &xofs, &rl, &update_from)) |
1564 | goto err_out; |
1565 | /* the fist allocated cluster was not merged */ |
1566 | if (!xofs) |
1567 | rl--; |
1568 | } |
1569 | } |
1570 | /* |
1571 | * Scatter the data from the linear data buffer to the volume. Note, a |
1572 | * partial final vcn is taken care of by the @count capping of write |
1573 | * length. |
1574 | */ |
1575 | for (hole_end = 0; count; rl++, ofs = 0, hole_end = 0) { |
1576 | if (rl->lcn == LCN_RL_NOT_MAPPED) { |
1577 | rl = ntfs_attr_find_vcn(na, rl->vcn); |
1578 | if (!rl) { |
1579 | if (errno == ENOENT) { |
1580 | errno = EIO; |
1581 | ntfs_log_perror("%s: Failed to find VCN" |
1582 | " #4", __FUNCTION__); |
1583 | } |
1584 | goto rl_err_out; |
1585 | } |
1586 | /* Needed for case when runs merged. */ |
1587 | ofs = pos + total - (rl->vcn << vol->cluster_size_bits); |
1588 | } |
1589 | if (!rl->length) { |
1590 | errno = EIO; |
1591 | ntfs_log_perror("%s: Zero run length", __FUNCTION__); |
1592 | goto rl_err_out; |
1593 | } |
1594 | if (rl->lcn < (LCN)0) { |
1595 | hole_end = rl->vcn + rl->length; |
1596 | |
1597 | if (rl->lcn != (LCN)LCN_HOLE) { |
1598 | errno = EIO; |
1599 | ntfs_log_perror("%s: Unexpected LCN (%lld)", |
1600 | __FUNCTION__, |
1601 | (long long)rl->lcn); |
1602 | goto rl_err_out; |
1603 | } |
1604 | if (ntfs_attr_fill_hole(na, fullcount, &ofs, &rl, |
1605 | &update_from)) |
1606 | goto err_out; |
1607 | } |
1608 | if (compressed) { |
1609 | while (rl->length |
1610 | && (ofs >= (rl->length << vol->cluster_size_bits))) { |
1611 | ofs -= rl->length << vol->cluster_size_bits; |
1612 | rl++; |
1613 | } |
1614 | } |
1615 | |
1616 | /* It is a real lcn, write it to the volume. */ |
1617 | to_write = min(count, (rl->length << vol->cluster_size_bits) - ofs); |
1618 | retry: |
1619 | ntfs_log_trace("Writing %lld bytes to vcn %lld, lcn %lld, ofs " |
1620 | "%lld.\n", (long long)to_write, (long long)rl->vcn, |
1621 | (long long)rl->lcn, (long long)ofs); |
1622 | if (!NVolReadOnly(vol)) { |
1623 | |
1624 | s64 wpos = (rl->lcn << vol->cluster_size_bits) + ofs; |
1625 | s64 wend = (rl->vcn << vol->cluster_size_bits) + ofs + to_write; |
1626 | u32 bsize = vol->cluster_size; |
1627 | /* Byte size needed to zero fill a cluster */ |
1628 | s64 rounding = ((wend + bsize - 1) & ~(s64)(bsize - 1)) - wend; |
1629 | /** |
1630 | * Zero fill to cluster boundary if we're writing at the |
1631 | * end of the attribute or into an ex-sparse cluster. |
1632 | * This will cause the kernel not to seek and read disk |
1633 | * blocks during write(2) to fill the end of the buffer |
1634 | * which increases write speed by 2-10 fold typically. |
1635 | * |
1636 | * This is done even for compressed files, because |
1637 | * data is generally first written uncompressed. |
1638 | */ |
1639 | if (rounding && ((wend == na->initialized_size) || |
1640 | (wend < (hole_end << vol->cluster_size_bits)))){ |
1641 | |
1642 | char *cb; |
1643 | |
1644 | rounding += to_write; |
1645 | |
1646 | cb = ntfs_malloc(rounding); |
1647 | if (!cb) |
1648 | goto err_out; |
1649 | |
1650 | memcpy(cb, b, to_write); |
1651 | memset(cb + to_write, 0, rounding - to_write); |
1652 | |
1653 | if (compressed) { |
1654 | written = ntfs_compressed_pwrite(na, |
1655 | rl, wpos, ofs, to_write, |
1656 | rounding, b, compressed_part); |
1657 | } else { |
1658 | written = ntfs_pwrite(vol->dev, wpos, |
1659 | rounding, cb); |
1660 | if (written == rounding) |
1661 | written = to_write; |
1662 | } |
1663 | |
1664 | free(cb); |
1665 | } else { |
1666 | if (compressed) { |
1667 | written = ntfs_compressed_pwrite(na, |
1668 | rl, wpos, ofs, to_write, |
1669 | to_write, b, compressed_part); |
1670 | } else |
1671 | written = ntfs_pwrite(vol->dev, wpos, |
1672 | to_write, b); |
1673 | } |
1674 | } else |
1675 | written = to_write; |
1676 | /* If everything ok, update progress counters and continue. */ |
1677 | if (written > 0) { |
1678 | total += written; |
1679 | count -= written; |
1680 | fullcount -= written; |
1681 | b = (const u8*)b + written; |
1682 | } |
1683 | if (written != to_write) { |
1684 | /* Partial write cannot be dealt with, stop there */ |
1685 | /* If the syscall was interrupted, try again. */ |
1686 | if (written == (s64)-1 && errno == EINTR) |
1687 | goto retry; |
1688 | if (!written) |
1689 | errno = EIO; |
1690 | goto rl_err_out; |
1691 | } |
1692 | compressed_part = 0; |
1693 | } |
1694 | done: |
1695 | if (ctx) |
1696 | ntfs_attr_put_search_ctx(ctx); |
1697 | /* Update mapping pairs if needed. */ |
1698 | if ((update_from != -1) |
1699 | || (compressed && !makingnonresident)) |
1700 | if (ntfs_attr_update_mapping_pairs(na, 0 /*update_from*/)) { |
1701 | /* |
1702 | * FIXME: trying to recover by goto rl_err_out; |
1703 | * could cause driver hang by infinite looping. |
1704 | */ |
1705 | total = -1; |
1706 | goto out; |
1707 | } |
1708 | out: |
1709 | ntfs_log_leave("\n"); |
1710 | return total; |
1711 | rl_err_out: |
1712 | eo = errno; |
1713 | if (total) { |
1714 | if (need_to.undo_initialized_size) { |
1715 | if (pos + total > na->initialized_size) |
1716 | goto done; |
1717 | /* |
1718 | * TODO: Need to try to change initialized_size. If it |
1719 | * succeeds goto done, otherwise goto err_out. (AIA) |
1720 | */ |
1721 | goto err_out; |
1722 | } |
1723 | goto done; |
1724 | } |
1725 | errno = eo; |
1726 | err_out: |
1727 | eo = errno; |
1728 | if (need_to.undo_initialized_size) { |
1729 | int err; |
1730 | |
1731 | err = 0; |
1732 | if (!ctx) { |
1733 | ctx = ntfs_attr_get_search_ctx(na->ni, NULL); |
1734 | if (!ctx) |
1735 | err = 1; |
1736 | } else |
1737 | ntfs_attr_reinit_search_ctx(ctx); |
1738 | if (!err) { |
1739 | err = ntfs_attr_lookup(na->type, na->name, |
1740 | na->name_len, 0, 0, NULL, 0, ctx); |
1741 | if (!err) { |
1742 | na->initialized_size = old_initialized_size; |
1743 | ctx->attr->initialized_size = cpu_to_sle64( |
1744 | old_initialized_size); |
1745 | err = ntfs_mft_record_write(vol, |
1746 | ctx->ntfs_ino->mft_no, |
1747 | ctx->mrec); |
1748 | } |
1749 | } |
1750 | if (err) { |
1751 | /* |
1752 | * FIXME: At this stage could try to recover by filling |
1753 | * old_initialized_size -> new_initialized_size with |
1754 | * data or at least zeroes. (AIA) |
1755 | */ |
1756 | ntfs_log_error("Eeek! Failed to recover from error. " |
1757 | "Leaving metadata in inconsistent " |
1758 | "state! Run chkdsk!\n"); |
1759 | } |
1760 | } |
1761 | if (ctx) |
1762 | ntfs_attr_put_search_ctx(ctx); |
1763 | /* Update mapping pairs if needed. */ |
1764 | if (update_from != -1) |
1765 | ntfs_attr_update_mapping_pairs(na, 0 /*update_from*/); |
1766 | /* Restore original data_size if needed. */ |
1767 | if (need_to.undo_data_size && ntfs_attr_truncate(na, old_data_size)) |
1768 | ntfs_log_perror("Failed to restore data_size"); |
1769 | errno = eo; |
1770 | errno_set: |
1771 | total = -1; |
1772 | goto out; |
1773 | } |
1774 | |
1775 | int ntfs_attr_pclose(ntfs_attr *na) |
1776 | { |
1777 | s64 ofs; |
1778 | int failed; |
1779 | BOOL ok = TRUE; |
1780 | VCN update_from = -1; |
1781 | ntfs_volume *vol; |
1782 | ntfs_attr_search_ctx *ctx = NULL; |
1783 | runlist_element *rl; |
1784 | int eo; |
1785 | s64 hole; |
1786 | int compressed_part; |
1787 | BOOL compressed; |
1788 | |
1789 | ntfs_log_enter("Entering for inode 0x%llx, attr 0x%x.\n", |
1790 | na->ni->mft_no, na->type); |
1791 | |
1792 | if (!na || !na->ni || !na->ni->vol) { |
1793 | errno = EINVAL; |
1794 | ntfs_log_perror("%s", __FUNCTION__); |
1795 | goto errno_set; |
1796 | } |
1797 | vol = na->ni->vol; |
1798 | compressed = (na->data_flags & ATTR_COMPRESSION_MASK) |
1799 | != const_cpu_to_le16(0); |
1800 | /* |
1801 | * Encrypted non-resident attributes are not supported. We return |
1802 | * access denied, which is what Windows NT4 does, too. |
1803 | */ |
1804 | if (NAttrEncrypted(na) && NAttrNonResident(na)) { |
1805 | errno = EACCES; |
1806 | goto errno_set; |
1807 | } |
1808 | /* If this is not a compressed attribute get out */ |
1809 | /* same if it is resident */ |
1810 | if (!compressed || !NAttrNonResident(na)) |
1811 | goto out; |
1812 | |
1813 | /* |
1814 | * For a compressed attribute, we must be sure there is an |
1815 | * available entry, so reserve it before it gets too late. |
1816 | */ |
1817 | if (ntfs_attr_map_whole_runlist(na)) |
1818 | goto err_out; |
1819 | na->rl = ntfs_rl_extend(na->rl,1); |
1820 | if (!na->rl) |
1821 | goto err_out; |
1822 | /* Find the runlist element containing the terminal vcn. */ |
1823 | rl = ntfs_attr_find_vcn(na, (na->initialized_size - 1) >> vol->cluster_size_bits); |
1824 | if (!rl) { |
1825 | /* |
1826 | * If the vcn is not present it is an out of bounds write. |
1827 | * However, we have already written the last byte uncompressed, |
1828 | * so getting this here must be an error of some kind. |
1829 | */ |
1830 | if (errno == ENOENT) { |
1831 | errno = EIO; |
1832 | ntfs_log_perror("%s: Failed to find VCN #5", __FUNCTION__); |
1833 | } |
1834 | goto err_out; |
1835 | } |
1836 | /* |
1837 | * Scatter the data from the linear data buffer to the volume. Note, a |
1838 | * partial final vcn is taken care of by the @count capping of write |
1839 | * length. |
1840 | */ |
1841 | compressed_part = 0; |
1842 | if ((rl->lcn >= 0) && (rl[1].lcn == (LCN)LCN_HOLE)) |
1843 | compressed_part |
1844 | = na->compression_block_clusters - rl[1].length; |
1845 | else |
1846 | if (rl->lcn == (LCN)LCN_HOLE) { |
1847 | if (rl->length < na->compression_block_clusters) |
1848 | compressed_part |
1849 | = na->compression_block_clusters |
1850 | - rl->length; |
1851 | else |
1852 | compressed_part |
1853 | = na->compression_block_clusters; |
1854 | } |
1855 | /* done, if the last block set was compressed */ |
1856 | if (compressed_part) |
1857 | goto out; |
1858 | |
1859 | ofs = na->initialized_size - (rl->vcn << vol->cluster_size_bits); |
1860 | |
1861 | if (rl->lcn == LCN_RL_NOT_MAPPED) { |
1862 | rl = ntfs_attr_find_vcn(na, rl->vcn); |
1863 | if (!rl) { |
1864 | if (errno == ENOENT) { |
1865 | errno = EIO; |
1866 | ntfs_log_perror("%s: Failed to find VCN" |
1867 | " #6", __FUNCTION__); |
1868 | } |
1869 | goto rl_err_out; |
1870 | } |
1871 | /* Needed for case when runs merged. */ |
1872 | ofs = na->initialized_size - (rl->vcn << vol->cluster_size_bits); |
1873 | } |
1874 | if (!rl->length) { |
1875 | errno = EIO; |
1876 | ntfs_log_perror("%s: Zero run length", __FUNCTION__); |
1877 | goto rl_err_out; |
1878 | } |
1879 | if (rl->lcn < (LCN)0) { |
1880 | hole = rl->vcn + rl->length; |
1881 | if (rl->lcn != (LCN)LCN_HOLE) { |
1882 | errno = EIO; |
1883 | ntfs_log_perror("%s: Unexpected LCN (%lld)", |
1884 | __FUNCTION__, |
1885 | (long long)rl->lcn); |
1886 | goto rl_err_out; |
1887 | } |
1888 | |
1889 | if (ntfs_attr_fill_hole(na, (s64)0, &ofs, &rl, &update_from)) |
1890 | goto err_out; |
1891 | } |
1892 | while (rl->length |
1893 | && (ofs >= (rl->length << vol->cluster_size_bits))) { |
1894 | ofs -= rl->length << vol->cluster_size_bits; |
1895 | rl++; |
1896 | } |
1897 | |
1898 | retry: |
1899 | failed = 0; |
1900 | if (!NVolReadOnly(vol)) { |
1901 | failed = ntfs_compressed_close(na, rl, ofs); |
1902 | #if CACHE_NIDATA_SIZE |
1903 | if (na->ni->mrec->flags & MFT_RECORD_IS_DIRECTORY |
1904 | ? na->type == AT_INDEX_ROOT && na->name == NTFS_INDEX_I30 |
1905 | : na->type == AT_DATA && na->name == AT_UNNAMED) { |
1906 | na->ni->data_size = na->data_size; |
1907 | na->ni->allocated_size = na->allocated_size; |
1908 | set_nino_flag(na->ni,KnownSize); |
1909 | } |
1910 | #endif |
1911 | } |
1912 | if (failed) { |
1913 | /* If the syscall was interrupted, try again. */ |
1914 | if (errno == EINTR) |
1915 | goto retry; |
1916 | else |
1917 | goto rl_err_out; |
1918 | } |
1919 | if (ctx) |
1920 | ntfs_attr_put_search_ctx(ctx); |
1921 | /* Update mapping pairs if needed. */ |
1922 | if (ntfs_attr_update_mapping_pairs(na, 0 /*update_from*/)) { |
1923 | /* |
1924 | * FIXME: trying to recover by goto rl_err_out; |
1925 | * could cause driver hang by infinite looping. |
1926 | */ |
1927 | ok = FALSE; |
1928 | goto out; |
1929 | } |
1930 | out: |
1931 | ntfs_log_leave("\n"); |
1932 | return (!ok); |
1933 | rl_err_out: |
1934 | /* |
1935 | * need not restore old sizes, only compressed_size |
1936 | * can have changed. It has been set according to |
1937 | * the current runlist while updating the mapping pairs, |
1938 | * and must be kept consistent with the runlists. |
1939 | */ |
1940 | err_out: |
1941 | eo = errno; |
1942 | if (ctx) |
1943 | ntfs_attr_put_search_ctx(ctx); |
1944 | /* Update mapping pairs if needed. */ |
1945 | ntfs_attr_update_mapping_pairs(na, 0 /*update_from*/); |
1946 | errno = eo; |
1947 | errno_set: |
1948 | ok = FALSE; |
1949 | goto out; |
1950 | } |
1951 | |
1952 | /** |
1953 | * ntfs_attr_mst_pread - multi sector transfer protected ntfs attribute read |
1954 | * @na: multi sector transfer protected ntfs attribute to read from |
1955 | * @pos: byte position in the attribute to begin reading from |
1956 | * @bk_cnt: number of mst protected blocks to read |
1957 | * @bk_size: size of each mst protected block in bytes |
1958 | * @dst: output data buffer |
1959 | * |
1960 | * This function will read @bk_cnt blocks of size @bk_size bytes each starting |
1961 | * at offset @pos from the ntfs attribute @na into the data buffer @b. |
1962 | * |
1963 | * On success, the multi sector transfer fixups are applied and the number of |
1964 | * read blocks is returned. If this number is lower than @bk_cnt this means |
1965 | * that the read has either reached end of attribute or that an error was |
1966 | * encountered during the read so that the read is partial. 0 means end of |
1967 | * attribute or nothing to read (also return 0 when @bk_cnt or @bk_size are 0). |
1968 | * |
1969 | * On error and nothing has been read, return -1 with errno set appropriately |
1970 | * to the return code of ntfs_attr_pread() or to EINVAL in case of invalid |
1971 | * arguments. |
1972 | * |
1973 | * NOTE: If an incomplete multi sector transfer is detected the magic is |
1974 | * changed to BAAD but no error is returned, i.e. it is possible that any of |
1975 | * the returned blocks have multi sector transfer errors. This should be |
1976 | * detected by the caller by checking each block with is_baad_recordp(&block). |
1977 | * The reasoning is that we want to fixup as many blocks as possible and we |
1978 | * want to return even bad ones to the caller so, e.g. in case of ntfsck, the |
1979 | * errors can be repaired. |
1980 | */ |
1981 | s64 ntfs_attr_mst_pread(ntfs_attr *na, const s64 pos, const s64 bk_cnt, |
1982 | const u32 bk_size, void *dst) |
1983 | { |
1984 | s64 br; |
1985 | u8 *end; |
1986 | |
1987 | ntfs_log_trace("Entering for inode 0x%llx, attr type 0x%x, pos 0x%llx.\n", |
1988 | (unsigned long long)na->ni->mft_no, na->type, |
1989 | (long long)pos); |
1990 | if (bk_cnt < 0 || bk_size % NTFS_BLOCK_SIZE) { |
1991 | errno = EINVAL; |
1992 | ntfs_log_perror("%s", __FUNCTION__); |
1993 | return -1; |
1994 | } |
1995 | br = ntfs_attr_pread(na, pos, bk_cnt * bk_size, dst); |
1996 | if (br <= 0) |
1997 | return br; |
1998 | br /= bk_size; |
1999 | for (end = (u8*)dst + br * bk_size; (u8*)dst < end; dst = (u8*)dst + |
2000 | bk_size) |
2001 | ntfs_mst_post_read_fixup((NTFS_RECORD*)dst, bk_size); |
2002 | /* Finally, return the number of blocks read. */ |
2003 | return br; |
2004 | } |
2005 | |
2006 | /** |
2007 | * ntfs_attr_mst_pwrite - multi sector transfer protected ntfs attribute write |
2008 | * @na: multi sector transfer protected ntfs attribute to write to |
2009 | * @pos: position in the attribute to write to |
2010 | * @bk_cnt: number of mst protected blocks to write |
2011 | * @bk_size: size of each mst protected block in bytes |
2012 | * @src: data buffer to write to disk |
2013 | * |
2014 | * This function will write @bk_cnt blocks of size @bk_size bytes each from |
2015 | * data buffer @b to multi sector transfer (mst) protected ntfs attribute @na |
2016 | * at position @pos. |
2017 | * |
2018 | * On success, return the number of successfully written blocks. If this number |
2019 | * is lower than @bk_cnt this means that an error was encountered during the |
2020 | * write so that the write is partial. 0 means nothing was written (also |
2021 | * return 0 when @bk_cnt or @bk_size are 0). |
2022 | * |
2023 | * On error and nothing has been written, return -1 with errno set |
2024 | * appropriately to the return code of ntfs_attr_pwrite(), or to EINVAL in case |
2025 | * of invalid arguments. |
2026 | * |
2027 | * NOTE: We mst protect the data, write it, then mst deprotect it using a quick |
2028 | * deprotect algorithm (no checking). This saves us from making a copy before |
2029 | * the write and at the same time causes the usn to be incremented in the |
2030 | * buffer. This conceptually fits in better with the idea that cached data is |
2031 | * always deprotected and protection is performed when the data is actually |
2032 | * going to hit the disk and the cache is immediately deprotected again |
2033 | * simulating an mst read on the written data. This way cache coherency is |
2034 | * achieved. |
2035 | */ |
2036 | s64 ntfs_attr_mst_pwrite(ntfs_attr *na, const s64 pos, s64 bk_cnt, |
2037 | const u32 bk_size, void *src) |
2038 | { |
2039 | s64 written, i; |
2040 | |
2041 | ntfs_log_trace("Entering for inode 0x%llx, attr type 0x%x, pos 0x%llx.\n", |
2042 | (unsigned long long)na->ni->mft_no, na->type, |
2043 | (long long)pos); |
2044 | if (bk_cnt < 0 || bk_size % NTFS_BLOCK_SIZE) { |
2045 | errno = EINVAL; |
2046 | return -1; |
2047 | } |
2048 | if (!bk_cnt) |
2049 | return 0; |
2050 | /* Prepare data for writing. */ |
2051 | for (i = 0; i < bk_cnt; ++i) { |
2052 | int err; |
2053 | |
2054 | err = ntfs_mst_pre_write_fixup((NTFS_RECORD*) |
2055 | ((u8*)src + i * bk_size), bk_size); |
2056 | if (err < 0) { |
2057 | /* Abort write at this position. */ |
2058 | ntfs_log_perror("%s #1", __FUNCTION__); |
2059 | if (!i) |
2060 | return err; |
2061 | bk_cnt = i; |
2062 | break; |
2063 | } |
2064 | } |
2065 | /* Write the prepared data. */ |
2066 | written = ntfs_attr_pwrite(na, pos, bk_cnt * bk_size, src); |
2067 | if (written <= 0) { |
2068 | ntfs_log_perror("%s: written=%lld", __FUNCTION__, |
2069 | (long long)written); |
2070 | } |
2071 | /* Quickly deprotect the data again. */ |
2072 | for (i = 0; i < bk_cnt; ++i) |
2073 | ntfs_mst_post_write_fixup((NTFS_RECORD*)((u8*)src + i * |
2074 | bk_size)); |
2075 | if (written <= 0) |
2076 | return written; |
2077 | /* Finally, return the number of complete blocks written. */ |
2078 | return written / bk_size; |
2079 | } |
2080 | |
2081 | /** |
2082 | * ntfs_attr_find - find (next) attribute in mft record |
2083 | * @type: attribute type to find |
2084 | * @name: attribute name to find (optional, i.e. NULL means don't care) |
2085 | * @name_len: attribute name length (only needed if @name present) |
2086 | * @ic: IGNORE_CASE or CASE_SENSITIVE (ignored if @name not present) |
2087 | * @val: attribute value to find (optional, resident attributes only) |
2088 | * @val_len: attribute value length |
2089 | * @ctx: search context with mft record and attribute to search from |
2090 | * |
2091 | * You shouldn't need to call this function directly. Use lookup_attr() instead. |
2092 | * |
2093 | * ntfs_attr_find() takes a search context @ctx as parameter and searches the |
2094 | * mft record specified by @ctx->mrec, beginning at @ctx->attr, for an |
2095 | * attribute of @type, optionally @name and @val. If found, ntfs_attr_find() |
2096 | * returns 0 and @ctx->attr will point to the found attribute. |
2097 | * |
2098 | * If not found, ntfs_attr_find() returns -1, with errno set to ENOENT and |
2099 | * @ctx->attr will point to the attribute before which the attribute being |
2100 | * searched for would need to be inserted if such an action were to be desired. |
2101 | * |
2102 | * On actual error, ntfs_attr_find() returns -1 with errno set to the error |
2103 | * code but not to ENOENT. In this case @ctx->attr is undefined and in |
2104 | * particular do not rely on it not changing. |
2105 | * |
2106 | * If @ctx->is_first is TRUE, the search begins with @ctx->attr itself. If it |
2107 | * is FALSE, the search begins after @ctx->attr. |
2108 | * |
2109 | * If @type is AT_UNUSED, return the first found attribute, i.e. one can |
2110 | * enumerate all attributes by setting @type to AT_UNUSED and then calling |
2111 | * ntfs_attr_find() repeatedly until it returns -1 with errno set to ENOENT to |
2112 | * indicate that there are no more entries. During the enumeration, each |
2113 | * successful call of ntfs_attr_find() will return the next attribute in the |
2114 | * mft record @ctx->mrec. |
2115 | * |
2116 | * If @type is AT_END, seek to the end and return -1 with errno set to ENOENT. |
2117 | * AT_END is not a valid attribute, its length is zero for example, thus it is |
2118 | * safer to return error instead of success in this case. This also allows us |
2119 | * to interoperate cleanly with ntfs_external_attr_find(). |
2120 | * |
2121 | * If @name is AT_UNNAMED search for an unnamed attribute. If @name is present |
2122 | * but not AT_UNNAMED search for a named attribute matching @name. Otherwise, |
2123 | * match both named and unnamed attributes. |
2124 | * |
2125 | * If @ic is IGNORE_CASE, the @name comparison is not case sensitive and |
2126 | * @ctx->ntfs_ino must be set to the ntfs inode to which the mft record |
2127 | * @ctx->mrec belongs. This is so we can get at the ntfs volume and hence at |
2128 | * the upcase table. If @ic is CASE_SENSITIVE, the comparison is case |
2129 | * sensitive. When @name is present, @name_len is the @name length in Unicode |
2130 | * characters. |
2131 | * |
2132 | * If @name is not present (NULL), we assume that the unnamed attribute is |
2133 | * being searched for. |
2134 | * |
2135 | * Finally, the resident attribute value @val is looked for, if present. |
2136 | * If @val is not present (NULL), @val_len is ignored. |
2137 | * |
2138 | * ntfs_attr_find() only searches the specified mft record and it ignores the |
2139 | * presence of an attribute list attribute (unless it is the one being searched |
2140 | * for, obviously). If you need to take attribute lists into consideration, use |
2141 | * ntfs_attr_lookup() instead (see below). This also means that you cannot use |
2142 | * ntfs_attr_find() to search for extent records of non-resident attributes, as |
2143 | * extents with lowest_vcn != 0 are usually described by the attribute list |
2144 | * attribute only. - Note that it is possible that the first extent is only in |
2145 | * the attribute list while the last extent is in the base mft record, so don't |
2146 | * rely on being able to find the first extent in the base mft record. |
2147 | * |
2148 | * Warning: Never use @val when looking for attribute types which can be |
2149 | * non-resident as this most likely will result in a crash! |
2150 | */ |
2151 | static int ntfs_attr_find(const ATTR_TYPES type, const ntfschar *name, |
2152 | const u32 name_len, const IGNORE_CASE_BOOL ic, |
2153 | const u8 *val, const u32 val_len, ntfs_attr_search_ctx *ctx) |
2154 | { |
2155 | ATTR_RECORD *a; |
2156 | ntfs_volume *vol; |
2157 | ntfschar *upcase; |
2158 | u32 upcase_len; |
2159 | |
2160 | ntfs_log_trace("attribute type 0x%x.\n", type); |
2161 | |
2162 | if (ctx->ntfs_ino) { |
2163 | vol = ctx->ntfs_ino->vol; |
2164 | upcase = vol->upcase; |
2165 | upcase_len = vol->upcase_len; |
2166 | } else { |
2167 | if (name && name != AT_UNNAMED) { |
2168 | errno = EINVAL; |
2169 | ntfs_log_perror("%s", __FUNCTION__); |
2170 | return -1; |
2171 | } |
2172 | vol = NULL; |
2173 | upcase = NULL; |
2174 | upcase_len = 0; |
2175 | } |
2176 | /* |
2177 | * Iterate over attributes in mft record starting at @ctx->attr, or the |
2178 | * attribute following that, if @ctx->is_first is TRUE. |
2179 | */ |
2180 | if (ctx->is_first) { |
2181 | a = ctx->attr; |
2182 | ctx->is_first = FALSE; |
2183 | } else |
2184 | a = (ATTR_RECORD*)((char*)ctx->attr + |
2185 | le32_to_cpu(ctx->attr->length)); |
2186 | for (;; a = (ATTR_RECORD*)((char*)a + le32_to_cpu(a->length))) { |
2187 | if (p2n(a) < p2n(ctx->mrec) || (char*)a > (char*)ctx->mrec + |
2188 | le32_to_cpu(ctx->mrec->bytes_allocated)) |
2189 | break; |
2190 | ctx->attr = a; |
2191 | if (((type != AT_UNUSED) && (le32_to_cpu(a->type) > |
2192 | le32_to_cpu(type))) || |
2193 | (a->type == AT_END)) { |
2194 | errno = ENOENT; |
2195 | return -1; |
2196 | } |
2197 | if (!a->length) |
2198 | break; |
2199 | /* If this is an enumeration return this attribute. */ |
2200 | if (type == AT_UNUSED) |
2201 | return 0; |
2202 | if (a->type != type) |
2203 | continue; |
2204 | /* |
2205 | * If @name is AT_UNNAMED we want an unnamed attribute. |
2206 | * If @name is present, compare the two names. |
2207 | * Otherwise, match any attribute. |
2208 | */ |
2209 | if (name == AT_UNNAMED) { |
2210 | /* The search failed if the found attribute is named. */ |
2211 | if (a->name_length) { |
2212 | errno = ENOENT; |
2213 | return -1; |
2214 | } |
2215 | } else { |
2216 | register int rc; |
2217 | if (name && ((rc = ntfs_names_full_collate(name, |
2218 | name_len, (ntfschar*)((char*)a + |
2219 | le16_to_cpu(a->name_offset)), |
2220 | a->name_length, ic, |
2221 | upcase, upcase_len)))) { |
2222 | /* |
2223 | * If @name collates before a->name, |
2224 | * there is no matching attribute. |
2225 | */ |
2226 | if (rc < 0) { |
2227 | errno = ENOENT; |
2228 | return -1; |
2229 | } |
2230 | /* If the strings are not equal, continue search. */ |
2231 | continue; |
2232 | } |
2233 | } |
2234 | /* |
2235 | * The names match or @name not present and attribute is |
2236 | * unnamed. If no @val specified, we have found the attribute |
2237 | * and are done. |
2238 | */ |
2239 | if (!val) |
2240 | return 0; |
2241 | /* @val is present; compare values. */ |
2242 | else { |
2243 | register int rc; |
2244 | |
2245 | rc = memcmp(val, (char*)a +le16_to_cpu(a->value_offset), |
2246 | min(val_len, |
2247 | le32_to_cpu(a->value_length))); |
2248 | /* |
2249 | * If @val collates before the current attribute's |
2250 | * value, there is no matching attribute. |
2251 | */ |
2252 | if (!rc) { |
2253 | register u32 avl; |
2254 | avl = le32_to_cpu(a->value_length); |
2255 | if (val_len == avl) |
2256 | return 0; |
2257 | if (val_len < avl) { |
2258 | errno = ENOENT; |
2259 | return -1; |
2260 | } |
2261 | } else if (rc < 0) { |
2262 | errno = ENOENT; |
2263 | return -1; |
2264 | } |
2265 | } |
2266 | } |
2267 | errno = EIO; |
2268 | ntfs_log_perror("%s: Corrupt inode (%lld)", __FUNCTION__, |
2269 | ctx->ntfs_ino ? (long long)ctx->ntfs_ino->mft_no : -1); |
2270 | return -1; |
2271 | } |
2272 | |
2273 | void ntfs_attr_name_free(char **name) |
2274 | { |
2275 | if (*name) { |
2276 | free(*name); |
2277 | *name = NULL; |
2278 | } |
2279 | } |
2280 | |
2281 | char *ntfs_attr_name_get(const ntfschar *uname, const int uname_len) |
2282 | { |
2283 | char *name = NULL; |
2284 | int name_len; |
2285 | |
2286 | name_len = ntfs_ucstombs(uname, uname_len, &name, 0); |
2287 | if (name_len < 0) { |
2288 | ntfs_log_perror("ntfs_ucstombs"); |
2289 | return NULL; |
2290 | |
2291 | } else if (name_len > 0) |
2292 | return name; |
2293 | |
2294 | ntfs_attr_name_free(&name); |
2295 | return NULL; |
2296 | } |
2297 | |
2298 | /** |
2299 | * ntfs_external_attr_find - find an attribute in the attribute list of an inode |
2300 | * @type: attribute type to find |
2301 | * @name: attribute name to find (optional, i.e. NULL means don't care) |
2302 | * @name_len: attribute name length (only needed if @name present) |
2303 | * @ic: IGNORE_CASE or CASE_SENSITIVE (ignored if @name not present) |
2304 | * @lowest_vcn: lowest vcn to find (optional, non-resident attributes only) |
2305 | * @val: attribute value to find (optional, resident attributes only) |
2306 | * @val_len: attribute value length |
2307 | * @ctx: search context with mft record and attribute to search from |
2308 | * |
2309 | * You shouldn't need to call this function directly. Use ntfs_attr_lookup() |
2310 | * instead. |
2311 | * |
2312 | * Find an attribute by searching the attribute list for the corresponding |
2313 | * attribute list entry. Having found the entry, map the mft record for read |
2314 | * if the attribute is in a different mft record/inode, find the attribute in |
2315 | * there and return it. |
2316 | * |
2317 | * If @type is AT_UNUSED, return the first found attribute, i.e. one can |
2318 | * enumerate all attributes by setting @type to AT_UNUSED and then calling |
2319 | * ntfs_external_attr_find() repeatedly until it returns -1 with errno set to |
2320 | * ENOENT to indicate that there are no more entries. During the enumeration, |
2321 | * each successful call of ntfs_external_attr_find() will return the next |
2322 | * attribute described by the attribute list of the base mft record described |
2323 | * by the search context @ctx. |
2324 | * |
2325 | * If @type is AT_END, seek to the end of the base mft record ignoring the |
2326 | * attribute list completely and return -1 with errno set to ENOENT. AT_END is |
2327 | * not a valid attribute, its length is zero for example, thus it is safer to |
2328 | * return error instead of success in this case. |
2329 | * |
2330 | * If @name is AT_UNNAMED search for an unnamed attribute. If @name is present |
2331 | * but not AT_UNNAMED search for a named attribute matching @name. Otherwise, |
2332 | * match both named and unnamed attributes. |
2333 | * |
2334 | * On first search @ctx->ntfs_ino must be the inode of the base mft record and |
2335 | * @ctx must have been obtained from a call to ntfs_attr_get_search_ctx(). |
2336 | * On subsequent calls, @ctx->ntfs_ino can be any extent inode, too |
2337 | * (@ctx->base_ntfs_ino is then the base inode). |
2338 | * |
2339 | * After finishing with the attribute/mft record you need to call |
2340 | * ntfs_attr_put_search_ctx() to cleanup the search context (unmapping any |
2341 | * mapped extent inodes, etc). |
2342 | * |
2343 | * Return 0 if the search was successful and -1 if not, with errno set to the |
2344 | * error code. |
2345 | * |
2346 | * On success, @ctx->attr is the found attribute, it is in mft record |
2347 | * @ctx->mrec, and @ctx->al_entry is the attribute list entry for this |
2348 | * attribute with @ctx->base_* being the base mft record to which @ctx->attr |
2349 | * belongs. |
2350 | * |
2351 | * On error ENOENT, i.e. attribute not found, @ctx->attr is set to the |
2352 | * attribute which collates just after the attribute being searched for in the |
2353 | * base ntfs inode, i.e. if one wants to add the attribute to the mft record |
2354 | * this is the correct place to insert it into, and if there is not enough |
2355 | * space, the attribute should be placed in an extent mft record. |
2356 | * @ctx->al_entry points to the position within @ctx->base_ntfs_ino->attr_list |
2357 | * at which the new attribute's attribute list entry should be inserted. The |
2358 | * other @ctx fields, base_ntfs_ino, base_mrec, and base_attr are set to NULL. |
2359 | * The only exception to this is when @type is AT_END, in which case |
2360 | * @ctx->al_entry is set to NULL also (see above). |
2361 | * |
2362 | * The following error codes are defined: |
2363 | * ENOENT Attribute not found, not an error as such. |
2364 | * EINVAL Invalid arguments. |
2365 | * EIO I/O error or corrupt data structures found. |
2366 | * ENOMEM Not enough memory to allocate necessary buffers. |
2367 | */ |
2368 | static int ntfs_external_attr_find(ATTR_TYPES type, const ntfschar *name, |
2369 | const u32 name_len, const IGNORE_CASE_BOOL ic, |
2370 | const VCN lowest_vcn, const u8 *val, const u32 val_len, |
2371 | ntfs_attr_search_ctx *ctx) |
2372 | { |
2373 | ntfs_inode *base_ni, *ni; |
2374 | ntfs_volume *vol; |
2375 | ATTR_LIST_ENTRY *al_entry, *next_al_entry; |
2376 | u8 *al_start, *al_end; |
2377 | ATTR_RECORD *a; |
2378 | ntfschar *al_name; |
2379 | u32 al_name_len; |
2380 | BOOL is_first_search = FALSE; |
2381 | |
2382 | ni = ctx->ntfs_ino; |
2383 | base_ni = ctx->base_ntfs_ino; |
2384 | ntfs_log_trace("Entering for inode %lld, attribute type 0x%x.\n", |
2385 | (unsigned long long)ni->mft_no, type); |
2386 | if (!base_ni) { |
2387 | /* First call happens with the base mft record. */ |
2388 | base_ni = ctx->base_ntfs_ino = ctx->ntfs_ino; |
2389 | ctx->base_mrec = ctx->mrec; |
2390 | } |
2391 | if (ni == base_ni) |
2392 | ctx->base_attr = ctx->attr; |
2393 | if (type == AT_END) |
2394 | goto not_found; |
2395 | vol = base_ni->vol; |
2396 | al_start = base_ni->attr_list; |
2397 | al_end = al_start + base_ni->attr_list_size; |
2398 | if (!ctx->al_entry) { |
2399 | ctx->al_entry = (ATTR_LIST_ENTRY*)al_start; |
2400 | is_first_search = TRUE; |
2401 | } |
2402 | /* |
2403 | * Iterate over entries in attribute list starting at @ctx->al_entry, |
2404 | * or the entry following that, if @ctx->is_first is TRUE. |
2405 | */ |
2406 | if (ctx->is_first) { |
2407 | al_entry = ctx->al_entry; |
2408 | ctx->is_first = FALSE; |
2409 | /* |
2410 | * If an enumeration and the first attribute is higher than |
2411 | * the attribute list itself, need to return the attribute list |
2412 | * attribute. |
2413 | */ |
2414 | if ((type == AT_UNUSED) && is_first_search && |
2415 | le32_to_cpu(al_entry->type) > |
2416 | le32_to_cpu(AT_ATTRIBUTE_LIST)) |
2417 | goto find_attr_list_attr; |
2418 | } else { |
2419 | al_entry = (ATTR_LIST_ENTRY*)((char*)ctx->al_entry + |
2420 | le16_to_cpu(ctx->al_entry->length)); |
2421 | /* |
2422 | * If this is an enumeration and the attribute list attribute |
2423 | * is the next one in the enumeration sequence, just return the |
2424 | * attribute list attribute from the base mft record as it is |
2425 | * not listed in the attribute list itself. |
2426 | */ |
2427 | if ((type == AT_UNUSED) && le32_to_cpu(ctx->al_entry->type) < |
2428 | le32_to_cpu(AT_ATTRIBUTE_LIST) && |
2429 | le32_to_cpu(al_entry->type) > |
2430 | le32_to_cpu(AT_ATTRIBUTE_LIST)) { |
2431 | int rc; |
2432 | find_attr_list_attr: |
2433 | |
2434 | /* Check for bogus calls. */ |
2435 | if (name || name_len || val || val_len || lowest_vcn) { |
2436 | errno = EINVAL; |
2437 | ntfs_log_perror("%s", __FUNCTION__); |
2438 | return -1; |
2439 | } |
2440 | |
2441 | /* We want the base record. */ |
2442 | ctx->ntfs_ino = base_ni; |
2443 | ctx->mrec = ctx->base_mrec; |
2444 | ctx->is_first = TRUE; |
2445 | /* Sanity checks are performed elsewhere. */ |
2446 | ctx->attr = (ATTR_RECORD*)((u8*)ctx->mrec + |
2447 | le16_to_cpu(ctx->mrec->attrs_offset)); |
2448 | |
2449 | /* Find the attribute list attribute. */ |
2450 | rc = ntfs_attr_find(AT_ATTRIBUTE_LIST, NULL, 0, |
2451 | IGNORE_CASE, NULL, 0, ctx); |
2452 | |
2453 | /* |
2454 | * Setup the search context so the correct |
2455 | * attribute is returned next time round. |
2456 | */ |
2457 | ctx->al_entry = al_entry; |
2458 | ctx->is_first = TRUE; |
2459 | |
2460 | /* Got it. Done. */ |
2461 | if (!rc) |
2462 | return 0; |
2463 | |
2464 | /* Error! If other than not found return it. */ |
2465 | if (errno != ENOENT) |
2466 | return rc; |
2467 | |
2468 | /* Not found?!? Absurd! */ |
2469 | errno = EIO; |
2470 | ntfs_log_error("Attribute list wasn't found"); |
2471 | return -1; |
2472 | } |
2473 | } |
2474 | for (;; al_entry = next_al_entry) { |
2475 | /* Out of bounds check. */ |
2476 | if ((u8*)al_entry < base_ni->attr_list || |
2477 | (u8*)al_entry > al_end) |
2478 | break; /* Inode is corrupt. */ |
2479 | ctx->al_entry = al_entry; |
2480 | /* Catch the end of the attribute list. */ |
2481 | if ((u8*)al_entry == al_end) |
2482 | goto not_found; |
2483 | if (!al_entry->length) |
2484 | break; |
2485 | if ((u8*)al_entry + 6 > al_end || (u8*)al_entry + |
2486 | le16_to_cpu(al_entry->length) > al_end) |
2487 | break; |
2488 | next_al_entry = (ATTR_LIST_ENTRY*)((u8*)al_entry + |
2489 | le16_to_cpu(al_entry->length)); |
2490 | if (type != AT_UNUSED) { |
2491 | if (le32_to_cpu(al_entry->type) > le32_to_cpu(type)) |
2492 | goto not_found; |
2493 | if (type != al_entry->type) |
2494 | continue; |
2495 | } |
2496 | al_name_len = al_entry->name_length; |
2497 | al_name = (ntfschar*)((u8*)al_entry + al_entry->name_offset); |
2498 | /* |
2499 | * If !@type we want the attribute represented by this |
2500 | * attribute list entry. |
2501 | */ |
2502 | if (type == AT_UNUSED) |
2503 | goto is_enumeration; |
2504 | /* |
2505 | * If @name is AT_UNNAMED we want an unnamed attribute. |
2506 | * If @name is present, compare the two names. |
2507 | * Otherwise, match any attribute. |
2508 | */ |
2509 | if (name == AT_UNNAMED) { |
2510 | if (al_name_len) |
2511 | goto not_found; |
2512 | } else { |
2513 | int rc; |
2514 | |
2515 | if (name && ((rc = ntfs_names_full_collate(name, |
2516 | name_len, al_name, al_name_len, ic, |
2517 | vol->upcase, vol->upcase_len)))) { |
2518 | |
2519 | /* |
2520 | * If @name collates before al_name, |
2521 | * there is no matching attribute. |
2522 | */ |
2523 | if (rc < 0) |
2524 | goto not_found; |
2525 | /* If the strings are not equal, continue search. */ |
2526 | continue; |
2527 | } |
2528 | } |
2529 | /* |
2530 | * The names match or @name not present and attribute is |
2531 | * unnamed. Now check @lowest_vcn. Continue search if the |
2532 | * next attribute list entry still fits @lowest_vcn. Otherwise |
2533 | * we have reached the right one or the search has failed. |
2534 | */ |
2535 | if (lowest_vcn && (u8*)next_al_entry >= al_start && |
2536 | (u8*)next_al_entry + 6 < al_end && |
2537 | (u8*)next_al_entry + le16_to_cpu( |
2538 | next_al_entry->length) <= al_end && |
2539 | sle64_to_cpu(next_al_entry->lowest_vcn) <= |
2540 | lowest_vcn && |
2541 | next_al_entry->type == al_entry->type && |
2542 | next_al_entry->name_length == al_name_len && |
2543 | ntfs_names_are_equal((ntfschar*)((char*) |
2544 | next_al_entry + |
2545 | next_al_entry->name_offset), |
2546 | next_al_entry->name_length, |
2547 | al_name, al_name_len, CASE_SENSITIVE, |
2548 | vol->upcase, vol->upcase_len)) |
2549 | continue; |
2550 | is_enumeration: |
2551 | if (MREF_LE(al_entry->mft_reference) == ni->mft_no) { |
2552 | if (MSEQNO_LE(al_entry->mft_reference) != |
2553 | le16_to_cpu( |
2554 | ni->mrec->sequence_number)) { |
2555 | ntfs_log_error("Found stale mft reference in " |
2556 | "attribute list!\n"); |
2557 | break; |
2558 | } |
2559 | } else { /* Mft references do not match. */ |
2560 | /* Do we want the base record back? */ |
2561 | if (MREF_LE(al_entry->mft_reference) == |
2562 | base_ni->mft_no) { |
2563 | ni = ctx->ntfs_ino = base_ni; |
2564 | ctx->mrec = ctx->base_mrec; |
2565 | } else { |
2566 | /* We want an extent record. */ |
2567 | ni = ntfs_extent_inode_open(base_ni, |
2568 | al_entry->mft_reference); |
2569 | if (!ni) |
2570 | break; |
2571 | ctx->ntfs_ino = ni; |
2572 | ctx->mrec = ni->mrec; |
2573 | } |
2574 | } |
2575 | a = ctx->attr = (ATTR_RECORD*)((char*)ctx->mrec + |
2576 | le16_to_cpu(ctx->mrec->attrs_offset)); |
2577 | /* |
2578 | * ctx->ntfs_ino, ctx->mrec, and ctx->attr now point to the |
2579 | * mft record containing the attribute represented by the |
2580 | * current al_entry. |
2581 | * |
2582 | * We could call into ntfs_attr_find() to find the right |
2583 | * attribute in this mft record but this would be less |
2584 | * efficient and not quite accurate as ntfs_attr_find() ignores |
2585 | * the attribute instance numbers for example which become |
2586 | * important when one plays with attribute lists. Also, because |
2587 | * a proper match has been found in the attribute list entry |
2588 | * above, the comparison can now be optimized. So it is worth |
2589 | * re-implementing a simplified ntfs_attr_find() here. |
2590 | * |
2591 | * Use a manual loop so we can still use break and continue |
2592 | * with the same meanings as above. |
2593 | */ |
2594 | do_next_attr_loop: |
2595 | if ((char*)a < (char*)ctx->mrec || (char*)a > (char*)ctx->mrec + |
2596 | le32_to_cpu(ctx->mrec->bytes_allocated)) |
2597 | break; |
2598 | if (a->type == AT_END) |
2599 | continue; |
2600 | if (!a->length) |
2601 | break; |
2602 | if (al_entry->instance != a->instance) |
2603 | goto do_next_attr; |
2604 | /* |
2605 | * If the type and/or the name are/is mismatched between the |
2606 | * attribute list entry and the attribute record, there is |
2607 | * corruption so we break and return error EIO. |
2608 | */ |
2609 | if (al_entry->type != a->type) |
2610 | break; |
2611 | if (!ntfs_names_are_equal((ntfschar*)((char*)a + |
2612 | le16_to_cpu(a->name_offset)), |
2613 | a->name_length, al_name, |
2614 | al_name_len, CASE_SENSITIVE, |
2615 | vol->upcase, vol->upcase_len)) |
2616 | break; |
2617 | ctx->attr = a; |
2618 | /* |
2619 | * If no @val specified or @val specified and it matches, we |
2620 | * have found it! Also, if !@type, it is an enumeration, so we |
2621 | * want the current attribute. |
2622 | */ |
2623 | if ((type == AT_UNUSED) || !val || (!a->non_resident && |
2624 | le32_to_cpu(a->value_length) == val_len && |
2625 | !memcmp((char*)a + le16_to_cpu(a->value_offset), |
2626 | val, val_len))) { |
2627 | return 0; |
2628 | } |
2629 | do_next_attr: |
2630 | /* Proceed to the next attribute in the current mft record. */ |
2631 | a = (ATTR_RECORD*)((char*)a + le32_to_cpu(a->length)); |
2632 | goto do_next_attr_loop; |
2633 | } |
2634 | if (ni != base_ni) { |
2635 | ctx->ntfs_ino = base_ni; |
2636 | ctx->mrec = ctx->base_mrec; |
2637 | ctx->attr = ctx->base_attr; |
2638 | } |
2639 | errno = EIO; |
2640 | ntfs_log_perror("Inode is corrupt (%lld)", (long long)base_ni->mft_no); |
2641 | return -1; |
2642 | not_found: |
2643 | /* |
2644 | * If we were looking for AT_END or we were enumerating and reached the |
2645 | * end, we reset the search context @ctx and use ntfs_attr_find() to |
2646 | * seek to the end of the base mft record. |
2647 | */ |
2648 | if (type == AT_UNUSED || type == AT_END) { |
2649 | ntfs_attr_reinit_search_ctx(ctx); |
2650 | return ntfs_attr_find(AT_END, name, name_len, ic, val, val_len, |
2651 | ctx); |
2652 | } |
2653 | /* |
2654 | * The attribute wasn't found. Before we return, we want to ensure |
2655 | * @ctx->mrec and @ctx->attr indicate the position at which the |
2656 | * attribute should be inserted in the base mft record. Since we also |
2657 | * want to preserve @ctx->al_entry we cannot reinitialize the search |
2658 | * context using ntfs_attr_reinit_search_ctx() as this would set |
2659 | * @ctx->al_entry to NULL. Thus we do the necessary bits manually (see |
2660 | * ntfs_attr_init_search_ctx() below). Note, we _only_ preserve |
2661 | * @ctx->al_entry as the remaining fields (base_*) are identical to |
2662 | * their non base_ counterparts and we cannot set @ctx->base_attr |
2663 | * correctly yet as we do not know what @ctx->attr will be set to by |
2664 | * the call to ntfs_attr_find() below. |
2665 | */ |
2666 | ctx->mrec = ctx->base_mrec; |
2667 | ctx->attr = (ATTR_RECORD*)((u8*)ctx->mrec + |
2668 | le16_to_cpu(ctx->mrec->attrs_offset)); |
2669 | ctx->is_first = TRUE; |
2670 | ctx->ntfs_ino = ctx->base_ntfs_ino; |
2671 | ctx->base_ntfs_ino = NULL; |
2672 | ctx->base_mrec = NULL; |
2673 | ctx->base_attr = NULL; |
2674 | /* |
2675 | * In case there are multiple matches in the base mft record, need to |
2676 | * keep enumerating until we get an attribute not found response (or |
2677 | * another error), otherwise we would keep returning the same attribute |
2678 | * over and over again and all programs using us for enumeration would |
2679 | * lock up in a tight loop. |
2680 | */ |
2681 | { |
2682 | int ret; |
2683 | |
2684 | do { |
2685 | ret = ntfs_attr_find(type, name, name_len, ic, val, |
2686 | val_len, ctx); |
2687 | } while (!ret); |
2688 | return ret; |
2689 | } |
2690 | } |
2691 | |
2692 | /** |
2693 | * ntfs_attr_lookup - find an attribute in an ntfs inode |
2694 | * @type: attribute type to find |
2695 | * @name: attribute name to find (optional, i.e. NULL means don't care) |
2696 | * @name_len: attribute name length (only needed if @name present) |
2697 | * @ic: IGNORE_CASE or CASE_SENSITIVE (ignored if @name not present) |
2698 | * @lowest_vcn: lowest vcn to find (optional, non-resident attributes only) |
2699 | * @val: attribute value to find (optional, resident attributes only) |
2700 | * @val_len: attribute value length |
2701 | * @ctx: search context with mft record and attribute to search from |
2702 | * |
2703 | * Find an attribute in an ntfs inode. On first search @ctx->ntfs_ino must |
2704 | * be the base mft record and @ctx must have been obtained from a call to |
2705 | * ntfs_attr_get_search_ctx(). |
2706 | * |
2707 | * This function transparently handles attribute lists and @ctx is used to |
2708 | * continue searches where they were left off at. |
2709 | * |
2710 | * If @type is AT_UNUSED, return the first found attribute, i.e. one can |
2711 | * enumerate all attributes by setting @type to AT_UNUSED and then calling |
2712 | * ntfs_attr_lookup() repeatedly until it returns -1 with errno set to ENOENT |
2713 | * to indicate that there are no more entries. During the enumeration, each |
2714 | * successful call of ntfs_attr_lookup() will return the next attribute, with |
2715 | * the current attribute being described by the search context @ctx. |
2716 | * |
2717 | * If @type is AT_END, seek to the end of the base mft record ignoring the |
2718 | * attribute list completely and return -1 with errno set to ENOENT. AT_END is |
2719 | * not a valid attribute, its length is zero for example, thus it is safer to |
2720 | * return error instead of success in this case. It should never be needed to |
2721 | * do this, but we implement the functionality because it allows for simpler |
2722 | * code inside ntfs_external_attr_find(). |
2723 | * |
2724 | * If @name is AT_UNNAMED search for an unnamed attribute. If @name is present |
2725 | * but not AT_UNNAMED search for a named attribute matching @name. Otherwise, |
2726 | * match both named and unnamed attributes. |
2727 | * |
2728 | * After finishing with the attribute/mft record you need to call |
2729 | * ntfs_attr_put_search_ctx() to cleanup the search context (unmapping any |
2730 | * mapped extent inodes, etc). |
2731 | * |
2732 | * Return 0 if the search was successful and -1 if not, with errno set to the |
2733 | * error code. |
2734 | * |
2735 | * On success, @ctx->attr is the found attribute, it is in mft record |
2736 | * @ctx->mrec, and @ctx->al_entry is the attribute list entry for this |
2737 | * attribute with @ctx->base_* being the base mft record to which @ctx->attr |
2738 | * belongs. If no attribute list attribute is present @ctx->al_entry and |
2739 | * @ctx->base_* are NULL. |
2740 | * |
2741 | * On error ENOENT, i.e. attribute not found, @ctx->attr is set to the |
2742 | * attribute which collates just after the attribute being searched for in the |
2743 | * base ntfs inode, i.e. if one wants to add the attribute to the mft record |
2744 | * this is the correct place to insert it into, and if there is not enough |
2745 | * space, the attribute should be placed in an extent mft record. |
2746 | * @ctx->al_entry points to the position within @ctx->base_ntfs_ino->attr_list |
2747 | * at which the new attribute's attribute list entry should be inserted. The |
2748 | * other @ctx fields, base_ntfs_ino, base_mrec, and base_attr are set to NULL. |
2749 | * The only exception to this is when @type is AT_END, in which case |
2750 | * @ctx->al_entry is set to NULL also (see above). |
2751 | * |
2752 | * |
2753 | * The following error codes are defined: |
2754 | * ENOENT Attribute not found, not an error as such. |
2755 | * EINVAL Invalid arguments. |
2756 | * EIO I/O error or corrupt data structures found. |
2757 | * ENOMEM Not enough memory to allocate necessary buffers. |
2758 | */ |
2759 | int ntfs_attr_lookup(const ATTR_TYPES type, const ntfschar *name, |
2760 | const u32 name_len, const IGNORE_CASE_BOOL ic, |
2761 | const VCN lowest_vcn, const u8 *val, const u32 val_len, |
2762 | ntfs_attr_search_ctx *ctx) |
2763 | { |
2764 | ntfs_volume *vol; |
2765 | ntfs_inode *base_ni; |
2766 | int ret = -1; |
2767 | |
2768 | ntfs_log_enter("Entering for attribute type 0x%x\n", type); |
2769 | |
2770 | if (!ctx || !ctx->mrec || !ctx->attr || (name && name != AT_UNNAMED && |
2771 | (!ctx->ntfs_ino || !(vol = ctx->ntfs_ino->vol) || |
2772 | !vol->upcase || !vol->upcase_len))) { |
2773 | errno = EINVAL; |
2774 | ntfs_log_perror("%s", __FUNCTION__); |
2775 | goto out; |
2776 | } |
2777 | |
2778 | if (ctx->base_ntfs_ino) |
2779 | base_ni = ctx->base_ntfs_ino; |
2780 | else |
2781 | base_ni = ctx->ntfs_ino; |
2782 | if (!base_ni || !NInoAttrList(base_ni) || type == AT_ATTRIBUTE_LIST) |
2783 | ret = ntfs_attr_find(type, name, name_len, ic, val, val_len, ctx); |
2784 | else |
2785 | ret = ntfs_external_attr_find(type, name, name_len, ic, |
2786 | lowest_vcn, val, val_len, ctx); |
2787 | out: |
2788 | ntfs_log_leave("\n"); |
2789 | return ret; |
2790 | } |
2791 | |
2792 | /** |
2793 | * ntfs_attr_position - find given or next attribute type in an ntfs inode |
2794 | * @type: attribute type to start lookup |
2795 | * @ctx: search context with mft record and attribute to search from |
2796 | * |
2797 | * Find an attribute type in an ntfs inode or the next attribute which is not |
2798 | * the AT_END attribute. Please see more details at ntfs_attr_lookup. |
2799 | * |
2800 | * Return 0 if the search was successful and -1 if not, with errno set to the |
2801 | * error code. |
2802 | * |
2803 | * The following error codes are defined: |
2804 | * EINVAL Invalid arguments. |
2805 | * EIO I/O error or corrupt data structures found. |
2806 | * ENOMEM Not enough memory to allocate necessary buffers. |
2807 | * ENOSPC No attribute was found after 'type', only AT_END. |
2808 | */ |
2809 | int ntfs_attr_position(const ATTR_TYPES type, ntfs_attr_search_ctx *ctx) |
2810 | { |
2811 | if (ntfs_attr_lookup(type, NULL, 0, CASE_SENSITIVE, 0, NULL, 0, ctx)) { |
2812 | if (errno != ENOENT) |
2813 | return -1; |
2814 | if (ctx->attr->type == AT_END) { |
2815 | errno = ENOSPC; |
2816 | return -1; |
2817 | } |
2818 | } |
2819 | return 0; |
2820 | } |
2821 | |
2822 | /** |
2823 | * ntfs_attr_init_search_ctx - initialize an attribute search context |
2824 | * @ctx: attribute search context to initialize |
2825 | * @ni: ntfs inode with which to initialize the search context |
2826 | * @mrec: mft record with which to initialize the search context |
2827 | * |
2828 | * Initialize the attribute search context @ctx with @ni and @mrec. |
2829 | */ |
2830 | static void ntfs_attr_init_search_ctx(ntfs_attr_search_ctx *ctx, |
2831 | ntfs_inode *ni, MFT_RECORD *mrec) |
2832 | { |
2833 | if (!mrec) |
2834 | mrec = ni->mrec; |
2835 | ctx->mrec = mrec; |
2836 | /* Sanity checks are performed elsewhere. */ |
2837 | ctx->attr = (ATTR_RECORD*)((u8*)mrec + le16_to_cpu(mrec->attrs_offset)); |
2838 | ctx->is_first = TRUE; |
2839 | ctx->ntfs_ino = ni; |
2840 | ctx->al_entry = NULL; |
2841 | ctx->base_ntfs_ino = NULL; |
2842 | ctx->base_mrec = NULL; |
2843 | ctx->base_attr = NULL; |
2844 | } |
2845 | |
2846 | /** |
2847 | * ntfs_attr_reinit_search_ctx - reinitialize an attribute search context |
2848 | * @ctx: attribute search context to reinitialize |
2849 | * |
2850 | * Reinitialize the attribute search context @ctx. |
2851 | * |
2852 | * This is used when a search for a new attribute is being started to reset |
2853 | * the search context to the beginning. |
2854 | */ |
2855 | void ntfs_attr_reinit_search_ctx(ntfs_attr_search_ctx *ctx) |
2856 | { |
2857 | if (!ctx->base_ntfs_ino) { |
2858 | /* No attribute list. */ |
2859 | ctx->is_first = TRUE; |
2860 | /* Sanity checks are performed elsewhere. */ |
2861 | ctx->attr = (ATTR_RECORD*)((u8*)ctx->mrec + |
2862 | le16_to_cpu(ctx->mrec->attrs_offset)); |
2863 | /* |
2864 | * This needs resetting due to ntfs_external_attr_find() which |
2865 | * can leave it set despite having zeroed ctx->base_ntfs_ino. |
2866 | */ |
2867 | ctx->al_entry = NULL; |
2868 | return; |
2869 | } /* Attribute list. */ |
2870 | ntfs_attr_init_search_ctx(ctx, ctx->base_ntfs_ino, ctx->base_mrec); |
2871 | return; |
2872 | } |
2873 | |
2874 | /** |
2875 | * ntfs_attr_get_search_ctx - allocate/initialize a new attribute search context |
2876 | * @ni: ntfs inode with which to initialize the search context |
2877 | * @mrec: mft record with which to initialize the search context |
2878 | * |
2879 | * Allocate a new attribute search context, initialize it with @ni and @mrec, |
2880 | * and return it. Return NULL on error with errno set. |
2881 | * |
2882 | * @mrec can be NULL, in which case the mft record is taken from @ni. |
2883 | * |
2884 | * Note: For low level utilities which know what they are doing we allow @ni to |
2885 | * be NULL and @mrec to be set. Do NOT do this unless you understand the |
2886 | * implications!!! For example it is no longer safe to call ntfs_attr_lookup(). |
2887 | */ |
2888 | ntfs_attr_search_ctx *ntfs_attr_get_search_ctx(ntfs_inode *ni, MFT_RECORD *mrec) |
2889 | { |
2890 | ntfs_attr_search_ctx *ctx; |
2891 | |
2892 | if (!ni && !mrec) { |
2893 | errno = EINVAL; |
2894 | ntfs_log_perror("NULL arguments"); |
2895 | return NULL; |
2896 | } |
2897 | ctx = ntfs_malloc(sizeof(ntfs_attr_search_ctx)); |
2898 | if (ctx) |
2899 | ntfs_attr_init_search_ctx(ctx, ni, mrec); |
2900 | return ctx; |
2901 | } |
2902 | |
2903 | /** |
2904 | * ntfs_attr_put_search_ctx - release an attribute search context |
2905 | * @ctx: attribute search context to free |
2906 | * |
2907 | * Release the attribute search context @ctx. |
2908 | */ |
2909 | void ntfs_attr_put_search_ctx(ntfs_attr_search_ctx *ctx) |
2910 | { |
2911 | // NOTE: save errno if it could change and function stays void! |
2912 | free(ctx); |
2913 | } |
2914 | |
2915 | /** |
2916 | * ntfs_attr_find_in_attrdef - find an attribute in the $AttrDef system file |
2917 | * @vol: ntfs volume to which the attribute belongs |
2918 | * @type: attribute type which to find |
2919 | * |
2920 | * Search for the attribute definition record corresponding to the attribute |
2921 | * @type in the $AttrDef system file. |
2922 | * |
2923 | * Return the attribute type definition record if found and NULL if not found |
2924 | * or an error occurred. On error the error code is stored in errno. The |
2925 | * following error codes are defined: |
2926 | * ENOENT - The attribute @type is not specified in $AttrDef. |
2927 | * EINVAL - Invalid parameters (e.g. @vol is not valid). |
2928 | */ |
2929 | ATTR_DEF *ntfs_attr_find_in_attrdef(const ntfs_volume *vol, |
2930 | const ATTR_TYPES type) |
2931 | { |
2932 | ATTR_DEF *ad; |
2933 | |
2934 | if (!vol || !vol->attrdef || !type) { |
2935 | errno = EINVAL; |
2936 | ntfs_log_perror("%s: type=%d", __FUNCTION__, type); |
2937 | return NULL; |
2938 | } |
2939 | for (ad = vol->attrdef; (u8*)ad - (u8*)vol->attrdef < |
2940 | vol->attrdef_len && ad->type; ++ad) { |
2941 | /* We haven't found it yet, carry on searching. */ |
2942 | if (le32_to_cpu(ad->type) < le32_to_cpu(type)) |
2943 | continue; |
2944 | /* We found the attribute; return it. */ |
2945 | if (ad->type == type) |
2946 | return ad; |
2947 | /* We have gone too far already. No point in continuing. */ |
2948 | break; |
2949 | } |
2950 | errno = ENOENT; |
2951 | ntfs_log_perror("%s: type=%d", __FUNCTION__, type); |
2952 | return NULL; |
2953 | } |
2954 | |
2955 | /** |
2956 | * ntfs_attr_size_bounds_check - check a size of an attribute type for validity |
2957 | * @vol: ntfs volume to which the attribute belongs |
2958 | * @type: attribute type which to check |
2959 | * @size: size which to check |
2960 | * |
2961 | * Check whether the @size in bytes is valid for an attribute of @type on the |
2962 | * ntfs volume @vol. This information is obtained from $AttrDef system file. |
2963 | * |
2964 | * Return 0 if valid and -1 if not valid or an error occurred. On error the |
2965 | * error code is stored in errno. The following error codes are defined: |
2966 | * ERANGE - @size is not valid for the attribute @type. |
2967 | * ENOENT - The attribute @type is not specified in $AttrDef. |
2968 | * EINVAL - Invalid parameters (e.g. @size is < 0 or @vol is not valid). |
2969 | */ |
2970 | int ntfs_attr_size_bounds_check(const ntfs_volume *vol, const ATTR_TYPES type, |
2971 | const s64 size) |
2972 | { |
2973 | ATTR_DEF *ad; |
2974 | s64 min_size, max_size; |
2975 | |
2976 | if (size < 0) { |
2977 | errno = EINVAL; |
2978 | ntfs_log_perror("%s: size=%lld", __FUNCTION__, |
2979 | (long long)size); |
2980 | return -1; |
2981 | } |
2982 | |
2983 | /* |
2984 | * $ATTRIBUTE_LIST shouldn't be greater than 0x40000, otherwise |
2985 | * Windows would crash. This is not listed in the AttrDef. |
2986 | */ |
2987 | if (type == AT_ATTRIBUTE_LIST && size > 0x40000) { |
2988 | errno = ERANGE; |
2989 | ntfs_log_perror("Too large attrlist (%lld)", (long long)size); |
2990 | return -1; |
2991 | } |
2992 | |
2993 | ad = ntfs_attr_find_in_attrdef(vol, type); |
2994 | if (!ad) |
2995 | return -1; |
2996 | |
2997 | min_size = sle64_to_cpu(ad->min_size); |
2998 | max_size = sle64_to_cpu(ad->max_size); |
2999 | |
3000 | if ((min_size && (size < min_size)) || |
3001 | ((max_size > 0) && (size > max_size))) { |
3002 | errno = ERANGE; |
3003 | ntfs_log_perror("Attr type %d size check failed (min,size,max=" |
3004 | "%lld,%lld,%lld)", type, (long long)min_size, |
3005 | (long long)size, (long long)max_size); |
3006 | return -1; |
3007 | } |
3008 | return 0; |
3009 | } |
3010 | |
3011 | /** |
3012 | * ntfs_attr_can_be_non_resident - check if an attribute can be non-resident |
3013 | * @vol: ntfs volume to which the attribute belongs |
3014 | * @type: attribute type to check |
3015 | * @name: attribute name to check |
3016 | * @name_len: attribute name length |
3017 | * |
3018 | * Check whether the attribute of @type and @name with name length @name_len on |
3019 | * the ntfs volume @vol is allowed to be non-resident. This information is |
3020 | * obtained from $AttrDef system file and is augmented by rules imposed by |
3021 | * Microsoft (e.g. see http://support.microsoft.com/kb/974729/). |
3022 | * |
3023 | * Return 0 if the attribute is allowed to be non-resident and -1 if not or an |
3024 | * error occurred. On error the error code is stored in errno. The following |
3025 | * error codes are defined: |
3026 | * EPERM - The attribute is not allowed to be non-resident. |
3027 | * ENOENT - The attribute @type is not specified in $AttrDef. |
3028 | * EINVAL - Invalid parameters (e.g. @vol is not valid). |
3029 | */ |
3030 | static int ntfs_attr_can_be_non_resident(const ntfs_volume *vol, const ATTR_TYPES type, |
3031 | const ntfschar *name, int name_len) |
3032 | { |
3033 | ATTR_DEF *ad; |
3034 | BOOL allowed; |
3035 | |
3036 | /* |
3037 | * Microsoft has decreed that $LOGGED_UTILITY_STREAM attributes with a |
3038 | * name of $TXF_DATA must be resident despite the entry for |
3039 | * $LOGGED_UTILITY_STREAM in $AttrDef allowing them to be non-resident. |
3040 | * Failure to obey this on the root directory mft record of a volume |
3041 | * causes Windows Vista and later to see the volume as a RAW volume and |
3042 | * thus cannot mount it at all. |
3043 | */ |
3044 | if ((type == AT_LOGGED_UTILITY_STREAM) |
3045 | && name |
3046 | && ntfs_names_are_equal(TXF_DATA, 9, name, name_len, |
3047 | CASE_SENSITIVE, vol->upcase, vol->upcase_len)) |
3048 | allowed = FALSE; |
3049 | else { |
3050 | /* Find the attribute definition record in $AttrDef. */ |
3051 | ad = ntfs_attr_find_in_attrdef(vol, type); |
3052 | if (!ad) |
3053 | return -1; |
3054 | /* Check the flags and return the result. */ |
3055 | allowed = !(ad->flags & ATTR_DEF_RESIDENT); |
3056 | } |
3057 | if (!allowed) { |
3058 | errno = EPERM; |
3059 | ntfs_log_trace("Attribute can't be non-resident\n"); |
3060 | return -1; |
3061 | } |
3062 | return 0; |
3063 | } |
3064 | |
3065 | /** |
3066 | * ntfs_attr_can_be_resident - check if an attribute can be resident |
3067 | * @vol: ntfs volume to which the attribute belongs |
3068 | * @type: attribute type which to check |
3069 | * |
3070 | * Check whether the attribute of @type on the ntfs volume @vol is allowed to |
3071 | * be resident. This information is derived from our ntfs knowledge and may |
3072 | * not be completely accurate, especially when user defined attributes are |
3073 | * present. Basically we allow everything to be resident except for index |
3074 | * allocation and extended attribute attributes. |
3075 | * |
3076 | * Return 0 if the attribute is allowed to be resident and -1 if not or an |
3077 | * error occurred. On error the error code is stored in errno. The following |
3078 | * error codes are defined: |
3079 | * EPERM - The attribute is not allowed to be resident. |
3080 | * EINVAL - Invalid parameters (e.g. @vol is not valid). |
3081 | * |
3082 | * Warning: In the system file $MFT the attribute $Bitmap must be non-resident |
3083 | * otherwise windows will not boot (blue screen of death)! We cannot |
3084 | * check for this here as we don't know which inode's $Bitmap is being |
3085 | * asked about so the caller needs to special case this. |
3086 | */ |
3087 | int ntfs_attr_can_be_resident(const ntfs_volume *vol, const ATTR_TYPES type) |
3088 | { |
3089 | if (!vol || !vol->attrdef || !type) { |
3090 | errno = EINVAL; |
3091 | return -1; |
3092 | } |
3093 | if (type != AT_INDEX_ALLOCATION) |
3094 | return 0; |
3095 | |
3096 | ntfs_log_trace("Attribute can't be resident\n"); |
3097 | errno = EPERM; |
3098 | return -1; |
3099 | } |
3100 | |
3101 | /** |
3102 | * ntfs_make_room_for_attr - make room for an attribute inside an mft record |
3103 | * @m: mft record |
3104 | * @pos: position at which to make space |
3105 | * @size: byte size to make available at this position |
3106 | * |
3107 | * @pos points to the attribute in front of which we want to make space. |
3108 | * |
3109 | * Return 0 on success or -1 on error. On error the error code is stored in |
3110 | * errno. Possible error codes are: |
3111 | * ENOSPC - There is not enough space available to complete operation. The |
3112 | * caller has to make space before calling this. |
3113 | * EINVAL - Input parameters were faulty. |
3114 | */ |
3115 | int ntfs_make_room_for_attr(MFT_RECORD *m, u8 *pos, u32 size) |
3116 | { |
3117 | u32 biu; |
3118 | |
3119 | ntfs_log_trace("Entering for pos 0x%d, size %u.\n", |
3120 | (int)(pos - (u8*)m), (unsigned) size); |
3121 | |
3122 | /* Make size 8-byte alignment. */ |
3123 | size = (size + 7) & ~7; |
3124 | |
3125 | /* Rigorous consistency checks. */ |
3126 | if (!m || !pos || pos < (u8*)m) { |
3127 | errno = EINVAL; |
3128 | ntfs_log_perror("%s: pos=%p m=%p", __FUNCTION__, pos, m); |
3129 | return -1; |
3130 | } |
3131 | /* The -8 is for the attribute terminator. */ |
3132 | if (pos - (u8*)m > (int)le32_to_cpu(m->bytes_in_use) - 8) { |
3133 | errno = EINVAL; |
3134 | return -1; |
3135 | } |
3136 | /* Nothing to do. */ |
3137 | if (!size) |
3138 | return 0; |
3139 | |
3140 | biu = le32_to_cpu(m->bytes_in_use); |
3141 | /* Do we have enough space? */ |
3142 | if (biu + size > le32_to_cpu(m->bytes_allocated) || |
3143 | pos + size > (u8*)m + le32_to_cpu(m->bytes_allocated)) { |
3144 | errno = ENOSPC; |
3145 | ntfs_log_trace("No enough space in the MFT record\n"); |
3146 | return -1; |
3147 | } |
3148 | /* Move everything after pos to pos + size. */ |
3149 | memmove(pos + size, pos, biu - (pos - (u8*)m)); |
3150 | /* Update mft record. */ |
3151 | m->bytes_in_use = cpu_to_le32(biu + size); |
3152 | return 0; |
3153 | } |
3154 | |
3155 | /** |
3156 | * ntfs_resident_attr_record_add - add resident attribute to inode |
3157 | * @ni: opened ntfs inode to which MFT record add attribute |
3158 | * @type: type of the new attribute |
3159 | * @name: name of the new attribute |
3160 | * @name_len: name length of the new attribute |
3161 | * @val: value of the new attribute |
3162 | * @size: size of new attribute (length of @val, if @val != NULL) |
3163 | * @flags: flags of the new attribute |
3164 | * |
3165 | * Return offset to attribute from the beginning of the mft record on success |
3166 | * and -1 on error. On error the error code is stored in errno. |
3167 | * Possible error codes are: |
3168 | * EINVAL - Invalid arguments passed to function. |
3169 | * EEXIST - Attribute of such type and with same name already exists. |
3170 | * EIO - I/O error occurred or damaged filesystem. |
3171 | */ |
3172 | int ntfs_resident_attr_record_add(ntfs_inode *ni, ATTR_TYPES type, |
3173 | ntfschar *name, u8 name_len, u8 *val, u32 size, |
3174 | ATTR_FLAGS data_flags) |
3175 | { |
3176 | ntfs_attr_search_ctx *ctx; |
3177 | u32 length; |
3178 | ATTR_RECORD *a; |
3179 | MFT_RECORD *m; |
3180 | int err, offset; |
3181 | ntfs_inode *base_ni; |
3182 | |
3183 | ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x, flags 0x%x.\n", |
3184 | (long long) ni->mft_no, (unsigned) type, (unsigned) data_flags); |
3185 | |
3186 | if (!ni || (!name && name_len)) { |
3187 | errno = EINVAL; |
3188 | return -1; |
3189 | } |
3190 | |
3191 | if (ntfs_attr_can_be_resident(ni->vol, type)) { |
3192 | if (errno == EPERM) |
3193 | ntfs_log_trace("Attribute can't be resident.\n"); |
3194 | else |
3195 | ntfs_log_trace("ntfs_attr_can_be_resident failed.\n"); |
3196 | return -1; |
3197 | } |
3198 | |
3199 | /* Locate place where record should be. */ |
3200 | ctx = ntfs_attr_get_search_ctx(ni, NULL); |
3201 | if (!ctx) |
3202 | return -1; |
3203 | /* |
3204 | * Use ntfs_attr_find instead of ntfs_attr_lookup to find place for |
3205 | * attribute in @ni->mrec, not any extent inode in case if @ni is base |
3206 | * file record. |
3207 | */ |
3208 | if (!ntfs_attr_find(type, name, name_len, CASE_SENSITIVE, val, size, |
3209 | ctx)) { |
3210 | err = EEXIST; |
3211 | ntfs_log_trace("Attribute already present.\n"); |
3212 | goto put_err_out; |
3213 | } |
3214 | if (errno != ENOENT) { |
3215 | err = EIO; |
3216 | goto put_err_out; |
3217 | } |
3218 | a = ctx->attr; |
3219 | m = ctx->mrec; |
3220 | |
3221 | /* Make room for attribute. */ |
3222 | length = offsetof(ATTR_RECORD, resident_end) + |
3223 | ((name_len * sizeof(ntfschar) + 7) & ~7) + |
3224 | ((size + 7) & ~7); |
3225 | if (ntfs_make_room_for_attr(ctx->mrec, (u8*) ctx->attr, length)) { |
3226 | err = errno; |
3227 | ntfs_log_trace("Failed to make room for attribute.\n"); |
3228 | goto put_err_out; |
3229 | } |
3230 | |
3231 | /* Setup record fields. */ |
3232 | offset = ((u8*)a - (u8*)m); |
3233 | a->type = type; |
3234 | a->length = cpu_to_le32(length); |
3235 | a->non_resident = 0; |
3236 | a->name_length = name_len; |
3237 | a->name_offset = (name_len |
3238 | ? cpu_to_le16(offsetof(ATTR_RECORD, resident_end)) |
3239 | : const_cpu_to_le16(0)); |
3240 | a->flags = data_flags; |
3241 | a->instance = m->next_attr_instance; |
3242 | a->value_length = cpu_to_le32(size); |
3243 | a->value_offset = cpu_to_le16(length - ((size + 7) & ~7)); |
3244 | if (val) |
3245 | memcpy((u8*)a + le16_to_cpu(a->value_offset), val, size); |
3246 | else |
3247 | memset((u8*)a + le16_to_cpu(a->value_offset), 0, size); |
3248 | if (type == AT_FILE_NAME) |
3249 | a->resident_flags = RESIDENT_ATTR_IS_INDEXED; |
3250 | else |
3251 | a->resident_flags = 0; |
3252 | if (name_len) |
3253 | memcpy((u8*)a + le16_to_cpu(a->name_offset), |
3254 | name, sizeof(ntfschar) * name_len); |
3255 | m->next_attr_instance = |
3256 | cpu_to_le16((le16_to_cpu(m->next_attr_instance) + 1) & 0xffff); |
3257 | if (ni->nr_extents == -1) |
3258 | base_ni = ni->base_ni; |
3259 | else |
3260 | base_ni = ni; |
3261 | if (type != AT_ATTRIBUTE_LIST && NInoAttrList(base_ni)) { |
3262 | if (ntfs_attrlist_entry_add(ni, a)) { |
3263 | err = errno; |
3264 | ntfs_attr_record_resize(m, a, 0); |
3265 | ntfs_log_trace("Failed add attribute entry to " |
3266 | "ATTRIBUTE_LIST.\n"); |
3267 | goto put_err_out; |
3268 | } |
3269 | } |
3270 | if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY |
3271 | ? type == AT_INDEX_ROOT && name == NTFS_INDEX_I30 |
3272 | : type == AT_DATA && name == AT_UNNAMED) { |
3273 | ni->data_size = size; |
3274 | ni->allocated_size = (size + 7) & ~7; |
3275 | set_nino_flag(ni,KnownSize); |
3276 | } |
3277 | ntfs_inode_mark_dirty(ni); |
3278 | ntfs_attr_put_search_ctx(ctx); |
3279 | return offset; |
3280 | put_err_out: |
3281 | ntfs_attr_put_search_ctx(ctx); |
3282 | errno = err; |
3283 | return -1; |
3284 | } |
3285 | |
3286 | /** |
3287 | * ntfs_non_resident_attr_record_add - add extent of non-resident attribute |
3288 | * @ni: opened ntfs inode to which MFT record add attribute |
3289 | * @type: type of the new attribute extent |
3290 | * @name: name of the new attribute extent |
3291 | * @name_len: name length of the new attribute extent |
3292 | * @lowest_vcn: lowest vcn of the new attribute extent |
3293 | * @dataruns_size: dataruns size of the new attribute extent |
3294 | * @flags: flags of the new attribute extent |
3295 | * |
3296 | * Return offset to attribute from the beginning of the mft record on success |
3297 | * and -1 on error. On error the error code is stored in errno. |
3298 | * Possible error codes are: |
3299 | * EINVAL - Invalid arguments passed to function. |
3300 | * EEXIST - Attribute of such type, with same lowest vcn and with same |
3301 | * name already exists. |
3302 | * EIO - I/O error occurred or damaged filesystem. |
3303 | */ |
3304 | int ntfs_non_resident_attr_record_add(ntfs_inode *ni, ATTR_TYPES type, |
3305 | ntfschar *name, u8 name_len, VCN lowest_vcn, int dataruns_size, |
3306 | ATTR_FLAGS flags) |
3307 | { |
3308 | ntfs_attr_search_ctx *ctx; |
3309 | u32 length; |
3310 | ATTR_RECORD *a; |
3311 | MFT_RECORD *m; |
3312 | ntfs_inode *base_ni; |
3313 | int err, offset; |
3314 | |
3315 | ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x, lowest_vcn %lld, " |
3316 | "dataruns_size %d, flags 0x%x.\n", |
3317 | (long long) ni->mft_no, (unsigned) type, |
3318 | (long long) lowest_vcn, dataruns_size, (unsigned) flags); |
3319 | |
3320 | if (!ni || dataruns_size <= 0 || (!name && name_len)) { |
3321 | errno = EINVAL; |
3322 | return -1; |
3323 | } |
3324 | |
3325 | if (ntfs_attr_can_be_non_resident(ni->vol, type, name, name_len)) { |
3326 | if (errno == EPERM) |
3327 | ntfs_log_perror("Attribute can't be non resident"); |
3328 | else |
3329 | ntfs_log_perror("ntfs_attr_can_be_non_resident failed"); |
3330 | return -1; |
3331 | } |
3332 | |
3333 | /* Locate place where record should be. */ |
3334 | ctx = ntfs_attr_get_search_ctx(ni, NULL); |
3335 | if (!ctx) |
3336 | return -1; |
3337 | /* |
3338 | * Use ntfs_attr_find instead of ntfs_attr_lookup to find place for |
3339 | * attribute in @ni->mrec, not any extent inode in case if @ni is base |
3340 | * file record. |
3341 | */ |
3342 | if (!ntfs_attr_find(type, name, name_len, CASE_SENSITIVE, NULL, 0, |
3343 | ctx)) { |
3344 | err = EEXIST; |
3345 | ntfs_log_perror("Attribute 0x%x already present", type); |
3346 | goto put_err_out; |
3347 | } |
3348 | if (errno != ENOENT) { |
3349 | ntfs_log_perror("ntfs_attr_find failed"); |
3350 | err = EIO; |
3351 | goto put_err_out; |
3352 | } |
3353 | a = ctx->attr; |
3354 | m = ctx->mrec; |
3355 | |
3356 | /* Make room for attribute. */ |
3357 | dataruns_size = (dataruns_size + 7) & ~7; |
3358 | length = offsetof(ATTR_RECORD, compressed_size) + ((sizeof(ntfschar) * |
3359 | name_len + 7) & ~7) + dataruns_size + |
3360 | ((flags & (ATTR_IS_COMPRESSED | ATTR_IS_SPARSE)) ? |
3361 | sizeof(a->compressed_size) : 0); |
3362 | if (ntfs_make_room_for_attr(ctx->mrec, (u8*) ctx->attr, length)) { |
3363 | err = errno; |
3364 | ntfs_log_perror("Failed to make room for attribute"); |
3365 | goto put_err_out; |
3366 | } |
3367 | |
3368 | /* Setup record fields. */ |
3369 | a->type = type; |
3370 | a->length = cpu_to_le32(length); |
3371 | a->non_resident = 1; |
3372 | a->name_length = name_len; |
3373 | a->name_offset = cpu_to_le16(offsetof(ATTR_RECORD, compressed_size) + |
3374 | ((flags & (ATTR_IS_COMPRESSED | ATTR_IS_SPARSE)) ? |
3375 | sizeof(a->compressed_size) : 0)); |
3376 | a->flags = flags; |
3377 | a->instance = m->next_attr_instance; |
3378 | a->lowest_vcn = cpu_to_sle64(lowest_vcn); |
3379 | a->mapping_pairs_offset = cpu_to_le16(length - dataruns_size); |
3380 | a->compression_unit = (flags & ATTR_IS_COMPRESSED) |
3381 | ? STANDARD_COMPRESSION_UNIT : 0; |
3382 | /* If @lowest_vcn == 0, than setup empty attribute. */ |
3383 | if (!lowest_vcn) { |
3384 | a->highest_vcn = cpu_to_sle64(-1); |
3385 | a->allocated_size = 0; |
3386 | a->data_size = 0; |
3387 | a->initialized_size = 0; |
3388 | /* Set empty mapping pairs. */ |
3389 | *((u8*)a + le16_to_cpu(a->mapping_pairs_offset)) = 0; |
3390 | } |
3391 | if (name_len) |
3392 | memcpy((u8*)a + le16_to_cpu(a->name_offset), |
3393 | name, sizeof(ntfschar) * name_len); |
3394 | m->next_attr_instance = |
3395 | cpu_to_le16((le16_to_cpu(m->next_attr_instance) + 1) & 0xffff); |
3396 | if (ni->nr_extents == -1) |
3397 | base_ni = ni->base_ni; |
3398 | else |
3399 | base_ni = ni; |
3400 | if (type != AT_ATTRIBUTE_LIST && NInoAttrList(base_ni)) { |
3401 | if (ntfs_attrlist_entry_add(ni, a)) { |
3402 | err = errno; |
3403 | ntfs_log_perror("Failed add attr entry to attrlist"); |
3404 | ntfs_attr_record_resize(m, a, 0); |
3405 | goto put_err_out; |
3406 | } |
3407 | } |
3408 | ntfs_inode_mark_dirty(ni); |
3409 | /* |
3410 | * Locate offset from start of the MFT record where new attribute is |
3411 | * placed. We need relookup it, because record maybe moved during |
3412 | * update of attribute list. |
3413 | */ |
3414 | ntfs_attr_reinit_search_ctx(ctx); |
3415 | if (ntfs_attr_lookup(type, name, name_len, CASE_SENSITIVE, |
3416 | lowest_vcn, NULL, 0, ctx)) { |
3417 | ntfs_log_perror("%s: attribute lookup failed", __FUNCTION__); |
3418 | ntfs_attr_put_search_ctx(ctx); |
3419 | return -1; |
3420 | |
3421 | } |
3422 | offset = (u8*)ctx->attr - (u8*)ctx->mrec; |
3423 | ntfs_attr_put_search_ctx(ctx); |
3424 | return offset; |
3425 | put_err_out: |
3426 | ntfs_attr_put_search_ctx(ctx); |
3427 | errno = err; |
3428 | return -1; |
3429 | } |
3430 | |
3431 | /** |
3432 | * ntfs_attr_record_rm - remove attribute extent |
3433 | * @ctx: search context describing the attribute which should be removed |
3434 | * |
3435 | * If this function succeed, user should reinit search context if he/she wants |
3436 | * use it anymore. |
3437 | * |
3438 | * Return 0 on success and -1 on error. On error the error code is stored in |
3439 | * errno. Possible error codes are: |
3440 | * EINVAL - Invalid arguments passed to function. |
3441 | * EIO - I/O error occurred or damaged filesystem. |
3442 | */ |
3443 | int ntfs_attr_record_rm(ntfs_attr_search_ctx *ctx) |
3444 | { |
3445 | ntfs_inode *base_ni, *ni; |
3446 | ATTR_TYPES type; |
3447 | |
3448 | if (!ctx || !ctx->ntfs_ino || !ctx->mrec || !ctx->attr) { |
3449 | errno = EINVAL; |
3450 | return -1; |
3451 | } |
3452 | |
3453 | ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x.\n", |
3454 | (long long) ctx->ntfs_ino->mft_no, |
3455 | (unsigned) le32_to_cpu(ctx->attr->type)); |
3456 | type = ctx->attr->type; |
3457 | ni = ctx->ntfs_ino; |
3458 | if (ctx->base_ntfs_ino) |
3459 | base_ni = ctx->base_ntfs_ino; |
3460 | else |
3461 | base_ni = ctx->ntfs_ino; |
3462 | |
3463 | /* Remove attribute itself. */ |
3464 | if (ntfs_attr_record_resize(ctx->mrec, ctx->attr, 0)) { |
3465 | ntfs_log_trace("Couldn't remove attribute record. Bug or damaged MFT " |
3466 | "record.\n"); |
3467 | if (NInoAttrList(base_ni) && type != AT_ATTRIBUTE_LIST) |
3468 | if (ntfs_attrlist_entry_add(ni, ctx->attr)) |
3469 | ntfs_log_trace("Rollback failed. Leaving inconstant " |
3470 | "metadata.\n"); |
3471 | errno = EIO; |
3472 | return -1; |
3473 | } |
3474 | ntfs_inode_mark_dirty(ni); |
3475 | |
3476 | /* |
3477 | * Remove record from $ATTRIBUTE_LIST if present and we don't want |
3478 | * delete $ATTRIBUTE_LIST itself. |
3479 | */ |
3480 | if (NInoAttrList(base_ni) && type != AT_ATTRIBUTE_LIST) { |
3481 | if (ntfs_attrlist_entry_rm(ctx)) { |
3482 | ntfs_log_trace("Couldn't delete record from " |
3483 | "$ATTRIBUTE_LIST.\n"); |
3484 | return -1; |
3485 | } |
3486 | } |
3487 | |
3488 | /* Post $ATTRIBUTE_LIST delete setup. */ |
3489 | if (type == AT_ATTRIBUTE_LIST) { |
3490 | if (NInoAttrList(base_ni) && base_ni->attr_list) |
3491 | free(base_ni->attr_list); |
3492 | base_ni->attr_list = NULL; |
3493 | NInoClearAttrList(base_ni); |
3494 | NInoAttrListClearDirty(base_ni); |
3495 | } |
3496 | |
3497 | /* Free MFT record, if it doesn't contain attributes. */ |
3498 | if (le32_to_cpu(ctx->mrec->bytes_in_use) - |
3499 | le16_to_cpu(ctx->mrec->attrs_offset) == 8) { |
3500 | if (ntfs_mft_record_free(ni->vol, ni)) { |
3501 | // FIXME: We need rollback here. |
3502 | ntfs_log_trace("Couldn't free MFT record.\n"); |
3503 | errno = EIO; |
3504 | return -1; |
3505 | } |
3506 | /* Remove done if we freed base inode. */ |
3507 | if (ni == base_ni) |
3508 | return 0; |
3509 | } |
3510 | |
3511 | if (type == AT_ATTRIBUTE_LIST || !NInoAttrList(base_ni)) |
3512 | return 0; |
3513 | |
3514 | /* Remove attribute list if we don't need it any more. */ |
3515 | if (!ntfs_attrlist_need(base_ni)) { |
3516 | ntfs_attr_reinit_search_ctx(ctx); |
3517 | if (ntfs_attr_lookup(AT_ATTRIBUTE_LIST, NULL, 0, CASE_SENSITIVE, |
3518 | 0, NULL, 0, ctx)) { |
3519 | /* |
3520 | * FIXME: Should we succeed here? Definitely something |
3521 | * goes wrong because NInoAttrList(base_ni) returned |
3522 | * that we have got attribute list. |
3523 | */ |
3524 | ntfs_log_trace("Couldn't find attribute list. Succeed " |
3525 | "anyway.\n"); |
3526 | return 0; |
3527 | } |
3528 | /* Deallocate clusters. */ |
3529 | if (ctx->attr->non_resident) { |
3530 | runlist *al_rl; |
3531 | |
3532 | al_rl = ntfs_mapping_pairs_decompress(base_ni->vol, |
3533 | ctx->attr, NULL); |
3534 | if (!al_rl) { |
3535 | ntfs_log_trace("Couldn't decompress attribute list " |
3536 | "runlist. Succeed anyway.\n"); |
3537 | return 0; |
3538 | } |
3539 | if (ntfs_cluster_free_from_rl(base_ni->vol, al_rl)) { |
3540 | ntfs_log_trace("Leaking clusters! Run chkdsk. " |
3541 | "Couldn't free clusters from " |
3542 | "attribute list runlist.\n"); |
3543 | } |
3544 | free(al_rl); |
3545 | } |
3546 | /* Remove attribute record itself. */ |
3547 | if (ntfs_attr_record_rm(ctx)) { |
3548 | /* |
3549 | * FIXME: Should we succeed here? BTW, chkdsk doesn't |
3550 | * complain if it find MFT record with attribute list, |
3551 | * but without extents. |
3552 | */ |
3553 | ntfs_log_trace("Couldn't remove attribute list. Succeed " |
3554 | "anyway.\n"); |
3555 | return 0; |
3556 | } |
3557 | } |
3558 | return 0; |
3559 | } |
3560 | |
3561 | /** |
3562 | * ntfs_attr_add - add attribute to inode |
3563 | * @ni: opened ntfs inode to which add attribute |
3564 | * @type: type of the new attribute |
3565 | * @name: name in unicode of the new attribute |
3566 | * @name_len: name length in unicode characters of the new attribute |
3567 | * @val: value of new attribute |
3568 | * @size: size of the new attribute / length of @val (if specified) |
3569 | * |
3570 | * @val should always be specified for always resident attributes (eg. FILE_NAME |
3571 | * attribute), for attributes that can become non-resident @val can be NULL |
3572 | * (eg. DATA attribute). @size can be specified even if @val is NULL, in this |
3573 | * case data size will be equal to @size and initialized size will be equal |
3574 | * to 0. |
3575 | * |
3576 | * If inode haven't got enough space to add attribute, add attribute to one of |
3577 | * it extents, if no extents present or no one of them have enough space, than |
3578 | * allocate new extent and add attribute to it. |
3579 | * |
3580 | * If on one of this steps attribute list is needed but not present, than it is |
3581 | * added transparently to caller. So, this function should not be called with |
3582 | * @type == AT_ATTRIBUTE_LIST, if you really need to add attribute list call |
3583 | * ntfs_inode_add_attrlist instead. |
3584 | * |
3585 | * On success return 0. On error return -1 with errno set to the error code. |
3586 | */ |
3587 | int ntfs_attr_add(ntfs_inode *ni, ATTR_TYPES type, |
3588 | ntfschar *name, u8 name_len, u8 *val, s64 size) |
3589 | { |
3590 | u32 attr_rec_size; |
3591 | int err, i, offset; |
3592 | BOOL is_resident; |
3593 | BOOL can_be_non_resident = FALSE; |
3594 | ntfs_inode *attr_ni; |
3595 | ntfs_attr *na; |
3596 | ATTR_FLAGS data_flags; |
3597 | |
3598 | if (!ni || size < 0 || type == AT_ATTRIBUTE_LIST) { |
3599 | errno = EINVAL; |
3600 | ntfs_log_perror("%s: ni=%p size=%lld", __FUNCTION__, ni, |
3601 | (long long)size); |
3602 | return -1; |
3603 | } |
3604 | |
3605 | ntfs_log_trace("Entering for inode %lld, attr %x, size %lld.\n", |
3606 | (long long)ni->mft_no, type, (long long)size); |
3607 | |
3608 | if (ni->nr_extents == -1) |
3609 | ni = ni->base_ni; |
3610 | |
3611 | /* Check the attribute type and the size. */ |
3612 | if (ntfs_attr_size_bounds_check(ni->vol, type, size)) { |
3613 | if (errno == ENOENT) |
3614 | errno = EIO; |
3615 | return -1; |
3616 | } |
3617 | |
3618 | /* Sanity checks for always resident attributes. */ |
3619 | if (ntfs_attr_can_be_non_resident(ni->vol, type, name, name_len)) { |
3620 | if (errno != EPERM) { |
3621 | err = errno; |
3622 | ntfs_log_perror("ntfs_attr_can_be_non_resident failed"); |
3623 | goto err_out; |
3624 | } |
3625 | /* @val is mandatory. */ |
3626 | if (!val) { |
3627 | errno = EINVAL; |
3628 | ntfs_log_perror("val is mandatory for always resident " |
3629 | "attributes"); |
3630 | return -1; |
3631 | } |
3632 | if (size > ni->vol->mft_record_size) { |
3633 | errno = ERANGE; |
3634 | ntfs_log_perror("Attribute is too big"); |
3635 | return -1; |
3636 | } |
3637 | } else |
3638 | can_be_non_resident = TRUE; |
3639 | |
3640 | /* |
3641 | * Determine resident or not will be new attribute. We add 8 to size in |
3642 | * non resident case for mapping pairs. |
3643 | */ |
3644 | if (!ntfs_attr_can_be_resident(ni->vol, type)) { |
3645 | is_resident = TRUE; |
3646 | } else { |
3647 | if (errno != EPERM) { |
3648 | err = errno; |
3649 | ntfs_log_perror("ntfs_attr_can_be_resident failed"); |
3650 | goto err_out; |
3651 | } |
3652 | is_resident = FALSE; |
3653 | } |
3654 | /* Calculate attribute record size. */ |
3655 | if (is_resident) |
3656 | attr_rec_size = offsetof(ATTR_RECORD, resident_end) + |
3657 | ((name_len * sizeof(ntfschar) + 7) & ~7) + |
3658 | ((size + 7) & ~7); |
3659 | else |
3660 | attr_rec_size = offsetof(ATTR_RECORD, non_resident_end) + |
3661 | ((name_len * sizeof(ntfschar) + 7) & ~7) + 8; |
3662 | |
3663 | /* |
3664 | * If we have enough free space for the new attribute in the base MFT |
3665 | * record, then add attribute to it. |
3666 | */ |
3667 | if (le32_to_cpu(ni->mrec->bytes_allocated) - |
3668 | le32_to_cpu(ni->mrec->bytes_in_use) >= attr_rec_size) { |
3669 | attr_ni = ni; |
3670 | goto add_attr_record; |
3671 | } |
3672 | |
3673 | /* Try to add to extent inodes. */ |
3674 | if (ntfs_inode_attach_all_extents(ni)) { |
3675 | err = errno; |
3676 | ntfs_log_perror("Failed to attach all extents to inode"); |
3677 | goto err_out; |
3678 | } |
3679 | for (i = 0; i < ni->nr_extents; i++) { |
3680 | attr_ni = ni->extent_nis[i]; |
3681 | if (le32_to_cpu(attr_ni->mrec->bytes_allocated) - |
3682 | le32_to_cpu(attr_ni->mrec->bytes_in_use) >= |
3683 | attr_rec_size) |
3684 | goto add_attr_record; |
3685 | } |
3686 | |
3687 | /* There is no extent that contain enough space for new attribute. */ |
3688 | if (!NInoAttrList(ni)) { |
3689 | /* Add attribute list not present, add it and retry. */ |
3690 | if (ntfs_inode_add_attrlist(ni)) { |
3691 | err = errno; |
3692 | ntfs_log_perror("Failed to add attribute list"); |
3693 | goto err_out; |
3694 | } |
3695 | return ntfs_attr_add(ni, type, name, name_len, val, size); |
3696 | } |
3697 | /* Allocate new extent. */ |
3698 | attr_ni = ntfs_mft_record_alloc(ni->vol, ni); |
3699 | if (!attr_ni) { |
3700 | err = errno; |
3701 | ntfs_log_perror("Failed to allocate extent record"); |
3702 | goto err_out; |
3703 | } |
3704 | |
3705 | add_attr_record: |
3706 | if ((ni->flags & FILE_ATTR_COMPRESSED) |
3707 | && (ni->vol->cluster_size <= MAX_COMPRESSION_CLUSTER_SIZE) |
3708 | && ((type == AT_DATA) |
3709 | || ((type == AT_INDEX_ROOT) && (name == NTFS_INDEX_I30)))) |
3710 | data_flags = ATTR_IS_COMPRESSED; |
3711 | else |
3712 | data_flags = const_cpu_to_le16(0); |
3713 | if (is_resident) { |
3714 | /* Add resident attribute. */ |
3715 | offset = ntfs_resident_attr_record_add(attr_ni, type, name, |
3716 | name_len, val, size, data_flags); |
3717 | if (offset < 0) { |
3718 | if (errno == ENOSPC && can_be_non_resident) |
3719 | goto add_non_resident; |
3720 | err = errno; |
3721 | ntfs_log_perror("Failed to add resident attribute"); |
3722 | goto free_err_out; |
3723 | } |
3724 | return 0; |
3725 | } |
3726 | |
3727 | add_non_resident: |
3728 | /* Add non resident attribute. */ |
3729 | offset = ntfs_non_resident_attr_record_add(attr_ni, type, name, |
3730 | name_len, 0, 8, data_flags); |
3731 | if (offset < 0) { |
3732 | err = errno; |
3733 | ntfs_log_perror("Failed to add non resident attribute"); |
3734 | goto free_err_out; |
3735 | } |
3736 | |
3737 | /* If @size == 0, we are done. */ |
3738 | if (!size) |
3739 | return 0; |
3740 | |
3741 | /* Open new attribute and resize it. */ |
3742 | na = ntfs_attr_open(ni, type, name, name_len); |
3743 | if (!na) { |
3744 | err = errno; |
3745 | ntfs_log_perror("Failed to open just added attribute"); |
3746 | goto rm_attr_err_out; |
3747 | } |
3748 | /* Resize and set attribute value. */ |
3749 | if (ntfs_attr_truncate(na, size) || |
3750 | (val && (ntfs_attr_pwrite(na, 0, size, val) != size))) { |
3751 | err = errno; |
3752 | ntfs_log_perror("Failed to initialize just added attribute"); |
3753 | if (ntfs_attr_rm(na)) |
3754 | ntfs_log_perror("Failed to remove just added attribute"); |
3755 | ntfs_attr_close(na); |
3756 | goto err_out; |
3757 | } |
3758 | ntfs_attr_close(na); |
3759 | return 0; |
3760 | |
3761 | rm_attr_err_out: |
3762 | /* Remove just added attribute. */ |
3763 | if (ntfs_attr_record_resize(attr_ni->mrec, |
3764 | (ATTR_RECORD*)((u8*)attr_ni->mrec + offset), 0)) |
3765 | ntfs_log_perror("Failed to remove just added attribute #2"); |
3766 | free_err_out: |
3767 | /* Free MFT record, if it doesn't contain attributes. */ |
3768 | if (le32_to_cpu(attr_ni->mrec->bytes_in_use) - |
3769 | le16_to_cpu(attr_ni->mrec->attrs_offset) == 8) |
3770 | if (ntfs_mft_record_free(attr_ni->vol, attr_ni)) |
3771 | ntfs_log_perror("Failed to free MFT record"); |
3772 | err_out: |
3773 | errno = err; |
3774 | return -1; |
3775 | } |
3776 | |
3777 | /* |
3778 | * Change an attribute flag |
3779 | */ |
3780 | |
3781 | int ntfs_attr_set_flags(ntfs_inode *ni, ATTR_TYPES type, |
3782 | ntfschar *name, u8 name_len, ATTR_FLAGS flags, ATTR_FLAGS mask) |
3783 | { |
3784 | ntfs_attr_search_ctx *ctx; |
3785 | int res; |
3786 | |
3787 | res = -1; |
3788 | /* Search for designated attribute */ |
3789 | ctx = ntfs_attr_get_search_ctx(ni, NULL); |
3790 | if (ctx) { |
3791 | if (!ntfs_attr_lookup(type, name, name_len, |
3792 | CASE_SENSITIVE, 0, NULL, 0, ctx)) { |
3793 | /* do the requested change (all small endian le16) */ |
3794 | ctx->attr->flags = (ctx->attr->flags & ~mask) |
3795 | | (flags & mask); |
3796 | NInoSetDirty(ni); |
3797 | res = 0; |
3798 | } |
3799 | ntfs_attr_put_search_ctx(ctx); |
3800 | } |
3801 | return (res); |
3802 | } |
3803 | |
3804 | |
3805 | /** |
3806 | * ntfs_attr_rm - remove attribute from ntfs inode |
3807 | * @na: opened ntfs attribute to delete |
3808 | * |
3809 | * Remove attribute and all it's extents from ntfs inode. If attribute was non |
3810 | * resident also free all clusters allocated by attribute. |
3811 | * |
3812 | * Return 0 on success or -1 on error with errno set to the error code. |
3813 | */ |
3814 | int ntfs_attr_rm(ntfs_attr *na) |
3815 | { |
3816 | ntfs_attr_search_ctx *ctx; |
3817 | int ret = 0; |
3818 | |
3819 | if (!na) { |
3820 | ntfs_log_trace("Invalid arguments passed.\n"); |
3821 | errno = EINVAL; |
3822 | return -1; |
3823 | } |
3824 | |
3825 | ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x.\n", |
3826 | (long long) na->ni->mft_no, na->type); |
3827 | |
3828 | /* Free cluster allocation. */ |
3829 | if (NAttrNonResident(na)) { |
3830 | if (ntfs_attr_map_whole_runlist(na)) |
3831 | return -1; |
3832 | if (ntfs_cluster_free(na->ni->vol, na, 0, -1) < 0) { |
3833 | ntfs_log_trace("Failed to free cluster allocation. Leaving " |
3834 | "inconstant metadata.\n"); |
3835 | ret = -1; |
3836 | } |
3837 | } |
3838 | |
3839 | /* Search for attribute extents and remove them all. */ |
3840 | ctx = ntfs_attr_get_search_ctx(na->ni, NULL); |
3841 | if (!ctx) |
3842 | return -1; |
3843 | while (!ntfs_attr_lookup(na->type, na->name, na->name_len, |
3844 | CASE_SENSITIVE, 0, NULL, 0, ctx)) { |
3845 | if (ntfs_attr_record_rm(ctx)) { |
3846 | ntfs_log_trace("Failed to remove attribute extent. Leaving " |
3847 | "inconstant metadata.\n"); |
3848 | ret = -1; |
3849 | } |
3850 | ntfs_attr_reinit_search_ctx(ctx); |
3851 | } |
3852 | ntfs_attr_put_search_ctx(ctx); |
3853 | if (errno != ENOENT) { |
3854 | ntfs_log_trace("Attribute lookup failed. Probably leaving inconstant " |
3855 | "metadata.\n"); |
3856 | ret = -1; |
3857 | } |
3858 | |
3859 | return ret; |
3860 | } |
3861 | |
3862 | /** |
3863 | * ntfs_attr_record_resize - resize an attribute record |
3864 | * @m: mft record containing attribute record |
3865 | * @a: attribute record to resize |
3866 | * @new_size: new size in bytes to which to resize the attribute record @a |
3867 | * |
3868 | * Resize the attribute record @a, i.e. the resident part of the attribute, in |
3869 | * the mft record @m to @new_size bytes. |
3870 | * |
3871 | * Return 0 on success and -1 on error with errno set to the error code. |
3872 | * The following error codes are defined: |
3873 | * ENOSPC - Not enough space in the mft record @m to perform the resize. |
3874 | * Note that on error no modifications have been performed whatsoever. |
3875 | * |
3876 | * Warning: If you make a record smaller without having copied all the data you |
3877 | * are interested in the data may be overwritten! |
3878 | */ |
3879 | int ntfs_attr_record_resize(MFT_RECORD *m, ATTR_RECORD *a, u32 new_size) |
3880 | { |
3881 | u32 old_size, alloc_size, attr_size; |
3882 | |
3883 | old_size = le32_to_cpu(m->bytes_in_use); |
3884 | alloc_size = le32_to_cpu(m->bytes_allocated); |
3885 | attr_size = le32_to_cpu(a->length); |
3886 | |
3887 | ntfs_log_trace("Sizes: old=%u alloc=%u attr=%u new=%u\n", |
3888 | (unsigned)old_size, (unsigned)alloc_size, |
3889 | (unsigned)attr_size, (unsigned)new_size); |
3890 | |
3891 | /* Align to 8 bytes, just in case the caller hasn't. */ |
3892 | new_size = (new_size + 7) & ~7; |
3893 | |
3894 | /* If the actual attribute length has changed, move things around. */ |
3895 | if (new_size != attr_size) { |
3896 | |
3897 | u32 new_muse = old_size - attr_size + new_size; |
3898 | |
3899 | /* Not enough space in this mft record. */ |
3900 | if (new_muse > alloc_size) { |
3901 | errno = ENOSPC; |
3902 | ntfs_log_trace("Not enough space in the MFT record " |
3903 | "(%u > %u)\n", new_muse, alloc_size); |
3904 | return -1; |
3905 | } |
3906 | |
3907 | if (a->type == AT_INDEX_ROOT && new_size > attr_size && |
3908 | new_muse + 120 > alloc_size && old_size + 120 <= alloc_size) { |
3909 | errno = ENOSPC; |
3910 | ntfs_log_trace("Too big INDEX_ROOT (%u > %u)\n", |
3911 | new_muse, alloc_size); |
3912 | return STATUS_RESIDENT_ATTRIBUTE_FILLED_MFT; |
3913 | } |
3914 | |
3915 | /* Move attributes following @a to their new location. */ |
3916 | memmove((u8 *)a + new_size, (u8 *)a + attr_size, |
3917 | old_size - ((u8 *)a - (u8 *)m) - attr_size); |
3918 | |
3919 | /* Adjust @m to reflect the change in used space. */ |
3920 | m->bytes_in_use = cpu_to_le32(new_muse); |
3921 | |
3922 | /* Adjust @a to reflect the new size. */ |
3923 | if (new_size >= offsetof(ATTR_REC, length) + sizeof(a->length)) |
3924 | a->length = cpu_to_le32(new_size); |
3925 | } |
3926 | return 0; |
3927 | } |
3928 | |
3929 | /** |
3930 | * ntfs_resident_attr_value_resize - resize the value of a resident attribute |
3931 | * @m: mft record containing attribute record |
3932 | * @a: attribute record whose value to resize |
3933 | * @new_size: new size in bytes to which to resize the attribute value of @a |
3934 | * |
3935 | * Resize the value of the attribute @a in the mft record @m to @new_size bytes. |
3936 | * If the value is made bigger, the newly "allocated" space is cleared. |
3937 | * |
3938 | * Return 0 on success and -1 on error with errno set to the error code. |
3939 | * The following error codes are defined: |
3940 | * ENOSPC - Not enough space in the mft record @m to perform the resize. |
3941 | * Note that on error no modifications have been performed whatsoever. |
3942 | */ |
3943 | int ntfs_resident_attr_value_resize(MFT_RECORD *m, ATTR_RECORD *a, |
3944 | const u32 new_size) |
3945 | { |
3946 | int ret; |
3947 | |
3948 | ntfs_log_trace("Entering for new size %u.\n", (unsigned)new_size); |
3949 | |
3950 | /* Resize the resident part of the attribute record. */ |
3951 | if ((ret = ntfs_attr_record_resize(m, a, (le16_to_cpu(a->value_offset) + |
3952 | new_size + 7) & ~7)) < 0) |
3953 | return ret; |
3954 | /* |
3955 | * If we made the attribute value bigger, clear the area between the |
3956 | * old size and @new_size. |
3957 | */ |
3958 | if (new_size > le32_to_cpu(a->value_length)) |
3959 | memset((u8*)a + le16_to_cpu(a->value_offset) + |
3960 | le32_to_cpu(a->value_length), 0, new_size - |
3961 | le32_to_cpu(a->value_length)); |
3962 | /* Finally update the length of the attribute value. */ |
3963 | a->value_length = cpu_to_le32(new_size); |
3964 | return 0; |
3965 | } |
3966 | |
3967 | /** |
3968 | * ntfs_attr_record_move_to - move attribute record to target inode |
3969 | * @ctx: attribute search context describing the attribute record |
3970 | * @ni: opened ntfs inode to which move attribute record |
3971 | * |
3972 | * If this function succeed, user should reinit search context if he/she wants |
3973 | * use it anymore. |
3974 | * |
3975 | * Return 0 on success and -1 on error with errno set to the error code. |
3976 | */ |
3977 | int ntfs_attr_record_move_to(ntfs_attr_search_ctx *ctx, ntfs_inode *ni) |
3978 | { |
3979 | ntfs_attr_search_ctx *nctx; |
3980 | ATTR_RECORD *a; |
3981 | int err; |
3982 | |
3983 | if (!ctx || !ctx->attr || !ctx->ntfs_ino || !ni) { |
3984 | ntfs_log_trace("Invalid arguments passed.\n"); |
3985 | errno = EINVAL; |
3986 | return -1; |
3987 | } |
3988 | |
3989 | ntfs_log_trace("Entering for ctx->attr->type 0x%x, ctx->ntfs_ino->mft_no " |
3990 | "0x%llx, ni->mft_no 0x%llx.\n", |
3991 | (unsigned) le32_to_cpu(ctx->attr->type), |
3992 | (long long) ctx->ntfs_ino->mft_no, |
3993 | (long long) ni->mft_no); |
3994 | |
3995 | if (ctx->ntfs_ino == ni) |
3996 | return 0; |
3997 | |
3998 | if (!ctx->al_entry) { |
3999 | ntfs_log_trace("Inode should contain attribute list to use this " |
4000 | "function.\n"); |
4001 | errno = EINVAL; |
4002 | return -1; |
4003 | } |
4004 | |
4005 | /* Find place in MFT record where attribute will be moved. */ |
4006 | a = ctx->attr; |
4007 | nctx = ntfs_attr_get_search_ctx(ni, NULL); |
4008 | if (!nctx) |
4009 | return -1; |
4010 | |
4011 | /* |
4012 | * Use ntfs_attr_find instead of ntfs_attr_lookup to find place for |
4013 | * attribute in @ni->mrec, not any extent inode in case if @ni is base |
4014 | * file record. |
4015 | */ |
4016 | if (!ntfs_attr_find(a->type, (ntfschar*)((u8*)a + le16_to_cpu( |
4017 | a->name_offset)), a->name_length, CASE_SENSITIVE, NULL, |
4018 | 0, nctx)) { |
4019 | ntfs_log_trace("Attribute of such type, with same name already " |
4020 | "present in this MFT record.\n"); |
4021 | err = EEXIST; |
4022 | goto put_err_out; |
4023 | } |
4024 | if (errno != ENOENT) { |
4025 | err = errno; |
4026 | ntfs_log_debug("Attribute lookup failed.\n"); |
4027 | goto put_err_out; |
4028 | } |
4029 | |
4030 | /* Make space and move attribute. */ |
4031 | if (ntfs_make_room_for_attr(ni->mrec, (u8*) nctx->attr, |
4032 | le32_to_cpu(a->length))) { |
4033 | err = errno; |
4034 | ntfs_log_trace("Couldn't make space for attribute.\n"); |
4035 | goto put_err_out; |
4036 | } |
4037 | memcpy(nctx->attr, a, le32_to_cpu(a->length)); |
4038 | nctx->attr->instance = nctx->mrec->next_attr_instance; |
4039 | nctx->mrec->next_attr_instance = cpu_to_le16( |
4040 | (le16_to_cpu(nctx->mrec->next_attr_instance) + 1) & 0xffff); |
4041 | ntfs_attr_record_resize(ctx->mrec, a, 0); |
4042 | ntfs_inode_mark_dirty(ctx->ntfs_ino); |
4043 | ntfs_inode_mark_dirty(ni); |
4044 | |
4045 | /* Update attribute list. */ |
4046 | ctx->al_entry->mft_reference = |
4047 | MK_LE_MREF(ni->mft_no, le16_to_cpu(ni->mrec->sequence_number)); |
4048 | ctx->al_entry->instance = nctx->attr->instance; |
4049 | ntfs_attrlist_mark_dirty(ni); |
4050 | |
4051 | ntfs_attr_put_search_ctx(nctx); |
4052 | return 0; |
4053 | put_err_out: |
4054 | ntfs_attr_put_search_ctx(nctx); |
4055 | errno = err; |
4056 | return -1; |
4057 | } |
4058 | |
4059 | /** |
4060 | * ntfs_attr_record_move_away - move away attribute record from it's mft record |
4061 | * @ctx: attribute search context describing the attribute record |
4062 | * @extra: minimum amount of free space in the new holder of record |
4063 | * |
4064 | * New attribute record holder must have free @extra bytes after moving |
4065 | * attribute record to it. |
4066 | * |
4067 | * If this function succeed, user should reinit search context if he/she wants |
4068 | * use it anymore. |
4069 | * |
4070 | * Return 0 on success and -1 on error with errno set to the error code. |
4071 | */ |
4072 | int ntfs_attr_record_move_away(ntfs_attr_search_ctx *ctx, int extra) |
4073 | { |
4074 | ntfs_inode *base_ni, *ni; |
4075 | MFT_RECORD *m; |
4076 | int i; |
4077 | |
4078 | if (!ctx || !ctx->attr || !ctx->ntfs_ino || extra < 0) { |
4079 | errno = EINVAL; |
4080 | ntfs_log_perror("%s: ctx=%p ctx->attr=%p extra=%d", __FUNCTION__, |
4081 | ctx, ctx ? ctx->attr : NULL, extra); |
4082 | return -1; |
4083 | } |
4084 | |
4085 | ntfs_log_trace("Entering for attr 0x%x, inode %llu\n", |
4086 | (unsigned) le32_to_cpu(ctx->attr->type), |
4087 | (unsigned long long)ctx->ntfs_ino->mft_no); |
4088 | |
4089 | if (ctx->ntfs_ino->nr_extents == -1) |
4090 | base_ni = ctx->base_ntfs_ino; |
4091 | else |
4092 | base_ni = ctx->ntfs_ino; |
4093 | |
4094 | if (!NInoAttrList(base_ni)) { |
4095 | errno = EINVAL; |
4096 | ntfs_log_perror("Inode %llu has no attrlist", |
4097 | (unsigned long long)base_ni->mft_no); |
4098 | return -1; |
4099 | } |
4100 | |
4101 | if (ntfs_inode_attach_all_extents(ctx->ntfs_ino)) { |
4102 | ntfs_log_perror("Couldn't attach extents, inode=%llu", |
4103 | (unsigned long long)base_ni->mft_no); |
4104 | return -1; |
4105 | } |
4106 | |
4107 | /* Walk through all extents and try to move attribute to them. */ |
4108 | for (i = 0; i < base_ni->nr_extents; i++) { |
4109 | ni = base_ni->extent_nis[i]; |
4110 | m = ni->mrec; |
4111 | |
4112 | if (ctx->ntfs_ino->mft_no == ni->mft_no) |
4113 | continue; |
4114 | |
4115 | if (le32_to_cpu(m->bytes_allocated) - |
4116 | le32_to_cpu(m->bytes_in_use) < |
4117 | le32_to_cpu(ctx->attr->length) + extra) |
4118 | continue; |
4119 | |
4120 | /* |
4121 | * ntfs_attr_record_move_to can fail if extent with other lowest |
4122 | * VCN already present in inode we trying move record to. So, |
4123 | * do not return error. |
4124 | */ |
4125 | if (!ntfs_attr_record_move_to(ctx, ni)) |
4126 | return 0; |
4127 | } |
4128 | |
4129 | /* |
4130 | * Failed to move attribute to one of the current extents, so allocate |
4131 | * new extent and move attribute to it. |
4132 | */ |
4133 | ni = ntfs_mft_record_alloc(base_ni->vol, base_ni); |
4134 | if (!ni) { |
4135 | ntfs_log_perror("Couldn't allocate MFT record"); |
4136 | return -1; |
4137 | } |
4138 | if (ntfs_attr_record_move_to(ctx, ni)) { |
4139 | ntfs_log_perror("Couldn't move attribute to MFT record"); |
4140 | return -1; |
4141 | } |
4142 | return 0; |
4143 | } |
4144 | |
4145 | /** |
4146 | * ntfs_attr_make_non_resident - convert a resident to a non-resident attribute |
4147 | * @na: open ntfs attribute to make non-resident |
4148 | * @ctx: ntfs search context describing the attribute |
4149 | * |
4150 | * Convert a resident ntfs attribute to a non-resident one. |
4151 | * |
4152 | * Return 0 on success and -1 on error with errno set to the error code. The |
4153 | * following error codes are defined: |
4154 | * EPERM - The attribute is not allowed to be non-resident. |
4155 | * TODO: others... |
4156 | * |
4157 | * NOTE to self: No changes in the attribute list are required to move from |
4158 | * a resident to a non-resident attribute. |
4159 | * |
4160 | * Warning: We do not set the inode dirty and we do not write out anything! |
4161 | * We expect the caller to do this as this is a fairly low level |
4162 | * function and it is likely there will be further changes made. |
4163 | */ |
4164 | int ntfs_attr_make_non_resident(ntfs_attr *na, |
4165 | ntfs_attr_search_ctx *ctx) |
4166 | { |
4167 | s64 new_allocated_size, bw; |
4168 | ntfs_volume *vol = na->ni->vol; |
4169 | ATTR_REC *a = ctx->attr; |
4170 | runlist *rl; |
4171 | int mp_size, mp_ofs, name_ofs, arec_size, err; |
4172 | |
4173 | ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x.\n", (unsigned long |
4174 | long)na->ni->mft_no, na->type); |
4175 | |
4176 | /* Some preliminary sanity checking. */ |
4177 | if (NAttrNonResident(na)) { |
4178 | ntfs_log_trace("Eeek! Trying to make non-resident attribute " |
4179 | "non-resident. Aborting...\n"); |
4180 | errno = EINVAL; |
4181 | return -1; |
4182 | } |
4183 | |
4184 | /* Check that the attribute is allowed to be non-resident. */ |
4185 | if (ntfs_attr_can_be_non_resident(vol, na->type, na->name, na->name_len)) |
4186 | return -1; |
4187 | |
4188 | new_allocated_size = (le32_to_cpu(a->value_length) + vol->cluster_size |
4189 | - 1) & ~(vol->cluster_size - 1); |
4190 | |
4191 | if (new_allocated_size > 0) { |
4192 | /* Start by allocating clusters to hold the attribute value. */ |
4193 | rl = ntfs_cluster_alloc(vol, 0, new_allocated_size >> |
4194 | vol->cluster_size_bits, -1, DATA_ZONE); |
4195 | if (!rl) |
4196 | return -1; |
4197 | } else |
4198 | rl = NULL; |
4199 | /* |
4200 | * Setup the in-memory attribute structure to be non-resident so that |
4201 | * we can use ntfs_attr_pwrite(). |
4202 | */ |
4203 | NAttrSetNonResident(na); |
4204 | na->rl = rl; |
4205 | na->allocated_size = new_allocated_size; |
4206 | na->data_size = na->initialized_size = le32_to_cpu(a->value_length); |
4207 | /* |
4208 | * FIXME: For now just clear all of these as we don't support them when |
4209 | * writing. |
4210 | */ |
4211 | NAttrClearSparse(na); |
4212 | NAttrClearEncrypted(na); |
4213 | if ((a->flags & ATTR_COMPRESSION_MASK) == ATTR_IS_COMPRESSED) { |
4214 | /* set compression writing parameters */ |
4215 | na->compression_block_size |
4216 | = 1 << (STANDARD_COMPRESSION_UNIT + vol->cluster_size_bits); |
4217 | na->compression_block_clusters = 1 << STANDARD_COMPRESSION_UNIT; |
4218 | } |
4219 | |
4220 | if (rl) { |
4221 | /* Now copy the attribute value to the allocated cluster(s). */ |
4222 | bw = ntfs_attr_pwrite(na, 0, le32_to_cpu(a->value_length), |
4223 | (u8*)a + le16_to_cpu(a->value_offset)); |
4224 | if (bw != le32_to_cpu(a->value_length)) { |
4225 | err = errno; |
4226 | ntfs_log_debug("Eeek! Failed to write out attribute value " |
4227 | "(bw = %lli, errno = %i). " |
4228 | "Aborting...\n", (long long)bw, err); |
4229 | if (bw >= 0) |
4230 | err = EIO; |
4231 | goto cluster_free_err_out; |
4232 | } |
4233 | } |
4234 | /* Determine the size of the mapping pairs array. */ |
4235 | mp_size = ntfs_get_size_for_mapping_pairs(vol, rl, 0, INT_MAX); |
4236 | if (mp_size < 0) { |
4237 | err = errno; |
4238 | ntfs_log_debug("Eeek! Failed to get size for mapping pairs array. " |
4239 | "Aborting...\n"); |
4240 | goto cluster_free_err_out; |
4241 | } |
4242 | /* Calculate new offsets for the name and the mapping pairs array. */ |
4243 | if (na->ni->flags & FILE_ATTR_COMPRESSED) |
4244 | name_ofs = (sizeof(ATTR_REC) + 7) & ~7; |
4245 | else |
4246 | name_ofs = (sizeof(ATTR_REC) - sizeof(a->compressed_size) + 7) & ~7; |
4247 | mp_ofs = (name_ofs + a->name_length * sizeof(ntfschar) + 7) & ~7; |
4248 | /* |
4249 | * Determine the size of the resident part of the non-resident |
4250 | * attribute record. (Not compressed thus no compressed_size element |
4251 | * present.) |
4252 | */ |
4253 | arec_size = (mp_ofs + mp_size + 7) & ~7; |
4254 | |
4255 | /* Resize the resident part of the attribute record. */ |
4256 | if (ntfs_attr_record_resize(ctx->mrec, a, arec_size) < 0) { |
4257 | err = errno; |
4258 | goto cluster_free_err_out; |
4259 | } |
4260 | |
4261 | /* |
4262 | * Convert the resident part of the attribute record to describe a |
4263 | * non-resident attribute. |
4264 | */ |
4265 | a->non_resident = 1; |
4266 | |
4267 | /* Move the attribute name if it exists and update the offset. */ |
4268 | if (a->name_length) |
4269 | memmove((u8*)a + name_ofs, (u8*)a + le16_to_cpu(a->name_offset), |
4270 | a->name_length * sizeof(ntfschar)); |
4271 | a->name_offset = cpu_to_le16(name_ofs); |
4272 | |
4273 | /* Setup the fields specific to non-resident attributes. */ |
4274 | a->lowest_vcn = cpu_to_sle64(0); |
4275 | a->highest_vcn = cpu_to_sle64((new_allocated_size - 1) >> |
4276 | vol->cluster_size_bits); |
4277 | |
4278 | a->mapping_pairs_offset = cpu_to_le16(mp_ofs); |
4279 | |
4280 | /* |
4281 | * Update the flags to match the in-memory ones. |
4282 | * However cannot change the compression state if we had |
4283 | * a fuse_file_info open with a mark for release. |
4284 | * The decisions about compression can only be made when |
4285 | * creating/recreating the stream, not when making non resident. |
4286 | */ |
4287 | a->flags &= ~(ATTR_IS_SPARSE | ATTR_IS_ENCRYPTED); |
4288 | if ((a->flags & ATTR_COMPRESSION_MASK) == ATTR_IS_COMPRESSED) { |
4289 | /* support only ATTR_IS_COMPRESSED compression mode */ |
4290 | a->compression_unit = STANDARD_COMPRESSION_UNIT; |
4291 | a->compressed_size = const_cpu_to_le64(0); |
4292 | } else { |
4293 | a->compression_unit = 0; |
4294 | a->flags &= ~ATTR_COMPRESSION_MASK; |
4295 | na->data_flags = a->flags; |
4296 | } |
4297 | |
4298 | memset(&a->reserved1, 0, sizeof(a->reserved1)); |
4299 | |
4300 | a->allocated_size = cpu_to_sle64(new_allocated_size); |
4301 | a->data_size = a->initialized_size = cpu_to_sle64(na->data_size); |
4302 | |
4303 | /* Generate the mapping pairs array in the attribute record. */ |
4304 | if (ntfs_mapping_pairs_build(vol, (u8*)a + mp_ofs, arec_size - mp_ofs, |
4305 | rl, 0, NULL) < 0) { |
4306 | // FIXME: Eeek! We need rollback! (AIA) |
4307 | ntfs_log_trace("Eeek! Failed to build mapping pairs. Leaving " |
4308 | "corrupt attribute record on disk. In memory " |
4309 | "runlist is still intact! Error code is %i. " |
4310 | "FIXME: Need to rollback instead!\n", errno); |
4311 | return -1; |
4312 | } |
4313 | |
4314 | /* Done! */ |
4315 | return 0; |
4316 | |
4317 | cluster_free_err_out: |
4318 | if (rl && ntfs_cluster_free(vol, na, 0, -1) < 0) |
4319 | ntfs_log_trace("Eeek! Failed to release allocated clusters in error " |
4320 | "code path. Leaving inconsistent metadata...\n"); |
4321 | NAttrClearNonResident(na); |
4322 | na->allocated_size = na->data_size; |
4323 | na->rl = NULL; |
4324 | free(rl); |
4325 | errno = err; |
4326 | return -1; |
4327 | } |
4328 | |
4329 | |
4330 | static int ntfs_resident_attr_resize(ntfs_attr *na, const s64 newsize); |
4331 | |
4332 | /** |
4333 | * ntfs_resident_attr_resize - resize a resident, open ntfs attribute |
4334 | * @na: resident ntfs attribute to resize |
4335 | * @newsize: new size (in bytes) to which to resize the attribute |
4336 | * |
4337 | * Change the size of a resident, open ntfs attribute @na to @newsize bytes. |
4338 | * |
4339 | * On success return 0 |
4340 | * On error return values are: |
4341 | * STATUS_RESIDENT_ATTRIBUTE_FILLED_MFT |
4342 | * STATUS_ERROR - otherwise |
4343 | * The following error codes are defined: |
4344 | * ENOMEM - Not enough memory to complete operation. |
4345 | * ERANGE - @newsize is not valid for the attribute type of @na. |
4346 | * ENOSPC - There is no enough space in base mft to resize $ATTRIBUTE_LIST. |
4347 | */ |
4348 | static int ntfs_resident_attr_resize_i(ntfs_attr *na, const s64 newsize) |
4349 | { |
4350 | ntfs_attr_search_ctx *ctx; |
4351 | ntfs_volume *vol; |
4352 | ntfs_inode *ni; |
4353 | int err, ret = STATUS_ERROR; |
4354 | |
4355 | ntfs_log_trace("Inode 0x%llx attr 0x%x new size %lld\n", |
4356 | (unsigned long long)na->ni->mft_no, na->type, |
4357 | (long long)newsize); |
4358 | |
4359 | /* Get the attribute record that needs modification. */ |
4360 | ctx = ntfs_attr_get_search_ctx(na->ni, NULL); |
4361 | if (!ctx) |
4362 | return -1; |
4363 | if (ntfs_attr_lookup(na->type, na->name, na->name_len, 0, 0, NULL, 0, |
4364 | ctx)) { |
4365 | err = errno; |
4366 | ntfs_log_perror("ntfs_attr_lookup failed"); |
4367 | goto put_err_out; |
4368 | } |
4369 | vol = na->ni->vol; |
4370 | /* |
4371 | * Check the attribute type and the corresponding minimum and maximum |
4372 | * sizes against @newsize and fail if @newsize is out of bounds. |
4373 | */ |
4374 | if (ntfs_attr_size_bounds_check(vol, na->type, newsize) < 0) { |
4375 | err = errno; |
4376 | if (err == ENOENT) |
4377 | err = EIO; |
4378 | ntfs_log_perror("%s: bounds check failed", __FUNCTION__); |
4379 | goto put_err_out; |
4380 | } |
4381 | /* |
4382 | * If @newsize is bigger than the mft record we need to make the |
4383 | * attribute non-resident if the attribute type supports it. If it is |
4384 | * smaller we can go ahead and attempt the resize. |
4385 | */ |
4386 | if (newsize < vol->mft_record_size) { |
4387 | /* Perform the resize of the attribute record. */ |
4388 | if (!(ret = ntfs_resident_attr_value_resize(ctx->mrec, ctx->attr, |
4389 | newsize))) { |
4390 | /* Update attribute size everywhere. */ |
4391 | na->data_size = na->initialized_size = newsize; |
4392 | na->allocated_size = (newsize + 7) & ~7; |
4393 | if ((na->data_flags & ATTR_COMPRESSION_MASK) |
4394 | || NAttrSparse(na)) |
4395 | na->compressed_size = na->allocated_size; |
4396 | if (na->ni->mrec->flags & MFT_RECORD_IS_DIRECTORY |
4397 | ? na->type == AT_INDEX_ROOT && na->name == NTFS_INDEX_I30 |
4398 | : na->type == AT_DATA && na->name == AT_UNNAMED) { |
4399 | na->ni->data_size = na->data_size; |
4400 | na->ni->allocated_size = na->allocated_size; |
4401 | set_nino_flag(na->ni,KnownSize); |
4402 | if (na->type == AT_DATA) |
4403 | NInoFileNameSetDirty(na->ni); |
4404 | } |
4405 | goto resize_done; |
4406 | } |
4407 | /* Prefer AT_INDEX_ALLOCATION instead of AT_ATTRIBUTE_LIST */ |
4408 | if (ret == STATUS_RESIDENT_ATTRIBUTE_FILLED_MFT) { |
4409 | err = errno; |
4410 | goto put_err_out; |
4411 | } |
4412 | } |
4413 | /* There is not enough space in the mft record to perform the resize. */ |
4414 | |
4415 | /* Make the attribute non-resident if possible. */ |
4416 | if (!ntfs_attr_make_non_resident(na, ctx)) { |
4417 | ntfs_inode_mark_dirty(ctx->ntfs_ino); |
4418 | ntfs_attr_put_search_ctx(ctx); |
4419 | /* Resize non-resident attribute */ |
4420 | return ntfs_attr_truncate(na, newsize); |
4421 | } else if (errno != ENOSPC && errno != EPERM) { |
4422 | err = errno; |
4423 | ntfs_log_perror("Failed to make attribute non-resident"); |
4424 | goto put_err_out; |
4425 | } |
4426 | |
4427 | /* Try to make other attributes non-resident and retry each time. */ |
4428 | ntfs_attr_init_search_ctx(ctx, NULL, na->ni->mrec); |
4429 | while (!ntfs_attr_lookup(AT_UNUSED, NULL, 0, 0, 0, NULL, 0, ctx)) { |
4430 | ntfs_attr *tna; |
4431 | ATTR_RECORD *a; |
4432 | |
4433 | a = ctx->attr; |
4434 | if (a->non_resident) |
4435 | continue; |
4436 | |
4437 | /* |
4438 | * Check out whether convert is reasonable. Assume that mapping |
4439 | * pairs will take 8 bytes. |
4440 | */ |
4441 | if (le32_to_cpu(a->length) <= offsetof(ATTR_RECORD, |
4442 | compressed_size) + ((a->name_length * |
4443 | sizeof(ntfschar) + 7) & ~7) + 8) |
4444 | continue; |
4445 | |
4446 | tna = ntfs_attr_open(na->ni, a->type, (ntfschar*)((u8*)a + |
4447 | le16_to_cpu(a->name_offset)), a->name_length); |
4448 | if (!tna) { |
4449 | err = errno; |
4450 | ntfs_log_perror("Couldn't open attribute"); |
4451 | goto put_err_out; |
4452 | } |
4453 | if (ntfs_attr_make_non_resident(tna, ctx)) { |
4454 | ntfs_attr_close(tna); |
4455 | continue; |
4456 | } |
4457 | ntfs_inode_mark_dirty(tna->ni); |
4458 | ntfs_attr_close(tna); |
4459 | ntfs_attr_put_search_ctx(ctx); |
4460 | return ntfs_resident_attr_resize(na, newsize); |
4461 | } |
4462 | /* Check whether error occurred. */ |
4463 | if (errno != ENOENT) { |
4464 | err = errno; |
4465 | ntfs_log_perror("%s: Attribute lookup failed 1", __FUNCTION__); |
4466 | goto put_err_out; |
4467 | } |
4468 | |
4469 | /* |
4470 | * The standard information and attribute list attributes can't be |
4471 | * moved out from the base MFT record, so try to move out others. |
4472 | */ |
4473 | if (na->type==AT_STANDARD_INFORMATION || na->type==AT_ATTRIBUTE_LIST) { |
4474 | ntfs_attr_put_search_ctx(ctx); |
4475 | if (ntfs_inode_free_space(na->ni, offsetof(ATTR_RECORD, |
4476 | non_resident_end) + 8)) { |
4477 | ntfs_log_perror("Could not free space in MFT record"); |
4478 | return -1; |
4479 | } |
4480 | return ntfs_resident_attr_resize(na, newsize); |
4481 | } |
4482 | |
4483 | /* |
4484 | * Move the attribute to a new mft record, creating an attribute list |
4485 | * attribute or modifying it if it is already present. |
4486 | */ |
4487 | |
4488 | /* Point search context back to attribute which we need resize. */ |
4489 | ntfs_attr_init_search_ctx(ctx, na->ni, NULL); |
4490 | if (ntfs_attr_lookup(na->type, na->name, na->name_len, CASE_SENSITIVE, |
4491 | 0, NULL, 0, ctx)) { |
4492 | ntfs_log_perror("%s: Attribute lookup failed 2", __FUNCTION__); |
4493 | err = errno; |
4494 | goto put_err_out; |
4495 | } |
4496 | |
4497 | /* |
4498 | * Check whether attribute is already single in this MFT record. |
4499 | * 8 added for the attribute terminator. |
4500 | */ |
4501 | if (le32_to_cpu(ctx->mrec->bytes_in_use) == |
4502 | le16_to_cpu(ctx->mrec->attrs_offset) + |
4503 | le32_to_cpu(ctx->attr->length) + 8) { |
4504 | err = ENOSPC; |
4505 | ntfs_log_trace("MFT record is filled with one attribute\n"); |
4506 | ret = STATUS_RESIDENT_ATTRIBUTE_FILLED_MFT; |
4507 | goto put_err_out; |
4508 | } |
4509 | |
4510 | /* Add attribute list if not present. */ |
4511 | if (na->ni->nr_extents == -1) |
4512 | ni = na->ni->base_ni; |
4513 | else |
4514 | ni = na->ni; |
4515 | if (!NInoAttrList(ni)) { |
4516 | ntfs_attr_put_search_ctx(ctx); |
4517 | if (ntfs_inode_add_attrlist(ni)) |
4518 | return -1; |
4519 | return ntfs_resident_attr_resize(na, newsize); |
4520 | } |
4521 | /* Allocate new mft record. */ |
4522 | ni = ntfs_mft_record_alloc(vol, ni); |
4523 | if (!ni) { |
4524 | err = errno; |
4525 | ntfs_log_perror("Couldn't allocate new MFT record"); |
4526 | goto put_err_out; |
4527 | } |
4528 | /* Move attribute to it. */ |
4529 | if (ntfs_attr_record_move_to(ctx, ni)) { |
4530 | err = errno; |
4531 | ntfs_log_perror("Couldn't move attribute to new MFT record"); |
4532 | goto put_err_out; |
4533 | } |
4534 | /* Update ntfs attribute. */ |
4535 | if (na->ni->nr_extents == -1) |
4536 | na->ni = ni; |
4537 | |
4538 | ntfs_attr_put_search_ctx(ctx); |
4539 | /* Try to perform resize once again. */ |
4540 | return ntfs_resident_attr_resize(na, newsize); |
4541 | |
4542 | resize_done: |
4543 | /* |
4544 | * Set the inode (and its base inode if it exists) dirty so it is |
4545 | * written out later. |
4546 | */ |
4547 | ntfs_inode_mark_dirty(ctx->ntfs_ino); |
4548 | ntfs_attr_put_search_ctx(ctx); |
4549 | return 0; |
4550 | put_err_out: |
4551 | ntfs_attr_put_search_ctx(ctx); |
4552 | errno = err; |
4553 | return ret; |
4554 | } |
4555 | |
4556 | static int ntfs_resident_attr_resize(ntfs_attr *na, const s64 newsize) |
4557 | { |
4558 | int ret; |
4559 | |
4560 | ntfs_log_enter("Entering\n"); |
4561 | ret = ntfs_resident_attr_resize_i(na, newsize); |
4562 | ntfs_log_leave("\n"); |
4563 | return ret; |
4564 | } |
4565 | |
4566 | /** |
4567 | * ntfs_attr_make_resident - convert a non-resident to a resident attribute |
4568 | * @na: open ntfs attribute to make resident |
4569 | * @ctx: ntfs search context describing the attribute |
4570 | * |
4571 | * Convert a non-resident ntfs attribute to a resident one. |
4572 | * |
4573 | * Return 0 on success and -1 on error with errno set to the error code. The |
4574 | * following error codes are defined: |
4575 | * EINVAL - Invalid arguments passed. |
4576 | * EPERM - The attribute is not allowed to be resident. |
4577 | * EIO - I/O error, damaged inode or bug. |
4578 | * ENOSPC - There is no enough space to perform conversion. |
4579 | * EOPNOTSUPP - Requested conversion is not supported yet. |
4580 | * |
4581 | * Warning: We do not set the inode dirty and we do not write out anything! |
4582 | * We expect the caller to do this as this is a fairly low level |
4583 | * function and it is likely there will be further changes made. |
4584 | */ |
4585 | static int ntfs_attr_make_resident(ntfs_attr *na, ntfs_attr_search_ctx *ctx) |
4586 | { |
4587 | ntfs_volume *vol = na->ni->vol; |
4588 | ATTR_REC *a = ctx->attr; |
4589 | int name_ofs, val_ofs, err = EIO; |
4590 | s64 arec_size, bytes_read; |
4591 | |
4592 | ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x.\n", (unsigned long |
4593 | long)na->ni->mft_no, na->type); |
4594 | |
4595 | /* Should be called for the first extent of the attribute. */ |
4596 | if (sle64_to_cpu(a->lowest_vcn)) { |
4597 | ntfs_log_trace("Eeek! Should be called for the first extent of the " |
4598 | "attribute. Aborting...\n"); |
4599 | errno = EINVAL; |
4600 | return -1; |
4601 | } |
4602 | |
4603 | /* Some preliminary sanity checking. */ |
4604 | if (!NAttrNonResident(na)) { |
4605 | ntfs_log_trace("Eeek! Trying to make resident attribute resident. " |
4606 | "Aborting...\n"); |
4607 | errno = EINVAL; |
4608 | return -1; |
4609 | } |
4610 | |
4611 | /* Make sure this is not $MFT/$BITMAP or Windows will not boot! */ |
4612 | if (na->type == AT_BITMAP && na->ni->mft_no == FILE_MFT) { |
4613 | errno = EPERM; |
4614 | return -1; |
4615 | } |
4616 | |
4617 | /* Check that the attribute is allowed to be resident. */ |
4618 | if (ntfs_attr_can_be_resident(vol, na->type)) |
4619 | return -1; |
4620 | |
4621 | if (na->data_flags & ATTR_IS_ENCRYPTED) { |
4622 | ntfs_log_trace("Making encrypted streams resident is not " |
4623 | "implemented yet.\n"); |
4624 | errno = EOPNOTSUPP; |
4625 | return -1; |
4626 | } |
4627 | |
4628 | /* Work out offsets into and size of the resident attribute. */ |
4629 | name_ofs = 24; /* = sizeof(resident_ATTR_REC); */ |
4630 | val_ofs = (name_ofs + a->name_length * sizeof(ntfschar) + 7) & ~7; |
4631 | arec_size = (val_ofs + na->data_size + 7) & ~7; |
4632 | |
4633 | /* Sanity check the size before we start modifying the attribute. */ |
4634 | if (le32_to_cpu(ctx->mrec->bytes_in_use) - le32_to_cpu(a->length) + |
4635 | arec_size > le32_to_cpu(ctx->mrec->bytes_allocated)) { |
4636 | errno = ENOSPC; |
4637 | ntfs_log_trace("Not enough space to make attribute resident\n"); |
4638 | return -1; |
4639 | } |
4640 | |
4641 | /* Read and cache the whole runlist if not already done. */ |
4642 | if (ntfs_attr_map_whole_runlist(na)) |
4643 | return -1; |
4644 | |
4645 | /* Move the attribute name if it exists and update the offset. */ |
4646 | if (a->name_length) { |
4647 | memmove((u8*)a + name_ofs, (u8*)a + le16_to_cpu(a->name_offset), |
4648 | a->name_length * sizeof(ntfschar)); |
4649 | } |
4650 | a->name_offset = cpu_to_le16(name_ofs); |
4651 | |
4652 | /* Resize the resident part of the attribute record. */ |
4653 | if (ntfs_attr_record_resize(ctx->mrec, a, arec_size) < 0) { |
4654 | /* |
4655 | * Bug, because ntfs_attr_record_resize should not fail (we |
4656 | * already checked that attribute fits MFT record). |
4657 | */ |
4658 | ntfs_log_error("BUG! Failed to resize attribute record. " |
4659 | "Please report to the %s. Aborting...\n", |
4660 | NTFS_DEV_LIST); |
4661 | errno = EIO; |
4662 | return -1; |
4663 | } |
4664 | |
4665 | /* Convert the attribute record to describe a resident attribute. */ |
4666 | a->non_resident = 0; |
4667 | a->flags = 0; |
4668 | a->value_length = cpu_to_le32(na->data_size); |
4669 | a->value_offset = cpu_to_le16(val_ofs); |
4670 | /* |
4671 | * If a data stream was wiped out, adjust the compression mode |
4672 | * to current state of compression flag |
4673 | */ |
4674 | if (!na->data_size |
4675 | && (na->type == AT_DATA) |
4676 | && (na->ni->vol->cluster_size <= MAX_COMPRESSION_CLUSTER_SIZE) |
4677 | && (na->ni->flags & FILE_ATTR_COMPRESSED)) { |
4678 | a->flags |= ATTR_IS_COMPRESSED; |
4679 | na->data_flags = a->flags; |
4680 | } |
4681 | /* |
4682 | * File names cannot be non-resident so we would never see this here |
4683 | * but at least it serves as a reminder that there may be attributes |
4684 | * for which we do need to set this flag. (AIA) |
4685 | */ |
4686 | if (a->type == AT_FILE_NAME) |
4687 | a->resident_flags = RESIDENT_ATTR_IS_INDEXED; |
4688 | else |
4689 | a->resident_flags = 0; |
4690 | a->reservedR = 0; |
4691 | |
4692 | /* Sanity fixup... Shouldn't really happen. (AIA) */ |
4693 | if (na->initialized_size > na->data_size) |
4694 | na->initialized_size = na->data_size; |
4695 | |
4696 | /* Copy data from run list to resident attribute value. */ |
4697 | bytes_read = ntfs_rl_pread(vol, na->rl, 0, na->initialized_size, |
4698 | (u8*)a + val_ofs); |
4699 | if (bytes_read != na->initialized_size) { |
4700 | if (bytes_read < 0) |
4701 | err = errno; |
4702 | ntfs_log_trace("Eeek! Failed to read attribute data. Leaving " |
4703 | "inconstant metadata. Run chkdsk. " |
4704 | "Aborting...\n"); |
4705 | errno = err; |
4706 | return -1; |
4707 | } |
4708 | |
4709 | /* Clear memory in gap between initialized_size and data_size. */ |
4710 | if (na->initialized_size < na->data_size) |
4711 | memset((u8*)a + val_ofs + na->initialized_size, 0, |
4712 | na->data_size - na->initialized_size); |
4713 | |
4714 | /* |
4715 | * Deallocate clusters from the runlist. |
4716 | * |
4717 | * NOTE: We can use ntfs_cluster_free() because we have already mapped |
4718 | * the whole run list and thus it doesn't matter that the attribute |
4719 | * record is in a transiently corrupted state at this moment in time. |
4720 | */ |
4721 | if (ntfs_cluster_free(vol, na, 0, -1) < 0) { |
4722 | err = errno; |
4723 | ntfs_log_perror("Eeek! Failed to release allocated clusters"); |
4724 | ntfs_log_trace("Ignoring error and leaving behind wasted " |
4725 | "clusters.\n"); |
4726 | } |
4727 | |
4728 | /* Throw away the now unused runlist. */ |
4729 | free(na->rl); |
4730 | na->rl = NULL; |
4731 | |
4732 | /* Update in-memory struct ntfs_attr. */ |
4733 | NAttrClearNonResident(na); |
4734 | NAttrClearSparse(na); |
4735 | NAttrClearEncrypted(na); |
4736 | na->initialized_size = na->data_size; |
4737 | na->allocated_size = na->compressed_size = (na->data_size + 7) & ~7; |
4738 | na->compression_block_size = 0; |
4739 | na->compression_block_size_bits = na->compression_block_clusters = 0; |
4740 | return 0; |
4741 | } |
4742 | |
4743 | /* |
4744 | * If we are in the first extent, then set/clean sparse bit, |
4745 | * update allocated and compressed size. |
4746 | */ |
4747 | static int ntfs_attr_update_meta(ATTR_RECORD *a, ntfs_attr *na, MFT_RECORD *m, |
4748 | ntfs_attr_search_ctx *ctx) |
4749 | { |
4750 | int sparse, ret = 0; |
4751 | |
4752 | ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x\n", |
4753 | (unsigned long long)na->ni->mft_no, na->type); |
4754 | |
4755 | if (a->lowest_vcn) |
4756 | goto out; |
4757 | |
4758 | a->allocated_size = cpu_to_sle64(na->allocated_size); |
4759 | |
4760 | /* Update sparse bit. */ |
4761 | sparse = ntfs_rl_sparse(na->rl); |
4762 | if (sparse == -1) { |
4763 | errno = EIO; |
4764 | goto error; |
4765 | } |
4766 | |
4767 | /* Attribute become sparse. */ |
4768 | if (sparse && !(a->flags & (ATTR_IS_SPARSE | ATTR_IS_COMPRESSED))) { |
4769 | /* |
4770 | * Move attribute to another mft record, if attribute is too |
4771 | * small to add compressed_size field to it and we have no |
4772 | * free space in the current mft record. |
4773 | */ |
4774 | if ((le32_to_cpu(a->length) - |
4775 | le16_to_cpu(a->mapping_pairs_offset) == 8) |
4776 | && !(le32_to_cpu(m->bytes_allocated) - |
4777 | le32_to_cpu(m->bytes_in_use))) { |
4778 | |
4779 | if (!NInoAttrList(na->ni)) { |
4780 | ntfs_attr_put_search_ctx(ctx); |
4781 | if (ntfs_inode_add_attrlist(na->ni)) |
4782 | goto leave; |
4783 | goto retry; |
4784 | } |
4785 | if (ntfs_attr_record_move_away(ctx, 8)) { |
4786 | ntfs_log_perror("Failed to move attribute"); |
4787 | goto error; |
4788 | } |
4789 | ntfs_attr_put_search_ctx(ctx); |
4790 | goto retry; |
4791 | } |
4792 | if (!(le32_to_cpu(a->length) - le16_to_cpu( |
4793 | a->mapping_pairs_offset))) { |
4794 | errno = EIO; |
4795 | ntfs_log_perror("Mapping pairs space is 0"); |
4796 | goto error; |
4797 | } |
4798 | |
4799 | NAttrSetSparse(na); |
4800 | a->flags |= ATTR_IS_SPARSE; |
4801 | a->compression_unit = STANDARD_COMPRESSION_UNIT; /* Windows |
4802 | set it so, even if attribute is not actually compressed. */ |
4803 | |
4804 | memmove((u8*)a + le16_to_cpu(a->name_offset) + 8, |
4805 | (u8*)a + le16_to_cpu(a->name_offset), |
4806 | a->name_length * sizeof(ntfschar)); |
4807 | |
4808 | a->name_offset = cpu_to_le16(le16_to_cpu(a->name_offset) + 8); |
4809 | |
4810 | a->mapping_pairs_offset = |
4811 | cpu_to_le16(le16_to_cpu(a->mapping_pairs_offset) + 8); |
4812 | } |
4813 | |
4814 | /* Attribute no longer sparse. */ |
4815 | if (!sparse && (a->flags & ATTR_IS_SPARSE) && |
4816 | !(a->flags & ATTR_IS_COMPRESSED)) { |
4817 | |
4818 | NAttrClearSparse(na); |
4819 | a->flags &= ~ATTR_IS_SPARSE; |
4820 | a->compression_unit = 0; |
4821 | |
4822 | memmove((u8*)a + le16_to_cpu(a->name_offset) - 8, |
4823 | (u8*)a + le16_to_cpu(a->name_offset), |
4824 | a->name_length * sizeof(ntfschar)); |
4825 | |
4826 | if (le16_to_cpu(a->name_offset) >= 8) |
4827 | a->name_offset = cpu_to_le16(le16_to_cpu(a->name_offset) - 8); |
4828 | |
4829 | a->mapping_pairs_offset = |
4830 | cpu_to_le16(le16_to_cpu(a->mapping_pairs_offset) - 8); |
4831 | } |
4832 | |
4833 | /* Update compressed size if required. */ |
4834 | if (sparse || (na->data_flags & ATTR_COMPRESSION_MASK)) { |
4835 | s64 new_compr_size; |
4836 | |
4837 | new_compr_size = ntfs_rl_get_compressed_size(na->ni->vol, na->rl); |
4838 | if (new_compr_size == -1) |
4839 | goto error; |
4840 | |
4841 | na->compressed_size = new_compr_size; |
4842 | a->compressed_size = cpu_to_sle64(new_compr_size); |
4843 | } |
4844 | /* |
4845 | * Set FILE_NAME dirty flag, to update sparse bit and |
4846 | * allocated size in the index. |
4847 | */ |
4848 | if (na->type == AT_DATA && na->name == AT_UNNAMED) { |
4849 | if (sparse) |
4850 | na->ni->allocated_size = na->compressed_size; |
4851 | else |
4852 | na->ni->allocated_size = na->allocated_size; |
4853 | NInoFileNameSetDirty(na->ni); |
4854 | } |
4855 | out: |
4856 | return ret; |
4857 | leave: ret = -1; goto out; /* return -1 */ |
4858 | retry: ret = -2; goto out; |
4859 | error: ret = -3; goto out; |
4860 | } |
4861 | |
4862 | #define NTFS_VCN_DELETE_MARK -2 |
4863 | /** |
4864 | * ntfs_attr_update_mapping_pairs_i - see ntfs_attr_update_mapping_pairs |
4865 | */ |
4866 | static int ntfs_attr_update_mapping_pairs_i(ntfs_attr *na, VCN from_vcn) |
4867 | { |
4868 | ntfs_attr_search_ctx *ctx; |
4869 | ntfs_inode *ni, *base_ni; |
4870 | MFT_RECORD *m; |
4871 | ATTR_RECORD *a; |
4872 | VCN stop_vcn; |
4873 | const runlist_element *stop_rl; |
4874 | int err, mp_size, cur_max_mp_size, exp_max_mp_size, ret = -1; |
4875 | BOOL finished_build; |
4876 | |
4877 | retry: |
4878 | if (!na || !na->rl || from_vcn) { |
4879 | errno = EINVAL; |
4880 | ntfs_log_perror("%s: na=%p", __FUNCTION__, na); |
4881 | return -1; |
4882 | } |
4883 | |
4884 | ntfs_log_trace("Entering for inode %llu, attr 0x%x\n", |
4885 | (unsigned long long)na->ni->mft_no, na->type); |
4886 | |
4887 | if (!NAttrNonResident(na)) { |
4888 | errno = EINVAL; |
4889 | ntfs_log_perror("%s: resident attribute", __FUNCTION__); |
4890 | return -1; |
4891 | } |
4892 | |
4893 | if (na->ni->nr_extents == -1) |
4894 | base_ni = na->ni->base_ni; |
4895 | else |
4896 | base_ni = na->ni; |
4897 | |
4898 | ctx = ntfs_attr_get_search_ctx(base_ni, NULL); |
4899 | if (!ctx) |
4900 | return -1; |
4901 | |
4902 | /* Fill attribute records with new mapping pairs. */ |
4903 | stop_vcn = 0; |
4904 | stop_rl = na->rl; |
4905 | finished_build = FALSE; |
4906 | while (!ntfs_attr_lookup(na->type, na->name, na->name_len, |
4907 | CASE_SENSITIVE, from_vcn, NULL, 0, ctx)) { |
4908 | a = ctx->attr; |
4909 | m = ctx->mrec; |
4910 | /* |
4911 | * If runlist is updating not from the beginning, then set |
4912 | * @stop_vcn properly, i.e. to the lowest vcn of record that |
4913 | * contain @from_vcn. Also we do not need @from_vcn anymore, |
4914 | * set it to 0 to make ntfs_attr_lookup enumerate attributes. |
4915 | */ |
4916 | if (from_vcn) { |
4917 | LCN first_lcn; |
4918 | |
4919 | stop_vcn = sle64_to_cpu(a->lowest_vcn); |
4920 | from_vcn = 0; |
4921 | /* |
4922 | * Check whether the first run we need to update is |
4923 | * the last run in runlist, if so, then deallocate |
4924 | * all attrubute extents starting this one. |
4925 | */ |
4926 | first_lcn = ntfs_rl_vcn_to_lcn(na->rl, stop_vcn); |
4927 | if (first_lcn == LCN_EINVAL) { |
4928 | errno = EIO; |
4929 | ntfs_log_perror("Bad runlist"); |
4930 | goto put_err_out; |
4931 | } |
4932 | if (first_lcn == LCN_ENOENT || |
4933 | first_lcn == LCN_RL_NOT_MAPPED) |
4934 | finished_build = TRUE; |
4935 | } |
4936 | |
4937 | /* |
4938 | * Check whether we finished mapping pairs build, if so mark |
4939 | * extent as need to delete (by setting highest vcn to |
4940 | * NTFS_VCN_DELETE_MARK (-2), we shall check it later and |
4941 | * delete extent) and continue search. |
4942 | */ |
4943 | if (finished_build) { |
4944 | ntfs_log_trace("Mark attr 0x%x for delete in inode " |
4945 | "%lld.\n", (unsigned)le32_to_cpu(a->type), |
4946 | (long long)ctx->ntfs_ino->mft_no); |
4947 | a->highest_vcn = cpu_to_sle64(NTFS_VCN_DELETE_MARK); |
4948 | ntfs_inode_mark_dirty(ctx->ntfs_ino); |
4949 | continue; |
4950 | } |
4951 | |
4952 | switch (ntfs_attr_update_meta(a, na, m, ctx)) { |
4953 | case -1: return -1; |
4954 | case -2: goto retry; |
4955 | case -3: goto put_err_out; |
4956 | } |
4957 | |
4958 | /* |
4959 | * Determine maximum possible length of mapping pairs, |
4960 | * if we shall *not* expand space for mapping pairs. |
4961 | */ |
4962 | cur_max_mp_size = le32_to_cpu(a->length) - |
4963 | le16_to_cpu(a->mapping_pairs_offset); |
4964 | /* |
4965 | * Determine maximum possible length of mapping pairs in the |
4966 | * current mft record, if we shall expand space for mapping |
4967 | * pairs. |
4968 | */ |
4969 | exp_max_mp_size = le32_to_cpu(m->bytes_allocated) - |
4970 | le32_to_cpu(m->bytes_in_use) + cur_max_mp_size; |
4971 | /* Get the size for the rest of mapping pairs array. */ |
4972 | mp_size = ntfs_get_size_for_mapping_pairs(na->ni->vol, stop_rl, |
4973 | stop_vcn, exp_max_mp_size); |
4974 | if (mp_size <= 0) { |
4975 | ntfs_log_perror("%s: get MP size failed", __FUNCTION__); |
4976 | goto put_err_out; |
4977 | } |
4978 | /* Test mapping pairs for fitting in the current mft record. */ |
4979 | if (mp_size > exp_max_mp_size) { |
4980 | /* |
4981 | * Mapping pairs of $ATTRIBUTE_LIST attribute must fit |
4982 | * in the base mft record. Try to move out other |
4983 | * attributes and try again. |
4984 | */ |
4985 | if (na->type == AT_ATTRIBUTE_LIST) { |
4986 | ntfs_attr_put_search_ctx(ctx); |
4987 | if (ntfs_inode_free_space(na->ni, mp_size - |
4988 | cur_max_mp_size)) { |
4989 | ntfs_log_perror("Attribute list is too " |
4990 | "big. Defragment the " |
4991 | "volume\n"); |
4992 | return -1; |
4993 | } |
4994 | goto retry; |
4995 | } |
4996 | |
4997 | /* Add attribute list if it isn't present, and retry. */ |
4998 | if (!NInoAttrList(base_ni)) { |
4999 | ntfs_attr_put_search_ctx(ctx); |
5000 | if (ntfs_inode_add_attrlist(base_ni)) { |
5001 | ntfs_log_perror("Can not add attrlist"); |
5002 | return -1; |
5003 | } |
5004 | goto retry; |
5005 | } |
5006 | |
5007 | /* |
5008 | * Set mapping pairs size to maximum possible for this |
5009 | * mft record. We shall write the rest of mapping pairs |
5010 | * to another MFT records. |
5011 | */ |
5012 | mp_size = exp_max_mp_size; |
5013 | } |
5014 | |
5015 | /* Change space for mapping pairs if we need it. */ |
5016 | if (((mp_size + 7) & ~7) != cur_max_mp_size) { |
5017 | if (ntfs_attr_record_resize(m, a, |
5018 | le16_to_cpu(a->mapping_pairs_offset) + |
5019 | mp_size)) { |
5020 | errno = EIO; |
5021 | ntfs_log_perror("Failed to resize attribute"); |
5022 | goto put_err_out; |
5023 | } |
5024 | } |
5025 | |
5026 | /* Update lowest vcn. */ |
5027 | a->lowest_vcn = cpu_to_sle64(stop_vcn); |
5028 | ntfs_inode_mark_dirty(ctx->ntfs_ino); |
5029 | if ((ctx->ntfs_ino->nr_extents == -1 || |
5030 | NInoAttrList(ctx->ntfs_ino)) && |
5031 | ctx->attr->type != AT_ATTRIBUTE_LIST) { |
5032 | ctx->al_entry->lowest_vcn = cpu_to_sle64(stop_vcn); |
5033 | ntfs_attrlist_mark_dirty(ctx->ntfs_ino); |
5034 | } |
5035 | |
5036 | /* |
5037 | * Generate the new mapping pairs array directly into the |
5038 | * correct destination, i.e. the attribute record itself. |
5039 | */ |
5040 | if (!ntfs_mapping_pairs_build(na->ni->vol, (u8*)a + le16_to_cpu( |
5041 | a->mapping_pairs_offset), mp_size, na->rl, |
5042 | stop_vcn, &stop_rl)) |
5043 | finished_build = TRUE; |
5044 | if (stop_rl) |
5045 | stop_vcn = stop_rl->vcn; |
5046 | else |
5047 | stop_vcn = 0; |
5048 | if (!finished_build && errno != ENOSPC) { |
5049 | ntfs_log_perror("Failed to build mapping pairs"); |
5050 | goto put_err_out; |
5051 | } |
5052 | a->highest_vcn = cpu_to_sle64(stop_vcn - 1); |
5053 | } |
5054 | /* Check whether error occurred. */ |
5055 | if (errno != ENOENT) { |
5056 | ntfs_log_perror("%s: Attribute lookup failed", __FUNCTION__); |
5057 | goto put_err_out; |
5058 | } |
5059 | |
5060 | /* Deallocate not used attribute extents and return with success. */ |
5061 | if (finished_build) { |
5062 | ntfs_attr_reinit_search_ctx(ctx); |
5063 | ntfs_log_trace("Deallocate marked extents.\n"); |
5064 | while (!ntfs_attr_lookup(na->type, na->name, na->name_len, |
5065 | CASE_SENSITIVE, 0, NULL, 0, ctx)) { |
5066 | if (sle64_to_cpu(ctx->attr->highest_vcn) != |
5067 | NTFS_VCN_DELETE_MARK) |
5068 | continue; |
5069 | /* Remove unused attribute record. */ |
5070 | if (ntfs_attr_record_rm(ctx)) { |
5071 | ntfs_log_perror("Could not remove unused attr"); |
5072 | goto put_err_out; |
5073 | } |
5074 | ntfs_attr_reinit_search_ctx(ctx); |
5075 | } |
5076 | if (errno != ENOENT) { |
5077 | ntfs_log_perror("%s: Attr lookup failed", __FUNCTION__); |
5078 | goto put_err_out; |
5079 | } |
5080 | ntfs_log_trace("Deallocate done.\n"); |
5081 | ntfs_attr_put_search_ctx(ctx); |
5082 | goto ok; |
5083 | } |
5084 | ntfs_attr_put_search_ctx(ctx); |
5085 | ctx = NULL; |
5086 | |
5087 | /* Allocate new MFT records for the rest of mapping pairs. */ |
5088 | while (1) { |
5089 | /* Calculate size of rest mapping pairs. */ |
5090 | mp_size = ntfs_get_size_for_mapping_pairs(na->ni->vol, |
5091 | na->rl, stop_vcn, INT_MAX); |
5092 | if (mp_size <= 0) { |
5093 | ntfs_log_perror("%s: get mp size failed", __FUNCTION__); |
5094 | goto put_err_out; |
5095 | } |
5096 | /* Allocate new mft record. */ |
5097 | ni = ntfs_mft_record_alloc(na->ni->vol, base_ni); |
5098 | if (!ni) { |
5099 | ntfs_log_perror("Could not allocate new MFT record"); |
5100 | goto put_err_out; |
5101 | } |
5102 | m = ni->mrec; |
5103 | /* |
5104 | * If mapping size exceed available space, set them to |
5105 | * possible maximum. |
5106 | */ |
5107 | cur_max_mp_size = le32_to_cpu(m->bytes_allocated) - |
5108 | le32_to_cpu(m->bytes_in_use) - |
5109 | (offsetof(ATTR_RECORD, compressed_size) + |
5110 | (((na->data_flags & ATTR_COMPRESSION_MASK) |
5111 | || NAttrSparse(na)) ? |
5112 | sizeof(a->compressed_size) : 0)) - |
5113 | ((sizeof(ntfschar) * na->name_len + 7) & ~7); |
5114 | if (mp_size > cur_max_mp_size) |
5115 | mp_size = cur_max_mp_size; |
5116 | /* Add attribute extent to new record. */ |
5117 | err = ntfs_non_resident_attr_record_add(ni, na->type, |
5118 | na->name, na->name_len, stop_vcn, mp_size, |
5119 | na->data_flags); |
5120 | if (err == -1) { |
5121 | err = errno; |
5122 | ntfs_log_perror("Could not add attribute extent"); |
5123 | if (ntfs_mft_record_free(na->ni->vol, ni)) |
5124 | ntfs_log_perror("Could not free MFT record"); |
5125 | errno = err; |
5126 | goto put_err_out; |
5127 | } |
5128 | a = (ATTR_RECORD*)((u8*)m + err); |
5129 | |
5130 | err = ntfs_mapping_pairs_build(na->ni->vol, (u8*)a + |
5131 | le16_to_cpu(a->mapping_pairs_offset), mp_size, na->rl, |
5132 | stop_vcn, &stop_rl); |
5133 | if (stop_rl) |
5134 | stop_vcn = stop_rl->vcn; |
5135 | else |
5136 | stop_vcn = 0; |
5137 | if (err < 0 && errno != ENOSPC) { |
5138 | err = errno; |
5139 | ntfs_log_perror("Failed to build MP"); |
5140 | if (ntfs_mft_record_free(na->ni->vol, ni)) |
5141 | ntfs_log_perror("Couldn't free MFT record"); |
5142 | errno = err; |
5143 | goto put_err_out; |
5144 | } |
5145 | a->highest_vcn = cpu_to_sle64(stop_vcn - 1); |
5146 | ntfs_inode_mark_dirty(ni); |
5147 | /* All mapping pairs has been written. */ |
5148 | if (!err) |
5149 | break; |
5150 | } |
5151 | ok: |
5152 | ret = 0; |
5153 | out: |
5154 | return ret; |
5155 | put_err_out: |
5156 | if (ctx) |
5157 | ntfs_attr_put_search_ctx(ctx); |
5158 | goto out; |
5159 | } |
5160 | #undef NTFS_VCN_DELETE_MARK |
5161 | |
5162 | /** |
5163 | * ntfs_attr_update_mapping_pairs - update mapping pairs for ntfs attribute |
5164 | * @na: non-resident ntfs open attribute for which we need update |
5165 | * @from_vcn: update runlist starting this VCN |
5166 | * |
5167 | * Build mapping pairs from @na->rl and write them to the disk. Also, this |
5168 | * function updates sparse bit, allocated and compressed size (allocates/frees |
5169 | * space for this field if required). |
5170 | * |
5171 | * @na->allocated_size should be set to correct value for the new runlist before |
5172 | * call to this function. Vice-versa @na->compressed_size will be calculated and |
5173 | * set to correct value during this function. |
5174 | * |
5175 | * FIXME: This function does not update sparse bit and compressed size correctly |
5176 | * if called with @from_vcn != 0. |
5177 | * |
5178 | * FIXME: Rewrite without using NTFS_VCN_DELETE_MARK define. |
5179 | * |
5180 | * On success return 0 and on error return -1 with errno set to the error code. |
5181 | * The following error codes are defined: |
5182 | * EINVAL - Invalid arguments passed. |
5183 | * ENOMEM - Not enough memory to complete operation. |
5184 | * ENOSPC - There is no enough space in base mft to resize $ATTRIBUTE_LIST |
5185 | * or there is no free MFT records left to allocate. |
5186 | */ |
5187 | int ntfs_attr_update_mapping_pairs(ntfs_attr *na, VCN from_vcn) |
5188 | { |
5189 | int ret; |
5190 | |
5191 | ntfs_log_enter("Entering\n"); |
5192 | ret = ntfs_attr_update_mapping_pairs_i(na, from_vcn); |
5193 | ntfs_log_leave("\n"); |
5194 | return ret; |
5195 | } |
5196 | |
5197 | /** |
5198 | * ntfs_non_resident_attr_shrink - shrink a non-resident, open ntfs attribute |
5199 | * @na: non-resident ntfs attribute to shrink |
5200 | * @newsize: new size (in bytes) to which to shrink the attribute |
5201 | * |
5202 | * Reduce the size of a non-resident, open ntfs attribute @na to @newsize bytes. |
5203 | * |
5204 | * On success return 0 and on error return -1 with errno set to the error code. |
5205 | * The following error codes are defined: |
5206 | * ENOMEM - Not enough memory to complete operation. |
5207 | * ERANGE - @newsize is not valid for the attribute type of @na. |
5208 | */ |
5209 | static int ntfs_non_resident_attr_shrink(ntfs_attr *na, const s64 newsize) |
5210 | { |
5211 | ntfs_volume *vol; |
5212 | ntfs_attr_search_ctx *ctx; |
5213 | VCN first_free_vcn; |
5214 | s64 nr_freed_clusters; |
5215 | int err; |
5216 | |
5217 | ntfs_log_trace("Inode 0x%llx attr 0x%x new size %lld\n", (unsigned long long) |
5218 | na->ni->mft_no, na->type, (long long)newsize); |
5219 | |
5220 | vol = na->ni->vol; |
5221 | |
5222 | /* |
5223 | * Check the attribute type and the corresponding minimum size |
5224 | * against @newsize and fail if @newsize is too small. |
5225 | */ |
5226 | if (ntfs_attr_size_bounds_check(vol, na->type, newsize) < 0) { |
5227 | if (errno == ERANGE) { |
5228 | ntfs_log_trace("Eeek! Size bounds check failed. " |
5229 | "Aborting...\n"); |
5230 | } else if (errno == ENOENT) |
5231 | errno = EIO; |
5232 | return -1; |
5233 | } |
5234 | |
5235 | /* The first cluster outside the new allocation. */ |
5236 | first_free_vcn = (newsize + vol->cluster_size - 1) >> |
5237 | vol->cluster_size_bits; |
5238 | /* |
5239 | * Compare the new allocation with the old one and only deallocate |
5240 | * clusters if there is a change. |
5241 | */ |
5242 | if ((na->allocated_size >> vol->cluster_size_bits) != first_free_vcn) { |
5243 | if (ntfs_attr_map_whole_runlist(na)) { |
5244 | ntfs_log_trace("Eeek! ntfs_attr_map_whole_runlist " |
5245 | "failed.\n"); |
5246 | return -1; |
5247 | } |
5248 | /* Deallocate all clusters starting with the first free one. */ |
5249 | nr_freed_clusters = ntfs_cluster_free(vol, na, first_free_vcn, |
5250 | -1); |
5251 | if (nr_freed_clusters < 0) { |
5252 | ntfs_log_trace("Eeek! Freeing of clusters failed. " |
5253 | "Aborting...\n"); |
5254 | return -1; |
5255 | } |
5256 | |
5257 | /* Truncate the runlist itself. */ |
5258 | if (ntfs_rl_truncate(&na->rl, first_free_vcn)) { |
5259 | /* |
5260 | * Failed to truncate the runlist, so just throw it |
5261 | * away, it will be mapped afresh on next use. |
5262 | */ |
5263 | free(na->rl); |
5264 | na->rl = NULL; |
5265 | ntfs_log_trace("Eeek! Run list truncation failed.\n"); |
5266 | return -1; |
5267 | } |
5268 | |
5269 | /* Prepare to mapping pairs update. */ |
5270 | na->allocated_size = first_free_vcn << vol->cluster_size_bits; |
5271 | /* Write mapping pairs for new runlist. */ |
5272 | if (ntfs_attr_update_mapping_pairs(na, 0 /*first_free_vcn*/)) { |
5273 | ntfs_log_trace("Eeek! Mapping pairs update failed. " |
5274 | "Leaving inconstant metadata. " |
5275 | "Run chkdsk.\n"); |
5276 | return -1; |
5277 | } |
5278 | } |
5279 | |
5280 | /* Get the first attribute record. */ |
5281 | ctx = ntfs_attr_get_search_ctx(na->ni, NULL); |
5282 | if (!ctx) |
5283 | return -1; |
5284 | |
5285 | if (ntfs_attr_lookup(na->type, na->name, na->name_len, CASE_SENSITIVE, |
5286 | 0, NULL, 0, ctx)) { |
5287 | err = errno; |
5288 | if (err == ENOENT) |
5289 | err = EIO; |
5290 | ntfs_log_trace("Eeek! Lookup of first attribute extent failed. " |
5291 | "Leaving inconstant metadata.\n"); |
5292 | goto put_err_out; |
5293 | } |
5294 | |
5295 | /* Update data and initialized size. */ |
5296 | na->data_size = newsize; |
5297 | ctx->attr->data_size = cpu_to_sle64(newsize); |
5298 | if (newsize < na->initialized_size) { |
5299 | na->initialized_size = newsize; |
5300 | ctx->attr->initialized_size = cpu_to_sle64(newsize); |
5301 | } |
5302 | /* Update data size in the index. */ |
5303 | if (na->ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) { |
5304 | if (na->type == AT_INDEX_ROOT && na->name == NTFS_INDEX_I30) { |
5305 | na->ni->data_size = na->data_size; |
5306 | na->ni->allocated_size = na->allocated_size; |
5307 | set_nino_flag(na->ni,KnownSize); |
5308 | } |
5309 | } else { |
5310 | if (na->type == AT_DATA && na->name == AT_UNNAMED) { |
5311 | na->ni->data_size = na->data_size; |
5312 | NInoFileNameSetDirty(na->ni); |
5313 | } |
5314 | } |
5315 | |
5316 | /* If the attribute now has zero size, make it resident. */ |
5317 | if (!newsize) { |
5318 | if (ntfs_attr_make_resident(na, ctx)) { |
5319 | /* If couldn't make resident, just continue. */ |
5320 | if (errno != EPERM) |
5321 | ntfs_log_error("Failed to make attribute " |
5322 | "resident. Leaving as is...\n"); |
5323 | } |
5324 | } |
5325 | |
5326 | /* Set the inode dirty so it is written out later. */ |
5327 | ntfs_inode_mark_dirty(ctx->ntfs_ino); |
5328 | /* Done! */ |
5329 | ntfs_attr_put_search_ctx(ctx); |
5330 | return 0; |
5331 | put_err_out: |
5332 | ntfs_attr_put_search_ctx(ctx); |
5333 | errno = err; |
5334 | return -1; |
5335 | } |
5336 | |
5337 | /** |
5338 | * ntfs_non_resident_attr_expand - expand a non-resident, open ntfs attribute |
5339 | * @na: non-resident ntfs attribute to expand |
5340 | * @newsize: new size (in bytes) to which to expand the attribute |
5341 | * |
5342 | * Expand the size of a non-resident, open ntfs attribute @na to @newsize bytes, |
5343 | * by allocating new clusters. |
5344 | * |
5345 | * On success return 0 and on error return -1 with errno set to the error code. |
5346 | * The following error codes are defined: |
5347 | * ENOMEM - Not enough memory to complete operation. |
5348 | * ERANGE - @newsize is not valid for the attribute type of @na. |
5349 | * ENOSPC - There is no enough space in base mft to resize $ATTRIBUTE_LIST. |
5350 | */ |
5351 | static int ntfs_non_resident_attr_expand_i(ntfs_attr *na, const s64 newsize) |
5352 | { |
5353 | LCN lcn_seek_from; |
5354 | VCN first_free_vcn; |
5355 | ntfs_volume *vol; |
5356 | ntfs_attr_search_ctx *ctx; |
5357 | runlist *rl, *rln; |
5358 | s64 org_alloc_size; |
5359 | int err; |
5360 | |
5361 | ntfs_log_trace("Inode %lld, attr 0x%x, new size %lld old size %lld\n", |
5362 | (unsigned long long)na->ni->mft_no, na->type, |
5363 | (long long)newsize, (long long)na->data_size); |
5364 | |
5365 | vol = na->ni->vol; |
5366 | |
5367 | /* |
5368 | * Check the attribute type and the corresponding maximum size |
5369 | * against @newsize and fail if @newsize is too big. |
5370 | */ |
5371 | if (ntfs_attr_size_bounds_check(vol, na->type, newsize) < 0) { |
5372 | if (errno == ENOENT) |
5373 | errno = EIO; |
5374 | ntfs_log_perror("%s: bounds check failed", __FUNCTION__); |
5375 | return -1; |
5376 | } |
5377 | |
5378 | /* Save for future use. */ |
5379 | org_alloc_size = na->allocated_size; |
5380 | /* The first cluster outside the new allocation. */ |
5381 | first_free_vcn = (newsize + vol->cluster_size - 1) >> |
5382 | vol->cluster_size_bits; |
5383 | /* |
5384 | * Compare the new allocation with the old one and only allocate |
5385 | * clusters if there is a change. |
5386 | */ |
5387 | if ((na->allocated_size >> vol->cluster_size_bits) < first_free_vcn) { |
5388 | if (ntfs_attr_map_whole_runlist(na)) { |
5389 | ntfs_log_perror("ntfs_attr_map_whole_runlist failed"); |
5390 | return -1; |
5391 | } |
5392 | |
5393 | /* |
5394 | * If we extend $DATA attribute on NTFS 3+ volume, we can add |
5395 | * sparse runs instead of real allocation of clusters. |
5396 | */ |
5397 | if (na->type == AT_DATA && vol->major_ver >= 3) { |
5398 | rl = ntfs_malloc(0x1000); |
5399 | if (!rl) |
5400 | return -1; |
5401 | |
5402 | rl[0].vcn = (na->allocated_size >> |
5403 | vol->cluster_size_bits); |
5404 | rl[0].lcn = LCN_HOLE; |
5405 | rl[0].length = first_free_vcn - |
5406 | (na->allocated_size >> vol->cluster_size_bits); |
5407 | rl[1].vcn = first_free_vcn; |
5408 | rl[1].lcn = LCN_ENOENT; |
5409 | rl[1].length = 0; |
5410 | } else { |
5411 | /* |
5412 | * Determine first after last LCN of attribute. |
5413 | * We will start seek clusters from this LCN to avoid |
5414 | * fragmentation. If there are no valid LCNs in the |
5415 | * attribute let the cluster allocator choose the |
5416 | * starting LCN. |
5417 | */ |
5418 | lcn_seek_from = -1; |
5419 | if (na->rl->length) { |
5420 | /* Seek to the last run list element. */ |
5421 | for (rl = na->rl; (rl + 1)->length; rl++) |
5422 | ; |
5423 | /* |
5424 | * If the last LCN is a hole or similar seek |
5425 | * back to last valid LCN. |
5426 | */ |
5427 | while (rl->lcn < 0 && rl != na->rl) |
5428 | rl--; |
5429 | /* |
5430 | * Only set lcn_seek_from it the LCN is valid. |
5431 | */ |
5432 | if (rl->lcn >= 0) |
5433 | lcn_seek_from = rl->lcn + rl->length; |
5434 | } |
5435 | |
5436 | rl = ntfs_cluster_alloc(vol, na->allocated_size >> |
5437 | vol->cluster_size_bits, first_free_vcn - |
5438 | (na->allocated_size >> |
5439 | vol->cluster_size_bits), lcn_seek_from, |
5440 | DATA_ZONE); |
5441 | if (!rl) { |
5442 | ntfs_log_perror("Cluster allocation failed " |
5443 | "(%lld)", |
5444 | (long long)first_free_vcn - |
5445 | ((long long)na->allocated_size >> |
5446 | vol->cluster_size_bits)); |
5447 | return -1; |
5448 | } |
5449 | } |
5450 | |
5451 | /* Append new clusters to attribute runlist. */ |
5452 | rln = ntfs_runlists_merge(na->rl, rl); |
5453 | if (!rln) { |
5454 | /* Failed, free just allocated clusters. */ |
5455 | err = errno; |
5456 | ntfs_log_perror("Run list merge failed"); |
5457 | ntfs_cluster_free_from_rl(vol, rl); |
5458 | free(rl); |
5459 | errno = err; |
5460 | return -1; |
5461 | } |
5462 | na->rl = rln; |
5463 | |
5464 | /* Prepare to mapping pairs update. */ |
5465 | na->allocated_size = first_free_vcn << vol->cluster_size_bits; |
5466 | /* Write mapping pairs for new runlist. */ |
5467 | if (ntfs_attr_update_mapping_pairs(na, 0 /*na->allocated_size >> |
5468 | vol->cluster_size_bits*/)) { |
5469 | err = errno; |
5470 | ntfs_log_perror("Mapping pairs update failed"); |
5471 | goto rollback; |
5472 | } |
5473 | } |
5474 | |
5475 | ctx = ntfs_attr_get_search_ctx(na->ni, NULL); |
5476 | if (!ctx) { |
5477 | err = errno; |
5478 | if (na->allocated_size == org_alloc_size) { |
5479 | errno = err; |
5480 | return -1; |
5481 | } else |
5482 | goto rollback; |
5483 | } |
5484 | |
5485 | if (ntfs_attr_lookup(na->type, na->name, na->name_len, CASE_SENSITIVE, |
5486 | 0, NULL, 0, ctx)) { |
5487 | err = errno; |
5488 | ntfs_log_perror("Lookup of first attribute extent failed"); |
5489 | if (err == ENOENT) |
5490 | err = EIO; |
5491 | if (na->allocated_size != org_alloc_size) { |
5492 | ntfs_attr_put_search_ctx(ctx); |
5493 | goto rollback; |
5494 | } else |
5495 | goto put_err_out; |
5496 | } |
5497 | |
5498 | /* Update data size. */ |
5499 | na->data_size = newsize; |
5500 | ctx->attr->data_size = cpu_to_sle64(newsize); |
5501 | /* Update data size in the index. */ |
5502 | if (na->ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) { |
5503 | if (na->type == AT_INDEX_ROOT && na->name == NTFS_INDEX_I30) { |
5504 | na->ni->data_size = na->data_size; |
5505 | na->ni->allocated_size = na->allocated_size; |
5506 | set_nino_flag(na->ni,KnownSize); |
5507 | } |
5508 | } else { |
5509 | if (na->type == AT_DATA && na->name == AT_UNNAMED) { |
5510 | na->ni->data_size = na->data_size; |
5511 | NInoFileNameSetDirty(na->ni); |
5512 | } |
5513 | } |
5514 | /* Set the inode dirty so it is written out later. */ |
5515 | ntfs_inode_mark_dirty(ctx->ntfs_ino); |
5516 | /* Done! */ |
5517 | ntfs_attr_put_search_ctx(ctx); |
5518 | return 0; |
5519 | rollback: |
5520 | /* Free allocated clusters. */ |
5521 | if (ntfs_cluster_free(vol, na, org_alloc_size >> |
5522 | vol->cluster_size_bits, -1) < 0) { |
5523 | err = EIO; |
5524 | ntfs_log_perror("Leaking clusters"); |
5525 | } |
5526 | /* Now, truncate the runlist itself. */ |
5527 | if (ntfs_rl_truncate(&na->rl, org_alloc_size >> |
5528 | vol->cluster_size_bits)) { |
5529 | /* |
5530 | * Failed to truncate the runlist, so just throw it away, it |
5531 | * will be mapped afresh on next use. |
5532 | */ |
5533 | free(na->rl); |
5534 | na->rl = NULL; |
5535 | ntfs_log_perror("Couldn't truncate runlist. Rollback failed"); |
5536 | } else { |
5537 | /* Prepare to mapping pairs update. */ |
5538 | na->allocated_size = org_alloc_size; |
5539 | /* Restore mapping pairs. */ |
5540 | if (ntfs_attr_update_mapping_pairs(na, 0 /*na->allocated_size >> |
5541 | vol->cluster_size_bits*/)) { |
5542 | ntfs_log_perror("Failed to restore old mapping pairs"); |
5543 | } |
5544 | } |
5545 | errno = err; |
5546 | return -1; |
5547 | put_err_out: |
5548 | ntfs_attr_put_search_ctx(ctx); |
5549 | errno = err; |
5550 | return -1; |
5551 | } |
5552 | |
5553 | |
5554 | static int ntfs_non_resident_attr_expand(ntfs_attr *na, const s64 newsize) |
5555 | { |
5556 | int ret; |
5557 | |
5558 | ntfs_log_enter("Entering\n"); |
5559 | ret = ntfs_non_resident_attr_expand_i(na, newsize); |
5560 | ntfs_log_leave("\n"); |
5561 | return ret; |
5562 | } |
5563 | |
5564 | /** |
5565 | * ntfs_attr_truncate - resize an ntfs attribute |
5566 | * @na: open ntfs attribute to resize |
5567 | * @newsize: new size (in bytes) to which to resize the attribute |
5568 | * |
5569 | * Change the size of an open ntfs attribute @na to @newsize bytes. If the |
5570 | * attribute is made bigger and the attribute is resident the newly |
5571 | * "allocated" space is cleared and if the attribute is non-resident the |
5572 | * newly allocated space is marked as not initialised and no real allocation |
5573 | * on disk is performed. |
5574 | * |
5575 | * On success return 0. |
5576 | * On error return values are: |
5577 | * STATUS_RESIDENT_ATTRIBUTE_FILLED_MFT |
5578 | * STATUS_ERROR - otherwise |
5579 | * The following error codes are defined: |
5580 | * EINVAL - Invalid arguments were passed to the function. |
5581 | * EOPNOTSUPP - The desired resize is not implemented yet. |
5582 | * EACCES - Encrypted attribute. |
5583 | */ |
5584 | int ntfs_attr_truncate(ntfs_attr *na, const s64 newsize) |
5585 | { |
5586 | int ret = STATUS_ERROR; |
5587 | s64 fullsize; |
5588 | BOOL compressed; |
5589 | |
5590 | if (!na || newsize < 0 || |
5591 | (na->ni->mft_no == FILE_MFT && na->type == AT_DATA)) { |
5592 | ntfs_log_trace("Invalid arguments passed.\n"); |
5593 | errno = EINVAL; |
5594 | return STATUS_ERROR; |
5595 | } |
5596 | |
5597 | ntfs_log_enter("Entering for inode %lld, attr 0x%x, size %lld\n", |
5598 | (unsigned long long)na->ni->mft_no, na->type, |
5599 | (long long)newsize); |
5600 | |
5601 | if (na->data_size == newsize) { |
5602 | ntfs_log_trace("Size is already ok\n"); |
5603 | ret = STATUS_OK; |
5604 | goto out; |
5605 | } |
5606 | /* |
5607 | * Encrypted attributes are not supported. We return access denied, |
5608 | * which is what Windows NT4 does, too. |
5609 | */ |
5610 | if (na->data_flags & ATTR_IS_ENCRYPTED) { |
5611 | errno = EACCES; |
5612 | ntfs_log_trace("Cannot truncate encrypted attribute\n"); |
5613 | goto out; |
5614 | } |
5615 | /* |
5616 | * TODO: Implement making handling of compressed attributes. |
5617 | * Currently we can only expand the attribute or delete it, |
5618 | * and only for ATTR_IS_COMPRESSED. This is however possible |
5619 | * for resident attributes when there is no open fuse context |
5620 | * (important case : $INDEX_ROOT:$I30) |
5621 | */ |
5622 | compressed = (na->data_flags & ATTR_COMPRESSION_MASK) |
5623 | != const_cpu_to_le16(0); |
5624 | if (compressed |
5625 | && NAttrNonResident(na) |
5626 | && (((na->data_flags & ATTR_COMPRESSION_MASK) != ATTR_IS_COMPRESSED) |
5627 | || (newsize && (newsize < na->data_size)))) { |
5628 | errno = EOPNOTSUPP; |
5629 | ntfs_log_perror("Failed to truncate compressed attribute"); |
5630 | goto out; |
5631 | } |
5632 | if (NAttrNonResident(na)) { |
5633 | /* |
5634 | * For compressed data, the last block must be fully |
5635 | * allocated, and we do not known the size of compression |
5636 | * block until the attribute has been made non-resident. |
5637 | * Moreover we can only process a single compression |
5638 | * block at a time (from where we are about to write), |
5639 | * so we silently do not allocate more. |
5640 | * |
5641 | * Note : do not request truncate on compressed files |
5642 | * unless being able to face the consequences ! |
5643 | */ |
5644 | if (compressed && newsize) |
5645 | fullsize = (na->initialized_size |
5646 | | (na->compression_block_size - 1)) + 1; |
5647 | else |
5648 | fullsize = newsize; |
5649 | if (fullsize > na->data_size) |
5650 | ret = ntfs_non_resident_attr_expand(na, fullsize); |
5651 | else |
5652 | ret = ntfs_non_resident_attr_shrink(na, fullsize); |
5653 | } else |
5654 | ret = ntfs_resident_attr_resize(na, newsize); |
5655 | out: |
5656 | ntfs_log_leave("Return status %d\n", ret); |
5657 | return ret; |
5658 | } |
5659 | |
5660 | /* |
5661 | * Stuff a hole in a compressed file |
5662 | * |
5663 | * An unallocated hole must be aligned on compression block size. |
5664 | * If needed current block and target block are stuffed with zeroes. |
5665 | * |
5666 | * Returns 0 if succeeded, |
5667 | * -1 if it failed (as explained in errno) |
5668 | */ |
5669 | |
5670 | static int stuff_hole(ntfs_attr *na, const s64 pos) |
5671 | { |
5672 | s64 size; |
5673 | s64 begin_size; |
5674 | s64 end_size; |
5675 | char *buf; |
5676 | int ret; |
5677 | |
5678 | ret = 0; |
5679 | /* |
5680 | * If the attribute is resident, the compression block size |
5681 | * is not defined yet and we can make no decision. |
5682 | * So we first try resizing to the target and if the |
5683 | * attribute is still resident, we're done |
5684 | */ |
5685 | if (!NAttrNonResident(na)) { |
5686 | ret = ntfs_resident_attr_resize(na, pos); |
5687 | if (!ret && !NAttrNonResident(na)) |
5688 | na->initialized_size = na->data_size = pos; |
5689 | } |
5690 | if (!ret && NAttrNonResident(na)) { |
5691 | /* does the hole span over several compression block ? */ |
5692 | if ((pos ^ na->initialized_size) |
5693 | & ~(na->compression_block_size - 1)) { |
5694 | begin_size = ((na->initialized_size - 1) |
5695 | | (na->compression_block_size - 1)) |
5696 | + 1 - na->initialized_size; |
5697 | end_size = pos & (na->compression_block_size - 1); |
5698 | size = (begin_size > end_size ? begin_size : end_size); |
5699 | } else { |
5700 | /* short stuffing in a single compression block */ |
5701 | begin_size = size = pos - na->initialized_size; |
5702 | end_size = 0; |
5703 | } |
5704 | if (size) |
5705 | buf = (char*)ntfs_malloc(size); |
5706 | else |
5707 | buf = (char*)NULL; |
5708 | if (buf || !size) { |
5709 | memset(buf,0,size); |
5710 | /* stuff into current block */ |
5711 | if (begin_size |
5712 | && (ntfs_attr_pwrite(na, |
5713 | na->initialized_size, begin_size, buf) |
5714 | != begin_size)) |
5715 | ret = -1; |
5716 | /* create an unstuffed hole */ |
5717 | if (!ret |
5718 | && ((na->initialized_size + end_size) < pos) |
5719 | && ntfs_non_resident_attr_expand(na, |
5720 | pos - end_size)) |
5721 | ret = -1; |
5722 | else |
5723 | na->initialized_size |
5724 | = na->data_size = pos - end_size; |
5725 | /* stuff into the target block */ |
5726 | if (!ret && end_size |
5727 | && (ntfs_attr_pwrite(na, |
5728 | na->initialized_size, end_size, buf) |
5729 | != end_size)) |
5730 | ret = -1; |
5731 | if (buf) |
5732 | free(buf); |
5733 | } else |
5734 | ret = -1; |
5735 | } |
5736 | /* make absolutely sure we have reached the target */ |
5737 | if (!ret && (na->initialized_size != pos)) { |
5738 | ntfs_log_error("Failed to stuff a compressed file" |
5739 | "target %lld reached %lld\n", |
5740 | (long long)pos, (long long)na->initialized_size); |
5741 | errno = EIO; |
5742 | ret = -1; |
5743 | } |
5744 | return (ret); |
5745 | } |
5746 | |
5747 | /** |
5748 | * ntfs_attr_readall - read the entire data from an ntfs attribute |
5749 | * @ni: open ntfs inode in which the ntfs attribute resides |
5750 | * @type: attribute type |
5751 | * @name: attribute name in little endian Unicode or AT_UNNAMED or NULL |
5752 | * @name_len: length of attribute @name in Unicode characters (if @name given) |
5753 | * @data_size: if non-NULL then store here the data size |
5754 | * |
5755 | * This function will read the entire content of an ntfs attribute. |
5756 | * If @name is AT_UNNAMED then look specifically for an unnamed attribute. |
5757 | * If @name is NULL then the attribute could be either named or not. |
5758 | * In both those cases @name_len is not used at all. |
5759 | * |
5760 | * On success a buffer is allocated with the content of the attribute |
5761 | * and which needs to be freed when it's not needed anymore. If the |
5762 | * @data_size parameter is non-NULL then the data size is set there. |
5763 | * |
5764 | * On error NULL is returned with errno set to the error code. |
5765 | */ |
5766 | void *ntfs_attr_readall(ntfs_inode *ni, const ATTR_TYPES type, |
5767 | ntfschar *name, u32 name_len, s64 *data_size) |
5768 | { |
5769 | ntfs_attr *na; |
5770 | void *data, *ret = NULL; |
5771 | s64 size; |
5772 | |
5773 | ntfs_log_enter("Entering\n"); |
5774 | |
5775 | na = ntfs_attr_open(ni, type, name, name_len); |
5776 | if (!na) { |
5777 | ntfs_log_perror("ntfs_attr_open failed"); |
5778 | goto err_exit; |
5779 | } |
5780 | data = ntfs_malloc(na->data_size); |
5781 | if (!data) |
5782 | goto out; |
5783 | |
5784 | size = ntfs_attr_pread(na, 0, na->data_size, data); |
5785 | if (size != na->data_size) { |
5786 | ntfs_log_perror("ntfs_attr_pread failed"); |
5787 | free(data); |
5788 | goto out; |
5789 | } |
5790 | ret = data; |
5791 | if (data_size) |
5792 | *data_size = size; |
5793 | out: |
5794 | ntfs_attr_close(na); |
5795 | err_exit: |
5796 | ntfs_log_leave("\n"); |
5797 | return ret; |
5798 | } |
5799 | |
5800 | |
5801 | |
5802 | int ntfs_attr_exist(ntfs_inode *ni, const ATTR_TYPES type, ntfschar *name, |
5803 | u32 name_len) |
5804 | { |
5805 | ntfs_attr_search_ctx *ctx; |
5806 | int ret; |
5807 | |
5808 | ntfs_log_trace("Entering\n"); |
5809 | |
5810 | ctx = ntfs_attr_get_search_ctx(ni, NULL); |
5811 | if (!ctx) |
5812 | return 0; |
5813 | |
5814 | ret = ntfs_attr_lookup(type, name, name_len, CASE_SENSITIVE, 0, NULL, 0, |
5815 | ctx); |
5816 | |
5817 | ntfs_attr_put_search_ctx(ctx); |
5818 | |
5819 | return !ret; |
5820 | } |
5821 | |
5822 | int ntfs_attr_remove(ntfs_inode *ni, const ATTR_TYPES type, ntfschar *name, |
5823 | u32 name_len) |
5824 | { |
5825 | ntfs_attr *na; |
5826 | int ret; |
5827 | |
5828 | ntfs_log_trace("Entering\n"); |
5829 | |
5830 | if (!ni) { |
5831 | ntfs_log_error("%s: NULL inode pointer", __FUNCTION__); |
5832 | errno = EINVAL; |
5833 | return -1; |
5834 | } |
5835 | |
5836 | na = ntfs_attr_open(ni, type, name, name_len); |
5837 | if (!na) { |
5838 | /* do not log removal of non-existent stream */ |
5839 | if (type != AT_DATA) { |
5840 | ntfs_log_perror("Failed to open attribute 0x%02x of inode " |
5841 | "0x%llx", type, (unsigned long long)ni->mft_no); |
5842 | } |
5843 | return -1; |
5844 | } |
5845 | |
5846 | ret = ntfs_attr_rm(na); |
5847 | if (ret) |
5848 | ntfs_log_perror("Failed to remove attribute 0x%02x of inode " |
5849 | "0x%llx", type, (unsigned long long)ni->mft_no); |
5850 | ntfs_attr_close(na); |
5851 | |
5852 | return ret; |
5853 | } |
5854 | |
5855 | /* Below macros are 32-bit ready. */ |
5856 | #define BCX(x) ((x) - (((x) >> 1) & 0x77777777) - \ |
5857 | (((x) >> 2) & 0x33333333) - \ |
5858 | (((x) >> 3) & 0x11111111)) |
5859 | #define BITCOUNT(x) (((BCX(x) + (BCX(x) >> 4)) & 0x0F0F0F0F) % 255) |
5860 | |
5861 | static u8 *ntfs_init_lut256(void) |
5862 | { |
5863 | int i; |
5864 | u8 *lut; |
5865 | |
5866 | lut = ntfs_malloc(256); |
5867 | if (lut) |
5868 | for(i = 0; i < 256; i++) |
5869 | *(lut + i) = 8 - BITCOUNT(i); |
5870 | return lut; |
5871 | } |
5872 | |
5873 | s64 ntfs_attr_get_free_bits(ntfs_attr *na) |
5874 | { |
5875 | u8 *buf, *lut; |
5876 | s64 br = 0; |
5877 | s64 total = 0; |
5878 | s64 nr_free = 0; |
5879 | |
5880 | lut = ntfs_init_lut256(); |
5881 | if (!lut) |
5882 | return -1; |
5883 | |
5884 | buf = ntfs_malloc(65536); |
5885 | if (!buf) |
5886 | goto out; |
5887 | |
5888 | while (1) { |
5889 | u32 *p; |
5890 | br = ntfs_attr_pread(na, total, 65536, buf); |
5891 | if (br <= 0) |
5892 | break; |
5893 | total += br; |
5894 | p = (u32 *)buf + br / 4 - 1; |
5895 | for (; (u8 *)p >= buf; p--) { |
5896 | nr_free += lut[ *p & 255] + |
5897 | lut[(*p >> 8) & 255] + |
5898 | lut[(*p >> 16) & 255] + |
5899 | lut[(*p >> 24) ]; |
5900 | } |
5901 | switch (br % 4) { |
5902 | case 3: nr_free += lut[*(buf + br - 3)]; |
5903 | case 2: nr_free += lut[*(buf + br - 2)]; |
5904 | case 1: nr_free += lut[*(buf + br - 1)]; |
5905 | } |
5906 | } |
5907 | free(buf); |
5908 | out: |
5909 | free(lut); |
5910 | if (!total || br < 0) |
5911 | return -1; |
5912 | return nr_free; |
5913 | } |
5914 |