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