2 * attrib.c - Attribute handling code. Part of the Linux-NTFS project.
4 * Copyright (c) 2000-2003 Anton Altaparmakov
5 * Copyright (c) 2002 Richard Russon
7 * This program/include file is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as published
9 * by the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program/include file is distributed in the hope that it will be
13 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program (in the main directory of the Linux-NTFS
19 * distribution in the file COPYING); if not, write to the Free Software
20 * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
43 uchar_t AT_UNNAMED[] = { const_cpu_to_le16('\0') };
46 * ntfs_get_attribute_value_length
48 s64 ntfs_get_attribute_value_length(const ATTR_RECORD *a)
56 return sle64_to_cpu(a->data_size);
58 return (s64)le32_to_cpu(a->value_length);
64 * ntfs_get_attribute_value
66 s64 ntfs_get_attribute_value(const ntfs_volume *vol, const MFT_RECORD *m,
67 const ATTR_RECORD *a, u8 *b)
70 if (!vol || !m || !a || !b) {
74 /* Complex attribute? */
76 puts("Enountered non-zero attribute flags. Cannot handle this "
81 if (!a->non_resident) { /* Attribute is resident. */
83 if (le32_to_cpu(a->value_length) +
84 le16_to_cpu(a->value_offset) > le32_to_cpu(a->length)) {
87 memcpy(b, (char*)a + le16_to_cpu(a->value_offset),
88 le32_to_cpu(a->value_length));
90 return (s64)le32_to_cpu(a->value_length);
91 } else { /* Attribute is not resident. */
96 /* If no data, return 0. */
97 if (!(a->data_size)) {
102 * FIXME: What about attribute lists?!? (AIA)
104 /* Decompress the mapping pairs array into a runlist. */
105 rl = ntfs_mapping_pairs_decompress(vol, a, NULL);
111 * FIXED: We were overflowing here in a nasty fashion when we
112 * reach the last cluster in the runlist as the buffer will
113 * only be big enough to hold data_size bytes while we are
114 * reading in allocated_size bytes which is usually larger
115 * than data_size, since the actual data is unlikely to have a
116 * size equal to a multiple of the cluster size!
118 /* Now load all clusters in the runlist into b. */
119 for (i = 0, total = 0; rl[i].length; i++) {
120 if (!rl[i+1].length) {
121 unsigned char *intbuf = NULL;
123 * We have reached the last run so we were
124 * going to overflow when executing the
125 * ntfs_pread() which is BAAAAAAAD!
127 * Allocate a new buffer with size:
128 * rl[i].length << vol->cluster_size_bits,
129 * do the read into our buffer, then
130 * memcpy the correct amount of data into
131 * the caller supplied buffer, free our
132 * buffer, and continue.
134 intbuf = malloc(rl[i].length <<
135 vol->cluster_size_bits);
138 perror("Couldn't allocate memory for "
139 "internal buffer.\n");
145 * FIXME: If compressed file: Only read if
146 * lcn != -1. Otherwise, we are dealing with a
147 * sparse run and we just memset the user buffer
148 * to 0 for the length of the run, which should
149 * be 16 (= compression unit size).
150 * FIXME: Really only when file is compressed,
151 * or can we have sparse runs in uncompressed
154 r = ntfs_pread(vol->dev, rl[i].lcn <<
155 vol->cluster_size_bits,
157 vol->cluster_size_bits, intbuf);
158 if (r != rl[i].length <<
159 vol->cluster_size_bits) {
160 #define ESTR "Error reading attribute value"
165 } else if (r < rl[i].length <<
166 vol->cluster_size_bits
168 fprintf(stderr, ESTR ": Ran "
169 "out of input data.\n");
172 fprintf(stderr, ESTR ": "
180 memcpy(b + total, intbuf,
181 sle64_to_cpu(a->data_size) - total);
183 total = sle64_to_cpu(a->data_size);
186 * FIXME: If compressed file: Only read if
187 * lcn != -1. Otherwise, we are dealing with a
188 * sparse run and we just memset the user buffer
189 * to 0 for the length of the run, which should
190 * be 16 (= compression unit size).
192 r = ntfs_pread(vol->dev, rl[i].lcn <<
193 vol->cluster_size_bits,
195 vol->cluster_size_bits,
197 if (r != rl[i].length <<
198 vol->cluster_size_bits) {
199 #define ESTR "Error reading attribute value"
204 } else if (r < rl[i].length <<
205 vol->cluster_size_bits
207 fprintf(stderr, ESTR ": Ran "
208 "out of input data.\n");
211 fprintf(stderr, ESTR ": "
228 /* Already cleaned up code below, but still look for FIXME:... */
233 * __ntfs_attr_init - primary initialization of an ntfs attribute structure
234 * @na: ntfs attribute to initialize
235 * @ni: ntfs inode with which to initialize the ntfs attribute
236 * @type: attribute type
237 * @name: attribute name in little endian Unicode or NULL
238 * @name_len: length of attribute @name in Unicode characters (if @name given)
240 * Initialize the ntfs attribute @na with @ni, @type, @name, and @name_len.
242 static __inline__ void __ntfs_attr_init(ntfs_attr *na, ntfs_inode *ni,
243 const ATTR_TYPES type, uchar_t *name, const u32 name_len)
250 na->name_len = name_len;
252 na->name = AT_UNNAMED;
258 * ntfs_attr_init - initialize an ntfs_attr with data sizes and status
270 * Final initialization for an ntfs attribute.
272 void ntfs_attr_init(ntfs_attr *na, const BOOL non_resident,
273 const BOOL compressed, const BOOL encrypted, const BOOL sparse,
274 const s64 allocated_size, const s64 data_size,
275 const s64 initialized_size, const s64 compressed_size,
276 const u8 compression_unit)
278 if (!NAttrInitialized(na)) {
280 NAttrSetNonResident(na);
282 NAttrSetCompressed(na);
284 NAttrSetEncrypted(na);
287 na->allocated_size = allocated_size;
288 na->data_size = data_size;
289 na->initialized_size = initialized_size;
290 if (compressed || sparse) {
291 ntfs_volume *vol = na->ni->vol;
293 na->compressed_size = compressed_size;
294 na->compression_block_clusters = 1 << compression_unit;
295 na->compression_block_size = 1 << (compression_unit +
296 vol->cluster_size_bits);
297 na->compression_block_size_bits = ffs(
298 na->compression_block_size) - 1;
300 NAttrSetInitialized(na);
305 * ntfs_attr_open - open an ntfs attribute for access
306 * @ni: open ntfs inode in which the ntfs attribute resides
307 * @type: attribute type
308 * @name: attribute name in little endian Unicode or NULL
309 * @name_len: length of attribute @name in Unicode characters (if @name given)
311 * Allocate a new ntfs attribute structure, initialize it with @ni, @type,
312 * @name, and @name_len, then return it. Return NULL on error with
313 * errno set to the error code.
315 * If looking for an unnamed attribute set @name to NULL. @name_len is not used
316 * at all in that case.
318 ntfs_attr *ntfs_attr_open(ntfs_inode *ni, const ATTR_TYPES type,
319 uchar_t *name, const u32 name_len)
321 ntfs_attr_search_ctx *ctx;
326 Dprintf("%s(): Entering for inode 0x%Lx, attr 0x%x.\n", __FUNCTION__,
327 (unsigned long long)ni->mft_no, type);
328 if (!ni || !ni->vol || !ni->mrec) {
332 na = calloc(sizeof(ntfs_attr), 1);
335 __ntfs_attr_init(na, ni, type, name, name_len);
337 ctx = ntfs_attr_get_search_ctx(ni, NULL);
343 if (ntfs_attr_lookup(type, name, name_len, 0, 0, NULL, 0, ctx)) {
348 if (a->non_resident) {
349 BOOL cs = a->flags & (ATTR_IS_COMPRESSED | ATTR_IS_SPARSE);
350 ntfs_attr_init(na, TRUE, a->flags & ATTR_IS_COMPRESSED,
351 a->flags & ATTR_IS_ENCRYPTED,
352 a->flags & ATTR_IS_SPARSE,
353 sle64_to_cpu(a->allocated_size),
354 sle64_to_cpu(a->data_size),
355 sle64_to_cpu(a->initialized_size),
356 cs ? sle64_to_cpu(a->compressed_size) : 0,
357 cs ? a->compression_unit : 0);
359 s64 l = le32_to_cpu(a->value_length);
360 if (a->flags & (ATTR_COMPRESSION_MASK | ATTR_IS_ENCRYPTED |
365 ntfs_attr_init(na, FALSE, FALSE, FALSE, FALSE, l, l, l, 0, 0);
367 ntfs_attr_put_search_ctx(ctx);
370 ntfs_attr_put_search_ctx(ctx);
377 * ntfs_attr_close - free an ntfs attribute structure
378 * @na: ntfs attribute structure to free
380 * Release all memory associated with the ntfs attribute @na and then release
383 void ntfs_attr_close(ntfs_attr *na)
385 if (NAttrNonResident(na) && na->rl)
387 /* Don't release if using an internal constant. */
388 if (na->name != AT_UNNAMED && na->name != I30)
395 * ntfs_attr_map_runlist - map (a part of) a runlist of an ntfs attribute
396 * @na: ntfs attribute for which to map (part of) a runlist
397 * @vcn: map runlist part containing this vcn
399 * Map the part of a runlist containing the @vcn of an the ntfs attribute @na.
401 * Return 0 on success and -1 on error with errno set to the error code.
403 int ntfs_attr_map_runlist(ntfs_attr *na, VCN vcn)
405 ntfs_attr_search_ctx *ctx;
408 Dprintf("%s(): Entering for inode 0x%Lx, attr 0x%x, vcn 0x%Lx.\n",
409 __FUNCTION__, (unsigned long long)na->ni->mft_no,
410 na->type, (long long)vcn);
412 ctx = ntfs_attr_get_search_ctx(na->ni, NULL);
416 /* Find the attribute in the mft record. */
417 if (!ntfs_attr_lookup(na->type, na->name, na->name_len, CASE_SENSITIVE,
418 vcn, NULL, 0, ctx)) {
421 /* Decode the runlist. */
422 rl = ntfs_mapping_pairs_decompress(na->ni->vol, ctx->attr,
427 ntfs_attr_put_search_ctx(ctx);
432 ntfs_attr_put_search_ctx(ctx);
438 * ntfs_attr_vcn_to_lcn - convert a vcn into a lcn given an ntfs attribute
439 * @na: ntfs attribute whose runlist to use for conversion
440 * @vcn: vcn to convert
442 * Convert the virtual cluster number @vcn of an attribute into a logical
443 * cluster number (lcn) of a device using the runlist @na->rl to map vcns to
444 * their corresponding lcns.
446 * If the @vcn is not mapped yet, attempt to map the attribute extent
447 * containing the @vcn and retry the vcn to lcn conversion.
449 * Since lcns must be >= 0, we use negative return values with special meaning:
451 * Return value Meaning / Description
452 * ==========================================
453 * -1 = LCN_HOLE Hole / not allocated on disk.
454 * -3 = LCN_ENOENT There is no such vcn in the attribute.
455 * -4 = LCN_EINVAL Input parameter error.
456 * -5 = LCN_EIO Corrupt fs, disk i/o error, or not enough memory.
458 LCN ntfs_attr_vcn_to_lcn(ntfs_attr *na, const VCN vcn)
461 BOOL is_retry = FALSE;
463 if (!na || !NAttrNonResident(na) || vcn < 0)
464 return (LCN)LCN_EINVAL;
466 /* Convert vcn to lcn. If that fails map the runlist and retry once. */
467 lcn = ntfs_rl_vcn_to_lcn(na->rl, vcn);
470 if (!is_retry && !ntfs_attr_map_runlist(na, vcn)) {
475 * If the attempt to map the runlist failed, or we are getting
476 * LCN_RL_NOT_MAPPED despite having mapped the attribute extent
477 * successfully, something is really badly wrong...
479 if (!is_retry || lcn == (LCN)LCN_RL_NOT_MAPPED)
481 /* lcn contains the appropriate error code. */
486 * ntfs_attr_find_vcn - find a vcn in the runlist of an ntfs attribute
487 * @na: ntfs attribute whose runlist to search
490 * Find the virtual cluster number @vcn in the runlist of the ntfs attribute
491 * @na and return the the address of the runlist element containing the @vcn.
493 * Note you need to distinguish between the lcn of the returned runlist
494 * element being >= 0 and LCN_HOLE. In the later case you have to return zeroes
495 * on read and allocate clusters on write. You need to update the runlist, the
496 * attribute itself as well as write the modified mft record to disk.
498 * If there is an error return NULL with errno set to the error code. The
499 * following error codes are defined:
500 * EINVAL Input parameter error.
501 * ENOENT There is no such vcn in the runlist.
502 * ENOMEM Not enough memory.
503 * EIO I/O error or corrupt metadata.
505 runlist_element *ntfs_attr_find_vcn(ntfs_attr *na, const VCN vcn)
508 BOOL is_retry = FALSE;
510 if (!na || !NAttrNonResident(na) || vcn < 0) {
521 if (vcn < rl[1].vcn) {
522 if (rl->lcn >= (LCN)LCN_HOLE)
529 case (LCN)LCN_RL_NOT_MAPPED:
531 case (LCN)LCN_ENOENT:
534 case (LCN)LCN_EINVAL:
543 /* The @vcn is in an unmapped region, map the runlist and retry. */
544 if (!is_retry && !ntfs_attr_map_runlist(na, vcn)) {
549 * If we already retried or the mapping attempt failed something has
550 * gone badly wrong. EINVAL and ENOENT coming from a failed mapping
551 * attempt are equivalent to errors for us as they should not happen
554 if (is_retry || errno == EINVAL || errno == ENOENT)
560 * ntfs_attr_pread - read from an attribute specified by an ntfs_attr structure
561 * @na: ntfs attribute to read from
562 * @pos: byte position in the attribute to begin reading from
563 * @count: number of bytes to read
564 * @b: output data buffer
566 * This function will read @count bytes starting at offset @pos from the ntfs
567 * attribute @na into the data buffer @b.
569 * On success, return the number of successfully read bytes. If this number is
570 * lower than @count this means that the read reached end of file or that an
571 * error was encountered during the read so that the read is partial. 0 means
572 * end of file or nothing was read (also return 0 when @count is 0).
574 * On error and nothing has been read, return -1 with errno set appropriately
575 * to the return code of ntfs_pread(), or to EINVAL in case of invalid
578 s64 ntfs_attr_pread(ntfs_attr *na, const s64 pos, s64 count, void *b)
580 s64 br, to_read, ofs, total, total2;
584 Dprintf("%s(): Entering for inode 0x%Lx, attr 0x%x, pos 0x%Lx, "
585 "count 0x%Lx.\n", __FUNCTION__,
586 (unsigned long long)na->ni->mft_no, na->type,
587 (long long)pos, (long long)count);
588 if (!na || !na->ni || !na->ni->vol || !b || pos < 0 || count < 0) {
594 * Encrypted attributes are not supported. We return access denied,
595 * which is what Windows NT4 does, too.
597 if (NAttrEncrypted(na)) {
601 /* If this is a compressed attribute it needs special treatment. */
602 if (NAttrCompressed(na)) {
603 // TODO: Implement reading compressed attributes! (AIA)
604 // return ntfs_attr_pread_compressed(ntfs_attr *na,
605 // const s64 pos, s64 count, void *b);
611 /* Truncate reads beyond end of attribute. */
612 if (pos + count > na->data_size) {
613 if (pos >= na->data_size)
615 count = na->data_size - pos;
617 /* If it is a resident attribute, get the value from the mft record. */
618 if (!NAttrNonResident(na)) {
619 ntfs_attr_search_ctx *ctx;
622 ctx = ntfs_attr_get_search_ctx(na->ni, NULL);
625 if (ntfs_attr_lookup(na->type, na->name, na->name_len, 0,
630 ntfs_attr_put_search_ctx(ctx);
634 val = (char*)ctx->attr + le16_to_cpu(ctx->attr->value_offset);
635 if (val < (char*)ctx->attr || val +
636 le32_to_cpu(ctx->attr->value_length) >
637 (char*)ctx->mrec + vol->mft_record_size) {
641 memcpy(b, val + pos, count);
642 ntfs_attr_put_search_ctx(ctx);
646 /* Zero out reads beyond initialized size. */
647 if (pos + count > na->initialized_size) {
648 if (pos >= na->initialized_size) {
652 total2 = pos + count - na->initialized_size;
654 memset((u8*)b + count, 0, total2);
656 /* Find the runlist element containing the vcn. */
657 rl = ntfs_attr_find_vcn(na, pos >> vol->cluster_size_bits);
660 * If the vcn is not present it is an out of bounds read.
661 * However, we already truncated the read to the data_size,
662 * so getting this here is an error.
669 * Gather the requested data into the linear destination buffer. Note,
670 * a partial final vcn is taken care of by the @count capping of read
673 ofs = pos - (rl->vcn << vol->cluster_size_bits);
674 for (; count; rl++, ofs = 0) {
677 if (rl->lcn < (LCN)0) {
678 if (rl->lcn != (LCN)LCN_HOLE)
680 /* It is a hole, just zero the matching @b range. */
681 to_read = min(count, (rl->length <<
682 vol->cluster_size_bits) - ofs);
683 memset(b, 0, to_read);
684 /* Update progress counters. */
690 /* It is a real lcn, read it into @dst. */
691 to_read = min(count, (rl->length << vol->cluster_size_bits) -
694 Dprintf("%s(): Reading 0x%Lx bytes from vcn 0x%Lx, lcn 0x%Lx, "
695 "ofs 0x%Lx.\n", __FUNCTION__, to_read,
696 rl->vcn, rl->lcn, ofs);
697 br = ntfs_pread(vol->dev, (rl->lcn << vol->cluster_size_bits) +
699 /* If everything ok, update progress counters and continue. */
706 /* If the syscall was interrupted, try again. */
707 if (br == (s64)-1 && errno == EINTR)
715 /* Finally, return the number of bytes read. */
716 return total + total2;
725 * ntfs_attr_pwrite - positioned write to an ntfs attribute
726 * @na: ntfs attribute to write to
727 * @pos: position in the attribute to write to
728 * @count: number of bytes to write
729 * @b: data buffer to write to disk
731 * This function will write @count bytes from data buffer @b to ntfs attribute
732 * @na at position @pos.
734 * On success, return the number of successfully written bytes. If this number
735 * is lower than @count this means that an error was encountered during the
736 * write so that the write is partial. 0 means nothing was written (also return
737 * 0 when @count is 0).
739 * On error and nothing has been written, return -1 with errno set
740 * appropriately to the return code of ntfs_pwrite(), or to EINVAL in case of
743 * NOTE: Currently changes in length of the attribute @na are not implemented.
744 * Thus if such a change is requested we return -1 with errno set to ENOTSUP.
746 s64 ntfs_attr_pwrite(ntfs_attr *na, const s64 pos, s64 count, void *b)
748 s64 written, to_write, ofs, total, old_initialized_size;
750 ntfs_attr_search_ctx *ctx = NULL;
754 unsigned int initialized_size : 1;
755 } need_to_undo = { 0 };
757 Dprintf("%s(): Entering for inode 0x%Lx, attr 0x%x, pos 0x%Lx, "
758 "count 0x%Lx.\n", __FUNCTION__, na->ni->mft_no,
759 na->type, (long long)pos, (long long)count);
760 if (!na || !na->ni || !na->ni->vol || !b || pos < 0 || count < 0) {
766 * Encrypted attributes are not supported. We return access denied,
767 * which is what Windows NT4 does, too.
769 if (NAttrEncrypted(na)) {
773 /* If this is a compressed attribute it needs special treatment. */
774 if (NAttrCompressed(na)) {
775 // TODO: Implement writing compressed attributes! (AIA)
776 // return ntfs_attr_pwrite_compressed(ntfs_attr *na,
777 // const s64 pos, s64 count, void *b);
783 /* If the write reaches beyond the end, extend the attribute. */
784 if (pos + count > na->data_size) {
785 // TODO: Need to extend the attribute. For now, just do a
786 // partial write or abort if completely out of bounds. (AIA)
787 if (pos >= na->data_size) {
791 count = na->data_size - pos;
793 old_initialized_size = na->initialized_size;
794 /* If it is a resident attribute, write the data to the mft record. */
795 if (!NAttrNonResident(na)) {
798 ctx = ntfs_attr_get_search_ctx(na->ni, NULL);
801 if (ntfs_attr_lookup(na->type, na->name, na->name_len, 0,
804 val = (char*)ctx->attr + le16_to_cpu(ctx->attr->value_offset);
805 if (val < (char*)ctx->attr || val +
806 le32_to_cpu(ctx->attr->value_length) >
807 (char*)ctx->mrec + vol->mft_record_size) {
811 memcpy(val + pos, b, count);
812 if (ntfs_mft_record_write(vol, ctx->ntfs_ino->mft_no,
815 * NOTE: We are in a bad state at this moment. We have
816 * dirtied the mft record but we failed to commit it to
817 * disk. Since we have read the mft record ok before,
818 * it is unlikely to fail writing it, so is ok to just
819 * return error here... (AIA)
823 ntfs_attr_put_search_ctx(ctx);
827 /* Find the runlist element containing the vcn. */
828 rl = ntfs_attr_find_vcn(na, pos >> vol->cluster_size_bits);
831 * If the vcn is not present it is an out of bounds write.
832 * However, we already extended the size of the attribute,
833 * so getting this here must be an error of some kind.
839 /* Handle writes beyond initialized_size. */
840 if (pos + count > na->initialized_size) {
841 /* Set initialized_size to @pos + @count. */
842 ctx = ntfs_attr_get_search_ctx(na->ni, NULL);
845 if (ntfs_attr_lookup(na->type, na->name, na->name_len, 0,
848 /* If write starts beyond initialized_size, zero the gap. */
849 if (pos > na->initialized_size) {
850 // TODO: Need to write zeroes in the region from
851 // na->initialized_size to @pos, then update the
852 // initialized size to equal @pos. If any sparse runs
853 // are encountered while filling the gap, need to
854 // honour them, i.e. do not instantiate them. Then can
855 // continue as if pos <= na->initialized_size, i.e. can
856 // just fall through and continue. (AIA)
860 ctx->attr->initialized_size = scpu_to_le64(pos + count);
861 if (ntfs_mft_record_write(vol, ctx->ntfs_ino->mft_no,
864 * Undo the change in the in-memory copy and send it
867 ctx->attr->initialized_size =
868 scpu_to_le64(old_initialized_size);
869 ntfs_mft_record_write(vol, ctx->ntfs_ino->mft_no,
873 na->initialized_size = pos + count;
874 ntfs_attr_put_search_ctx(ctx);
877 * NOTE: At this point the initialized_size in the mft record
878 * has been updated BUT there is random data on disk thus if
879 * we decide to abort, we MUST change the initialized_size
882 need_to_undo.initialized_size = 1;
885 * Scatter the data from the linear data buffer to the volume. Note, a
886 * partial final vcn is taken care of by the @count capping of write
889 ofs = pos - (rl->vcn << vol->cluster_size_bits);
890 for (; count; rl++, ofs = 0) {
895 if (rl->lcn < (LCN)0) {
899 if (rl->lcn != (LCN)LCN_HOLE) {
904 * It is a hole. Check if the data buffer is zero in
905 * this region and if not instantiate the hole.
907 to_write = min(count, (rl->length <<
908 vol->cluster_size_bits) - ofs);
909 written = to_write / sizeof(unsigned long);
911 for (t = 0; t < written; t++) {
912 if (((unsigned long*)b)[t]) {
917 cnt = to_write & (sizeof(unsigned long) - 1);
922 b2 = (u8*)b + (to_write &
923 ~(sizeof(unsigned long) - 1));
924 for (i = 0; i < cnt; i++) {
932 // TODO: Need to instantiate the hole. Then get
933 // the runlist element again checking if it is
934 // ok and fall through to do the writing. (AIA)
939 * The buffer region is zero, update progress counters
940 * and proceed with next run.
947 /* It is a real lcn, write it to the volume. */
948 to_write = min(count, (rl->length << vol->cluster_size_bits) -
951 Dprintf("%s(): Writing 0x%Lx bytes to vcn 0x%Lx, lcn 0x%Lx, "
952 "ofs 0x%Lx.\n", __FUNCTION__, to_write,
953 rl->vcn, rl->lcn, ofs);
954 if (!NVolReadOnly(vol))
955 written = ntfs_pwrite(vol->dev, (rl->lcn <<
956 vol->cluster_size_bits) + ofs,
960 /* If everything ok, update progress counters and continue. */
967 /* If the syscall was interrupted, try again. */
968 if (written == (s64)-1 && errno == EINTR)
976 ntfs_attr_put_search_ctx(ctx);
977 /* Finally, return the number of bytes written. */
982 if (need_to_undo.initialized_size) {
983 if (pos + total > na->initialized_size)
985 // TODO: Need to try to change initialized_size. If it
986 // succeeds goto done, otherwise goto err_out. (AIA)
995 if (need_to_undo.initialized_size) {
1000 ctx = ntfs_attr_get_search_ctx(na->ni, NULL);
1004 ntfs_attr_reinit_search_ctx(ctx);
1006 err = ntfs_attr_lookup(na->type, na->name,
1007 na->name_len, 0, 0, NULL, 0, ctx);
1009 na->initialized_size = old_initialized_size;
1010 ctx->attr->initialized_size = scpu_to_le64(
1011 old_initialized_size);
1012 err = ntfs_mft_record_write(vol,
1013 ctx->ntfs_ino->mft_no,
1018 Dputs("Eeek! Failed to recover from error. Leaving "
1019 "metadata in inconsistent state! Run "
1021 // FIXME: At this stage could try to recover by filling
1022 // old_initialized_size -> new_initialized_size with
1023 // data or at least zeroes. (AIA)
1027 ntfs_attr_put_search_ctx(ctx);
1033 * ntfs_attr_mst_pread - multi sector transfer protected ntfs attribute read
1034 * @na: multi sector transfer protected ntfs attribute to read from
1035 * @pos: byte position in the attribute to begin reading from
1036 * @bk_cnt: number of mst protected blocks to read
1037 * @bk_size: size of each mst protected block in bytes
1038 * @b: output data buffer
1040 * This function will read @bk_cnt blocks of size @bk_size bytes each starting
1041 * at offset @pos from the ntfs attribute @na into the data buffer @b.
1043 * On success, the multi sector transfer fixups are applied and the number of
1044 * read blocks is returned. If this number is lower than @bk_cnt this means
1045 * that the read has either reached end of attribute or that an error was
1046 * encountered during the read so that the read is partial. 0 means end of
1047 * attribute or nothing to read (also return 0 when @bk_cnt or @bk_size are 0).
1049 * On error and nothing has been read, return -1 with errno set appropriately
1050 * to the return code of ntfs_attr_pread() or to EINVAL in case of invalid
1053 * NOTE: If an incomplete multi sector transfer is detected the magic is
1054 * changed to BAAD but no error is returned, i.e. it is possible that any of
1055 * the returned blocks have multi sector transfer errors. This should be
1056 * detected by the caller by checking each block with is_baad_recordp(&block).
1057 * The reasoning is that we want to fixup as many blocks as possible and we
1058 * want to return even bad ones to the caller so, e.g. in case of ntfsck, the
1059 * errors can be repaired.
1061 s64 ntfs_attr_mst_pread(ntfs_attr *na, const s64 pos, const s64 bk_cnt,
1062 const u32 bk_size, void *b)
1067 Dprintf("%s(): Entering for inode 0x%Lx, attr type 0x%x, pos 0x%Lx.\n",
1068 __FUNCTION__, (unsigned long long)na->ni->mft_no,
1069 na->type, (long long)pos);
1070 if (bk_cnt < 0 || bk_size % NTFS_SECTOR_SIZE) {
1074 br = ntfs_attr_pread(na, pos, bk_cnt * bk_size, b);
1078 for (end = (u8*)b + br * bk_size; (u8*)b < end; (u8*)b += bk_size)
1079 ntfs_mst_post_read_fixup((NTFS_RECORD*)b, bk_size);
1080 /* Finally, return the number of blocks read. */
1085 * ntfs_attr_mst_pwrite - multi sector transfer protected ntfs attribute write
1086 * @na: multi sector transfer protected ntfs attribute to write to
1087 * @pos: position in the attribute to write to
1088 * @bk_cnt: number of mst protected blocks to write
1089 * @bk_size: size of each mst protected block in bytes
1090 * @b: data buffer to write to disk
1092 * This function will write @bk_cnt blocks of size @bk_size bytes each from
1093 * data buffer @b to multi sector transfer (mst) protected ntfs attribute @na
1096 * On success, return the number of successfully written blocks. If this number
1097 * is lower than @bk_cnt this means that an error was encountered during the
1098 * write so that the write is partial. 0 means nothing was written (also
1099 * return 0 when @bk_cnt or @bk_size are 0).
1101 * On error and nothing has been written, return -1 with errno set
1102 * appropriately to the return code of ntfs_attr_pwrite(), or to EINVAL in case
1103 * of invalid arguments.
1105 * NOTE: We mst protect the data, write it, then mst deprotect it using a quick
1106 * deprotect algorithm (no checking). This saves us from making a copy before
1107 * the write and at the same time causes the usn to be incremented in the
1108 * buffer. This conceptually fits in better with the idea that cached data is
1109 * always deprotected and protection is performed when the data is actually
1110 * going to hit the disk and the cache is immediately deprotected again
1111 * simulating an mst read on the written data. This way cache coherency is
1114 s64 ntfs_attr_mst_pwrite(ntfs_attr *na, const s64 pos, s64 bk_cnt,
1115 const u32 bk_size, void *b)
1119 Dprintf("%s(): Entering for inode 0x%Lx, attr type 0x%x, pos 0x%Lx.\n",
1120 __FUNCTION__, (unsigned long long)na->ni->mft_no,
1121 na->type, (long long)pos);
1122 if (bk_cnt < 0 || bk_size % NTFS_SECTOR_SIZE) {
1128 /* Prepare data for writing. */
1129 for (i = 0; i < bk_cnt; ++i) {
1132 err = ntfs_mst_pre_write_fixup((NTFS_RECORD*)
1133 ((u8*)b + i * bk_size), bk_size);
1135 /* Abort write at this position. */
1142 /* Write the prepared data. */
1143 written = ntfs_attr_pwrite(na, pos, bk_cnt * bk_size, b);
1144 /* Quickly deprotect the data again. */
1145 for (i = 0; i < bk_cnt; ++i)
1146 ntfs_mst_post_write_fixup((NTFS_RECORD*)((u8*)b + i * bk_size));
1149 /* Finally, return the number of complete blocks written. */
1150 return written / bk_size;
1156 * ntfs_attr_find - find (next) attribute in mft record
1157 * @type: attribute type to find
1158 * @name: attribute name to find (optional, i.e. NULL means don't care)
1159 * @name_len: attribute name length (only needed if @name present)
1160 * @ic: IGNORE_CASE or CASE_SENSITIVE (ignored if @name not present)
1161 * @val: attribute value to find (optional, resident attributes only)
1162 * @val_len: attribute value length
1163 * @ctx: search context with mft record and attribute to search from
1165 * You shouldn't need to call this function directly. Use lookup_attr() instead.
1167 * ntfs_attr_find() takes a search context @ctx as parameter and searches the
1168 * mft record specified by @ctx->mrec, beginning at @ctx->attr, for an
1169 * attribute of @type, optionally @name and @val. If found, ntfs_attr_find()
1170 * returns 0 and @ctx->attr will point to the found attribute. If not found,
1171 * ntfs_attr_find() returns -1, with errno set to the error code and @ctx->attr
1172 * is undefined (i.e. do not rely on it not changing).
1174 * If @ctx->is_first is TRUE, the search begins with @ctx->attr itself. If it
1175 * is FALSE, the search begins after @ctx->attr.
1177 * If @type is zero (i.e. AT_UNUSED), return the first found attribute, i.e.
1178 * one can enumerate all attributes by setting @type to zero and then calling
1179 * ntfs_attr_find() repeatedly until it returns -1 with errno set to ENOENT to
1180 * indicate that there are no more entries. During the enumeration, each
1181 * successful call of ntfs_attr_find() will return the next attribute in the
1182 * mft record @ctx->mrec.
1184 * If @type is AT_END, seek to the end and return -1 with errno set to ENOENT.
1185 * AT_END is not a valid attribute, its length is zero for example, thus it is
1186 * safer to return error instead of success in this case. This also allows us
1187 * to interoperate cleanly with ntfs_external_attr_find().
1189 * If @name is AT_UNNAMED search for an unnamed attribute. If @name is present
1190 * but not AT_UNNAMED search for a named attribute matching @name. Otherwise,
1191 * match both named and unnamed attributes.
1193 * If @ic is IGNORE_CASE, the @name comparisson is not case sensitive and
1194 * @ctx->ntfs_ino must be set to the ntfs inode to which the mft record
1195 * @ctx->mrec belongs. This is so we can get at the ntfs volume and hence at
1196 * the upcase table. If @ic is CASE_SENSITIVE, the comparison is case
1197 * sensitive. When @name is present, @name_len is the @name length in Unicode
1200 * If @name is not present (NULL), we assume that the unnamed attribute is
1201 * being searched for.
1203 * Finally, the resident attribute value @val is looked for, if present.
1204 * If @val is not present (NULL), @val_len is ignored.
1206 * ntfs_attr_find() only searches the specified mft record and it ignores the
1207 * presence of an attribute list attribute (unless it is the one being searched
1208 * for, obviously). If you need to take attribute lists into consideration, use
1209 * ntfs_attr_lookup() instead (see below). This also means that you cannot use
1210 * ntfs_attr_find() to search for extent records of non-resident attributes, as
1211 * extents with lowest_vcn != 0 are usually described by the attribute list
1212 * attribute only. - Note that it is possible that the first extent is only in
1213 * the attribute list while the last extent is in the base mft record, so don't
1214 * rely on being able to find the first extent in the base mft record.
1216 * Warning: Never use @val when looking for attribute types which can be
1217 * non-resident as this most likely will result in a crash!
1219 static int ntfs_attr_find(const ATTR_TYPES type, const uchar_t *name,
1220 const u32 name_len, const IGNORE_CASE_BOOL ic,
1221 const u8 *val, const u32 val_len, ntfs_attr_search_ctx *ctx)
1228 if (!ctx || !ctx->mrec || !ctx->attr) {
1232 if (ic == IGNORE_CASE) {
1233 vol = ctx->ntfs_ino->vol;
1234 upcase = vol->upcase;
1235 upcase_len = vol->upcase_len;
1242 * Iterate over attributes in mft record starting at @ctx->attr, or the
1243 * attribute following that, if @ctx->is_first is TRUE.
1245 if (ctx->is_first) {
1247 ctx->is_first = FALSE;
1249 a = (ATTR_RECORD*)((char*)ctx->attr +
1250 le32_to_cpu(ctx->attr->length));
1251 for (;; a = (ATTR_RECORD*)((char*)a + le32_to_cpu(a->length))) {
1252 if (p2n(a) < p2n(ctx->mrec) || (char*)a > (char*)ctx->mrec +
1253 le32_to_cpu(ctx->mrec->bytes_allocated))
1256 /* We catch $END with this more general check, too... */
1257 if ((type && (le32_to_cpu(a->type) > le32_to_cpu(type))) ||
1258 (a->type == AT_END)) {
1264 /* If this is an enumeration return this attribute. */
1267 if (a->type != type)
1270 * If @name is AT_UNNAMED we want an unnamed attribute.
1271 * If @name is present, compare the two names.
1272 * Otherwise, match any attribute.
1274 if (name == AT_UNNAMED) {
1275 /* The search failed if the found attribute is named. */
1276 if (a->name_length) {
1280 } else if (name && !ntfs_names_are_equal(name, name_len,
1281 (uchar_t*)((char*)a + le16_to_cpu(a->name_offset)),
1282 a->name_length, ic, upcase, upcase_len)) {
1285 rc = ntfs_names_collate(name, name_len,
1286 (uchar_t*)((char*)a +
1287 le16_to_cpu(a->name_offset)),
1288 a->name_length, 1, IGNORE_CASE,
1289 upcase, upcase_len);
1291 * If @name collates before a->name, there is no
1292 * matching attribute.
1298 /* If the strings are not equal, continue search. */
1301 rc = ntfs_names_collate(name, name_len,
1302 (uchar_t*)((char*)a +
1303 le16_to_cpu(a->name_offset)),
1304 a->name_length, 1, CASE_SENSITIVE,
1305 upcase, upcase_len);
1314 * The names match or @name not present and attribute is
1315 * unnamed. If no @val specified, we have found the attribute
1320 /* @val is present; compare values. */
1324 rc = memcmp(val, (char*)a +le16_to_cpu(a->value_offset),
1326 le32_to_cpu(a->value_length)));
1328 * If @val collates before the current attribute's
1329 * value, there is no matching attribute.
1333 avl = le32_to_cpu(a->value_length);
1336 if (val_len < avl) {
1340 } else if (rc < 0) {
1346 Dputs("ntfs_attr_find(): File is corrupt. Run chkdsk.");
1354 * ntfs_external_attr_find - find an attribute in the attribute list of an inode
1355 * @type: attribute type to find
1356 * @name: attribute name to find (optional, i.e. NULL means don't care)
1357 * @name_len: attribute name length (only needed if @name present)
1358 * @ic: IGNORE_CASE or CASE_SENSITIVE (ignored if @name not present)
1359 * @lowest_vcn: lowest vcn to find (optional, non-resident attributes only)
1360 * @val: attribute value to find (optional, resident attributes only)
1361 * @val_len: attribute value length
1362 * @ctx: search context with mft record and attribute to search from
1364 * You shouldn't need to call this function directly. Use ntfs_attr_lookup()
1367 * Find an attribute by searching the attribute list for the corresponding
1368 * attribute list entry. Having found the entry, map the mft record for read
1369 * if the attribute is in a different mft record/inode, find the attribute in
1370 * there and return it.
1372 * If @type is zero (i.e. AT_UNUSED), return the first found attribute, i.e.
1373 * one can enumerate all attributes by setting @type to zero and then calling
1374 * ntfs_external_attr_find() repeatedly until it returns -1 with errno set to
1375 * ENOENT to indicate that there are no more entries. During the enumeration,
1376 * each successful call of ntfs_external_attr_find() will return the next
1377 * attribute described by the attribute list of the base mft record described
1378 * by the search context @ctx.
1380 * If @type is AT_END, seek to the end and return -1 with errno set to ENOENT.
1381 * AT_END is not a valid attribute, its length is zero for example, thus it is
1382 * safer to return error instead of success in this case.
1384 * If @name is AT_UNNAMED search for an unnamed attribute. If @name is present
1385 * but not AT_UNNAMED search for a named attribute matching @name. Otherwise,
1386 * match both named and unnamed attributes.
1388 * On first search @ctx->ntfs_ino must be the inode of the base mft record and
1389 * @ctx must have been obtained from a call to ntfs_attr_get_search_ctx().
1390 * On subsequent calls, @ctx->ntfs_ino can be any extent inode, too
1391 * (@ctx->base_ntfs_ino is then the base inode).
1393 * After finishing with the attribute/mft record you need to call
1394 * ntfs_attr_put_search_ctx() to cleanup the search context (unmapping any
1395 * mapped extent inodes, etc).
1397 * Return 0 if the search was successful and -1 if not, with errno set to the
1400 * On success, @ctx->attr is the found attribute and it is in mft record
1403 * On error, @ctx->attr is the attribute which collates just after the attribute
1404 * being searched for in the base ntfs inode, i.e. if one wants to add the
1405 * attribute to the mft record this is the correct place to insert it into,
1406 * and if there is not enough space, the attribute should be placed in an
1407 * extent mft record. @ctx->al_entry points to the position within
1408 * @ctx->base_ntfs_ino->attr_list at which the new attribute's attribute list
1409 * entry should be inserted.
1411 * The following error codes are defined:
1412 * ENOENT Attribute not found, not an error as such.
1413 * EINVAL Invalid arguments.
1414 * EIO I/O error or corrupt data structures found.
1415 * ENOMEM Not enough memory to allocate necessary buffers.
1417 static int ntfs_external_attr_find(ATTR_TYPES type, const uchar_t *name,
1418 const u32 name_len, const IGNORE_CASE_BOOL ic,
1419 const VCN lowest_vcn, const u8 *val, const u32 val_len,
1420 ntfs_attr_search_ctx *ctx)
1422 ntfs_inode *base_ni, *ni;
1424 ATTR_LIST_ENTRY *al_entry, *next_al_entry;
1425 char *al_start, *al_end;
1429 BOOL is_first_search = FALSE;
1432 base_ni = ctx->base_ntfs_ino;
1433 Dprintf("Entering for inode %Lu, attribute type 0x%x.\n",
1434 (unsigned long long)ni->mft_no, type);
1436 /* First call happens with the base mft record. */
1437 base_ni = ctx->base_ntfs_ino = ctx->ntfs_ino;
1438 ctx->base_mrec = ctx->mrec;
1443 ctx->base_attr = ctx->attr;
1445 al_start = base_ni->attr_list;
1446 al_end = al_start + base_ni->attr_list_size;
1447 if (!ctx->al_entry) {
1448 ctx->al_entry = (ATTR_LIST_ENTRY*)al_start;
1449 is_first_search = TRUE;
1452 * Iterate over entries in attribute list starting at @ctx->al_entry,
1453 * or the entry following that, if @ctx->is_first is TRUE.
1455 if (ctx->is_first) {
1456 al_entry = ctx->al_entry;
1457 ctx->is_first = FALSE;
1459 * If an enumeration and the first attribute is higher than
1460 * the attribute list itself, need to return the attribute list
1463 if (!type && is_first_search && le16_to_cpu(al_entry->type) >
1464 le16_to_cpu(AT_ATTRIBUTE_LIST))
1465 goto find_attr_list_attr;
1467 al_entry = (ATTR_LIST_ENTRY*)((char*)ctx->al_entry +
1468 le16_to_cpu(ctx->al_entry->length));
1470 * If this is an enumeration and the attribute list attribute
1471 * is the next one in the enumeration sequence, just return the
1472 * attribute list attribute from the base mft record as it is
1473 * not listed in the attribute list itself.
1475 if (!type && le16_to_cpu(ctx->al_entry->type) <
1476 le16_to_cpu(AT_ATTRIBUTE_LIST) &&
1477 le16_to_cpu(al_entry->type) >
1478 le16_to_cpu(AT_ATTRIBUTE_LIST)) {
1480 find_attr_list_attr:
1482 /* Check for bogus calls. */
1483 if (name || name_len || val || val_len || lowest_vcn) {
1488 /* We want the base record. */
1489 ctx->ntfs_ino = base_ni;
1490 ctx->mrec = ctx->base_mrec;
1491 ctx->is_first = TRUE;
1492 /* Sanity checks are performed elsewhere. */
1493 ctx->attr = (ATTR_RECORD*)((u8*)ctx->mrec +
1494 le16_to_cpu(ctx->mrec->attrs_offset));
1496 /* Find the attribute list attribute. */
1497 rc = ntfs_attr_find(AT_ATTRIBUTE_LIST, NULL, 0,
1498 IGNORE_CASE, NULL, 0, ctx);
1501 * Setup the search context so the correct
1502 * attribute is returned next time round.
1504 ctx->al_entry = al_entry;
1505 ctx->is_first = TRUE;
1511 /* Error! If other than not found return it. */
1512 if (errno != ENOENT)
1515 /* Not found?!? Absurd! Must be a bug... )-: */
1516 Dprintf("%s(): BUG! Attribute list attribute not found "
1517 "but it exists! Returning error "
1518 "(EINVAL).", __FUNCTION__);
1523 for (;; al_entry = next_al_entry) {
1524 /* Out of bounds check. */
1525 if ((u8*)al_entry < base_ni->attr_list ||
1526 (char*)al_entry > al_end)
1527 break; /* Inode is corrupt. */
1528 ctx->al_entry = al_entry;
1529 /* Catch the end of the attribute list. */
1530 if ((char*)al_entry == al_end)
1532 if (!al_entry->length)
1534 if ((char*)al_entry + 6 > al_end || (char*)al_entry +
1535 le16_to_cpu(al_entry->length) > al_end)
1537 next_al_entry = (ATTR_LIST_ENTRY*)((char*)al_entry +
1538 le16_to_cpu(al_entry->length));
1540 if (le32_to_cpu(al_entry->type) > le32_to_cpu(type))
1542 if (type != al_entry->type)
1545 al_name_len = al_entry->name_length;
1546 al_name = (uchar_t*)((char*)al_entry + al_entry->name_offset);
1548 * If !@type we want the attribute represented by this
1549 * attribute list entry.
1552 goto is_enumeration;
1554 * If @name is AT_UNNAMED we want an unnamed attribute.
1555 * If @name is present, compare the two names.
1556 * Otherwise, match any attribute.
1558 if (name == AT_UNNAMED) {
1561 } else if (name && !ntfs_names_are_equal(al_name, al_name_len,
1562 name, name_len, ic, vol->upcase,
1566 rc = ntfs_names_collate(name, name_len, al_name,
1567 al_name_len, 1, IGNORE_CASE,
1568 vol->upcase, vol->upcase_len);
1570 * If @name collates before al_name, there is no
1571 * matching attribute.
1575 /* If the strings are not equal, continue search. */
1579 * FIXME: Reverse engineering showed 0, IGNORE_CASE but
1580 * that is inconsistent with ntfs_attr_find(). The
1581 * subsequent rc checks were also different. Perhaps I
1582 * made a mistake in one of the two. Need to recheck
1583 * which is correct or at least see what is going
1586 rc = ntfs_names_collate(name, name_len, al_name,
1587 al_name_len, 1, CASE_SENSITIVE,
1588 vol->upcase, vol->upcase_len);
1595 * The names match or @name not present and attribute is
1596 * unnamed. Now check @lowest_vcn. Continue search if the
1597 * next attribute list entry still fits @lowest_vcn. Otherwise
1598 * we have reached the right one or the search has failed.
1600 if (lowest_vcn && (char*)next_al_entry >= al_start &&
1601 (char*)next_al_entry + 6 < al_end &&
1602 (char*)next_al_entry + le16_to_cpu(
1603 next_al_entry->length) <= al_end &&
1604 sle64_to_cpu(next_al_entry->lowest_vcn) <=
1606 next_al_entry->type == al_entry->type &&
1607 next_al_entry->name_length == al_name_len &&
1608 ntfs_names_are_equal((uchar_t*)((char*)
1610 next_al_entry->name_offset),
1611 next_al_entry->name_length,
1612 al_name, al_name_len, CASE_SENSITIVE,
1613 vol->upcase, vol->upcase_len))
1616 if (MREF_LE(al_entry->mft_reference) == ni->mft_no) {
1617 if (MSEQNO_LE(al_entry->mft_reference) !=
1619 ni->mrec->sequence_number)) {
1620 Dputs("Found stale mft reference in attribute "
1624 } else { /* Mft references do not match. */
1625 /* Do we want the base record back? */
1626 if (MREF_LE(al_entry->mft_reference) ==
1628 ni = ctx->ntfs_ino = base_ni;
1629 ctx->mrec = ctx->base_mrec;
1631 /* We want an extent record. */
1632 ni = ntfs_extent_inode_open(base_ni,
1633 al_entry->mft_reference);
1635 Dperror("Failed to map extent inode");
1639 ctx->mrec = ni->mrec;
1641 ctx->attr = (ATTR_RECORD*)((char*)ctx->mrec +
1642 le16_to_cpu(ctx->mrec->attrs_offset));
1645 * ctx->ntfs_ino, ctx->mrec, and ctx->attr now point to the
1646 * mft record containing the attribute represented by the
1650 * We could call into ntfs_attr_find() to find the right
1651 * attribute in this mft record but this would be less
1652 * efficient and not quite accurate as ntfs_attr_find() ignores
1653 * the attribute instance numbers for example which become
1654 * important when one plays with attribute lists. Also, because
1655 * a proper match has been found in the attribute list entry
1656 * above, the comparison can now be optimized. So it is worth
1657 * re-implementing a simplified ntfs_attr_find() here.
1661 * Use a manual loop so we can still use break and continue
1662 * with the same meanings as above.
1665 if ((char*)a < (char*)ctx->mrec || (char*)a > (char*)ctx->mrec +
1666 le32_to_cpu(ctx->mrec->bytes_allocated))
1668 if (a->type == AT_END)
1672 if (al_entry->instance != a->instance)
1675 * If the type and/or the name are/is mismatched between the
1676 * attribute list entry and the attribute record, there is
1677 * corruption so we break and return error EIO.
1679 if (al_entry->type != a->type)
1681 if (!ntfs_names_are_equal((uchar_t*)((char*)a +
1682 le16_to_cpu(a->name_offset)),
1683 a->name_length, al_name,
1684 al_name_len, CASE_SENSITIVE,
1685 vol->upcase, vol->upcase_len))
1689 * If no @val specified or @val specified and it matches, we
1690 * have found it! Also, if !@type, it is an enumeration, so we
1691 * want the current attribute.
1693 if (!type || !val || (!a->non_resident &&
1694 le32_to_cpu(a->value_length) == val_len &&
1695 !memcmp((char*)a + le16_to_cpu(a->value_offset),
1700 /* Proceed to the next attribute in the current mft record. */
1701 a = (ATTR_RECORD*)((char*)a + le32_to_cpu(a->length));
1702 goto do_next_attr_loop;
1704 if (ni != base_ni) {
1705 ctx->ntfs_ino = base_ni;
1706 ctx->mrec = ctx->base_mrec;
1707 ctx->attr = ctx->base_attr;
1709 Dputs("Inode is corrupt.");
1714 * Seek to the end of the base mft record, i.e. when we return false,
1715 * ctx->mrec and ctx->attr indicate where the attribute should be
1716 * inserted into the attribute record.
1717 * And of course ctx->al_entry points to the end of the attribute
1718 * list inside ctx->base_ntfs_ino->attr_list.
1720 * FIXME: Do we really want to do this here? Think about it... (AIA)
1722 ntfs_attr_reinit_search_ctx(ctx);
1724 * If we were enumerating and reached the end, we can't just use !@type
1725 * because that would return the first attribute instead of the last
1726 * one. Thus we just change @type to AT_END which causes
1727 * ntfs_attr_find() to seek to the end. We also do the same when an
1728 * attribute extent was searched for (i.e. @lowest_vcn != 0), as we
1729 * otherwise rewind the search back to the first extent and we get
1730 * that extent returned twice during a search for all extents.
1732 if (!type || lowest_vcn)
1734 return ntfs_attr_find(type, name, name_len, ic, val, val_len, ctx);
1738 * ntfs_attr_lookup - find an attribute in an ntfs inode
1739 * @type: attribute type to find
1740 * @name: attribute name to find (optional, i.e. NULL means don't care)
1741 * @name_len: attribute name length (only needed if @name present)
1742 * @ic: IGNORE_CASE or CASE_SENSITIVE (ignored if @name not present)
1743 * @lowest_vcn: lowest vcn to find (optional, non-resident attributes only)
1744 * @val: attribute value to find (optional, resident attributes only)
1745 * @val_len: attribute value length
1746 * @ctx: search context with mft record and attribute to search from
1748 * Find an attribute in an ntfs inode. On first search @ctx->ntfs_ino must
1749 * be the base mft record and @ctx must have been obtained from a call to
1750 * ntfs_attr_get_search_ctx().
1752 * This function transparently handles attribute lists and @ctx is used to
1753 * continue searches where they were left off at.
1755 * If @type is zero (i.e. AT_UNUSED), return the first found attribute, i.e.
1756 * one can enumerate all attributes by setting @type to zero and then calling
1757 * ntfs_attr_lookup() repeatedly until it returns -1 with errno set to ENOENT
1758 * to indicate that there are no more entries. During the enumeration, each
1759 * successful call of ntfs_attr_lookup() will return the next attribute, with
1760 * the current attribute being described by the search context @ctx.
1762 * If @type is AT_END, seek to the end of the attribute and return -1 with
1763 * errno set to ENOENT. AT_END is not a valid attribute, its length is zero for
1764 * example, thus it is safer to return error instead of success in this case.
1765 * It should never ne needed to do this, but we implement the functionality
1766 * because it allows for simpler code inside ntfs_external_attr_find().
1768 * If @name is AT_UNNAMED search for an unnamed attribute. If @name is present
1769 * but not AT_UNNAMED search for a named attribute matching @name. Otherwise,
1770 * match both named and unnamed attributes.
1772 * After finishing with the attribute/mft record you need to call
1773 * ntfs_attr_put_search_ctx() to cleanup the search context (unmapping any
1774 * mapped extent inodes, etc).
1776 * Return 0 if the search was successful and -1 if not, with errno set to the
1779 * On success, @ctx->attr is the found attribute and it is in mft record
1782 * On error, @ctx->attr is the attribute which collates just after the attribute
1783 * being searched for, i.e. if one wants to add the attribute to the mft
1784 * record this is the correct place to insert it into. @ctx->al_entry points to
1785 * the position within @ctx->base_ntfs_ino->attr_list at which the new
1786 * attribute's attribute list entry should be inserted.
1788 * The following error codes are defined:
1789 * ENOENT Attribute not found, not an error as such.
1790 * EINVAL Invalid arguments.
1791 * EIO I/O error or corrupt data structures found.
1792 * ENOMEM Not enough memory to allocate necessary buffers.
1794 int ntfs_attr_lookup(const ATTR_TYPES type, const uchar_t *name,
1795 const u32 name_len, const IGNORE_CASE_BOOL ic,
1796 const VCN lowest_vcn, const u8 *val, const u32 val_len,
1797 ntfs_attr_search_ctx *ctx)
1799 ntfs_inode *base_ni;
1801 if (!ctx || !ctx->mrec || !ctx->attr) {
1805 if (ctx->base_ntfs_ino)
1806 base_ni = ctx->base_ntfs_ino;
1808 base_ni = ctx->ntfs_ino;
1809 if (!base_ni || !NInoAttrList(base_ni) || type == AT_ATTRIBUTE_LIST)
1810 return ntfs_attr_find(type, name, name_len, ic, val, val_len,
1812 return ntfs_external_attr_find(type, name, name_len, ic, lowest_vcn,
1819 * ntfs_attr_init_search_ctx - initialize an attribute search context
1820 * @ctx: attribute search context to initialize
1821 * @ni: ntfs inode with which to initialize the search context
1822 * @mrec: mft record with which to initialize the search context
1824 * Initialize the attribute search context @ctx with @ni and @mrec.
1826 static __inline__ void ntfs_attr_init_search_ctx(ntfs_attr_search_ctx *ctx,
1827 ntfs_inode *ni, MFT_RECORD *mrec)
1832 /* Sanity checks are performed elsewhere. */
1833 ctx->attr = (ATTR_RECORD*)((char*)mrec +
1834 le16_to_cpu(mrec->attrs_offset));
1835 ctx->is_first = TRUE;
1837 ctx->al_entry = NULL;
1838 ctx->base_ntfs_ino = NULL;
1839 ctx->base_mrec = NULL;
1840 ctx->base_attr = NULL;
1844 * ntfs_attr_reinit_search_ctx - reinitialize an attribute search context
1845 * @ctx: attribute search context to reinitialize
1847 * Reinitialize the attribute search context @ctx.
1849 * This is used when a search for a new attribute is being started to reset
1850 * the search context to the beginning.
1852 void ntfs_attr_reinit_search_ctx(ntfs_attr_search_ctx *ctx)
1854 if (!ctx->base_ntfs_ino) {
1855 /* No attribute list. */
1856 ctx->is_first = TRUE;
1857 /* Sanity checks are performed elsewhere. */
1858 ctx->attr = (ATTR_RECORD*)((char*)ctx->mrec +
1859 le16_to_cpu(ctx->mrec->attrs_offset));
1861 } /* Attribute list. */
1862 ntfs_attr_init_search_ctx(ctx, ctx->base_ntfs_ino, ctx->base_mrec);
1867 * ntfs_attr_get_search_ctx - allocate/initialize a new attribute search context
1868 * @ctx: address of pointer in which to return the new search context
1869 * @ni: ntfs inode with which to initialize the search context
1870 * @mrec: mft record with which to initialize the search context
1872 * Allocate a new attribute search context, initialize it with @ni and @mrec,
1873 * and return it. Return NULL on error with errno set to ENOMEM.
1875 * @ni can be NULL if the search context is only going to be used for searching
1876 * for the attribute list attribute and for searches ignoring the contents of
1877 * the attribute list attribute.
1879 * If @ni is specified, @mrec can be NULL, in which case the mft record is
1882 * If both @ni and @mrec are specified, the mft record is taken from @mrec and
1883 * the value of @ni->mrec is ignored.
1885 ntfs_attr_search_ctx *ntfs_attr_get_search_ctx(ntfs_inode *ni, MFT_RECORD *mrec)
1887 ntfs_attr_search_ctx *ctx = malloc(sizeof(ntfs_attr_search_ctx));
1889 ntfs_attr_init_search_ctx(ctx, ni, mrec);
1894 * ntfs_attr_put_search_ctx - release an attribute search context
1895 * @ctx: attribute search context to free
1897 * Release the attribute search context @ctx.
1899 void ntfs_attr_put_search_ctx(ntfs_attr_search_ctx *ctx)
1906 * ntfs_attr_find_in_attrdef - find an attribute in the $AttrDef system file
1907 * @vol: ntfs volume to which the attribute belongs
1908 * @type: attribute type which to find
1910 * Search for the attribute definition record corresponding to the attribute
1911 * @type in the $AttrDef system file.
1913 * Return the attribute type definition record if found and NULL if not found
1914 * or an error occured. On error the error code is stored in errno. The
1915 * following error codes are defined:
1916 * ENOENT - The attribute @type is not specified in $AttrDef.
1917 * EINVAL - Invalid parameters (e.g. @vol is not valid).
1919 ATTR_DEF *ntfs_attr_find_in_attrdef(const ntfs_volume *vol,
1920 const ATTR_TYPES type)
1924 if (!vol || !vol->attrdef || !type) {
1928 for (ad = vol->attrdef; (u8*)ad - (u8*)vol->attrdef <
1929 vol->attrdef_len && ad->type; ++ad) {
1930 /* We haven't found it yet, carry on searching. */
1931 if (le32_to_cpu(ad->type) < le32_to_cpu(type))
1933 /* We found the attribute; return it. */
1934 if (ad->type == type)
1936 /* We have gone too far already. No point in continuing. */
1939 /* Attribute not found?!? */
1945 * ntfs_attr_size_bounds_check - check a size of an attribute type for validity
1946 * @vol: ntfs volume to which the attribute belongs
1947 * @type: attribute type which to check
1948 * @size: size which to check
1950 * Check whether the @size in bytes is valid for an attribute of @type on the
1951 * ntfs volume @vol. This information is obtained from $AttrDef system file.
1953 * Return 0 if valid and -1 if not valid or an error occured. On error the
1954 * error code is stored in errno. The following error codes are defined:
1955 * ERANGE - @size is not valid for the attribute @type.
1956 * ENOENT - The attribute @type is not specified in $AttrDef.
1957 * EINVAL - Invalid parameters (e.g. @size is < 0 or @vol is not valid).
1959 int ntfs_attr_size_bounds_check(const ntfs_volume *vol, const ATTR_TYPES type,
1968 ad = ntfs_attr_find_in_attrdef(vol, type);
1971 /* We found the attribute. - Do the bounds check. */
1972 if (size >= le64_to_cpu(ad->min_size) &&
1973 size <= le64_to_cpu(ad->max_size))
1975 /* @size is out of range! */
1981 * ntfs_attr_can_be_non_resident - check if an attribute can be non-resident
1982 * @vol: ntfs volume to which the attribute belongs
1983 * @type: attribute type which to check
1985 * Check whether the attribute of @type on the ntfs volume @vol is allowed to
1986 * be non-resident. This information is obtained from $AttrDef system file.
1988 * Return 0 if the attribute is allowed to be non-resident and -1 if not or an
1989 * error occured. On error the error code is stored in errno. The following
1990 * error codes are defined:
1991 * EPERM - The attribute is not allowed to be non-resident.
1992 * ENOENT - The attribute @type is not specified in $AttrDef.
1993 * EINVAL - Invalid parameters (e.g. @vol is not valid).
1995 int ntfs_attr_can_be_non_resident(const ntfs_volume *vol, const ATTR_TYPES type)
2000 * $DATA is always allowed to be non-resident even if $AttrDef does not
2001 * specify this in the flags of the $DATA attribute definition record.
2003 if (type == AT_DATA)
2005 /* Find the attribute definition record in $AttrDef. */
2006 ad = ntfs_attr_find_in_attrdef(vol, type);
2009 /* Check the flags and return the result. */
2010 if (ad->flags & CAN_BE_NON_RESIDENT)
2017 * ntfs_attr_record_resize - resize an attribute record
2018 * @m: mft record containing attribute record
2019 * @a: attribute record to resize
2020 * @new_size: new size in bytes to which to resize the attribute record @a
2022 * Resize the attribute record @a, i.e. the resident part of the attribute, in
2023 * the mft record @m to @new_size bytes.
2025 * Return 0 on success and -1 on error with errno set to the error code.
2026 * The following error codes are defined:
2027 * ENOSPC - Not enough space in the mft record @m to perform the resize.
2028 * Note that on error no modifications have been performed whatsoever.
2030 * Warning: If you make a record smaller without having copied all the data you
2031 * are interested in the data may be overwritten!
2033 static int ntfs_attr_record_resize(MFT_RECORD *m, ATTR_RECORD *a, u32 new_size)
2035 /* Align to 8 bytes, just in case the caller hasn't. */
2036 new_size = (new_size + 7) & ~7;
2038 /* If the actual attribute length has changed, move things around. */
2039 if (new_size != le32_to_cpu(a->length)) {
2040 u32 new_muse = le32_to_cpu(m->bytes_in_use) -
2041 le32_to_cpu(a->length) + new_size;
2042 /* Not enough space in this mft record. */
2043 if (new_muse > le32_to_cpu(m->bytes_allocated)) {
2047 /* Move attributes following @a to their new location. */
2048 memmove((u8*)a + new_size, (u8*)a + le32_to_cpu(a->length),
2049 le32_to_cpu(m->bytes_in_use) - ((u8*)a -
2050 (u8*)m) - le32_to_cpu(a->length));
2051 /* Adjust @m to reflect the change in used space. */
2052 m->bytes_in_use = cpu_to_le32(new_muse);
2053 /* Adjust @a to reflect the new size. */
2054 a->length = cpu_to_le32(new_size);
2060 * ntfs_resident_attr_value_resize - resize the value of a resident attribute
2061 * @m: mft record containing attribute record
2062 * @a: attribute record whose value to resize
2063 * @new_size: new size in bytes to which to resize the attribute value of @a
2065 * Resize the value of the attribute @a in the mft record @m to @new_size bytes.
2066 * If the value is made bigger, the newly "allocated" space is cleared.
2068 * Return 0 on success and -1 on error with errno set to the error code.
2069 * The following error codes are defined:
2070 * ENOSPC - Not enough space in the mft record @m to perform the resize.
2071 * Note that on error no modifications have been performed whatsoever.
2073 int ntfs_resident_attr_value_resize(MFT_RECORD *m, ATTR_RECORD *a,
2077 * Check that the attribute name hasn't been placed after the
2078 * attribute value/mapping pairs array. If it has we need to move it.
2079 * TODO: Implement the move. For now just abort. (AIA)
2081 if (a->name_length) {
2082 BOOL move_name = FALSE;
2083 if (a->non_resident) {
2084 if (le16_to_cpu(a->name_offset) >=
2085 le16_to_cpu(a->mapping_pairs_offset))
2088 if (le16_to_cpu(a->name_offset) >=
2089 le16_to_cpu(a->value_offset))
2095 fprintf(stderr, "%s(): Eeek! Name is placed after the "
2096 "%s. Aborting...\n", __FUNCTION__,
2097 a->non_resident ? "mapping pairs array":
2103 /* Resize the resident part of the attribute record. */
2104 if (ntfs_attr_record_resize(m, a, (le16_to_cpu(a->value_offset) +
2105 new_size + 7) & ~7) < 0) {
2106 if (errno != ENOSPC) {
2110 fprintf(stderr, "%s(): Eeek! Attribute record resize "
2111 "failed. Aborting...\n", __FUNCTION__);
2117 * If we made the attribute value bigger, clear the area between the
2118 * old size and @new_size.
2120 if (new_size > le32_to_cpu(a->value_length))
2121 memset((u8*)a + le16_to_cpu(a->value_offset) +
2122 le32_to_cpu(a->value_length), 0, new_size -
2123 le32_to_cpu(a->value_length));
2124 /* Finally update the length of the attribute value. */
2125 a->value_length = cpu_to_le32(new_size);
2130 * ntfs_attr_make_non_resident - convert a resident to a non-resident attribute
2131 * @na: open ntfs attribute to make non-resident
2132 * @ctx: ntfs search context describing the attribute
2134 * Convert a resident ntfs attribute to a non-resident one.
2136 * Return 0 on success and -1 on error with errno set to the error code.
2138 * NOTE to self: No changes in the attribute list are required to move from
2139 * a resident to a non-resident attribute.
2141 * Warning: We do not set the inode dirty and we do not write out anything!
2142 * We expect the caller to do this as this is a fairly low level
2143 * function and it is likely there will be further changes made.
2145 static int ntfs_attr_make_non_resident(ntfs_attr *na,
2146 ntfs_attr_search_ctx *ctx)
2148 s64 new_allocated_size, bw;
2149 ntfs_volume *vol = na->ni->vol;
2150 ATTR_REC *a = ctx->attr;
2152 int mp_size, mp_ofs, name_ofs, arec_size, err;
2154 /* Some preliminary sanity checking. */
2155 if (NAttrNonResident(na)) {
2157 fprintf(stderr, "%s(): Eeek! Trying to make non-resident "
2158 "attribute non-resident. Aborting...\n",
2164 * Check that the attribute name hasn't been placed after the
2165 * attribute value. If it has we need to move it.
2166 * TODO: Implement the move. For now just abort. (AIA)
2168 if (a->name_length && le16_to_cpu(a->name_offset) >=
2169 le16_to_cpu(a->value_offset)) {
2171 fprintf(stderr, "%s(): Eeek! Name is placed after the "
2172 "attribute value. Aborting...\n", __FUNCTION__);
2177 new_allocated_size = (le32_to_cpu(a->value_length) + vol->cluster_size
2178 - 1) & ~(vol->cluster_size - 1);
2180 /* Start by allocating clusters to hold the attribute value. */
2181 rl = ntfs_cluster_alloc(vol, new_allocated_size >>
2182 vol->cluster_size_bits, -1, DATA_ZONE);
2184 if (errno != ENOSPC) {
2188 fprintf(stderr, "%s(): Eeek! Failed to allocate "
2189 "cluster(s). Aborting...\n",
2197 * Setup the in-memory attribute structure to be non-resident so that
2198 * we can use ntfs_attr_pwrite().
2200 NAttrSetNonResident(na);
2202 na->allocated_size = new_allocated_size;
2203 na->data_size = na->initialized_size = le32_to_cpu(a->value_length);
2205 * For now just clear all of these as we don't support them when
2208 NAttrClearCompressed(na);
2209 NAttrClearSparse(na);
2210 NAttrClearEncrypted(na);
2212 /* Now copy the attribute value to the allocated cluster(s). */
2213 bw = ntfs_attr_pwrite(na, 0, le32_to_cpu(a->value_length),
2214 (u8*)a + le16_to_cpu(a->value_offset));
2215 if (bw != le32_to_cpu(a->value_length)) {
2218 fprintf(stderr, "%s(): Eeek! Failed to write out attribute "
2219 "value (bw = %Li, errno = %i). Aborting...\n",
2220 __FUNCTION__, (long long)bw, err);
2223 goto cluster_free_err_out;
2226 /* Determine the size of the mapping pairs array. */
2227 mp_size = ntfs_get_size_for_mapping_pairs(vol, rl);
2231 fprintf(stderr, "%s(): Eeek! Failed to get size for mapping "
2232 "pairs array. Aborting...\n", __FUNCTION__);
2233 goto cluster_free_err_out;
2236 /* Calculate new offsets for the name and the mapping pairs array. */
2237 name_ofs = (sizeof(ATTR_REC) - sizeof(a->compressed_size) + 7) & ~7;
2238 mp_ofs = (name_ofs + a->name_length + 7) & ~7;
2241 * Determine the size of the resident part of the non-resident
2242 * attribute record. (Not compressed thus no compressed_size element
2245 arec_size = (mp_ofs + mp_size + 7) & ~7;
2248 if (a->name_length && (le16_to_cpu(a->name_offset) + a->name_length >
2251 fprintf(stderr, "%s(): Eeek! Name exceeds new record size! "
2252 "Not supported. Aborting...\n", __FUNCTION__);
2254 goto cluster_free_err_out;
2257 /* Resize the resident part of the attribute record. */
2258 if (ntfs_attr_record_resize(ctx->mrec, a, arec_size) < 0) {
2260 if (err != ENOSPC) {
2262 fprintf(stderr, "%s(): Eeek! Failed to resize "
2263 "attribute record. Aborting...\n",
2266 goto cluster_free_err_out;
2270 * Convert the resident part of the attribute record to describe a
2271 * non-resident attribute.
2273 a->non_resident = 1;
2275 /* Move the attribute name if it exists and update the offset. */
2277 memmove((u8*)a + name_ofs, (u8*)a + le16_to_cpu(a->name_offset),
2278 a->name_length * sizeof(uchar_t));
2279 a->name_offset = cpu_to_le16(name_ofs);
2281 /* Update the flags to match the in-memory ones. */
2282 a->flags &= ~(ATTR_IS_SPARSE | ATTR_IS_ENCRYPTED |
2283 ATTR_COMPRESSION_MASK);
2285 /* Setup the fields specific to non-resident attributes. */
2286 a->lowest_vcn = scpu_to_le64(0);
2287 if (na->data_size != 0)
2288 a->highest_vcn = scpu_to_le64(0);
2290 a->highest_vcn = scpu_to_le64(-1);
2292 a->mapping_pairs_offset = cpu_to_le16(mp_ofs);
2294 a->compression_unit = 0;
2296 memset(&a->reserved1, 0, sizeof(a->reserved1));
2298 a->allocated_size = scpu_to_le64(new_allocated_size);
2299 a->data_size = a->initialized_size = scpu_to_le64(na->data_size);
2301 /* Generate the mapping pairs array in the attribute record. */
2302 if (ntfs_mapping_pairs_build(vol, (u8*)a + mp_ofs, arec_size - mp_ofs,
2305 // FIXME: Eeek! We need rollback! (AIA)
2306 fprintf(stderr, "%s(): Eeek! Failed to build mapping pairs. "
2307 "Leaving corrupt attribute record on disk. "
2308 "In memory runlist is still intact! Error "
2309 "code is %i. FIXME: Need to rollback "
2310 "instead!\n", __FUNCTION__, err);
2318 cluster_free_err_out:
2319 if (ntfs_cluster_free(vol, na, 0, -1) < 0)
2320 fprintf(stderr, "%s(): Eeek! Failed to release allocated "
2321 "clusters in error code path. Leaving "
2322 "inconsistent metadata...\n", __FUNCTION__);
2323 NAttrClearNonResident(na);
2324 na->allocated_size = na->data_size;
2332 * ntfs_resident_attr_resize - resize a resident, open ntfs attribute
2333 * @na: resident ntfs attribute to resize
2334 * @newsize: new size (in bytes) to which to resize the attribute
2336 * Change the size of a resident, open ntfs attribute @na to @newsize bytes.
2338 * On success return 0 and on error return -1 with errno set to the error code.
2339 * The following error codes are defined:
2340 * ENOTSUP - The desired resize is not implemented yet.
2341 * ENOMEM - Not enough memory to complete operation.
2342 * ERANGE - @newsize is not valid for the attribute type of @na.
2344 static int ntfs_resident_attr_resize(ntfs_attr *na, const s64 newsize)
2346 ntfs_attr_search_ctx *ctx;
2350 Dprintf("%s(): Entering for inode 0x%Lx, attr 0x%x.\n", __FUNCTION__,
2351 (unsigned long long)na->ni->mft_no, na->type);
2352 /* Get the attribute record that needs modification. */
2353 ctx = ntfs_attr_get_search_ctx(na->ni, NULL);
2356 if (ntfs_attr_lookup(na->type, na->name, na->name_len, 0, 0, NULL, 0,
2363 * Check the attribute type and the corresponding minimum and maximum
2364 * sizes against @newsize and fail if @newsize is out of bounds.
2366 if (ntfs_attr_size_bounds_check(vol, na->type, newsize) < 0) {
2368 if (err == ERANGE) {
2370 fprintf(stderr, "%s(): Eeek! Size bounds check "
2371 "failed. Aborting...\n", __FUNCTION__);
2372 } else if (err == ENOENT)
2377 * If @newsize is bigger than the mft record we need to make the
2378 * attribute non-resident if the attribute type supports it. If it is
2379 * smaller we can go ahead and attempt the resize.
2381 if (newsize < vol->mft_record_size) {
2382 /* Perform the resize of the attribute record. */
2383 if (!ntfs_resident_attr_value_resize(ctx->mrec, ctx->attr,
2385 /* Update the ntfs attribute structure, too. */
2386 na->allocated_size = na->data_size =
2387 na->initialized_size = newsize;
2388 if (NAttrCompressed(na) || NAttrSparse(na))
2389 na->compressed_size = newsize;
2392 /* Error! If not enough space, just continue. */
2393 if (errno != ENOSPC) {
2397 fprintf(stderr, "%s(): Eeek! Failed to resize "
2398 "resident part of attribute. "
2399 "Aborting...\n", __FUNCTION__);
2403 /* There is not enough space in the mft record to perform the resize. */
2405 /* Check if the attribute is allowed to be non-resident. */
2406 if (!ntfs_attr_can_be_non_resident(vol, na->type)) {
2407 /* Make the attribute non-resident. */
2408 if (!ntfs_attr_make_non_resident(na, ctx)) {
2409 // TODO: Attribute is now non-resident. Resize it!
2410 // goto resize_done;
2411 fprintf(stderr, "%s(): TODO: Resize attribute now that "
2412 "it is non-resident.\n", __FUNCTION__);
2413 ntfs_inode_mark_dirty(ctx->ntfs_ino);
2417 /* Error! If not enough space, just continue. */
2418 if (errno != ENOSPC) {
2421 fprintf(stderr, "%s(): Eeek! Failed to make attribute "
2422 "non-resident. Aborting...\n",
2428 * If the attribute can be non-resident but an error occured
2429 * while making it non-resident, abort.
2431 if (errno != EPERM) {
2435 /* Attribute is not allowed to be non-resident, continue. */
2438 // TODO: Try to make other attributes non-resident.
2440 // TODO: Move the attribute to a new mft record, creating an attribute
2441 // list attribute or modifying it if it is already present.
2448 * Set the inode (and its base inode if it exists) dirty so it is
2449 * written out later.
2451 ntfs_inode_mark_dirty(ctx->ntfs_ino);
2453 ntfs_attr_put_search_ctx(ctx);
2456 ntfs_attr_put_search_ctx(ctx);
2461 static int ntfs_attr_make_resident(ntfs_attr *na, ntfs_attr_search_ctx *ctx)
2463 // FIXME: For now we cheat and assume there is no attribute list
2465 if (NInoAttrList(na->ni)) {
2470 /* Make sure this is not $MFT/$BITMAP or Windows will not boot! */
2471 if (na->type == AT_BITMAP && na->ni->mft_no == FILE_MFT) {
2479 //NAttrClearNonResident(na);
2484 * ntfs_non_resident_attr_shrink - shrink a non-resident, open ntfs attribute
2485 * @na: non-resident ntfs attribute to shrink
2486 * @newsize: new size (in bytes) to which to shrink the attribute
2488 * Reduce the size of a non-resident, open ntfs attribute @na to @newsize bytes.
2490 * On success return 0 and on error return -1 with errno set to the error code.
2491 * The following error codes are defined:
2492 * ENOTSUP - The desired resize is not implemented yet.
2493 * ENOMEM - Not enough memory to complete operation.
2494 * ERANGE - @newsize is not valid for the attribute type of @na.
2496 static int ntfs_non_resident_attr_shrink(ntfs_attr *na, const s64 newsize)
2499 ntfs_attr_search_ctx *ctx;
2503 s64 nr_freed_clusters;
2504 u32 new_alen, new_muse;
2507 Dprintf("%s(): Entering for inode 0x%Lx, attr 0x%x.\n", __FUNCTION__,
2508 (unsigned long long)na->ni->mft_no, na->type);
2512 /* Get the first attribute record that needs modification. */
2513 ctx = ntfs_attr_get_search_ctx(na->ni, NULL);
2516 if (ntfs_attr_lookup(na->type, na->name, na->name_len, 0, newsize >>
2517 vol->cluster_size_bits, NULL, 0, ctx)) {
2526 * Check the attribute type and the corresponding minimum size
2527 * against @newsize and fail if @newsize is too small.
2529 if (ntfs_attr_size_bounds_check(vol, na->type, newsize) < 0) {
2531 if (err == ERANGE) {
2533 fprintf(stderr, "%s(): Eeek! Size bounds check "
2534 "failed. Aborting...\n", __FUNCTION__);
2535 } else if (err == ENOENT)
2540 // When extents/an attribute list is/are present it is very complicated:
2541 // TODO: For the current extent:
2542 // TODO: free the required clusters
2543 // FIXME: how do we deal with extents that haven't been loaded yet?
2544 // do we just fault them in first so that the runlist is
2545 // complete and we are done with deallocations in one go?
2546 // TODO: update the run list in na->rl
2547 // TODO: update the sizes, etc in the ntfs attribute structure na
2548 // TODO: update the mapping pairs array
2549 // TODO: mark the inode dirty
2550 // TODO: For all subsequent extents:
2551 // TODO: free all clusters specified by the extent (FIXME: unless
2552 // already done above!)
2553 // TODO: completely delete each extent attribute record from its
2555 // TODO: free the mft record if there are no attributes left in it
2556 // (to do so update the $MFT/$Bitmap as well as the mft
2557 // record header in use flag, etc)
2558 // TODO: write the updated mft record to disk
2559 // TODO: remove the extent inode from the list of loaded extent
2560 // inodes in the base inode
2561 // TODO: free all memory associated with the extent inode
2562 // TODO: update the attribute list attribute in ni->attr_list, removing
2563 // all entries corresponding to deleted attributes
2564 // TODO: if the attribute list attribute is resident:
2565 // TODO: update the actual attribute in the base mft
2566 // record from ni->attr_list
2567 // if the attribute list attribute is not resident:
2568 // TODO: update the attribute list attribute run list in
2569 // ni->attr_list_rl, freeing any no longer used
2571 // TODO: mark the inode attribute list as containing
2573 // TODO: update the mapping pairs array from
2575 // TODO: mark the base inode dirty
2577 // TODO: Implement attribute list support as desribed above. (AIA)
2578 if (NInoAttrList(na->ni)) {
2582 // FIXME: We now know that we don't have an attribute list. Thus we
2583 // are in the base inode only and hence it is all easier, even
2584 // if we are cheating for now... (AIA)
2586 /* The first cluster outside the new allocation. */
2587 first_free_vcn = (newsize + vol->cluster_size - 1) >>
2588 vol->cluster_size_bits;
2590 * Compare the new allocation with the old one and only deallocate
2591 * clusters if there is a change.
2593 if ((na->allocated_size >> vol->cluster_size_bits) != first_free_vcn) {
2594 /* Deallocate all clusters starting with the first free one. */
2595 nr_freed_clusters = ntfs_cluster_free(vol, na, first_free_vcn,
2597 if (nr_freed_clusters < 0) {
2600 fprintf(stderr, "%s(): Eeek! Freeing of clusters "
2601 "failed. Aborting...\n", __FUNCTION__);
2604 /* Truncate the runlist itself. */
2605 if (ntfs_rl_truncate(&na->rl, first_free_vcn)) {
2607 // FIXME: Eeek! We need rollback! (AIA)
2608 fprintf(stderr, "%s(): Eeek! Run list truncation "
2609 "failed. Leaving inconsistent "
2610 "metadata!\n", __FUNCTION__);
2613 /* Update the attribute record and the ntfs_attr structure. */
2614 na->allocated_size = first_free_vcn << vol->cluster_size_bits;
2615 a->allocated_size = scpu_to_le64(na->allocated_size);
2616 if (NAttrCompressed(na) || NAttrSparse(na)) {
2617 na->compressed_size -= nr_freed_clusters <<
2618 vol->cluster_size_bits;
2619 // FIXME: Bug catcher. Remove later... (AIA)
2620 if (!newsize && na->compressed_size) {
2621 fprintf(stderr, "%s(): Eeek! !newsize but "
2622 "na->compressed_size not zero "
2623 "(= %Li)! Fixing up by hand!\n",
2624 __FUNCTION__, (long long)
2625 na->compressed_size);
2626 na->compressed_size = 0;
2628 a->compressed_size = scpu_to_le64(na->compressed_size);
2630 // FIXME: Bug catcher. Remove later... (AIA)
2631 if (na->compressed_size < 0) {
2632 // FIXME: Eeek! BUG!
2633 fprintf(stderr, "%s(): Eeek! Compressed size "
2634 "is negative. Leaving "
2635 "inconsistent metadata!\n",
2642 * Reminder: It is ok for a->highest_vcn to be -1 for zero
2646 a->highest_vcn = scpu_to_le64(first_free_vcn - 1);
2647 /* Get the size for the new mapping pairs array. */
2648 mp_size = ntfs_get_size_for_mapping_pairs(vol, na->rl);
2651 // FIXME: Eeek! We need rollback! (AIA)
2652 fprintf(stderr, "%s(): Eeek! Get size for mapping "
2653 "pairs failed. Leaving inconsistent "
2654 "metadata!\n", __FUNCTION__);
2658 * Generate the new mapping pairs array directly into the
2659 * correct destination, i.e. the attribute record itself.
2661 if (ntfs_mapping_pairs_build(vol, (u8*)a + le16_to_cpu(
2662 a->mapping_pairs_offset), mp_size, na->rl)) {
2664 // FIXME: Eeek! We need rollback! (AIA)
2665 fprintf(stderr, "%s(): Eeek! Mapping pairs build "
2666 "failed. Leaving inconsistent "
2667 "metadata!\n", __FUNCTION__);
2671 * Check that the attribute name hasn't been placed after the
2672 * attribute value/mapping pairs array. If it has we need to
2673 * move it. TODO: Implement the move. For now just abort. (AIA)
2675 if (a->name_length) {
2676 BOOL move_name = FALSE;
2677 if (a->non_resident) {
2678 if (le16_to_cpu(a->name_offset) >= le16_to_cpu(
2679 a->mapping_pairs_offset))
2682 if (le16_to_cpu(a->name_offset) >=
2683 le16_to_cpu(a->value_offset))
2689 fprintf(stderr, "%s(): Eeek! Name is placed "
2690 "after the %s. Aborting...\n",
2691 __FUNCTION__, a->non_resident ?
2692 "mapping pairs array":
2699 * Calculate the new attribute length and mft record bytes
2702 new_alen = (le16_to_cpu(a->mapping_pairs_offset) + mp_size +
2704 new_muse = le32_to_cpu(m->bytes_in_use) -
2705 le32_to_cpu(a->length) + new_alen;
2706 if (new_muse > le32_to_cpu(m->bytes_allocated)) {
2707 // FIXME: Eeek! BUG()
2708 fprintf(stderr, "%s(): Eeek! Ran out of space in mft "
2709 "record. Leaving inconsistent "
2710 "metadata!\n", __FUNCTION__);
2714 /* Move the following attributes forward. */
2715 memmove((u8*)a + new_alen, (u8*)a + le32_to_cpu(a->length),
2716 le32_to_cpu(m->bytes_in_use) - ((u8*)a -
2717 (u8*)m) - le32_to_cpu(a->length));
2718 /* Update the sizes of the attribute and mft records. */
2719 a->length = cpu_to_le32(new_alen);
2720 m->bytes_in_use = cpu_to_le32(new_muse);
2722 /* Update the attribute record and the ntfs attribute structure. */
2723 na->data_size = newsize;
2724 a->data_size = scpu_to_le64(newsize);
2725 if (newsize < na->initialized_size) {
2726 na->initialized_size = newsize;
2727 a->initialized_size = scpu_to_le64(newsize);
2729 /* If the attribute now has zero size, make it resident. */
2731 if (ntfs_attr_make_resident(na, ctx)) {
2732 /* If couldn't make resident, just continue. */
2734 Dprintf("%s(): Failed to make attribute "
2735 "resident. Leaving as is...\n",
2739 /* Set the inode dirty so it is written out later. */
2740 ntfs_inode_mark_dirty(ctx->ntfs_ino);
2742 ntfs_attr_put_search_ctx(ctx);
2745 ntfs_attr_put_search_ctx(ctx);
2751 * ntfs_attr_truncate - resize an ntfs attribute
2752 * @na: open ntfs attribute to resize
2753 * @newsize: new size (in bytes) to which to resize the attribute
2755 * Change the size of an open ntfs attribute @na to @newsize bytes. If the
2756 * attribute is made bigger and the attribute is resident the newly
2757 * "allocated" space is cleared and if the attribute is non-resident the
2758 * newly allocated space is marked as not initialised and no real allocation
2759 * on disk is performed. FIXME: Do we have to create sparse runs or can we just
2760 * leave the runlist to finish below data_size, i.e. can we have
2761 * allocated_size < data_size? I guess that what we can't and thus we will have
2762 * to set the sparse bit of the attribute and create sparse runs to ensure that
2763 * allocated_size is >= data_size. We don't need to clear the partial run at
2764 * the end of the real allocation because we leave initialized_size low enough.
2765 * FIXME: Do we want that? Alternatively, we leave initialized_size = data_size
2766 * and do clear the partial run. The latter approach would be more inline with
2767 * what windows would do, even though windows wouldn't even make the attribute
2768 * sparse, it would just allocate clusters instead. TODO: Check what happens on
2769 * WinXP and .NET. FIXME: Make sure to check what NT4 does with an NTFS1.2
2770 * volume that has sparse files. I suspect it will blow up so we will need to
2771 * perform allocations of clusters, like NT4 would do for NTFS1.2 while we can
2772 * use sparse attributes on NTFS3.x.
2774 * On success return 0 and on error return -1 with errno set to the error code.
2775 * The following error codes are defined:
2776 * EINVAL - Invalid arguments were passed to the function.
2777 * ENOTSUP - The desired resize is not implemented yet.
2779 * NOTE: At present attributes can only be made smaller using this function,
2782 int ntfs_attr_truncate(ntfs_attr *na, const s64 newsize)
2784 if (!na || newsize < 0) {
2789 * Encrypted attributes are not supported. We return access denied,
2790 * which is what Windows NT4 does, too.
2792 if (NAttrEncrypted(na)) {
2797 * TODO: Implement making non-resident attributes bigger/filling in of
2798 * uninitialized holes as well as handling of compressed attributes.
2800 if ((NAttrNonResident(na) && newsize > na->initialized_size) ||
2801 NAttrCompressed(na)) {
2806 if (NAttrNonResident(na))
2807 return ntfs_non_resident_attr_shrink(na, newsize);
2808 return ntfs_resident_attr_resize(na, newsize);