1N/A * runlist.c - Run list handling code. Part of the Linux-NTFS project. 1N/A * Copyright (c) 2002-2005 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_rl_mm - runlist memmove 1N/A * ntfs_rl_mc - runlist memory copy 1N/A * ntfs_rl_realloc - Reallocate memory for runlists 1N/A * @rl: original runlist 1N/A * @old_size: number of runlist elements in the original runlist @rl 1N/A * @new_size: number of runlist elements we need space for 1N/A * As the runlists grow, more memory will be required. To prevent large 1N/A * numbers of small reallocations of memory, this function returns a 4kiB block 1N/A * N.B. If the new allocation doesn't require a different number of 4kiB 1N/A * blocks in memory, the function will return the original pointer. 1N/A * On success, return a pointer to the newly allocated, or recycled, memory. 1N/A * On error, return NULL with errno set to the error code. 1N/A * ntfs_rl_are_mergeable - test if two runlists can be joined together 1N/A * @dst: original runlist 1N/A * @src: new runlist to test for mergeability with @dst 1N/A * Test if two runlists can be joined together. For this, their VCNs and LCNs 1N/A * Return: TRUE Success, the runlists can be merged. 1N/A * FALSE Failure, the runlists cannot be merged. 1N/A /* We can merge unmapped regions even if they are misaligned. */ 1N/A /* If the runs are misaligned, we cannot merge them. */ 1N/A /* If both runs are non-sparse and contiguous, we can merge them. */ 1N/A /* If we are merging two holes, we can merge them. */ 1N/A * __ntfs_rl_merge - merge two runlists without testing if they can be merged 1N/A * @dst: original, destination runlist 1N/A * @src: new runlist to merge with @dst 1N/A * Merge the two runlists, writing into the destination runlist @dst. The 1N/A * caller must make sure the runlists can be merged or this will corrupt the 1N/A * destination runlist. 1N/A * ntfs_rl_append - append a runlist after a given element 1N/A * @dst: original runlist to be worked on 1N/A * @dsize: number of elements in @dst (including end marker) 1N/A * @src: runlist to be inserted into @dst 1N/A * @ssize: number of elements in @src (excluding end marker) 1N/A * @loc: append the new runlist @src after this element in @dst 1N/A * Append the runlist @src after element @loc in @dst. Merge the right end of 1N/A * the new runlist, if necessary. Adjust the size of the hole before the 1N/A * On success, return a pointer to the new, combined, runlist. Note, both 1N/A * runlists @dst and @src are deallocated before returning so you cannot use 1N/A * the pointers for anything any more. (Strictly speaking the returned runlist 1N/A * may be the same as @dst but this is irrelevant.) 1N/A * On error, return NULL, with errno set to the error code. Both runlists are 1N/A /* First, check if the right hand end needs merging. */ 1N/A /* Space required: @dst size + @src size, less one if we merged. */ 1N/A * We are guaranteed to succeed from here so can start modifying the 1N/A * original runlists. 1N/A /* First, merge the right hand end, if necessary. */ 1N/A /* marker - First run after the @src runs that have been inserted */ 1N/A /* Move the tail of @dst out of the way, then copy in @src. */ 1N/A /* Adjust the size of the preceding hole. */ 1N/A /* We may have changed the length of the file, so fix the end marker */ 1N/A * ntfs_rl_insert - insert a runlist into another 1N/A * @dst: original runlist to be worked on 1N/A * @dsize: number of elements in @dst (including end marker) 1N/A * @src: new runlist to be inserted 1N/A * @ssize: number of elements in @src (excluding end marker) 1N/A * @loc: insert the new runlist @src before this element in @dst 1N/A * Insert the runlist @src before element @loc in the runlist @dst. Merge the 1N/A * left end of the new runlist, if necessary. Adjust the size of the hole 1N/A * after the inserted runlist. 1N/A * On success, return a pointer to the new, combined, runlist. Note, both 1N/A * runlists @dst and @src are deallocated before returning so you cannot use 1N/A * the pointers for anything any more. (Strictly speaking the returned runlist 1N/A * may be the same as @dst but this is irrelevant.) 1N/A * On error, return NULL, with errno set to the error code. Both runlists are 1N/A /* disc => Discontinuity between the end of @dst and the start of @src. 1N/A * This means we might need to insert a "notmapped" run. 1N/A /* Space required: @dst size + @src size, less one if we merged, plus 1N/A * one if there was a discontinuity. 1N/A * We are guaranteed to succeed from here so can start modifying the 1N/A * marker - First run after the @src runs that have been inserted 1N/A * Nominally: marker = @loc + @ssize (location + number of runs in @src) 1N/A * If "left", then the first run in @src has been merged with one in @dst. 1N/A * If "disc", then @dst and @src don't meet and we need an extra run to fill the gap. 1N/A /* Move the tail of @dst out of the way, then copy in @src. */ 1N/A /* Adjust the VCN of the first run after the insertion ... */ 1N/A /* ... and the length. */ 1N/A /* Writing beyond the end of the file and there's a discontinuity. */ 1N/A * ntfs_rl_replace - overwrite a runlist element with another runlist 1N/A * @dst: original runlist to be worked on 1N/A * @dsize: number of elements in @dst (including end marker) 1N/A * @src: new runlist to be inserted 1N/A * @ssize: number of elements in @src (excluding end marker) 1N/A * @loc: index in runlist @dst to overwrite with @src 1N/A * Replace the runlist element @dst at @loc with @src. Merge the left and 1N/A * right ends of the inserted runlist, if necessary. 1N/A * On success, return a pointer to the new, combined, runlist. Note, both 1N/A * runlists @dst and @src are deallocated before returning so you cannot use 1N/A * the pointers for anything any more. (Strictly speaking the returned runlist 1N/A * may be the same as @dst but this is irrelevant.) 1N/A * On error, return NULL, with errno set to the error code. Both runlists are 1N/A int tail;
/* Start of tail of @dst */ 1N/A /* First, see if the left and right ends need merging. */ 1N/A /* Allocate some space. We'll need less if the left, right, or both 1N/A * ends get merged. The -1 accounts for the run being replaced. 1N/A * We are guaranteed to succeed from here so can start modifying the 1N/A * original runlists. 1N/A /* First, merge the left and right ends, if necessary. */ 1N/A * tail - Offset of the tail of @dst 1N/A * Nominally: @tail = @loc + 1 (location, skipping the replaced run) 1N/A * If "right", then one of @dst's runs is already merged into @src. 1N/A * marker - First run after the @src runs that have been inserted 1N/A * Nominally: @marker = @loc + @ssize (location + number of runs in @src) 1N/A * If "left", then the first run in @src has been merged with one in @dst. 1N/A /* Move the tail of @dst out of the way, then copy in @src. */ 1N/A /* We may have changed the length of the file, so fix the end marker */ 1N/A * ntfs_rl_split - insert a runlist into the centre of a hole 1N/A * @dst: original runlist to be worked on 1N/A * @dsize: number of elements in @dst (including end marker) 1N/A * @src: new runlist to be inserted 1N/A * @ssize: number of elements in @src (excluding end marker) 1N/A * @loc: index in runlist @dst at which to split and insert @src 1N/A * Split the runlist @dst at @loc into two and insert @new in between the two 1N/A * fragments. No merging of runlists is necessary. Adjust the size of the 1N/A * holes either side. 1N/A * On success, return a pointer to the new, combined, runlist. Note, both 1N/A * runlists @dst and @src are deallocated before returning so you cannot use 1N/A * the pointers for anything any more. (Strictly speaking the returned runlist 1N/A * may be the same as @dst but this is irrelevant.) 1N/A * On error, return NULL, with errno set to the error code. Both runlists are 1N/A /* Space required: @dst size + @src size + one new hole. */ 1N/A * We are guaranteed to succeed from here so can start modifying the 1N/A * original runlists. 1N/A /* Move the tail of @dst out of the way, then copy in @src. */ 1N/A /* Adjust the size of the holes either size of @src. */ 1N/A * ntfs_runlists_merge - merge two runlists into one 1N/A * @drl: original runlist to be worked on 1N/A * @srl: new runlist to be merged into @drl 1N/A * First we sanity check the two runlists @srl and @drl to make sure that they 1N/A * are sensible and can be merged. The runlist @srl must be either after the 1N/A * runlist @drl or completely within a hole (or unmapped region) in @drl. 1N/A * Merging of runlists is necessary in two cases: 1N/A * 1. When attribute lists are used and a further extent is being mapped. 1N/A * 2. When new clusters are allocated to fill a hole or extend a file. 1N/A * There are four possible ways @srl can be merged. It can: 1N/A * - be inserted at the beginning of a hole, 1N/A * - split the hole in two and be inserted between the two fragments, 1N/A * - be appended at the end of a hole, or it can 1N/A * - replace the whole hole. 1N/A * It can also be appended to the end of the runlist, which is just a variant 1N/A * of the insert case. 1N/A * On success, return a pointer to the new, combined, runlist. Note, both 1N/A * runlists @drl and @srl are deallocated before returning so you cannot use 1N/A * the pointers for anything any more. (Strictly speaking the returned runlist 1N/A * may be the same as @dst but this is irrelevant.) 1N/A * On error, return NULL, with errno set to the error code. Both runlists are 1N/A * left unmodified. The following error codes are defined: 1N/A * ENOMEM Not enough memory to allocate runlist array. 1N/A * EINVAL Invalid parameters were passed in. 1N/A * ERANGE The runlists overlap and cannot be merged. 1N/A int di,
si;
/* Current index into @[ds]rl. */ 1N/A int sstart;
/* First index with lcn > LCN_RL_NOT_MAPPED. */ 1N/A int dins;
/* Index into @drl at which to insert @srl. */ 1N/A /* Check for silly calling... */ 1N/A /* Check for the case where the first mapping is being done now. */ 1N/A /* Complete the source runlist if necessary. */ 1N/A /* Scan to the end of the source runlist. */ 1N/A /* Insert start element at the front of the runlist. */ 1N/A /* Skip any unmapped start element(s) in the source runlist. */ 1N/A /* Can't have an entirely unmapped source runlist. */ 1N/A "unmapped source runlist.\n");
1N/A /* Record the starting points. */ 1N/A * Skip forward in @drl until we reach the position where @srl needs to 1N/A * be inserted. If we reach the end of @drl, @srl just needs to be 1N/A /* Sanity check for illegal overlaps. */ 1N/A /* Scan to the end of both runlists in order to know their sizes. */ 1N/A /* Scan to the last element with lcn >= LCN_HOLE. */ 1N/A int ds =
dend +
1;
/* Number of elements in drl & srl */ 1N/A /* Or we'll lose an end marker */ 1N/A /* We only need to care if @srl ended after @drl. */ 1N/A * We need to create an unmapped runlist element in 1N/A * @drl or extend an existing one before adding the 1N/A * ENOENT terminator. 1N/A /* Add an unmapped runlist element. */ 1N/A * extra memory already! (AIA) 1N/A /* Need to set vcn if it isn't set already. */ 1N/A /* We now used up a slot. */ 1N/A /* Finally add the ENOENT terminator. */ 1N/A * memory already! (AIA) 1N/A /* The merge was completed successfully. */ 1N/A /* Critical error! We cannot afford to fail here. */ 1N/A * ntfs_mapping_pairs_decompress - convert mapping pairs array to runlist 1N/A * @vol: ntfs volume on which the attribute resides 1N/A * @attr: attribute record whose mapping pairs array to decompress 1N/A * @old_rl: optional runlist in which to insert @attr's runlist 1N/A * Decompress the attribute @attr's mapping pairs array into a runlist. On 1N/A * success, return the decompressed runlist. 1N/A * If @old_rl is not NULL, decompressed runlist is inserted into the 1N/A * appropriate place in @old_rl and the resultant, combined runlist is 1N/A * returned. The original @old_rl is deallocated. 1N/A * On error, return NULL with errno set to the error code. @old_rl is left 1N/A * unmodified in that case. 1N/A * The following error codes are defined: 1N/A * ENOMEM Not enough memory to allocate runlist array. 1N/A * EIO Corrupt runlist. 1N/A * EINVAL Invalid parameters were passed in. 1N/A * ERANGE The two runlists overlap. 1N/A * FIXME: For now we take the conceptionally simplest approach of creating the 1N/A * new runlist disregarding the already existing one and then splicing the 1N/A * two into one, if that is possible (we check for overlap and discard the new 1N/A * runlist if overlap present before returning NULL, with errno = ERANGE). 1N/A const u8 *
buf;
/* Current position in mapping pairs array. */ 1N/A runlist_elements. */ 1N/A u8 b;
/* Current byte offset in buf. */ 1N/A /* Make sure attr exists and is non-resident. */ 1N/A /* Start at vcn = lowest_vcn and lcn 0. */ 1N/A /* Get start of the mapping pairs array. */ 1N/A /* Current position in runlist array. */ 1N/A /* Allocate first 4kiB block and set current runlist size to 4kiB. */ 1N/A /* Insert unmapped starting element if necessary. */ 1N/A * Allocate more memory if needed, including space for the 1N/A * not-mapped and terminator elements. 1N/A /* Enter the current vcn into the current runlist element. */ 1N/A * Get the change in vcn, i.e. the run length in clusters. 1N/A * Doing it this way ensures that we signextend negative values. 1N/A * A negative run length doesn't make any sense, but hey, I 1N/A * didn't make up the NTFS specs and Windows NT4 treats the run 1N/A * length as a signed value so that's how it is... 1N/A }
else {
/* The length entry is compulsory. */ 1N/A * Assume a negative length to indicate data corruption and 1N/A * hence clean-up and return NULL. 1N/A * Enter the current run length into the current runlist 1N/A /* Increment the current vcn by the current run length. */ 1N/A * There might be no lcn change at all, as is the case for 1N/A * sparse clusters on NTFS 3.0+, in which case we set the lcn 1N/A /* Get the lcn change which really can be negative. */ 1N/A /* Change the current lcn to it's new value. */ 1N/A * On NTFS 1.2-, apparently can have lcn == -1 to 1N/A * indicate a hole. But we haven't verified ourselves 1N/A * whether it is really the lcn or the deltaxcn that is 1N/A * -1. So if either is found give us a message so we 1N/A * can investigate it further! 1N/A /* Check lcn is not below -1. */ 1N/A /* Enter the current lcn into the runlist element. */ 1N/A /* Get to the next runlist element. */ 1N/A /* Increment the buffer position to the next mapping pair. */ 1N/A * If there is a highest_vcn specified, it must be equal to the final 1N/A * vcn in the runlist - 1, or something has gone badly wrong. 1N/A /* Setup not mapped runlist element if this is the base extent. */ 1N/A * A highest_vcn of zero means this is a single extent 1N/A * attribute so simply terminate the runlist with LCN_ENOENT). 1N/A * If there is a difference between the highest_vcn and 1N/A * the highest cluster, the runlist is either corrupt 1N/A * or, more likely, there are more extents following 1N/A "0x%llx, max_cluster = 0x%llx\n",
1N/A "0x%llx, max_cluster = 0x%llx\n",
1N/A }
else /* Not the base extent. There may be more extents to follow. */ 1N/A /* Setup terminating runlist element. */ 1N/A /* If no existing runlist was specified, we are done. */ 1N/A /* Now combine the new and old runlists checking for overlaps. */ 1N/A * ntfs_rl_vcn_to_lcn - convert a vcn into a lcn given a runlist 1N/A * @rl: 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 @rl to map vcns to their 1N/A * corresponding lcns. 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 * -2 = LCN_RL_NOT_MAPPED This is part of the runlist which has not been 1N/A * inserted into the runlist yet. 1N/A * -3 = LCN_ENOENT There is no such vcn in the attribute. 1N/A * -4 = LCN_EINVAL Input parameter error. 1N/A * If rl is NULL, assume that we have found an unmapped runlist. The 1N/A * caller can then attempt to map it and fail appropriately if 1N/A /* Catch out of lower bounds vcn. */ 1N/A * The terminator element is setup to the correct value, i.e. one of 1N/A * LCN_HOLE, LCN_RL_NOT_MAPPED, or LCN_ENOENT. 1N/A /* Just in case... We could replace this with BUG() some day. */ 1N/A * ntfs_rl_pread - gather read from disk 1N/A * @vol: ntfs volume to read from 1N/A * @rl: runlist specifying where to read the data from 1N/A * @pos: byte position within runlist @rl at which to begin the read 1N/A * @count: number of bytes to read 1N/A * @b: data buffer into which to read from disk 1N/A * This function will read @count bytes from the volume @vol to the data buffer 1N/A * @b gathering the data as specified by the runlist @rl. The read begins at 1N/A * offset @pos into the runlist @rl. 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 * 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 * NOTE: If we encounter EOF while reading we return EIO because we assume that 1N/A * the run list must point to valid locations within the ntfs volume. 1N/A /* Seek in @rl to the run containing @pos. */ 1N/A /* Offset in the run at which to begin reading. */ 1N/A /* It is a hole. Just fill buffer @b with zeroes. */ 1N/A /* Update counters and proceed with next run. */ 1N/A /* It is a real lcn, read it from the volume. */ 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_rl_pwrite - scatter write to disk 1N/A * @vol: ntfs volume to write to 1N/A * @rl: runlist specifying where to write the data to 1N/A * @pos: byte position within runlist @rl at which to begin the write 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 the volume @vol 1N/A * scattering the data as specified by the runlist @rl. The write begins at 1N/A * offset @pos into the runlist @rl. 1N/A * On success, return the number of successfully written bytes. If this number 1N/A * is lower than @count this means that the write has been interrupted in 1N/A * flight or that an error was encountered during the write so that the write 1N/A * is partial. 0 means nothing was written (also return 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 to EINVAL in case 1N/A * of invalid arguments. 1N/A /* Seek in @rl to the run containing @pos. */ 1N/A /* Offset in the run at which to begin writing. */ 1N/A * It is a hole. Check if the buffer is zero in this 1N/A * region and if not abort with error. 1N/A if (((
unsigned long*)b)[t])
1N/A ~(
sizeof(
unsigned long) -
1));
1N/A * The buffer region is zero, update progress counters 1N/A * and proceed with next run. 1N/A /* It is a real lcn, write it to the volume. */ 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 written. */ 1N/A * ntfs_rl_fill_zero - fill given region with zeroes 1N/A * @vol: ntfs volume to write to 1N/A * @rl: runlist specifying where to write zeroes to 1N/A * @pos: byte position within runlist @rl at which to begin the zeroing 1N/A * @count: number of bytes to fill with zeros 1N/A * Return 0 on success and -1 on error with errno set to the error code. 1N/A * ntfs_get_nr_significant_bytes - get number of bytes needed to store a number 1N/A * @n: number for which to get the number of bytes for 1N/A * Return the number of bytes required to store @n unambiguously as 1N/A * This is used in the context of the mapping pairs array to determine how 1N/A * many bytes will be needed in the array to store a given logical cluster 1N/A * number (lcn) or a specific run length. 1N/A * Return the number of bytes written. This function cannot fail. 1N/A }
while (l != 0
LL && l != -
1LL);
1N/A j = (n >>
8 * (i -
1)) &
0xff;
1N/A /* If the sign bit is wrong, we need an extra byte. */ 1N/A if ((n < 0
LL && j >= 0) || (n > 0
LL && j < 0))
1N/A * ntfs_get_size_for_mapping_pairs - get bytes needed for mapping pairs array 1N/A * @vol: ntfs volume (needed for the ntfs version) 1N/A * @rl: runlist for which to determine the size of the mapping pairs 1N/A * @start_vcn: vcn at which to start the mapping pairs array 1N/A * Walk the runlist @rl and calculate the size in bytes of the mapping pairs 1N/A * array corresponding to the runlist @rl, starting at vcn @start_vcn. This 1N/A * for example allows us to allocate a buffer of the right size when building 1N/A * the mapping pairs array. 1N/A * If @rl is NULL, just return 1 (for the single terminator byte). 1N/A * Return the calculated size in bytes on success. On error, return -1 with 1N/A * errno set to the error code. The following error codes are defined: 1N/A * EINVAL - Run list contains unmapped elements. Make sure to only pass 1N/A * fully mapped runlists to this function. 1N/A * - @start_vcn is invalid. 1N/A * EIO - The runlist is corrupt. 1N/A /* Skip to runlist element containing @start_vcn. */ 1N/A /* Always need the terminating zero byte. */ 1N/A /* Do the first partial run if present. */ 1N/A /* We know rl->length != 0 already. */ 1N/A /* Header byte + length. */ 1N/A * If the logical cluster number (lcn) denotes a hole and we 1N/A * are on NTFS 3.0+, we don't store it at all, i.e. we need 1N/A * zero space. On earlier NTFS versions we just store the lcn. 1N/A * Note: this assumes that on NTFS 1.2-, holes are stored with 1N/A * an lcn of -1 and not a delta_lcn of -1 (unless both are -1). 1N/A /* Change in lcn. */ 1N/A /* Go to next runlist element. */ 1N/A /* Do the full runs. */ 1N/A /* Header byte + length. */ 1N/A * If the logical cluster number (lcn) denotes a hole and we 1N/A * are on NTFS 3.0+, we don't store it at all, i.e. we need 1N/A * zero space. On earlier NTFS versions we just store the lcn. 1N/A * Note: this assumes that on NTFS 1.2-, holes are stored with 1N/A * an lcn of -1 and not a delta_lcn of -1 (unless both are -1). 1N/A /* Change in lcn. */ 1N/A * ntfs_write_significant_bytes - write the significant bytes of a number 1N/A * @dst: destination buffer to write to 1N/A * @dst_max: pointer to last byte of destination buffer for bounds checking 1N/A * @n: number whose significant bytes to write 1N/A * Store in @dst, the minimum bytes of the number @n which are required to 1N/A * identify @n unambiguously as a signed number, taking care not to exceed 1N/A * @dest_max, the maximum position within @dst to which we are allowed to 1N/A * This is used when building the mapping pairs array of a runlist to compress 1N/A * a given logical cluster number (lcn) or a specific run length to the minimum 1N/A * Return the number of bytes written on success. On error, i.e. the 1N/A * destination buffer @dst is too small, return -1 with errno set ENOSPC. 1N/A }
while (l != 0
LL && l != -
1LL);
1N/A j = (n >>
8 * (i -
1)) &
0xff;
1N/A /* If the sign bit is wrong, we need an extra byte. */ 1N/A }
else if (n > 0
LL && j < 0) {
1N/A * ntfs_mapping_pairs_build - build the mapping pairs array from a runlist 1N/A * @vol: ntfs volume (needed for the ntfs version) 1N/A * @dst: destination buffer to which to write the mapping pairs array 1N/A * @dst_len: size of destination buffer @dst in bytes 1N/A * @rl: runlist for which to build the mapping pairs array 1N/A * @start_vcn: vcn at which to start the mapping pairs array 1N/A * @stop_vcn: first vcn outside destination buffer on success or ENOSPC error 1N/A * Create the mapping pairs array from the runlist @rl, starting at vcn 1N/A * @start_vcn and save the array in @dst. @dst_len is the size of @dst in 1N/A * bytes and it should be at least equal to the value obtained by calling 1N/A * ntfs_get_size_for_mapping_pairs(). 1N/A * If @rl is NULL, just write a single terminator byte to @dst. 1N/A * On success or ENOSPC error, if @stop_vcn is not NULL, *@stop_vcn is set to 1N/A * the first vcn outside the destination buffer. Note that on error @dst has 1N/A * been filled with all the mapping pairs that will fit, thus it can be treated 1N/A * as partial success, in that a new attribute extent needs to be created or the 1N/A * next extent has to be used and the mapping pairs build has to be continued 1N/A * with @start_vcn set to *@stop_vcn. 1N/A * Return 0 on success. On error, return -1 with errno set to the error code. 1N/A * The following error codes are defined: 1N/A * EINVAL - Run list contains unmapped elements. Make sure to only pass 1N/A * fully mapped runlists to this function. 1N/A * - @start_vcn is invalid. 1N/A * EIO - The runlist is corrupt. 1N/A * ENOSPC - The destination buffer is too small. 1N/A /* Terminator byte. */ 1N/A /* Skip to runlist element containing @start_vcn. */ 1N/A * @dst_max is used for bounds checking in 1N/A * ntfs_write_significant_bytes(). 1N/A /* Do the first partial run if present. */ 1N/A /* We know rl->length != 0 already. */ 1N/A * If the logical cluster number (lcn) denotes a hole and we 1N/A * are on NTFS 3.0+, we don't store it at all, i.e. we need 1N/A * zero space. On earlier NTFS versions we just write the lcn 1N/A * change. FIXME: Do we need to write the lcn change or just 1N/A * the lcn in that case? Not sure as I have never seen this 1N/A * case on NT4. - We assume that we just need to write the lcn 1N/A * change until someone tells us otherwise... (AIA) 1N/A /* Write change in lcn. */ 1N/A /* Update header byte. */ 1N/A /* Position at next mapping pairs array element. */ 1N/A /* Go to next runlist element. */ 1N/A /* Do the full runs. */ 1N/A * If the logical cluster number (lcn) denotes a hole and we 1N/A * are on NTFS 3.0+, we don't store it at all, i.e. we need 1N/A * zero space. On earlier NTFS versions we just write the lcn 1N/A * change. FIXME: Do we need to write the lcn change or just 1N/A * the lcn in that case? Not sure as I have never seen this 1N/A * case on NT4. - We assume that we just need to write the lcn 1N/A * change until someone tells us otherwise... (AIA) 1N/A /* Write change in lcn. */ 1N/A /* Update header byte. */ 1N/A /* Position at next mapping pairs array element. */ 1N/A /* Add terminator byte. */ 1N/A /* Add terminator byte. */ 1N/A * ntfs_rl_truncate - truncate a runlist starting at a specified vcn 1N/A * @arl: address of runlist to truncate 1N/A * @start_vcn: first vcn which should be cut off 1N/A * Truncate the runlist *@arl starting at vcn @start_vcn as well as the memory 1N/A * buffer holding the runlist. 1N/A * Return 0 on success and -1 on error with errno set to the error code. 1N/A * NOTE: @arl is the address of the runlist. We need the address so we can 1N/A * modify the pointer to the runlist with the new, reallocated memory buffer. 1N/A /* Find the starting vcn in the run list. */ 1N/A /* Truncate the run. */ 1N/A * If a run was partially truncated, make the following runlist 1N/A * element a terminator instead of the truncated runlist 1N/A * ntfs_rl_sparse - check whether runlist have sparse regions or not. 1N/A * @rl: runlist to check 1N/A * This function just skips not mapped regions assuming they are not sparse, 1N/A * so you need to ensure that runlist is fully mapped if you want perform full 1N/A * Return 1 if have, 0 if not, -1 on error with errno set to the error code. 1N/A * ntfs_rl_get_compressed_size - calculate length of non sparse regions 1N/A * @vol: ntfs volume (need for cluster size) 1N/A * @rl: runlist to calculate for 1N/A * Return compressed size or -1 on error with errno set to the error code. 1N/A * test_rl_dump_runlist - Runlist test: Display the contents of a runlist 1N/A int abbr = 0;
/* abbreviate long lists */ 1N/A const char *
lcn_str[
5] = {
"HOLE",
"NOTMAP",
"ENOENT",
"XXXX" };
1N/A for (i = 0; ; i++,
rl++) {
1N/A if ((i >
3) && (i < (
len -
3)))
1N/A * test_rl_runlists_merge - Runlist test: Merge two runlists 1N/A * test_rl_read_buffer - Runlist test: Read a file containing a runlist 1N/A * test_rl_pure_src - Runlist test: Complicate the simple tests a little 1N/A * test_rl_pure_test - Runlist test: Perform tests using simple runlists 1N/A * test_rl_pure - Runlist test: Create tests using simple runlists 1N/A { 0, -
1,
100 },
/* HOLE */ 1N/A {
100,
1100,
100 },
/* DATA */ 1N/A {
200, -
1,
100 },
/* HOLE */ 1N/A {
300,
1300,
100 },
/* DATA */ 1N/A {
400, -
1,
100 },
/* HOLE */ 1N/A {
500, -
3, 0 }
/* NOENT */ 1N/A { 0,
1000,
100 },
/* DATA */ 1N/A {
100, -
1,
100 },
/* HOLE */ 1N/A {
200, -
3, 0 }
/* NOENT */ 1N/A { 0,
1000,
100 },
/* DATA */ 1N/A {
100, -
3, 0 }
/* NOENT */ 1N/A { 0, -
3, 0 }
/* NOENT */ 1N/A { 0, -
2,
100 },
/* NOTMAP */ 1N/A {
100,
1100,
100 },
/* DATA */ 1N/A {
200, -
2,
100 },
/* NOTMAP */ 1N/A {
300,
1300,
100 },
/* DATA */ 1N/A {
400, -
2,
100 },
/* NOTMAP */ 1N/A {
500, -
3, 0 }
/* NOENT */ 1N/A { 0,
1000,
100 },
/* DATA */ 1N/A {
100, -
2,
100 },
/* NOTMAP */ 1N/A {
200, -
3, 0 }
/* NOENT */ 1N/A printf(
"rl pure [contig|noncontig] [single|multi]\n");
1N/A printf(
"rl pure [contig|noncontig] [single|multi]\n");
1N/A * test_rl_zero - Runlist test: Merge a zero-length runlist 1N/A * test_rl_frag_combine - Runlist test: Perform tests using fragmented files 1N/A * test_rl_frag - Runlist test: Create tests using very fragmented files 1N/A * test_rl_main - Runlist test: Program start (main)