📄 runlist.c
字号:
} /* Skip to runlist element containing @start_vcn. */ while (rl->length && start_vcn >= rl[1].vcn) rl++; if ((!rl->length && start_vcn > rl->vcn) || start_vcn < rl->vcn) { errno = EINVAL; return -1; } prev_lcn = 0; /* Always need the terminating zero byte. */ rls = 1; /* Do the first partial run if present. */ if (start_vcn > rl->vcn) { s64 delta; /* We know rl->length != 0 already. */ if (rl->length < 0 || rl->lcn < LCN_HOLE) goto err_out; delta = start_vcn - rl->vcn; /* Header byte + length. */ rls += 1 + ntfs_get_nr_significant_bytes(rl->length - delta); /* * If the logical cluster number (lcn) denotes a hole and we * are on NTFS 3.0+, we don't store it at all, i.e. we need * zero space. On earlier NTFS versions we just store the lcn. * Note: this assumes that on NTFS 1.2-, holes are stored with * an lcn of -1 and not a delta_lcn of -1 (unless both are -1). */ if (rl->lcn >= 0 || vol->major_ver < 3) { prev_lcn = rl->lcn; if (rl->lcn >= 0) prev_lcn += delta; /* Change in lcn. */ rls += ntfs_get_nr_significant_bytes(prev_lcn); } /* Go to next runlist element. */ rl++; } /* Do the full runs. */ for (; rl->length; rl++) { if (rl->length < 0 || rl->lcn < LCN_HOLE) goto err_out; /* Header byte + length. */ rls += 1 + ntfs_get_nr_significant_bytes(rl->length); /* * If the logical cluster number (lcn) denotes a hole and we * are on NTFS 3.0+, we don't store it at all, i.e. we need * zero space. On earlier NTFS versions we just store the lcn. * Note: this assumes that on NTFS 1.2-, holes are stored with * an lcn of -1 and not a delta_lcn of -1 (unless both are -1). */ if (rl->lcn >= 0 || vol->major_ver < 3) { /* Change in lcn. */ rls += ntfs_get_nr_significant_bytes(rl->lcn - prev_lcn); prev_lcn = rl->lcn; } } return rls;err_out: if (rl->lcn == LCN_RL_NOT_MAPPED) errno = EINVAL; else errno = EIO; return -1;}/** * ntfs_write_significant_bytes - write the significant bytes of a number * @dst: destination buffer to write to * @dst_max: pointer to last byte of destination buffer for bounds checking * @n: number whose significant bytes to write * * Store in @dst, the minimum bytes of the number @n which are required to * identify @n unambiguously as a signed number, taking care not to exceed * @dest_max, the maximum position within @dst to which we are allowed to * write. * * This is used when building the mapping pairs array of a runlist to compress * a given logical cluster number (lcn) or a specific run length to the minimum * size possible. * * Return the number of bytes written on success. On error, i.e. the * destination buffer @dst is too small, return -1 with errno set ENOSPC. */__inline__ int ntfs_write_significant_bytes(u8 *dst, const u8 *dst_max, const s64 n){ s64 l = n; int i; s8 j; i = 0; do { if (dst > dst_max) goto err_out; *dst++ = l & 0xffLL; l >>= 8; i++; } while (l != 0LL && l != -1LL); j = (n >> 8 * (i - 1)) & 0xff; /* If the sign bit is wrong, we need an extra byte. */ if (n < 0LL && j >= 0) { if (dst > dst_max) goto err_out; i++; *dst = (u8)-1; } else if (n > 0LL && j < 0) { if (dst > dst_max) goto err_out; i++; *dst = 0; } return i;err_out: errno = ENOSPC; return -1;}/** * ntfs_mapping_pairs_build - build the mapping pairs array from a runlist * @vol: ntfs volume (needed for the ntfs version) * @dst: destination buffer to which to write the mapping pairs array * @dst_len: size of destination buffer @dst in bytes * @rl: runlist for which to build the mapping pairs array * @start_vcn: vcn at which to start the mapping pairs array * @stop_vcn: first vcn outside destination buffer on success or ENOSPC error * * Create the mapping pairs array from the runlist @rl, starting at vcn * @start_vcn and save the array in @dst. @dst_len is the size of @dst in * bytes and it should be at least equal to the value obtained by calling * ntfs_get_size_for_mapping_pairs(). * * If @rl is NULL, just write a single terminator byte to @dst. * * On success or ENOSPC error, if @stop_vcn is not NULL, *@stop_vcn is set to * the first vcn outside the destination buffer. Note that on error @dst has * been filled with all the mapping pairs that will fit, thus it can be treated * as partial success, in that a new attribute extent needs to be created or the * next extent has to be used and the mapping pairs build has to be continued * with @start_vcn set to *@stop_vcn. * * Return 0 on success. On error, return -1 with errno set to the error code. * The following error codes are defined: * EINVAL - Run list contains unmapped elements. Make sure to only pass * fully mapped runlists to this function. * - @start_vcn is invalid. * EIO - The runlist is corrupt. * ENOSPC - The destination buffer is too small. */int ntfs_mapping_pairs_build(const ntfs_volume *vol, u8 *dst, const int dst_len, const runlist_element *rl, const VCN start_vcn, VCN *const stop_vcn){ LCN prev_lcn; u8 *dst_max, *dst_next; s8 len_len, lcn_len; if (start_vcn < 0) goto val_err; if (!rl) { if (start_vcn) goto val_err; if (stop_vcn) *stop_vcn = 0; if (dst_len < 1) { errno = ENOSPC; return -1; } /* Terminator byte. */ *dst = 0; return 0; } /* Skip to runlist element containing @start_vcn. */ while (rl->length && start_vcn >= rl[1].vcn) rl++; if ((!rl->length && start_vcn > rl->vcn) || start_vcn < rl->vcn) goto val_err; /* * @dst_max is used for bounds checking in * ntfs_write_significant_bytes(). */ dst_max = dst + dst_len - 1; prev_lcn = 0; /* Do the first partial run if present. */ if (start_vcn > rl->vcn) { s64 delta; /* We know rl->length != 0 already. */ if (rl->length < 0 || rl->lcn < LCN_HOLE) goto err_out; delta = start_vcn - rl->vcn; /* Write length. */ len_len = ntfs_write_significant_bytes(dst + 1, dst_max, rl->length - delta); if (len_len < 0) goto size_err; /* * If the logical cluster number (lcn) denotes a hole and we * are on NTFS 3.0+, we don't store it at all, i.e. we need * zero space. On earlier NTFS versions we just write the lcn * change. FIXME: Do we need to write the lcn change or just * the lcn in that case? Not sure as I have never seen this * case on NT4. - We assume that we just need to write the lcn * change until someone tells us otherwise... (AIA) */ if (rl->lcn >= 0 || vol->major_ver < 3) { prev_lcn = rl->lcn; if (rl->lcn >= 0) prev_lcn += delta; /* Write change in lcn. */ lcn_len = ntfs_write_significant_bytes(dst + 1 + len_len, dst_max, prev_lcn); if (lcn_len < 0) goto size_err; } else lcn_len = 0; dst_next = dst + len_len + lcn_len + 1; if (dst_next > dst_max) goto size_err; /* Update header byte. */ *dst = lcn_len << 4 | len_len; /* Position at next mapping pairs array element. */ dst = dst_next; /* Go to next runlist element. */ rl++; } /* Do the full runs. */ for (; rl->length; rl++) { if (rl->length < 0 || rl->lcn < LCN_HOLE) goto err_out; /* Write length. */ len_len = ntfs_write_significant_bytes(dst + 1, dst_max, rl->length); if (len_len < 0) goto size_err; /* * If the logical cluster number (lcn) denotes a hole and we * are on NTFS 3.0+, we don't store it at all, i.e. we need * zero space. On earlier NTFS versions we just write the lcn * change. FIXME: Do we need to write the lcn change or just * the lcn in that case? Not sure as I have never seen this * case on NT4. - We assume that we just need to write the lcn * change until someone tells us otherwise... (AIA) */ if (rl->lcn >= 0 || vol->major_ver < 3) { /* Write change in lcn. */ lcn_len = ntfs_write_significant_bytes(dst + 1 + len_len, dst_max, rl->lcn - prev_lcn); if (lcn_len < 0) goto size_err; prev_lcn = rl->lcn; } else lcn_len = 0; dst_next = dst + len_len + lcn_len + 1; if (dst_next > dst_max) goto size_err; /* Update header byte. */ *dst = lcn_len << 4 | len_len; /* Position at next mapping pairs array element. */ dst += 1 + len_len + lcn_len; } /* Set stop vcn. */ if (stop_vcn) *stop_vcn = rl->vcn; /* Add terminator byte. */ *dst = 0; return 0;size_err: /* Set stop vcn. */ if (stop_vcn) *stop_vcn = rl->vcn; /* Add terminator byte. */ *dst = 0; errno = ENOSPC; return -1;val_err: errno = EINVAL; return -1;err_out: if (rl->lcn == LCN_RL_NOT_MAPPED) errno = EINVAL; else errno = EIO; return -1;}/** * ntfs_rl_truncate - truncate a runlist starting at a specified vcn * @arl: address of runlist to truncate * @start_vcn: first vcn which should be cut off * * Truncate the runlist *@arl starting at vcn @start_vcn as well as the memory * buffer holding the runlist. * * Return 0 on success and -1 on error with errno set to the error code. * * NOTE: @arl is the address of the runlist. We need the address so we can * modify the pointer to the runlist with the new, reallocated memory buffer. */int ntfs_rl_truncate(runlist **arl, const VCN start_vcn){ runlist *rl; BOOL is_end; if (!arl || !*arl) { errno = EINVAL; return -1; } rl = *arl; if (start_vcn < rl->vcn) { // FIXME: Eeek! BUG() ntfs_log_trace("Eeek! start_vcn lies outside front of runlist! " "Aborting.\n"); errno = EIO; return -1; } /* Find the starting vcn in the run list. */ while (rl->length) { if (start_vcn < rl[1].vcn) break; rl++; } if (!rl->length) { // FIXME: Weird, probably a BUG()! ntfs_log_trace("Weird! Asking to truncate already truncated " "runlist?!? Abort.\n"); errno = EIO; return -1; } if (start_vcn < rl->vcn) { // FIXME: Eeek! BUG() ntfs_log_trace("Eeek! start_vcn < rl->vcn! Aborting.\n"); errno = EIO; return -1; } if (rl->length) { is_end = FALSE; /* Truncate the run. */ rl->length = start_vcn - rl->vcn; /* * If a run was partially truncated, make the following runlist * element a terminator instead of the truncated runlist * element itself. */ if (rl->length) { ++rl; if (!rl->length) is_end = TRUE; rl->vcn = start_vcn; rl->length = 0; } } else is_end = TRUE; rl->lcn = (LCN)LCN_ENOENT; /* Reallocate memory if necessary. */ if (!is_end) { size_t new_size = (rl - *arl + 1) * sizeof(runlist_element); rl = realloc(*arl, new_size); if (rl) *arl = rl; else if (!new_size) *arl = NULL; else { // FIXME: Eeek! ntfs_log_trace("Eeek! Failed to reallocate runlist buffer! " "Continuing regardless and returning success.\n"); } } /* Done! */ return 0;}/** * ntfs_rl_sparse - check whether runlist have sparse regions or not. * @rl: runlist to check * * Return 1 if have, 0 if not, -1 on error with errno set to the error code. */int ntfs_rl_sparse(runlist *rl){ runlist *rlc; if (!rl) { ntfs_log_trace("Invalid argument passed.\n"); errno = EINVAL; return -1; } for (rlc = rl; rlc->length; rlc++) if (rlc->lcn < 0) { if (rlc->lcn != LCN_HOLE) { ntfs_log_trace("Received unmapped runlist.\n"); errno = EINVAL; return -1; } return 1; } return 0;}/** * ntfs_rl_get_compressed_size - calculate length of non sparse regions * @vol: ntfs volume (need for cluster size) * @rl: runlist to calculate for * * Return compressed size or -1 on error with errno set to the error code. */s64 ntfs_rl_get_compressed_size(ntfs_volume *vol, runlist *rl){ runlist *rlc; s64 ret = 0; if (!rl) { ntfs_log_trace("Invalid argument passed.\n"); errno = EINVAL; return -1; } for (rlc = rl; rlc->length; rlc++) { if (rlc->lcn < 0) { if (rlc->lcn != LCN_HOLE) { ntfs_log_trace("Received unmapped runlist.\n"); errno = EINVAL; return -1; } } else
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -