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