From 2dc7362ba945c743e0d880ef3a0e5ad37ba62bb5 Mon Sep 17 00:00:00 2001 From: jpandre Date: Tue, 3 Feb 2009 17:12:04 +0000 Subject: [PATCH] Improved computation of runlist for fragmented files O(n) instead of O(n*n) --- include/ntfs-3g/runlist.h | 4 ++-- libntfs-3g/attrib.c | 38 +++++++++++++++++++++++++------------ libntfs-3g/mft.c | 4 ++-- libntfs-3g/runlist.c | 40 +++++++++++++++++++-------------------- 4 files changed, 50 insertions(+), 36 deletions(-) diff --git a/include/ntfs-3g/runlist.h b/include/ntfs-3g/runlist.h index 11950e19..16a78ffa 100644 --- a/include/ntfs-3g/runlist.h +++ b/include/ntfs-3g/runlist.h @@ -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); diff --git a/libntfs-3g/attrib.c b/libntfs-3g/attrib.c index 9fa2df56..ce664fd0 100644 --- a/libntfs-3g/attrib.c +++ b/libntfs-3g/attrib.c @@ -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"); diff --git a/libntfs-3g/mft.c b/libntfs-3g/mft.c index d638cc51..bd3a15c2 100644 --- a/libntfs-3g/mft.c +++ b/libntfs-3g/mft.c @@ -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"); diff --git a/libntfs-3g/runlist.c b/libntfs-3g/runlist.c index 6418c143..ee48d833 100644 --- a/libntfs-3g/runlist.c +++ b/libntfs-3g/runlist.c @@ -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: