1N/A * attrib.c - Attribute handling code. Part of the Linux-NTFS project. 1N/A * Copyright (c) 2000-2006 Anton Altaparmakov 1N/A * Copyright (c) 2002-2005 Richard Russon 1N/A * Copyright (c) 2002-2006 Szabolcs Szakacsits 1N/A * Copyright (c) 2004-2007 Yura Pakhuchiy 1N/A * modify it under the terms of the GNU General Public License as published 1N/A * by the Free Software Foundation; either version 2 of the License, or 1N/A * (at your option) any later version. 1N/A * useful, but WITHOUT ANY WARRANTY; without even the implied warranty 1N/A * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1N/A * GNU General Public License for more details. 1N/A * You should have received a copy of the GNU General Public License 1N/A * along with this program (in the main directory of the Linux-NTFS 1N/A * distribution in the file COPYING); if not, write to the Free Software 1N/A * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 1N/A * ntfs_get_attribute_value_length - Find the length of an attribute 1N/A * ntfs_get_attribute_value - Get a copy of an attribute 1N/A /* Sanity checks. */ 1N/A /* Complex attribute? */ 1N/A * Ignore the flags in case they are not zero for an attribute list 1N/A * attribute. Windows does not complain about invalid flags and chkdsk 1N/A * does not detect or fix them so we need to cope with it, too. 1N/A /* Attribute is resident. */ 1N/A /* Attribute is not resident. */ 1N/A /* If no data, return 0. */ 1N/A * FIXME: What about attribute lists?!? (AIA) 1N/A /* Decompress the mapping pairs array into a runlist. */ 1N/A * FIXED: We were overflowing here in a nasty fashion when we 1N/A * reach the last cluster in the runlist as the buffer will 1N/A * only be big enough to hold data_size bytes while we are 1N/A * reading in allocated_size bytes which is usually larger 1N/A * than data_size, since the actual data is unlikely to have a 1N/A * size equal to a multiple of the cluster size! 1N/A * FIXED2: We were also overflowing here in the same fashion 1N/A * when the data_size was more than one run smaller than the 1N/A * allocated size which happens with Windows XP sometimes. 1N/A /* Now load all clusters in the runlist into b. */ 1N/A * We have reached the last run so we were going to 1N/A * overflow when executing the ntfs_pread() which is 1N/A * Allocate a new buffer with size: 1N/A * rl[i].length << vol->cluster_size_bits, do the 1N/A * read into our buffer, then memcpy the correct 1N/A * amount of data into the caller supplied buffer, 1N/A * free our buffer, and continue. 1N/A * We have reached the end of data size so we were 1N/A * going to overflow in the same fashion. 1N/A * Temporary fix: same as above. 1N/A * FIXME: If compressed file: Only read if lcn != -1. 1N/A * Otherwise, we are dealing with a sparse run and we 1N/A * just memset the user buffer to 0 for the length of 1N/A * the run, which should be 16 (= compression unit 1N/A * FIXME: Really only when file is compressed, or can 1N/A * we have sparse runs in uncompressed files as well? 1N/A * - Yes we can, in sparse files! But not necessarily 1N/A * size of 16, just run length. 1N/A#
define ESTR "Error reading attribute value" 1N/A * FIXME: If compressed file: Only read if lcn != -1. 1N/A * Otherwise, we are dealing with a sparse run and we just 1N/A * memset the user buffer to 0 for the length of the run, which 1N/A * should be 16 (= compression unit size). 1N/A * FIXME: Really only when file is compressed, or can 1N/A * we have sparse runs in uncompressed files as well? 1N/A * - Yes we can, in sparse files! But not necessarily size of 1N/A * 16, just run length. 1N/A#
define ESTR "Error reading attribute value" 1N/A/* Already cleaned up code below, but still look for FIXME:... */ 1N/A * __ntfs_attr_init - primary initialization of an ntfs attribute structure 1N/A * @na: ntfs attribute to initialize 1N/A * @ni: ntfs inode with which to initialize the ntfs attribute 1N/A * @type: attribute type 1N/A * @name: attribute name in little endian Unicode or NULL 1N/A * @name_len: length of attribute @name in Unicode characters (if @name given) 1N/A * Initialize the ntfs attribute @na with @ni, @type, @name, and @name_len. 1N/A * ntfs_attr_init - initialize an ntfs_attr with data sizes and status 1N/A * @initialized_size: 1N/A * @compression_unit: 1N/A * Final initialization for an ntfs attribute. 1N/A * ntfs_attr_open - open an ntfs attribute for access 1N/A * @ni: open ntfs inode in which the ntfs attribute resides 1N/A * @type: attribute type 1N/A * @name: attribute name in little endian Unicode or AT_UNNAMED or NULL 1N/A * @name_len: length of attribute @name in Unicode characters (if @name given) 1N/A * Allocate a new ntfs attribute structure, initialize it with @ni, @type, 1N/A * @name, and @name_len, then return it. Return NULL on error with 1N/A * errno set to the error code. 1N/A * If @name is AT_UNNAMED look specifically for an unnamed attribute. If you 1N/A * do not care whether the attribute is named or not set @name to NULL. In 1N/A * both those cases @name_len is not used at all. 1N/A /* Check cache, maybe this attribute already opened? */ 1N/A "increment reference count and " 1N/A /* Search failed. Properly open attrbute. */ 1N/A * Wipe the flags in case they are not zero for an attribute list 1N/A * attribute. Windows does not complain about invalid flags and chkdsk 1N/A * does not detect or fix them so we need to cope with it, too. 1N/A (l +
7) & ~
7, l, l,
cs ? (l +
7) & ~
7 : 0, 0);
1N/A * ntfs_attr_close - free an ntfs attribute structure 1N/A * @na: ntfs attribute structure to free 1N/A * Release all memory associated with the ntfs attribute @na and then release 1N/A /* Don't release if using an internal constant. */ 1N/A * ntfs_attr_map_runlist - map (a part of) a runlist of an ntfs attribute 1N/A * @na: ntfs attribute for which to map (part of) a runlist 1N/A * @vcn: map runlist part containing this vcn 1N/A * Map the part of a runlist containing the @vcn of the ntfs attribute @na. 1N/A * Return 0 on success and -1 on error with errno set to the error code. 1N/A /* Find the attribute in the mft record. */ 1N/A /* Decode the runlist. */ 1N/A * ntfs_attr_map_runlist_range - map (a part of) a runlist of an ntfs attribute 1N/A * @na: ntfs attribute for which to map (part of) a runlist 1N/A * @from_vcn: map runlist part starting this vcn 1N/A * @to_vcn: map runlist part ending this vcn 1N/A * Map the part of a runlist from containing the @from_vcn to containing the 1N/A * @to_vcn of an ntfs attribute @na. It is OK for @to_vcn to be beyond last run. 1N/A * Return 0 on success and -1 on error with errno set to the error code. 1N/A "from_vcn 0x%llx, to_vcn 0x%llx.\n",
1N/A /* Map extent with @from_vcn. */ 1N/A /* Skip not interesting to us runs. */ 1N/A /* We reached the end of runlist, just exit. */ 1N/A /* Check for errors. */ 1N/A /* Runlist is not mapped here. */ 1N/A /* Find the attribute in the mft record. */ 1N/A /* Decode the runlist. */ 1N/A * ntfs_attr_map_whole_runlist - map the whole runlist of an ntfs attribute 1N/A * @na: ntfs attribute for which to map the runlist 1N/A * Map the whole runlist of the ntfs attribute @na. For an attribute made up 1N/A * of only one attribute extent this is the same as calling 1N/A * ntfs_attr_map_runlist(na, 0) but for an attribute with multiple extents this 1N/A * will map the runlist fragments from each of the extents thus giving access 1N/A * to the entirety of the disk allocation of an attribute. 1N/A * Return 0 on success and -1 on error with errno set to the error code. 1N/A /* Map all attribute extents one by one. */ 1N/A /* Decode the runlist. */ 1N/A /* Are we in the first extent? */ 1N/A "non zero lowest_vcn. " 1N/A "Inode is corrupt.\n");
1N/A /* Get the last vcn in the attribute. */ 1N/A /* Get the lowest vcn for the next extent. */ 1N/A /* Only one extent or error, which we catch below. */ 1N/A /* Avoid endless loops due to corruption. */ 1N/A "Inode is corrupt.\n");
1N/A "attribute. Bug or corrupt inode.\n");
1N/A * ntfs_attr_vcn_to_lcn - convert a vcn into a lcn given an ntfs attribute 1N/A * @na: ntfs attribute whose runlist to use for conversion 1N/A * @vcn: vcn to convert 1N/A * Convert the virtual cluster number @vcn of an attribute into a logical 1N/A * cluster number (lcn) of a device using the runlist @na->rl to map vcns to 1N/A * their corresponding lcns. 1N/A * If the @vcn is not mapped yet, attempt to map the attribute extent 1N/A * containing the @vcn and retry the vcn to lcn conversion. 1N/A * Since lcns must be >= 0, we use negative return values with special meaning: 1N/A * Return value Meaning / Description 1N/A * ========================================== 1N/A * -1 = LCN_HOLE Hole / not allocated on disk. 1N/A * -3 = LCN_ENOENT There is no such vcn in the attribute. 1N/A * -4 = LCN_EINVAL Input parameter error. 1N/A * -5 = LCN_EIO Corrupt fs, disk i/o error, or not enough memory. 1N/A /* Convert vcn to lcn. If that fails map the runlist and retry once. */ 1N/A * If the attempt to map the runlist failed, or we are getting 1N/A * LCN_RL_NOT_MAPPED despite having mapped the attribute extent 1N/A * successfully, something is really badly wrong... 1N/A /* lcn contains the appropriate error code. */ 1N/A * ntfs_attr_find_vcn - find a vcn in the runlist of an ntfs attribute 1N/A * @na: ntfs attribute whose runlist to search 1N/A * Find the virtual cluster number @vcn in the runlist of the ntfs attribute 1N/A * @na and return the the address of the runlist element containing the @vcn. 1N/A * Note you need to distinguish between the lcn of the returned runlist 1N/A * element being >= 0 and LCN_HOLE. In the later case you have to return zeroes 1N/A * on read and allocate clusters on write. You need to update the runlist, the 1N/A * attribute itself as well as write the modified mft record to disk. 1N/A * If there is an error return NULL with errno set to the error code. The 1N/A * following error codes are defined: 1N/A * EINVAL Input parameter error. 1N/A * ENOENT There is no such vcn in the runlist. 1N/A * ENOMEM Not enough memory. 1N/A * EIO I/O error or corrupt metadata. 1N/A /* The @vcn is in an unmapped region, map the runlist and retry. */ 1N/A * If we already retried or the mapping attempt failed something has 1N/A * gone badly wrong. EINVAL and ENOENT coming from a failed mapping 1N/A * attempt are equivalent to errors for us as they should not happen 1N/A * in our code paths. 1N/A * ntfs_attr_pread - read from an attribute specified by an ntfs_attr structure 1N/A * @na: ntfs attribute to read from 1N/A * @pos: byte position in the attribute to begin reading from 1N/A * @count: number of bytes to read 1N/A * @b: output data buffer 1N/A * This function will read @count bytes starting at offset @pos from the ntfs 1N/A * attribute @na into the data buffer @b. 1N/A * On success, return the number of successfully read bytes. If this number is 1N/A * lower than @count this means that the read reached end of file or that an 1N/A * error was encountered during the read so that the read is partial. 0 means 1N/A * end of file or nothing was read (also return 0 when @count is 0). 1N/A * On error and nothing has been read, return -1 with errno set appropriately 1N/A * to the return code of ntfs_pread(), or to EINVAL in case of invalid 1N/A * If this is a compressed attribute it needs special treatment, but 1N/A * only if it is non-resident. 1N/A * Encrypted non-resident attributes are not supported. We return 1N/A * access denied, which is what Windows NT4 does, too. 1N/A /* Truncate reads beyond end of attribute. */ 1N/A /* If it is a resident attribute, get the value from the mft record. */ 1N/A /* Zero out reads beyond initialized size. */ 1N/A /* Find the runlist element containing the vcn. */ 1N/A * If the vcn is not present it is an out of bounds read. 1N/A * However, we already truncated the read to the data_size, 1N/A * so getting this here is an error. 1N/A * Gather the requested data into the linear destination buffer. Note, 1N/A * a partial final vcn is taken care of by the @count capping of read 1N/A /* Needed for case when runs merged. */ 1N/A /* It is a hole, just zero the matching @b range. */ 1N/A /* Update progress counters. */ 1N/A /* It is a real lcn, read it into @dst. */ 1N/A /* If everything ok, update progress counters and continue. */ 1N/A /* If the syscall was interrupted, try again. */ 1N/A /* Finally, return the number of bytes read. */ 1N/A * ntfs_attr_pwrite - positioned write to an ntfs attribute 1N/A * @na: ntfs attribute to write to 1N/A * @pos: position in the attribute to write to 1N/A * @count: number of bytes to write 1N/A * @b: data buffer to write to disk 1N/A * This function will write @count bytes from data buffer @b to ntfs attribute 1N/A * @na at position @pos. 1N/A * On success, return the number of successfully written bytes. If this number 1N/A * is lower than @count this means that an error was encountered during the 1N/A * write so that the write is partial. 0 means nothing was written (also return 1N/A * 0 when @count is 0). 1N/A * On error and nothing has been written, return -1 with errno set 1N/A * appropriately to the return code of ntfs_pwrite(), or to EINVAL in case of 1N/A * invalid arguments. 1N/A * Encrypted non-resident attributes are not supported. We return 1N/A * access denied, which is what Windows NT4 does, too. 1N/A /* If this is a compressed attribute it needs special treatment. */ 1N/A // TODO: Implement writing compressed attributes! (AIA) 1N/A // return ntfs_attr_pwrite_compressed(ntfs_attr *na, 1N/A // const s64 pos, s64 count, void *b); 1N/A /* If the write reaches beyond the end, extend the attribute. */ 1N/A /* If it is a resident attribute, write the data to the mft record. */ 1N/A * NOTE: We are in a bad state at this moment. We have 1N/A * dirtied the mft record but we failed to commit it to 1N/A * disk. Since we have read the mft record ok before, 1N/A * it is unlikely to fail writing it, so is ok to just 1N/A * return error here... (AIA) 1N/A /* Handle writes beyond initialized_size. */ 1N/A * Map runlist between initialized size and place we start 1N/A /* Set initialized_size to @pos + @count. */ 1N/A /* If write starts beyond initialized_size, zero the gap. */ 1N/A * Undo the change in the in-memory copy and send it 1N/A * NOTE: At this point the initialized_size in the mft record 1N/A * has been updated BUT there is random data on disk thus if 1N/A * we decide to abort, we MUST change the initialized_size 1N/A /* Find the runlist element containing the vcn. */ 1N/A * If the vcn is not present it is an out of bounds write. 1N/A * However, we already extended the size of the attribute, 1N/A * so getting this here must be an error of some kind. 1N/A * Scatter the data from the linear data buffer to the volume. Note, a 1N/A * partial final vcn is taken care of by the @count capping of write 1N/A /* Needed for case when runs merged. */ 1N/A /* Instantiate the hole. */ 1N/A * Map whole runlist to be able update mapping pairs 1N/A * Restore @rl, it probably get lost during runlist 1N/A "mapping whole runlist. Please " 1N/A "report to the %s.\n",
1N/A * Search backwards to find the best lcn to start 1N/A /* Backwards search failed, search forwards. */ 1N/A /* Allocate clusters to instantiate the hole. */ 1N/A "for hole instantiating.\n");
1N/A /* Merge runlists. */ 1N/A "allocated clusters. Leaving " 1N/A "inconsistent metadata. " 1N/A * It's definitely a BUG, if we failed to find 1N/A * @cur_vcn, because we missed it during 1N/A * instantiating of the hole. 1N/A "instantiating. Please report " 1N/A /* If leaved part of the hole go to the next run. */ 1N/A /* Now LCN shouldn't be less than 0. */ 1N/A "Please report to the %s.\n",
1N/A * Clusters that replaced hole are merged with 1N/A * previous run, so we need to update offset. 1N/A * We left part of the hole, so update we need 1N/A * Clear region between start of @rl->vcn cluster and 1N/A * @ofs if necessary. 1N/A /* It is a real lcn, write it to the volume. */ 1N/A int bsize =
4096;
/* FIXME: Test whether we need 1N/A PAGE_SIZE here. Eg., on IA64. */ 1N/A * Write 4096 size blocks if it's possible. This will 1N/A * cause the kernel not to seek and read disk blocks for 1N/A * filling the end of the buffer which increases write 1N/A /* If everything ok, update progress counters and continue. */ 1N/A /* If the syscall was interrupted, try again. */ 1N/A /* Update mapping pairs if needed. */ 1N/A /* FIXME: We want rollback here. */ 1N/A "Leaving inconsistent metadata. " 1N/A "Run chkdsk!",
"ntfs_attr_pwrite");
1N/A /* Finally, return the number of bytes written. */ 1N/A * TODO: Need to try to change initialized_size. If it 1N/A * succeeds goto done, otherwise goto err_out. (AIA) 1N/A * FIXME: At this stage could try to recover by filling 1N/A * old_initialized_size -> new_initialized_size with 1N/A * data or at least zeroes. (AIA) 1N/A "Leaving metadata in inconsistent " 1N/A "state! Run chkdsk!\n");
1N/A /* Update mapping pairs if needed. */ 1N/A /* Restore original data_size if needed. */ 1N/A * ntfs_attr_mst_pread - multi sector transfer protected ntfs attribute read 1N/A * @na: multi sector transfer protected ntfs attribute to read from 1N/A * @pos: byte position in the attribute to begin reading from 1N/A * @bk_cnt: number of mst protected blocks to read 1N/A * @bk_size: size of each mst protected block in bytes 1N/A * @dst: output data buffer 1N/A * This function will read @bk_cnt blocks of size @bk_size bytes each starting 1N/A * at offset @pos from the ntfs attribute @na into the data buffer @b. 1N/A * On success, the multi sector transfer fixups are applied and the number of 1N/A * read blocks is returned. If this number is lower than @bk_cnt this means 1N/A * that the read has either reached end of attribute or that an error was 1N/A * encountered during the read so that the read is partial. 0 means end of 1N/A * attribute or nothing to read (also return 0 when @bk_cnt or @bk_size are 0). 1N/A * On error and nothing has been read, return -1 with errno set appropriately 1N/A * to the return code of ntfs_attr_pread() or to EINVAL in case of invalid 1N/A * NOTE: If an incomplete multi sector transfer is detected the magic is 1N/A * changed to BAAD but no error is returned, i.e. it is possible that any of 1N/A * the returned blocks have multi sector transfer errors. This should be 1N/A * detected by the caller by checking each block with is_baad_recordp(&block). 1N/A * The reasoning is that we want to fixup as many blocks as possible and we 1N/A * want to return even bad ones to the caller so, e.g. in case of ntfsck, the 1N/A * errors can be repaired. 1N/A /* Finally, return the number of blocks read. */ 1N/A * ntfs_attr_mst_pwrite - multi sector transfer protected ntfs attribute write 1N/A * @na: multi sector transfer protected ntfs attribute to write to 1N/A * @pos: position in the attribute to write to 1N/A * @bk_cnt: number of mst protected blocks to write 1N/A * @bk_size: size of each mst protected block in bytes 1N/A * @src: data buffer to write to disk 1N/A * This function will write @bk_cnt blocks of size @bk_size bytes each from 1N/A * data buffer @b to multi sector transfer (mst) protected ntfs attribute @na 1N/A * On success, return the number of successfully written blocks. If this number 1N/A * is lower than @bk_cnt this means that an error was encountered during the 1N/A * write so that the write is partial. 0 means nothing was written (also 1N/A * return 0 when @bk_cnt or @bk_size are 0). 1N/A * On error and nothing has been written, return -1 with errno set 1N/A * appropriately to the return code of ntfs_attr_pwrite(), or to EINVAL in case 1N/A * of invalid arguments. 1N/A * NOTE: We mst protect the data, write it, then mst deprotect it using a quick 1N/A * deprotect algorithm (no checking). This saves us from making a copy before 1N/A * the write and at the same time causes the usn to be incremented in the 1N/A * buffer. This conceptually fits in better with the idea that cached data is 1N/A * always deprotected and protection is performed when the data is actually 1N/A * going to hit the disk and the cache is immediately deprotected again 1N/A * simulating an mst read on the written data. This way cache coherency is 1N/A /* Prepare data for writing. */ 1N/A /* Abort write at this position. */ 1N/A /* Write the prepared data. */ 1N/A /* Quickly deprotect the data again. */ 1N/A /* Finally, return the number of complete blocks written. */ 1N/A * ntfs_attr_find - find (next) attribute in mft record 1N/A * @type: attribute type to find 1N/A * @name: attribute name to find (optional, i.e. NULL means don't care) 1N/A * @name_len: attribute name length (only needed if @name present) 1N/A * @ic: IGNORE_CASE or CASE_SENSITIVE (ignored if @name not present) 1N/A * @val: attribute value to find (optional, resident attributes only) 1N/A * @val_len: attribute value length 1N/A * @ctx: search context with mft record and attribute to search from 1N/A * You shouldn't need to call this function directly. Use lookup_attr() instead. 1N/A * ntfs_attr_find() takes a search context @ctx as parameter and searches the 1N/A * mft record specified by @ctx->mrec, beginning at @ctx->attr, for an 1N/A * attribute of @type, optionally @name and @val. If found, ntfs_attr_find() 1N/A * returns 0 and @ctx->attr will point to the found attribute. 1N/A * If not found, ntfs_attr_find() returns -1, with errno set to ENOENT and 1N/A * @ctx->attr will point to the attribute before which the attribute being 1N/A * searched for would need to be inserted if such an action were to be desired. 1N/A * On actual error, ntfs_attr_find() returns -1 with errno set to the error 1N/A * code but not to ENOENT. In this case @ctx->attr is undefined and in 1N/A * particular do not rely on it not changing. 1N/A * If @ctx->is_first is TRUE, the search begins with @ctx->attr itself. If it 1N/A * is FALSE, the search begins after @ctx->attr. 1N/A * If @type is AT_UNUSED, return the first found attribute, i.e. one can 1N/A * enumerate all attributes by setting @type to AT_UNUSED and then calling 1N/A * ntfs_attr_find() repeatedly until it returns -1 with errno set to ENOENT to 1N/A * indicate that there are no more entries. During the enumeration, each 1N/A * successful call of ntfs_attr_find() will return the next attribute in the 1N/A * mft record @ctx->mrec. 1N/A * If @type is AT_END, seek to the end and return -1 with errno set to ENOENT. 1N/A * AT_END is not a valid attribute, its length is zero for example, thus it is 1N/A * safer to return error instead of success in this case. This also allows us 1N/A * to interoperate cleanly with ntfs_external_attr_find(). 1N/A * If @name is AT_UNNAMED search for an unnamed attribute. If @name is present 1N/A * but not AT_UNNAMED search for a named attribute matching @name. Otherwise, 1N/A * match both named and unnamed attributes. 1N/A * If @ic is IGNORE_CASE, the @name comparison is not case sensitive and 1N/A * @ctx->ntfs_ino must be set to the ntfs inode to which the mft record 1N/A * @ctx->mrec belongs. This is so we can get at the ntfs volume and hence at 1N/A * the upcase table. If @ic is CASE_SENSITIVE, the comparison is case 1N/A * sensitive. When @name is present, @name_len is the @name length in Unicode 1N/A * If @name is not present (NULL), we assume that the unnamed attribute is 1N/A * being searched for. 1N/A * Finally, the resident attribute value @val is looked for, if present. 1N/A * If @val is not present (NULL), @val_len is ignored. 1N/A * ntfs_attr_find() only searches the specified mft record and it ignores the 1N/A * presence of an attribute list attribute (unless it is the one being searched 1N/A * for, obviously). If you need to take attribute lists into consideration, use 1N/A * ntfs_attr_lookup() instead (see below). This also means that you cannot use 1N/A * ntfs_attr_find() to search for extent records of non-resident attributes, as 1N/A * extents with lowest_vcn != 0 are usually described by the attribute list 1N/A * attribute only. - Note that it is possible that the first extent is only in 1N/A * the attribute list while the last extent is in the base mft record, so don't 1N/A * rely on being able to find the first extent in the base mft record. 1N/A * Warning: Never use @val when looking for attribute types which can be 1N/A * non-resident as this most likely will result in a crash! 1N/A * Iterate over attributes in mft record starting at @ctx->attr, or the 1N/A * attribute following that, if @ctx->is_first is TRUE. 1N/A /* If this is an enumeration return this attribute. */ 1N/A * If @name is AT_UNNAMED we want an unnamed attribute. 1N/A * If @name is present, compare the two names. 1N/A * Otherwise, match any attribute. 1N/A /* The search failed if the found attribute is named. */ 1N/A * If @name collates before a->name, there is no 1N/A * matching attribute. 1N/A /* If the strings are not equal, continue search. */ 1N/A * The names match or @name not present and attribute is 1N/A * unnamed. If no @val specified, we have found the attribute 1N/A /* @val is present; compare values. */ 1N/A * If @val collates before the current attribute's 1N/A * value, there is no matching attribute. 1N/A * ntfs_external_attr_find - find an attribute in the attribute list of an inode 1N/A * @type: attribute type to find 1N/A * @name: attribute name to find (optional, i.e. NULL means don't care) 1N/A * @name_len: attribute name length (only needed if @name present) 1N/A * @ic: IGNORE_CASE or CASE_SENSITIVE (ignored if @name not present) 1N/A * @lowest_vcn: lowest vcn to find (optional, non-resident attributes only) 1N/A * @val: attribute value to find (optional, resident attributes only) 1N/A * @val_len: attribute value length 1N/A * @ctx: search context with mft record and attribute to search from 1N/A * You shouldn't need to call this function directly. Use ntfs_attr_lookup() 1N/A * Find an attribute by searching the attribute list for the corresponding 1N/A * attribute list entry. Having found the entry, map the mft record for read 1N/A * if the attribute is in a different mft record/inode, find the attribute in 1N/A * there and return it. 1N/A * If @type is AT_UNUSED, return the first found attribute, i.e. one can 1N/A * enumerate all attributes by setting @type to AT_UNUSED and then calling 1N/A * ntfs_external_attr_find() repeatedly until it returns -1 with errno set to 1N/A * ENOENT to indicate that there are no more entries. During the enumeration, 1N/A * each successful call of ntfs_external_attr_find() will return the next 1N/A * attribute described by the attribute list of the base mft record described 1N/A * by the search context @ctx. 1N/A * If @type is AT_END, seek to the end of the base mft record ignoring the 1N/A * attribute list completely and return -1 with errno set to ENOENT. AT_END is 1N/A * not a valid attribute, its length is zero for example, thus it is safer to 1N/A * return error instead of success in this case. 1N/A * If @name is AT_UNNAMED search for an unnamed attribute. If @name is present 1N/A * but not AT_UNNAMED search for a named attribute matching @name. Otherwise, 1N/A * match both named and unnamed attributes. 1N/A * On first search @ctx->ntfs_ino must be the inode of the base mft record and 1N/A * @ctx must have been obtained from a call to ntfs_attr_get_search_ctx(). 1N/A * On subsequent calls, @ctx->ntfs_ino can be any extent inode, too 1N/A * (@ctx->base_ntfs_ino is then the base inode). 1N/A * ntfs_attr_put_search_ctx() to cleanup the search context (unmapping any 1N/A * mapped extent inodes, etc). 1N/A * Return 0 if the search was successful and -1 if not, with errno set to the 1N/A * On success, @ctx->attr is the found attribute, it is in mft record 1N/A * @ctx->mrec, and @ctx->al_entry is the attribute list entry for this 1N/A * attribute with @ctx->base_* being the base mft record to which @ctx->attr 1N/A * On error ENOENT, i.e. attribute not found, @ctx->attr is set to the 1N/A * attribute which collates just after the attribute being searched for in the 1N/A * base ntfs inode, i.e. if one wants to add the attribute to the mft record 1N/A * this is the correct place to insert it into, and if there is not enough 1N/A * space, the attribute should be placed in an extent mft record. 1N/A * @ctx->al_entry points to the position within @ctx->base_ntfs_ino->attr_list 1N/A * at which the new attribute's attribute list entry should be inserted. The 1N/A * other @ctx fields, base_ntfs_ino, base_mrec, and base_attr are set to NULL. 1N/A * The only exception to this is when @type is AT_END, in which case 1N/A * @ctx->al_entry is set to NULL also (see above). 1N/A * The following error codes are defined: 1N/A * ENOENT Attribute not found, not an error as such. 1N/A * EINVAL Invalid arguments. 1N/A * EIO I/O error or corrupt data structures found. 1N/A * ENOMEM Not enough memory to allocate necessary buffers. 1N/A /* First call happens with the base mft record. */ 1N/A * Iterate over entries in attribute list starting at @ctx->al_entry, 1N/A * or the entry following that, if @ctx->is_first is TRUE. 1N/A * If an enumeration and the first attribute is higher than 1N/A * the attribute list itself, need to return the attribute list 1N/A * If this is an enumeration and the attribute list attribute 1N/A * is the next one in the enumeration sequence, just return the 1N/A * attribute list attribute from the base mft record as it is 1N/A * not listed in the attribute list itself. 1N/A /* Check for bogus calls. */ 1N/A /* We want the base record. */ 1N/A /* Sanity checks are performed elsewhere. */ 1N/A /* Find the attribute list attribute. */ 1N/A * Setup the search context so the correct 1N/A * attribute is returned next time round. 1N/A /* Error! If other than not found return it. */ 1N/A /* Not found?!? Absurd! Must be a bug... )-: */ 1N/A "found but it exists! " 1N/A "Returning error (EINVAL).\n");
1N/A /* Out of bounds check. */ 1N/A break;
/* Inode is corrupt. */ 1N/A /* Catch the end of the attribute list. */ 1N/A * If !@type we want the attribute represented by this 1N/A * attribute list entry. 1N/A * If @name is AT_UNNAMED we want an unnamed attribute. 1N/A * If @name is present, compare the two names. 1N/A * Otherwise, match any attribute. 1N/A * If @name collates before al_name, there is no 1N/A * matching attribute. 1N/A /* If the strings are not equal, continue search. */ 1N/A * FIXME: Reverse engineering showed 0, IGNORE_CASE but 1N/A * that is inconsistent with ntfs_attr_find(). The 1N/A * subsequent rc checks were also different. Perhaps I 1N/A * made a mistake in one of the two. Need to recheck 1N/A * which is correct or at least see what is going 1N/A * The names match or @name not present and attribute is 1N/A * unnamed. Now check @lowest_vcn. Continue search if the 1N/A * next attribute list entry still fits @lowest_vcn. Otherwise 1N/A * we have reached the right one or the search has failed. 1N/A "attribute list!\n");
1N/A }
else {
/* Mft references do not match. */ 1N/A /* Do we want the base record back? */ 1N/A /* We want an extent record. */ 1N/A * ctx->ntfs_ino, ctx->mrec, and ctx->attr now point to the 1N/A * mft record containing the attribute represented by the 1N/A * We could call into ntfs_attr_find() to find the right 1N/A * attribute in this mft record but this would be less 1N/A * efficient and not quite accurate as ntfs_attr_find() ignores 1N/A * the attribute instance numbers for example which become 1N/A * important when one plays with attribute lists. Also, because 1N/A * a proper match has been found in the attribute list entry 1N/A * above, the comparison can now be optimized. So it is worth 1N/A * re-implementing a simplified ntfs_attr_find() here. 1N/A * Use a manual loop so we can still use break and continue 1N/A * with the same meanings as above. 1N/A * attribute list entry and the attribute record, there is 1N/A * corruption so we break and return error EIO. 1N/A * If no @val specified or @val specified and it matches, we 1N/A * have found it! Also, if !@type, it is an enumeration, so we 1N/A * want the current attribute. 1N/A /* Proceed to the next attribute in the current mft record. */ 1N/A * If we were looking for AT_END or we were enumerating and reached the 1N/A * end, we reset the search context @ctx and use ntfs_attr_find() to 1N/A * seek to the end of the base mft record. 1N/A * The attribute wasn't found. Before we return, we want to ensure 1N/A * @ctx->mrec and @ctx->attr indicate the position at which the 1N/A * attribute should be inserted in the base mft record. Since we also 1N/A * want to preserve @ctx->al_entry we cannot reinitialize the search 1N/A * context using ntfs_attr_reinit_search_ctx() as this would set 1N/A * @ctx->al_entry to NULL. Thus we do the necessary bits manually (see 1N/A * ntfs_attr_init_search_ctx() below). Note, we _only_ preserve 1N/A * @ctx->al_entry as the remaining fields (base_*) are identical to 1N/A * their non base_ counterparts and we cannot set @ctx->base_attr 1N/A * correctly yet as we do not know what @ctx->attr will be set to by 1N/A * the call to ntfs_attr_find() below. 1N/A * In case there are multiple matches in the base mft record, need to 1N/A * keep enumerating until we get an attribute not found response (or 1N/A * another error), otherwise we would keep returning the same attribute 1N/A * over and over again and all programs using us for enumeration would 1N/A * lock up in a tight loop. 1N/A * ntfs_attr_lookup - find an attribute in an ntfs inode 1N/A * @type: attribute type to find 1N/A * @name: attribute name to find (optional, i.e. NULL means don't care) 1N/A * @name_len: attribute name length (only needed if @name present) 1N/A * @ic: IGNORE_CASE or CASE_SENSITIVE (ignored if @name not present) 1N/A * @lowest_vcn: lowest vcn to find (optional, non-resident attributes only) 1N/A * @val: attribute value to find (optional, resident attributes only) 1N/A * @val_len: attribute value length 1N/A * @ctx: search context with mft record and attribute to search from 1N/A * Find an attribute in an ntfs inode. On first search @ctx->ntfs_ino must 1N/A * be the base mft record and @ctx must have been obtained from a call to 1N/A * ntfs_attr_get_search_ctx(). 1N/A * This function transparently handles attribute lists and @ctx is used to 1N/A * continue searches where they were left off at. 1N/A * If @type is AT_UNUSED, return the first found attribute, i.e. one can 1N/A * enumerate all attributes by setting @type to AT_UNUSED and then calling 1N/A * ntfs_attr_lookup() repeatedly until it returns -1 with errno set to ENOENT 1N/A * to indicate that there are no more entries. During the enumeration, each 1N/A * successful call of ntfs_attr_lookup() will return the next attribute, with 1N/A * the current attribute being described by the search context @ctx. 1N/A * If @type is AT_END, seek to the end of the base mft record ignoring the 1N/A * attribute list completely and return -1 with errno set to ENOENT. AT_END is 1N/A * not a valid attribute, its length is zero for example, thus it is safer to 1N/A * return error instead of success in this case. It should never be needed to 1N/A * do this, but we implement the functionality because it allows for simpler 1N/A * code inside ntfs_external_attr_find(). 1N/A * If @name is AT_UNNAMED search for an unnamed attribute. If @name is present 1N/A * but not AT_UNNAMED search for a named attribute matching @name. Otherwise, 1N/A * match both named and unnamed attributes. 1N/A * ntfs_attr_put_search_ctx() to cleanup the search context (unmapping any 1N/A * mapped extent inodes, etc). 1N/A * Return 0 if the search was successful and -1 if not, with errno set to the 1N/A * On success, @ctx->attr is the found attribute, it is in mft record 1N/A * @ctx->mrec, and @ctx->al_entry is the attribute list entry for this 1N/A * attribute with @ctx->base_* being the base mft record to which @ctx->attr 1N/A * belongs. If no attribute list attribute is present @ctx->al_entry and 1N/A * @ctx->base_* are NULL. 1N/A * On error ENOENT, i.e. attribute not found, @ctx->attr is set to the 1N/A * attribute which collates just after the attribute being searched for in the 1N/A * base ntfs inode, i.e. if one wants to add the attribute to the mft record 1N/A * this is the correct place to insert it into, and if there is not enough 1N/A * space, the attribute should be placed in an extent mft record. 1N/A * @ctx->al_entry points to the position within @ctx->base_ntfs_ino->attr_list 1N/A * at which the new attribute's attribute list entry should be inserted. The 1N/A * other @ctx fields, base_ntfs_ino, base_mrec, and base_attr are set to NULL. 1N/A * The only exception to this is when @type is AT_END, in which case 1N/A * @ctx->al_entry is set to NULL also (see above). 1N/A * The following error codes are defined: 1N/A * ENOENT Attribute not found, not an error as such. 1N/A * EINVAL Invalid arguments. 1N/A * EIO I/O error or corrupt data structures found. 1N/A * ENOMEM Not enough memory to allocate necessary buffers. 1N/A * ntfs_attr_init_search_ctx - initialize an attribute search context 1N/A * @ctx: attribute search context to initialize 1N/A * @ni: ntfs inode with which to initialize the search context 1N/A * @mrec: mft record with which to initialize the search context 1N/A * Initialize the attribute search context @ctx with @ni and @mrec. 1N/A /* Sanity checks are performed elsewhere. */ 1N/A * ntfs_attr_reinit_search_ctx - reinitialize an attribute search context 1N/A * @ctx: attribute search context to reinitialize 1N/A * Reinitialize the attribute search context @ctx. 1N/A * This is used when a search for a new attribute is being started to reset 1N/A * the search context to the beginning. 1N/A /* No attribute list. */ 1N/A /* Sanity checks are performed elsewhere. */ 1N/A * This needs resetting due to ntfs_external_attr_find() which 1N/A * can leave it set despite having zeroed ctx->base_ntfs_ino. 1N/A }
/* Attribute list. */ 1N/A * @ni: ntfs inode with which to initialize the search context 1N/A * @mrec: mft record with which to initialize the search context 1N/A * Allocate a new attribute search context, initialize it with @ni and @mrec, 1N/A * and return it. Return NULL on error with errno set to ENOMEM. 1N/A * @mrec can be NULL, in which case the mft record is taken from @ni. 1N/A * Note: For low level utilities which know what they are doing we allow @ni to 1N/A * be NULL and @mrec to be set. Do NOT do this unless you understand the 1N/A * implications!!! For example it is no longer safe to call ntfs_attr_lookup() 1N/A * ntfs_attr_put_search_ctx - release an attribute search context 1N/A * @ctx: attribute search context to free 1N/A * Release the attribute search context @ctx. This function does not change 1N/A * errno and doing nothing if NULL passed to it. 1N/A * ntfs_attr_find_in_attrdef - find an attribute in the $AttrDef system file 1N/A * @vol: ntfs volume to which the attribute belongs 1N/A * @type: attribute type which to find 1N/A * Search for the attribute definition record corresponding to the attribute 1N/A * @type in the $AttrDef system file. 1N/A * Return the attribute type definition record if found and NULL if not found 1N/A * or an error occurred. On error the error code is stored in errno. The 1N/A * following error codes are defined: 1N/A * ENOENT - The attribute @type is not specified in $AttrDef. 1N/A * EINVAL - Invalid parameters (e.g. @vol is not valid). 1N/A /* We haven't found it yet, carry on searching. */ 1N/A /* We found the attribute; return it. */ 1N/A /* We have gone too far already. No point in continuing. */ 1N/A /* Attribute not found?!? */ 1N/A * ntfs_attr_size_bounds_check - check a size of an attribute type for validity 1N/A * @vol: ntfs volume to which the attribute belongs 1N/A * @type: attribute type which to check 1N/A * @size: size which to check 1N/A * Check whether the @size in bytes is valid for an attribute of @type on the 1N/A * ntfs volume @vol. This information is obtained from $AttrDef system file. 1N/A * Return 0 if valid and -1 if not valid or an error occurred. On error the 1N/A * error code is stored in errno. The following error codes are defined: 1N/A * ERANGE - @size is not valid for the attribute @type. 1N/A * ENOENT - The attribute @type is not specified in $AttrDef. 1N/A * EINVAL - Invalid parameters (e.g. @size is < 0 or @vol is not valid). 1N/A * $ATTRIBUTE_LIST should be not greater than 0x40000, but this is not 1N/A * listed in the AttrDef. 1N/A /* We found the attribute. - Do the bounds check. */ 1N/A /* @size is out of range! */ 1N/A * ntfs_attr_can_be_non_resident - check if an attribute can be non-resident 1N/A * @vol: ntfs volume to which the attribute belongs 1N/A * @type: attribute type which to check 1N/A * Check whether the attribute of @type on the ntfs volume @vol is allowed to 1N/A * be non-resident. This information is obtained from $AttrDef system file. 1N/A * Return 0 if the attribute is allowed to be non-resident and -1 if not or an 1N/A * error occurred. On error the error code is stored in errno. The following 1N/A * error codes are defined: 1N/A * EPERM - The attribute is not allowed to be non-resident. 1N/A * ENOENT - The attribute @type is not specified in $AttrDef. 1N/A * EINVAL - Invalid parameters (e.g. @vol is not valid). 1N/A /* Find the attribute definition record in $AttrDef. */ 1N/A /* Check the flags and return the result. */ 1N/A * ntfs_attr_can_be_resident - check if an attribute can be resident 1N/A * @vol: ntfs volume to which the attribute belongs 1N/A * @type: attribute type which to check 1N/A * Check whether the attribute of @type on the ntfs volume @vol is allowed to 1N/A * be resident. This information is derived from our ntfs knowledge and may 1N/A * not be completely accurate, especially when user defined attributes are 1N/A * present. Basically we allow everything to be resident except for index 1N/A * allocation and extended attribute attributes. 1N/A * Return 0 if the attribute is allowed to be resident and -1 if not or an 1N/A * error occurred. On error the error code is stored in errno. The following 1N/A * error codes are defined: 1N/A * EPERM - The attribute is not allowed to be resident. 1N/A * EINVAL - Invalid parameters (e.g. @vol is not valid). 1N/A * Warning: In the system file $MFT the attribute $Bitmap must be non-resident 1N/A * otherwise windows will not boot (blue screen of death)! We cannot 1N/A * check for this here as we don't know which inode's $Bitmap is being 1N/A * asked about so the caller needs to special case this. 1N/A * ntfs_make_room_for_attr - make room for an attribute inside an mft record 1N/A * @pos: position at which to make space 1N/A * @size: byte size to make available at this position 1N/A * @pos points to the attribute in front of which we want to make space. 1N/A * Return 0 on success or -1 on error. On error the error code is stored in 1N/A * errno. Possible error codes are: 1N/A * ENOSPC - There is not enough space available to complete operation. The 1N/A * caller has to make space before calling this. 1N/A * EINVAL - Input parameters were faulty. 1N/A /* Make size 8-byte alignment. */ 1N/A /* Rigorous consistency checks. */ 1N/A /* The -8 is for the attribute terminator. */ 1N/A /* Nothing to do. */ 1N/A /* Do we have enough space? */ 1N/A /* Move everything after pos to pos + size. */ 1N/A /* Update mft record. */ 1N/A * ntfs_resident_attr_record_add - add resident attribute to inode 1N/A * @ni: opened ntfs inode to which MFT record add attribute 1N/A * @type: type of the new attribute 1N/A * @name: name of the new attribute 1N/A * @name_len: name length of the new attribute 1N/A * @val: value of the new attribute 1N/A * @size: size of new attribute (length of @val, if @val != NULL) 1N/A * @flags: flags of the new attribute 1N/A * Return offset to attribute from the beginning of the mft record on success 1N/A * and -1 on error. On error the error code is stored in errno. 1N/A * Possible error codes are: 1N/A * EINVAL - Invalid arguments passed to function. 1N/A * EEXIST - Attribute of such type and with same name already exists. 1N/A * EIO - I/O error occurred or damaged filesystem. 1N/A /* Locate place where record should be. */ 1N/A * Use ntfs_attr_find instead of ntfs_attr_lookup to find place for 1N/A * attribute in @ni->mrec, not any extent inode in case if @ni is base 1N/A /* Make room for attribute. */ 1N/A /* Setup record fields. */ 1N/A "ATTRIBUTE_LIST.\n");
1N/A * ntfs_non_resident_attr_record_add - add extent of non-resident attribute 1N/A * @ni: opened ntfs inode to which MFT record add attribute 1N/A * @type: type of the new attribute extent 1N/A * @name: name of the new attribute extent 1N/A * @name_len: name length of the new attribute extent 1N/A * @lowest_vcn: lowest vcn of the new attribute extent 1N/A * @dataruns_size: dataruns size of the new attribute extent 1N/A * @flags: flags of the new attribute extent 1N/A * Return offset to attribute from the beginning of the mft record on success 1N/A * and -1 on error. On error the error code is stored in errno. 1N/A * Possible error codes are: 1N/A * EINVAL - Invalid arguments passed to function. 1N/A * EEXIST - Attribute of such type, with same lowest vcn and with same 1N/A * name already exists. 1N/A * EIO - I/O error occurred or damaged filesystem. 1N/A "dataruns_size %d, flags 0x%x.\n",
1N/A /* Locate place where record should be. */ 1N/A * Use ntfs_attr_find instead of ntfs_attr_lookup to find place for 1N/A * attribute in @ni->mrec, not any extent inode in case if @ni is base 1N/A /* Make room for attribute. */ 1N/A /* Setup record fields. */ 1N/A /* If @lowest_vcn == 0, than setup empty attribute. */ 1N/A /* Set empty mapping pairs. */ 1N/A "ATTRIBUTE_LIST.\n");
1N/A * Locate offset from start of the MFT record where new attribute is 1N/A * placed. We need relookup it, because record maybe moved during 1N/A * update of attribute list. 1N/A "inconsistent metadata.\n");
1N/A * ntfs_attr_record_rm - remove attribute extent 1N/A * @ctx: search context describing the attribute which should be removed 1N/A * If this function succeed, user should reinit search context if he/she wants 1N/A * Return 0 on success and -1 on error. On error the error code is stored in 1N/A * errno. Possible error codes are: 1N/A * EINVAL - Invalid arguments passed to function. 1N/A * EIO - I/O error occurred or damaged filesystem. 1N/A /* Remove attribute itself. */ 1N/A "Bug or damaged MFT record.\n");
1N/A "inconsistent metadata.\n");
1N/A * Remove record from $ATTRIBUTE_LIST if present and we don't want 1N/A * delete $ATTRIBUTE_LIST itself. 1N/A "$ATTRIBUTE_LIST.\n");
1N/A /* Post $ATTRIBUTE_LIST delete setup. */ 1N/A /* Free MFT record, if it isn't contain attributes. */ 1N/A // FIXME: We need rollback here. 1N/A /* Remove done if we freed base inode. */ 1N/A /* Remove attribute list if we don't need it any more. */ 1N/A * FIXME: Should we succeed here? Definitely something 1N/A * goes wrong because NInoAttrList(base_ni) returned 1N/A * that we have got attribute list. 1N/A /* Deallocate clusters. */ 1N/A "list runlist. Succeed " 1N/A "Couldn't free clusters from " 1N/A "attribute list runlist.\n");
1N/A /* Remove attribute record itself. */ 1N/A * FIXME: Should we succeed here? BTW, chkdsk doesn't 1N/A * complain if it find MFT record with attribute list, 1N/A * but without extents. 1N/A "Succeed anyway.\n");
1N/A * ntfs_attr_add - add attribute to inode 1N/A * @ni: opened ntfs inode to which add attribute 1N/A * @type: type of the new attribute 1N/A * @name: name in unicode of the new attribute 1N/A * @name_len: name length in unicode characters of the new attribute 1N/A * @val: value of new attribute 1N/A * @size: size of the new attribute / length of @val (if specified) 1N/A * @val should always be specified for always resident attributes (eg. FILE_NAME 1N/A * attribute), for attributes that can become non-resident @val can be NULL 1N/A * (eg. DATA attribute). @size can be specified even if @val is NULL, in this 1N/A * case data size will be equal to @size and initialized size will be equal 1N/A * If inode haven't got enough space to add attribute, add attribute to one of 1N/A * it extents, if no extents present or no one of them have enough space, than 1N/A * allocate new extent and add attribute to it. 1N/A * If on one of this steps attribute list is needed but not present, than it is 1N/A * added transparently to caller. So, this function should not be called with 1N/A * @type == AT_ATTRIBUTE_LIST, if you really need to add attribute list call 1N/A * ntfs_inode_add_attrlist instead. 1N/A * On success return 0. On error return -1 with errno set to the error code. 1N/A /* Check the attribute type and the size. */ 1N/A /* Sanity checks for always resident attributes. */ 1N/A /* @val is mandatory. */ 1N/A /* Check whether attribute can be resident. */ 1N/A /* Calculate attribute record size. */ 1N/A else /* We add 8 for space for mapping pairs. */ 1N/A * If we have enough free space for the new attribute in the base MFT 1N/A * record, then add attribute to it. 1N/A /* Try to add to extent inodes. */ 1N/A * If failed to find space for resident attribute, then try to find 1N/A * space for non resident one. 1N/A * FIXME: Try to make other attributes non-resident here. Factor out 1N/A * code from ntfs_resident_attr_resize. 1N/A /* There is no extent that contain enough space for new attribute. */ 1N/A /* Add attribute list not present, add it and retry. */ 1N/A /* Allocate new extent for attribute. */ 1N/A * Determine resident or not will be attribute using heuristics and 1N/A * calculate attribute record size. FIXME: small code duplication here. 1N/A }
else {
/* We add 8 for space for mapping pairs. */ 1N/A /* Add resident attribute. */ 1N/A /* Add non resident attribute. */ 1N/A /* If @size == 0, we are done. */ 1N/A /* Open new attribute and resize it. */ 1N/A /* Resize and set attribute value. */ 1N/A "Probably leaving inconsistent " 1N/A /* Remove just added attribute. */ 1N/A /* Free MFT record, if it isn't contain attributes. */ 1N/A "inconsistent metadata.\n");
1N/A * ntfs_attr_rm - remove attribute from ntfs inode 1N/A * @na: opened ntfs attribute to delete 1N/A * Remove attribute and all it's extents from ntfs inode. If attribute was non 1N/A * resident also free all clusters allocated by attribute. This function always 1N/A * closes @na upon exit (both on success and failure). 1N/A * Return 0 on success or -1 on error with errno set to the error code. 1N/A /* Free cluster allocation. */ 1N/A "Leaving inconsistent metadata.\n");
1N/A /* Search for attribute extents and remove them all. */ 1N/A "Leaving inconsistent metadata.\n");
1N/A "Probably leaving inconsistent metadata.\n");
1N/A /* Throw away now non-exist attribute. */ 1N/A * ntfs_attr_record_resize - resize an attribute record 1N/A * @m: mft record containing attribute record 1N/A * @a: attribute record to resize 1N/A * @new_size: new size in bytes to which to resize the attribute record @a 1N/A * Resize the attribute record @a, i.e. the resident part of the attribute, in 1N/A * the mft record @m to @new_size bytes. 1N/A * Return 0 on success and -1 on error with errno set to the error code. 1N/A * The following error codes are defined: 1N/A * ENOSPC - Not enough space in the mft record @m to perform the resize. 1N/A * Note that on error no modifications have been performed whatsoever. 1N/A * Warning: If you make a record smaller without having copied all the data you 1N/A * are interested in the data may be overwritten! 1N/A /* Align to 8 bytes, just in case the caller hasn't. */ 1N/A /* If the actual attribute length has changed, move things around. */ 1N/A /* Not enough space in this mft record. */ 1N/A /* Move attributes following @a to their new location. */ 1N/A /* Adjust @m to reflect the change in used space. */ 1N/A /* Adjust @a to reflect the new size. */ 1N/A * ntfs_resident_attr_value_resize - resize the value of a resident attribute 1N/A * @m: mft record containing attribute record 1N/A * @a: attribute record whose value to resize 1N/A * @new_size: new size in bytes to which to resize the attribute value of @a 1N/A * Resize the value of the attribute @a in the mft record @m to @new_size bytes. 1N/A * If the value is made bigger, the newly "allocated" space is cleared. 1N/A * Return 0 on success and -1 on error with errno set to the error code. 1N/A * The following error codes are defined: 1N/A * ENOSPC - Not enough space in the mft record @m to perform the resize. 1N/A * Note that on error no modifications have been performed whatsoever. 1N/A * Check that the attribute name hasn't been placed after the 1N/A * attribute value. Chkdsk treat this as corruption. 1N/A "Corrupted inode. Run chkdsk. Aborting...\n");
1N/A /* Resize the resident part of the attribute record. */ 1N/A * If we made the attribute value bigger, clear the area between the 1N/A * old size and @new_size. 1N/A /* Finally update the length of the attribute value. */ 1N/A * ntfs_attr_record_move_to - move attribute record to target inode 1N/A * @ctx: attribute search context describing the attribute record 1N/A * @ni: opened ntfs inode to which move attribute record 1N/A * If this function succeed, user should reinit search context if he/she wants 1N/A * Return 0 on success and -1 on error with errno set to the error code. 1N/A "ctx->ntfs_ino->mft_no 0x%llx, ni->mft_no 0x%llx.\n",
1N/A "this function.\n");
1N/A /* Find place in MFT record where attribute will be moved. */ 1N/A * Use ntfs_attr_find instead of ntfs_attr_lookup to find place for 1N/A * attribute in @ni->mrec, not any extent inode in case if @ni is base 1N/A "present in this MFT record.\n");
1N/A /* Make space and move attribute. */ 1N/A /* Update attribute list. */ 1N/A * ntfs_attr_record_move_away - move away attribute record from it's mft record 1N/A * @ctx: attribute search context describing the attribute record 1N/A * @extra: minimum amount of free space in the new holder of record 1N/A * New attribute record holder must have free @extra bytes after moving 1N/A * attribute record to it. 1N/A * If this function succeed, user should reinit search context if he/she wants 1N/A * Return 0 on success and -1 on error with errno set to the error code. 1N/A "this function.\n");
1N/A /* Walk through all extents and try to move attribute to them. */ 1N/A * ntfs_attr_record_move_to can fail if extent with other lowest 1N/A * VCN already present in inode we trying move record to. So, 1N/A * do not return error. 1N/A * Failed to move attribute to one of the current extents, so allocate 1N/A * new extent and move attribute to it. 1N/A * ntfs_attr_make_non_resident - convert a resident to a non-resident attribute 1N/A * @na: open ntfs attribute to make non-resident 1N/A * @ctx: ntfs search context describing the attribute 1N/A * Convert a resident ntfs attribute to a non-resident one. 1N/A * Return 0 on success and -1 on error with errno set to the error code. The 1N/A * following error codes are defined: 1N/A * EPERM - The attribute is not allowed to be non-resident. 1N/A * NOTE to self: No changes in the attribute list are required to move from 1N/A * a resident to a non-resident attribute. 1N/A * Warning: We do not set the inode dirty and we do not write out anything! 1N/A * We expect the caller to do this as this is a fairly low level 1N/A * function and it is likely there will be further changes made. 1N/A /* Some preliminary sanity checking. */ 1N/A "non-resident. Aborting...\n");
1N/A /* Check that the attribute is allowed to be non-resident. */ 1N/A * Check that the attribute name hasn't been placed after the 1N/A * attribute value. Chkdsk treat this as corruption. 1N/A "Corrupted inode. Run chkdsk. Aborting...\n");
1N/A /* Start by allocating clusters to hold the attribute value. */ 1N/A "cluster(s). Aborting...\n");
1N/A * Setup the in-memory attribute structure to be non-resident so that 1N/A * we can use ntfs_attr_pwrite(). 1N/A * FIXME: For now just clear all of these as we don't support them when 1N/A /* Now copy the attribute value to the allocated cluster(s). */ 1N/A "(bw = %lli, errno = %i). " 1N/A /* Determine the size of the mapping pairs array. */ 1N/A /* Calculate new offsets for the name and the mapping pairs array. */ 1N/A * Determine the size of the resident part of the non-resident 1N/A * attribute record. (Not compressed thus no compressed_size element 1N/A /* Resize the resident part of the attribute record. */ 1N/A * Convert the resident part of the attribute record to describe a 1N/A * non-resident attribute. 1N/A /* Move the attribute name if it exists and update the offset. */ 1N/A /* Update the flags to match the in-memory ones. */ 1N/A /* Setup the fields specific to non-resident attributes. */ 1N/A /* Generate the mapping pairs array in the attribute record. */ 1N/A // FIXME: Eeek! We need rollback! (AIA) 1N/A "corrupt attribute record on disk. In memory " 1N/A "runlist is still intact! Error code is %i. " 1N/A "FIXME: Need to rollback instead!\n",
errno);
1N/A "code path. Leaving inconsistent metadata...\n");
1N/A * ntfs_resident_attr_resize - resize a resident, open ntfs attribute 1N/A * @na: resident ntfs attribute to resize 1N/A * @newsize: new size (in bytes) to which to resize the attribute 1N/A * Change the size of a resident, open ntfs attribute @na to @newsize bytes. 1N/A * On success return 0 and on error return -1 with errno set to the error code. 1N/A * The following error codes are defined: 1N/A * ENOMEM - Not enough memory to complete operation. 1N/A * ERANGE - @newsize is not valid for the attribute type of @na. 1N/A * ENOSPC - There is no enough space on the volume to allocate 1N/A * new clusters or in base mft to resize $ATTRIBUTE_LIST. 1N/A * EOVERFLOW - Resident attribute can not become non resident and 1N/A * already filled whole MFT record, but had not reached 1N/A * @newsize bytes length. 1N/A /* Get the attribute record that needs modification. */ 1N/A * Check the attribute type and the corresponding minimum and maximum 1N/A * sizes against @newsize and fail if @newsize is out of bounds. 1N/A * If @newsize is bigger than the MFT record we need to make the 1N/A * attribute non-resident if the attribute type supports it. If it is 1N/A * smaller we can go ahead and attempt the resize. 1N/A /* Perform the resize of the attribute record. */ 1N/A /* Update attribute size everywhere. */ 1N/A /* Error! If not enough space, just continue. */ 1N/A "of attribute. Aborting...\n");
1N/A /* There is not enough space in the MFT record to perform the resize. */ 1N/A /* Make the attribute non-resident if possible. */ 1N/A /* Resize non-resident attribute */ 1N/A /* Try to make other attributes non-resident and retry each time. */ 1N/A * Check out whether convert is reasonable. Assume that mapping 1N/A * pairs will take 8 bytes. 1N/A /* Check whether error occurred. */ 1N/A /* We can't move out attribute list, thus move out others. */ 1N/A "to make attribute list non " 1N/A * Move the attribute to a new MFT record, creating an attribute list 1N/A * attribute or modifying it if it is already present. 1N/A /* Point search context back to attribute which we need resize. */ 1N/A * Force index allocation creation instead of moving out index root 1N/A * from the base MFT record. 1N/A * Check whether attribute is already single in the this MFT record. 1N/A * 8 added for the attribute terminator. 1N/A /* Add attribute list if not present. */ 1N/A /* Allocate new MFT record. */ 1N/A /* Move attribute to it. */ 1N/A /* Update ntfs attribute. */ 1N/A /* Try to perform resize once again. */ 1N/A * Set the inode (and its base inode if it exists) dirty so it is 1N/A * written out later. 1N/A * ntfs_attr_make_resident - convert a non-resident to a resident attribute 1N/A * @na: open ntfs attribute to make resident 1N/A * @ctx: ntfs search context describing the attribute 1N/A * Convert a non-resident ntfs attribute to a resident one. 1N/A * Return 0 on success and -1 on error with errno set to the error code. The 1N/A * following error codes are defined: 1N/A * EINVAL - Invalid arguments passed. 1N/A * EPERM - The attribute is not allowed to be resident. 1N/A * EIO - I/O error, damaged inode or bug. 1N/A * ENOSPC - There is no enough space to perform conversion. 1N/A * EOPNOTSUPP - Requested conversion is not supported yet. 1N/A * Warning: We do not set the inode dirty and we do not write out anything! 1N/A * We expect the caller to do this as this is a fairly low level 1N/A * function and it is likely there will be further changes made. 1N/A /* Should be called for the first extent of the attribute. */ 1N/A "attribute. Aborting...\n");
1N/A /* Some preliminary sanity checking. */ 1N/A /* Make sure this is not $MFT/$BITMAP or Windows will not boot! */ 1N/A /* Check that the attribute is allowed to be resident. */ 1N/A * Check that the attribute name hasn't been placed after the 1N/A * mapping pairs array. Chkdsk treat this as corruption. 1N/A "mapping pairs array. Run chkdsk. Aborting.\n");
1N/A "is not implemented yet.\n");
1N/A /* Work out offsets into and size of the resident attribute. */ 1N/A /* Sanity check the size before we start modifying the attribute. */ 1N/A /* Read and cache the whole runlist if not already done. */ 1N/A /* Move the attribute name if it exists and update the offset. */ 1N/A /* Resize the resident part of the attribute record. */ 1N/A * Bug, because ntfs_attr_record_resize should not fail (we 1N/A * already checked that attribute fits MFT record). 1N/A "Please report to the %s. Aborting...\n",
1N/A /* Convert the attribute record to describe a resident attribute. */ 1N/A * File names cannot be non-resident so we would never see this here 1N/A * but at least it serves as a reminder that there may be attributes 1N/A * for which we do need to set this flag. (AIA) 1N/A /* Sanity fixup... Shouldn't really happen. (AIA) */ 1N/A /* Copy data from run list to resident attribute value. */ 1N/A "inconsistent metadata. Run chkdsk. " 1N/A /* Clear memory in gap between initialized_size and data_size. */ 1N/A * Deallocate clusters from the runlist. 1N/A * NOTE: We can use ntfs_cluster_free() because we have already mapped 1N/A * the whole run list and thus it doesn't matter that the attribute 1N/A * record is in a transiently corrupted state at this moment in time. 1N/A /* Throw away the now unused runlist. */ 1N/A /* Update in-memory struct ntfs_attr. */ 1N/A * ntfs_attr_update_mapping_pairs - update mapping pairs for ntfs attribute 1N/A * @na: non-resident ntfs open attribute for which we need update 1N/A * @from_vcn: update runlist starting this VCN 1N/A * Build mapping pairs from @na->rl and write them to the disk. Also, this 1N/A * space for this field if required). 1N/A * @na->allocated_size should be set to correct value for the new runlist before 1N/A * call to this function. Vice-versa @na->compressed_size will be calculated and 1N/A * set to correct value during this function. 1N/A * New runlist should be fully formed starting @from_vcn. Runs before @from_vcn 1N/A * can be mapped or not, but on-disk structures should not be modified before 1N/A * call to this function so they can be mapped if necessary. 1N/A * FIXME: Make it O(1) for sparse files too, not only for normal. 1N/A * FIXME: Rewrite without using NTFS_VCN_DELETE_MARK define. 1N/A * NOTE: Be careful in the future with updating bits on compressed files (at 1N/A * present assumed that on-disk flag is already set/cleared before call to 1N/A * On success return 0 and on error return -1 with errno set to the error code. 1N/A * The following error codes are defined: 1N/A * EINVAL - Invalid arguments passed. 1N/A * ENOMEM - Not enough memory to complete operation. 1N/A * ENOSPC - There is no enough space in base mft to resize $ATTRIBUTE_LIST 1N/A * or there is no free MFT records left to allocate. 1N/A /* Fill attribute records with new mapping pairs. */ 1N/A * If runlist is updating not from the beginning, then set 1N/A * @stop_vcn properly, i.e. to the lowest vcn of record that 1N/A * contain @from_vcn. Also we do not need @from_vcn anymore, 1N/A * set it to 0 to make ntfs_attr_lookup enumerate attributes. 1N/A * Check whether the first run we need to update is 1N/A * the last run in runlist, if so, then deallocate 1N/A * all attribute extents starting this one. 1N/A * Check whether we finished mapping pairs build, if so mark 1N/A * extent as need to delete (by setting highest vcn to 1N/A * NTFS_VCN_DELETE_MARK (-2), we shall check it later and 1N/A * delete extent) and continue search. 1N/A * Check that the attribute name hasn't been placed after the 1N/A * mapping pairs array. Windows treat this as a corruption. 1N/A "placed after the mapping " 1N/A "pairs array. Run chkdsk.\n");
1N/A * If we in the first extent, then set/clean sparse bit, 1N/A * update allocated and compressed size. 1N/A /* Update allocated size. */ 1N/A * Check whether part of runlist we are updating is 1N/A * If new part or on-disk attribute is not sparse, then 1N/A * we should fully map runlist to make final decision. 1N/A "before @from_vcn.\n");
1N/A * Reconsider whether whole runlist is sparse 1N/A * if new part is not. 1N/A * We need to move attribute to another mft 1N/A * record, if attribute is to small to add 1N/A * compressed_size field to it and we have no 1N/A * free space in the current mft record. 1N/A "attribute to another " 1N/A "extent. Aborting..\n");
1N/A "allocated for mapping " 1N/A "pairs should not be 0." 1N/A * We should update all mapping pairs, because 1N/A * we shifted their starting position. 1N/A /* Attribute becomes normal. */ 1N/A * Windows defragmentation tool do not update 1N/A * name offset correctly for unnamed 1N/A * attributes, but chkdsk do not like when it 1N/A * negative, so do not change it at all if it 1N/A * would become negative. 1N/A * We should update all mapping pairs, because 1N/A * we shifted their starting position. 1N/A /* Update compressed size if required. */ 1N/A * Set FILE_NAME dirty flag, to update sparse bit and 1N/A * allocated size in the index. 1N/A * We do want to do anything for the first extent in 1N/A * case we are updating mapping pairs not from the 1N/A /* Get the size for the rest of mapping pairs array. */ 1N/A * Determine maximum possible length of mapping pairs, 1N/A * if we shall *not* expand space for mapping pairs. 1N/A * Determine maximum possible length of mapping pairs in the 1N/A * current mft record, if we shall expand space for mapping 1N/A /* Test mapping pairs for fitting in the current mft record. */ 1N/A * Mapping pairs of $ATTRIBUTE_LIST attribute must fit 1N/A * in the base mft record. Try to move out other 1N/A * attributes and try again. 1N/A "pairs size to big, " 1N/A "can't fit them in the " 1N/A "Defragment volume and " 1N/A "try once again.\n");
1N/A /* Add attribute list if it isn't present, and retry. */ 1N/A * Set mapping pairs size to maximum possible for this 1N/A * mft record. We shall write the rest of mapping pairs 1N/A * to another MFT records. 1N/A /* Change space for mapping pairs if we need it. */ 1N/A "record. Please run chkdsk and " 1N/A "if that doesn't find any " 1N/A "errors please report you saw " 1N/A "this message to %s.\n",
1N/A /* Update lowest vcn. */ 1N/A * Generate the new mapping pairs array directly into the 1N/A * correct destination, i.e. the attribute record itself. 1N/A "Please run chkdsk and if that doesn't " 1N/A "find any errors please report you saw " 1N/A /* Check whether error occurred. */ 1N/A /* Deallocate not used attribute extents and return with success. */ 1N/A /* Remove unused attribute record. */ 1N/A "attribute record.\n");
1N/A /* Allocate new MFT records for the rest of mapping pairs. */ 1N/A /* Calculate size of rest mapping pairs. */ 1N/A /* Allocate new mft record. */ 1N/A * If mapping size exceed available space, set them to 1N/A /* Add attribute extent to new record. */ 1N/A "Please run chkdsk and if that doesn't " 1N/A "find any errors please report you saw " 1N/A /* All mapping pairs has been written. */ 1N/A * ntfs_non_resident_attr_shrink - shrink a non-resident, open ntfs attribute 1N/A * @na: non-resident ntfs attribute to shrink 1N/A * @newsize: new size (in bytes) to which to shrink the attribute 1N/A * Reduce the size of a non-resident, open ntfs attribute @na to @newsize bytes. 1N/A * On success return 0 and on error return -1 with errno set to the error code. 1N/A * The following error codes are defined: 1N/A * ENOMEM - Not enough memory to complete operation. 1N/A * ERANGE - @newsize is not valid for the attribute type of @na. 1N/A * Check the attribute type and the corresponding minimum size 1N/A * against @newsize and fail if @newsize is too small. 1N/A /* The first cluster outside the new allocation. */ 1N/A * Compare the new allocation with the old one and only deallocate 1N/A * clusters if there is a change. 1N/A /* Deallocate all clusters starting with the first free one. */ 1N/A /* Truncate the runlist itself. */ 1N/A * Failed to truncate the runlist, so just throw it 1N/A * away, it will be mapped afresh on next use. 1N/A /* Prepare to mapping pairs update. */ 1N/A /* Write mapping pairs for new runlist. */ 1N/A "Leaving inconsistent metadata. " 1N/A /* Get the first attribute record. */ 1N/A "Leaving inconsistent metadata.\n");
1N/A /* Update data and initialized size. */ 1N/A /* Update data size in the index. */ 1N/A /* If the attribute now has zero size, make it resident. */ 1N/A /* If couldn't make resident, just continue. */ 1N/A "resident. Leaving as is...\n");
1N/A /* Set the inode dirty so it is written out later. */ 1N/A * ntfs_non_resident_attr_expand - expand a non-resident, open ntfs attribute 1N/A * @na: non-resident ntfs attribute to expand 1N/A * @newsize: new size (in bytes) to which to expand the attribute 1N/A * @sparse: if TRUE then will create hole if possible 1N/A * Expand the size of a non-resident, open ntfs attribute @na to @newsize bytes, 1N/A * by allocating new clusters. 1N/A * On success return 0 and on error return -1 with errno set to the error code. 1N/A * The following error codes are defined: 1N/A * ENOMEM - Not enough memory to complete operation. 1N/A * ERANGE - @newsize is not valid for the attribute type of @na. 1N/A * ENOSPC - There is no enough space in base mft to resize $ATTRIBUTE_LIST. 1N/A "current size %lld.\n",
1N/A * Check the attribute type and the corresponding maximum size 1N/A * against @newsize and fail if @newsize is too big. 1N/A /* Save for future use. */ 1N/A /* The first cluster outside the new allocation. */ 1N/A * Compare the new allocation with the old one and only allocate 1N/A * clusters if there is a change. 1N/A /* Map required part of runlist. */ 1N/A * If we extend $DATA attribute on NTFS 3+ volume, we can add 1N/A * sparse runs instead of real allocation of clusters. 1N/A * Determine first after last LCN of attribute. 1N/A * We will start seek clusters from this LCN to avoid 1N/A * fragmentation. If there are no valid LCNs in the 1N/A * attribute let the cluster allocator choose the 1N/A /* Seek to the last run list element. */ 1N/A * If the last LCN is a hole or similar seek 1N/A * back to last valid LCN. 1N/A * Only set lcn_seek_from it the LCN is valid. 1N/A /* Append new clusters to attribute runlist. */ 1N/A /* Failed, free just allocated clusters. */ 1N/A /* Prepare to mapping pairs update. */ 1N/A /* Write mapping pairs for new runlist. */ 1N/A /* Update data size. */ 1N/A /* Update data size in the index. */ 1N/A /* Set the inode dirty so it is written out later. */ 1N/A /* Free allocated clusters. */ 1N/A /* Now, truncate the runlist itself. */ 1N/A * Failed to truncate the runlist, so just throw it away, it 1N/A * will be mapped afresh on next use. 1N/A /* Prepare to mapping pairs update. */ 1N/A /* Restore mapping pairs. */ 1N/A "Rollback failed.\n");
1N/A * __ntfs_attr_truncate - resize an ntfs attribute 1N/A * @na: open ntfs attribute to resize 1N/A * @newsize: new size (in bytes) to which to resize the attribute 1N/A * @sparse: if TRUE then will create hole if possible 1N/A * Change the size of an open ntfs attribute @na to @newsize bytes. If the 1N/A * attribute is made bigger and the attribute is resident the newly 1N/A * "allocated" space is cleared and if the attribute is non-resident the 1N/A * newly allocated space is marked as not initialised and no real allocation 1N/A * on disk is performed. 1N/A * On success return 0 and on error return -1 with errno set to the error code. 1N/A * The following error codes are defined: 1N/A * EINVAL - Invalid arguments were passed to the function. 1N/A * EACCES - Attribute is encrypted. 1N/A * ERANGE - @newsize is not valid for the attribute type of @na. 1N/A * ENOSPC - There is no enough space on the volume to allocate 1N/A * new clusters or in base mft to resize $ATTRIBUTE_LIST. 1N/A * EOVERFLOW - Resident attribute can not become non resident and 1N/A * already filled whole MFT record, but had not reached 1N/A * @newsize bytes length. 1N/A * EOPNOTSUPP - The desired resize is not implemented yet. 1N/A * Encrypted attributes are not supported. We return access denied, 1N/A * which is what Windows NT4 does, too. 1N/A * TODO: Implement making handling of compressed attributes. 1N/A * Wrapper around __ntfs_attr_truncate that always tries to creates hole 1N/A * ntfs_attr_readall - read the entire data from an ntfs attribute 1N/A * @ni: open ntfs inode in which the ntfs attribute resides 1N/A * @type: attribute type 1N/A * @name: attribute name in little endian Unicode or AT_UNNAMED or NULL 1N/A * @name_len: length of attribute @name in Unicode characters (if @name given) 1N/A * @data_size: if non-NULL then store here the data size 1N/A * This function will read the entire content of an ntfs attribute. 1N/A * If @name is AT_UNNAMED then look specifically for an unnamed attribute. 1N/A * If @name is NULL then the attribute could be either named or not. 1N/A * In both those cases @name_len is not used at all. 1N/A * On success a buffer is allocated with the content of the attribute 1N/A * and which needs to be freed when it's not needed anymore. If the 1N/A * @data_size parameter is non-NULL then the data size is set there. 1N/A * On error NULL is returned with errno set to the error code. 1N/A * ntfs_attr_exist - FIXME: description