Improved computation of runlist for fragmented files O(n) instead of O(n*n)

N2009_11_14_FIXES
jpandre 2009-02-03 17:12:04 +00:00
parent 42968369c4
commit 2dc7362ba9
4 changed files with 50 additions and 36 deletions

View File

@ -65,14 +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 VCN start_vcn);
const runlist_element *rl, const VCN start_vcn, int max_size);
extern int ntfs_write_significant_bytes(u8 *dst, const u8 *dst_max,
const s64 n);
extern 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);
const VCN start_vcn, runlist_element const **stop_rl);
extern int ntfs_rl_truncate(runlist **arl, const VCN start_vcn);

View File

@ -5,7 +5,7 @@
* Copyright (c) 2002-2005 Richard Russon
* Copyright (c) 2002-2008 Szabolcs Szakacsits
* Copyright (c) 2004-2007 Yura Pakhuchiy
* Copyright (c) 2007-2008 Jean-Pierre Andre
* Copyright (c) 2007-2009 Jean-Pierre Andre
*
* This program/include file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published
@ -3690,7 +3690,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, 0);
mp_size = ntfs_get_size_for_mapping_pairs(vol, rl, 0, INT_MAX);
if (mp_size < 0) {
err = errno;
ntfs_log_debug("Eeek! Failed to get size for mapping pairs array. "
@ -4278,6 +4278,7 @@ static int ntfs_attr_update_mapping_pairs_i(ntfs_attr *na, VCN from_vcn)
MFT_RECORD *m;
ATTR_RECORD *a;
VCN stop_vcn;
const runlist_element *stop_rl;
int err, mp_size, cur_max_mp_size, exp_max_mp_size, ret = -1;
BOOL finished_build;
retry:
@ -4307,6 +4308,7 @@ retry:
/* Fill attribute records with new mapping pairs. */
stop_vcn = 0;
stop_rl = na->rl;
finished_build = FALSE;
while (!ntfs_attr_lookup(na->type, na->name, na->name_len,
CASE_SENSITIVE, from_vcn, NULL, 0, ctx)) {
@ -4360,13 +4362,6 @@ retry:
case -3: goto put_err_out;
}
/* Get the size for the rest of mapping pairs array. */
mp_size = ntfs_get_size_for_mapping_pairs(na->ni->vol, na->rl,
stop_vcn);
if (mp_size <= 0) {
ntfs_log_perror("%s: get MP size failed", __FUNCTION__);
goto put_err_out;
}
/*
* Determine maximum possible length of mapping pairs,
* if we shall *not* expand space for mapping pairs.
@ -4380,6 +4375,17 @@ retry:
*/
exp_max_mp_size = le32_to_cpu(m->bytes_allocated) -
le32_to_cpu(m->bytes_in_use) + cur_max_mp_size;
/* Get the size for the rest of mapping pairs array. */
/* old code equivalent
mp_size = ntfs_get_size_for_mapping_pairs(na->ni->vol, na->rl,
stop_vcn, INT_MAX);
*/
mp_size = ntfs_get_size_for_mapping_pairs(na->ni->vol, stop_rl,
stop_vcn, exp_max_mp_size);
if (mp_size <= 0) {
ntfs_log_perror("%s: get MP size failed", __FUNCTION__);
goto put_err_out;
}
/* Test mapping pairs for fitting in the current mft record. */
if (mp_size > exp_max_mp_size) {
/*
@ -4444,8 +4450,12 @@ retry:
*/
if (!ntfs_mapping_pairs_build(na->ni->vol, (u8*)a + le16_to_cpu(
a->mapping_pairs_offset), mp_size, na->rl,
stop_vcn, &stop_vcn))
stop_vcn, &stop_rl))
finished_build = TRUE;
if (stop_rl)
stop_vcn = stop_rl->vcn;
else
stop_vcn = 0;
if (!finished_build && errno != ENOSPC) {
ntfs_log_perror("Failed to build mapping pairs");
goto put_err_out;
@ -4489,7 +4499,7 @@ retry:
while (1) {
/* Calculate size of rest mapping pairs. */
mp_size = ntfs_get_size_for_mapping_pairs(na->ni->vol,
na->rl, stop_vcn);
na->rl, stop_vcn, INT_MAX);
if (mp_size <= 0) {
ntfs_log_perror("%s: get mp size failed", __FUNCTION__);
goto put_err_out;
@ -4528,7 +4538,11 @@ retry:
err = ntfs_mapping_pairs_build(na->ni->vol, (u8*)a +
le16_to_cpu(a->mapping_pairs_offset), mp_size, na->rl,
stop_vcn, &stop_vcn);
stop_vcn, &stop_rl);
if (stop_rl)
stop_vcn = stop_rl->vcn;
else
stop_vcn = 0;
if (err < 0 && errno != ENOSPC) {
err = errno;
ntfs_log_perror("Failed to build MP");

View File

@ -721,7 +721,7 @@ static int ntfs_mft_bitmap_extend_allocation_i(ntfs_volume *vol)
goto undo_alloc;
}
/* Get the size for the new mapping pairs array for this extent. */
mp_size = ntfs_get_size_for_mapping_pairs(vol, rl2, ll);
mp_size = ntfs_get_size_for_mapping_pairs(vol, rl2, ll, INT_MAX);
if (mp_size <= 0) {
ntfs_log_error("Get size for mapping pairs failed for "
"mft bitmap attribute extent.\n");
@ -1070,7 +1070,7 @@ static int ntfs_mft_data_extend_allocation(ntfs_volume *vol)
goto undo_alloc;
}
/* Get the size for the new mapping pairs array for this extent. */
mp_size = ntfs_get_size_for_mapping_pairs(vol, rl2, ll);
mp_size = ntfs_get_size_for_mapping_pairs(vol, rl2, ll, INT_MAX);
if (mp_size <= 0) {
ntfs_log_error("Get size for mapping pairs failed for "
"mft data attribute extent.\n");

View File

@ -5,6 +5,7 @@
* Copyright (c) 2002-2005 Richard Russon
* Copyright (c) 2002-2008 Szabolcs Szakacsits
* Copyright (c) 2004 Yura Pakhuchiy
* Copyright (c) 2007-2009 Jean-Pierre Andre
*
* This program/include file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published
@ -1219,19 +1220,18 @@ errno_set:
*/
int ntfs_get_nr_significant_bytes(const s64 n)
{
s64 l = n;
u64 l;
int i;
s8 j;
i = 0;
do {
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) || (n > 0LL && j < 0))
i++;
l = (n < 0 ? ~n : n);
i = 1;
if (l >= 128) {
l >>= 7;
do {
i++;
l >>= 8;
} while (l);
}
return i;
}
@ -1256,7 +1256,7 @@ int ntfs_get_nr_significant_bytes(const s64 n)
* EIO - The runlist is corrupt.
*/
int ntfs_get_size_for_mapping_pairs(const ntfs_volume *vol,
const runlist_element *rl, const VCN start_vcn)
const runlist_element *rl, const VCN start_vcn, int max_size)
{
LCN prev_lcn;
int rls;
@ -1315,7 +1315,7 @@ int ntfs_get_size_for_mapping_pairs(const ntfs_volume *vol,
rl++;
}
/* Do the full runs. */
for (; rl->length; rl++) {
for (; rl->length && (rls < max_size); rl++) {
if (rl->length < 0 || rl->lcn < LCN_HOLE)
goto err_out;
/* Header byte + length. */
@ -1430,7 +1430,7 @@ err_out:
*/
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)
const VCN start_vcn, runlist_element const **stop_rl)
{
LCN prev_lcn;
u8 *dst_max, *dst_next;
@ -1442,8 +1442,8 @@ int ntfs_mapping_pairs_build(const ntfs_volume *vol, u8 *dst,
if (!rl) {
if (start_vcn)
goto val_err;
if (stop_vcn)
*stop_vcn = 0;
if (stop_rl)
*stop_rl = rl;
if (dst_len < 1)
goto nospc_err;
goto ok;
@ -1538,8 +1538,8 @@ int ntfs_mapping_pairs_build(const ntfs_volume *vol, u8 *dst,
dst += 1 + len_len + lcn_len;
}
/* Set stop vcn. */
if (stop_vcn)
*stop_vcn = rl->vcn;
if (stop_rl)
*stop_rl = rl;
ok:
/* Add terminator byte. */
*dst = 0;
@ -1547,8 +1547,8 @@ out:
return ret;
size_err:
/* Set stop vcn. */
if (stop_vcn)
*stop_vcn = rl->vcn;
if (stop_rl)
*stop_rl = rl;
/* Add terminator byte. */
*dst = 0;
nospc_err: