From 06086ae5c7602331d6f0a6a94b1887d7689f8e50 Mon Sep 17 00:00:00 2001 From: "cantab.net!aia21" Date: Mon, 6 Sep 2004 09:27:16 +0000 Subject: [PATCH] Add start_vcn parameter to ntfs_get_size_for_mapping_pairs() and ntfs_mapping_pairs_build() and adapt all callers. (Logical change 1.533) --- include/ntfs/runlist.h | 5 +- libntfs/attrib.c | 12 +-- libntfs/runlist.c | 161 ++++++++++++++++++++++++++++++++++------- ntfsprogs/mkntfs.c | 8 +- ntfsprogs/ntfsmove.c | 7 +- ntfsprogs/ntfsresize.c | 4 +- 6 files changed, 152 insertions(+), 45 deletions(-) diff --git a/include/ntfs/runlist.h b/include/ntfs/runlist.h index b22b46dc..e79a1106 100644 --- a/include/ntfs/runlist.h +++ b/include/ntfs/runlist.h @@ -65,13 +65,14 @@ extern runlist_element *ntfs_mapping_pairs_decompress(const ntfs_volume *vol, extern int ntfs_get_nr_significant_bytes(const s64 n); extern int ntfs_get_size_for_mapping_pairs(const ntfs_volume *vol, - const runlist_element *rl); + const runlist_element *rl, const VCN start_vcn); extern int ntfs_write_significant_bytes(s8 *dst, const s8 *dst_max, const s64 n); extern int ntfs_mapping_pairs_build(const ntfs_volume *vol, s8 *dst, - const int dst_len, const runlist_element *rl); + const int dst_len, const runlist_element *rl, + const VCN start_vcn); extern int ntfs_rl_truncate(runlist **rl, const VCN start_vcn); diff --git a/libntfs/attrib.c b/libntfs/attrib.c index 4f0ddffe..fcb172b4 100644 --- a/libntfs/attrib.c +++ b/libntfs/attrib.c @@ -2440,7 +2440,7 @@ static int ntfs_attr_make_non_resident(ntfs_attr *na, } } /* Determine the size of the mapping pairs array. */ - mp_size = ntfs_get_size_for_mapping_pairs(vol, rl); + mp_size = ntfs_get_size_for_mapping_pairs(vol, rl, 0); if (mp_size < 0) { err = errno; // FIXME: Eeek! @@ -2513,7 +2513,7 @@ static int ntfs_attr_make_non_resident(ntfs_attr *na, /* Generate the mapping pairs array in the attribute record. */ if (ntfs_mapping_pairs_build(vol, (u8*)a + mp_ofs, arec_size - mp_ofs, - rl) < 0) { + rl, 0) < 0) { err = errno; // FIXME: Eeek! We need rollback! (AIA) Dprintf("%s(): Eeek! Failed to build mapping pairs. Leaving " @@ -3018,7 +3018,7 @@ static int ntfs_non_resident_attr_shrink(ntfs_attr *na, const s64 newsize) if (a->highest_vcn) a->highest_vcn = scpu_to_le64(first_free_vcn - 1); /* Get the size for the new mapping pairs array. */ - mp_size = ntfs_get_size_for_mapping_pairs(vol, na->rl); + mp_size = ntfs_get_size_for_mapping_pairs(vol, na->rl, 0); if (mp_size <= 0) { err = errno; // FIXME: Eeek! We need rollback! (AIA) @@ -3032,7 +3032,7 @@ static int ntfs_non_resident_attr_shrink(ntfs_attr *na, const s64 newsize) * correct destination, i.e. the attribute record itself. */ if (ntfs_mapping_pairs_build(vol, (u8*)a + le16_to_cpu( - a->mapping_pairs_offset), mp_size, na->rl)) { + a->mapping_pairs_offset), mp_size, na->rl, 0)) { err = errno; // FIXME: Eeek! We need rollback! (AIA) Dprintf("%s(): Eeek! Mapping pairs build " @@ -3270,7 +3270,7 @@ static int ntfs_non_resident_attr_expand(ntfs_attr *na, const s64 newsize) na->rl = rln; /* Get the size for the new mapping pairs array. */ - mp_size = ntfs_get_size_for_mapping_pairs(vol, na->rl); + mp_size = ntfs_get_size_for_mapping_pairs(vol, na->rl, 0); if (mp_size <= 0) { err = errno; Dprintf("%s(): Eeek! Get size for mapping " @@ -3344,7 +3344,7 @@ static int ntfs_non_resident_attr_expand(ntfs_attr *na, const s64 newsize) * correct destination, i.e. the attribute record itself. */ if (ntfs_mapping_pairs_build(vol, (u8*)a + le16_to_cpu( - a->mapping_pairs_offset), mp_size, na->rl)) { + a->mapping_pairs_offset), mp_size, na->rl, 0)) { err = errno; Dprintf("%s(): BUG! Mapping pairs build " "failed. Please run chkdsk and if " diff --git a/libntfs/runlist.c b/libntfs/runlist.c index 16a5d253..b2c7e8ac 100644 --- a/libntfs/runlist.c +++ b/libntfs/runlist.c @@ -1238,10 +1238,12 @@ __inline__ int ntfs_get_nr_significant_bytes(const s64 n) * ntfs_get_size_for_mapping_pairs - get bytes needed for mapping pairs array * @vol: ntfs volume (needed for the ntfs version) * @rl: runlist for which to determine the size of the mapping pairs + * @start_vcn: vcn at which to start the mapping pairs array * * Walk the runlist @rl and calculate the size in bytes of the mapping pairs - * array corresponding to the runlist @rl. This for example allows us to - * allocate a buffer of the right size when building the mapping pairs array. + * array corresponding to the runlist @rl, starting at vcn @start_vcn. This + * for example allows us to allocate a buffer of the right size when building + * the mapping pairs array. * * If @rl is NULL, just return 1 (for the single terminator byte). * @@ -1249,41 +1251,86 @@ __inline__ int ntfs_get_nr_significant_bytes(const s64 n) * 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. */ int ntfs_get_size_for_mapping_pairs(const ntfs_volume *vol, - const runlist_element *rl) + const runlist_element *rl, const VCN start_vcn) { LCN prev_lcn; - int i, rls; + int rls; - if (!rl) + if (start_vcn < 0) { + errno = EINVAL; + return -1; + } + if (!rl) { + if (start_vcn) { + errno = EINVAL; + return -1; + } return 1; + } + /* 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 termining zero byte. */ rls = 1; - for (prev_lcn = i = 0; rl[i].length; i++) { - if (rl[i].length < 0 || rl[i].lcn < LCN_HOLE) + /* 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[i].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[i].lcn == LCN_HOLE && vol->major_ver >= 3) - continue; + 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); /* - * Change in 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 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). */ - rls += ntfs_get_nr_significant_bytes(rl[i].lcn - prev_lcn); - prev_lcn = rl[i].lcn; + 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[i].lcn == LCN_RL_NOT_MAPPED) + if (rl->lcn == LCN_RL_NOT_MAPPED) errno = EINVAL; else errno = EIO; @@ -1348,10 +1395,12 @@ err_out: * @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 * - * Create the mapping pairs array from the runlist @rl 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(). + * 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. * @@ -1359,35 +1408,87 @@ err_out: * 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, s8 *dst, - const int dst_len, const runlist_element *rl) + const int dst_len, const runlist_element *rl, + const VCN start_vcn) { LCN prev_lcn; s8 *dst_max; - int i; s8 len_len, lcn_len; + if (start_vcn < 0) + goto val_err; if (!rl) { + if (start_vcn) + goto val_err; if (dst_len < 1) goto size_err; /* 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; - for (prev_lcn = i = 0; rl[i].length; i++) { - if (rl[i].length < 0 || rl[i].lcn < LCN_HOLE) + 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; + /* Update header byte. */ + *dst = lcn_len << 4 | len_len; + /* Position ourselves at next mapping pairs array element. */ + dst += 1 + len_len + lcn_len; + /* 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[i].length); + rl->length); if (len_len < 0) goto size_err; /* @@ -1399,12 +1500,13 @@ int ntfs_mapping_pairs_build(const ntfs_volume *vol, s8 *dst, * case on NT4. - We assume that we just need to write the lcn * change until someone tells us otherwise... (AIA) */ - if (rl[i].lcn != LCN_HOLE || vol->major_ver < 3) { + 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[i].lcn - prev_lcn); + len_len, dst_max, rl->lcn - prev_lcn); if (lcn_len < 0) goto size_err; - prev_lcn = rl[i].lcn; + prev_lcn = rl->lcn; } else lcn_len = 0; /* Update header byte. */ @@ -1420,8 +1522,11 @@ int ntfs_mapping_pairs_build(const ntfs_volume *vol, s8 *dst, size_err: errno = ENOSPC; return -1; +val_err: + errno = EINVAL; + return -1; err_out: - if (rl[i].lcn == LCN_RL_NOT_MAPPED) + if (rl->lcn == LCN_RL_NOT_MAPPED) errno = EINVAL; else errno = EIO; diff --git a/ntfsprogs/mkntfs.c b/ntfsprogs/mkntfs.c index 48ae7d2d..b2e3a23e 100644 --- a/ntfsprogs/mkntfs.c +++ b/ntfsprogs/mkntfs.c @@ -1235,7 +1235,7 @@ static int insert_positioned_attr_in_mft_record(MFT_RECORD *m, } else { hdr_size = 64; if (val_len) { - mpa_size = ntfs_get_size_for_mapping_pairs(vol, rl); + mpa_size = ntfs_get_size_for_mapping_pairs(vol, rl, 0); if (mpa_size < 0) { err = -errno; Eprintf("Failed to get size for mapping " @@ -1322,7 +1322,7 @@ static int insert_positioned_attr_in_mft_record(MFT_RECORD *m, Eprintf("Error writing non-resident attribute value." "\n"); err = ntfs_mapping_pairs_build(vol, (s8*)a + hdr_size + - ((name_len + 7) & ~7), mpa_size, rl); + ((name_len + 7) & ~7), mpa_size, rl, 0); } a->initialized_size = cpu_to_le64(inited_size); if (err < 0 || bw != val_len) { @@ -1431,7 +1431,7 @@ static int insert_non_resident_attr_in_mft_record(MFT_RECORD *m, } else { hdr_size = 64; if (val_len) { - mpa_size = ntfs_get_size_for_mapping_pairs(vol, rl); + mpa_size = ntfs_get_size_for_mapping_pairs(vol, rl, 0); if (mpa_size < 0) { err = -errno; Eprintf("Failed to get size for mapping " @@ -1512,7 +1512,7 @@ static int insert_non_resident_attr_in_mft_record(MFT_RECORD *m, Eprintf("Error writing non-resident attribute value." "\n"); err = ntfs_mapping_pairs_build(vol, (s8*)a + hdr_size + - ((name_len + 7) & ~7), mpa_size, rl); + ((name_len + 7) & ~7), mpa_size, rl, 0); } if (err < 0 || bw != val_len) { // FIXME: Handle error. diff --git a/ntfsprogs/ntfsmove.c b/ntfsprogs/ntfsmove.c index b969245a..d805a94f 100644 --- a/ntfsprogs/ntfsmove.c +++ b/ntfsprogs/ntfsmove.c @@ -669,7 +669,7 @@ static s64 move_datarun (ntfs_volume *vol, ntfs_inode *ino, ATTR_RECORD *rec, printf ("move %lld,%lld,%lld to %lld,%lld,%lld\n", run->vcn, run->lcn, run->length, to->vcn, to->lcn, to->length); - need_from = ntfs_get_size_for_mapping_pairs (vol, from); + need_from = ntfs_get_size_for_mapping_pairs(vol, from, 0); printf ("orig data run = %d bytes\n", need_from); //ntfs_debug_runlist_dump2 (from, 5, "\t"); @@ -683,7 +683,7 @@ static s64 move_datarun (ntfs_volume *vol, ntfs_inode *ino, ATTR_RECORD *rec, //ntfs_debug_runlist_dump2 (from, 5, "\t"); - need_to = ntfs_get_size_for_mapping_pairs (vol, from); + need_to = ntfs_get_size_for_mapping_pairs(vol, from, 0); printf ("new data run = %d bytes\n", need_to); need_from = calc_attr_length (rec, need_from); @@ -708,7 +708,8 @@ static s64 move_datarun (ntfs_volume *vol, ntfs_inode *ino, ATTR_RECORD *rec, memset (((u8*)rec) +rec->mapping_pairs_offset, 0, need_to - rec->mapping_pairs_offset); // update data runs - ntfs_mapping_pairs_build (vol, ((u8*)rec) + rec->mapping_pairs_offset, need_to, from); + ntfs_mapping_pairs_build(vol, ((u8*)rec) + rec->mapping_pairs_offset, + need_to, from, 0); // commit ntfs_inode_mark_dirty (ino); diff --git a/ntfsprogs/ntfsresize.c b/ntfsprogs/ntfsresize.c index 2b580e7f..0de41876 100644 --- a/ntfsprogs/ntfsresize.c +++ b/ntfsprogs/ntfsresize.c @@ -1097,7 +1097,7 @@ static void replace_attribute_runlist(ntfs_volume *vol, rl_fixup(&rl); - if ((mp_size = ntfs_get_size_for_mapping_pairs(vol, rl)) == -1) + if ((mp_size = ntfs_get_size_for_mapping_pairs(vol, rl, 0)) == -1) perr_exit("ntfs_get_size_for_mapping_pairs"); if (a->name_length) { @@ -1157,7 +1157,7 @@ static void replace_attribute_runlist(ntfs_volume *vol, if (!(mp = calloc(1, mp_size))) perr_exit("Couldn't get memory"); - if (ntfs_mapping_pairs_build(vol, mp, mp_size, rl)) + if (ntfs_mapping_pairs_build(vol, mp, mp_size, rl, 0)) perr_exit("ntfs_mapping_pairs_build"); memmove((u8*)a + le16_to_cpu(a->mapping_pairs_offset), mp, mp_size);