Add start_vcn parameter to ntfs_get_size_for_mapping_pairs() and

ntfs_mapping_pairs_build() and adapt all callers.

(Logical change 1.533)
edge.strict_endians
cantab.net!aia21 2004-09-06 09:27:16 +00:00
parent 3dc22bbae1
commit 06086ae5c7
6 changed files with 152 additions and 45 deletions

View File

@ -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);

View File

@ -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 "

View File

@ -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;

View File

@ -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.

View File

@ -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);

View File

@ -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);