From da742f48daed3f95f59a32f6f251a14f6c7d5255 Mon Sep 17 00:00:00 2001 From: "cantab.net!aia21" Date: Tue, 11 May 2004 09:21:24 +0000 Subject: [PATCH] =?UTF-8?q?-=20Fix=20a=20bug=20where=20we=20would=20not=20?= =?UTF-8?q?always=20detect=20that=20we=20have=20reached=20the=20=20=20end?= =?UTF-8?q?=20of=20a=20compression=20block=20because=20we=20were=20ending?= =?UTF-8?q?=20at=20minus=20one=20byte=20=20=20which=20is=20effectively=20t?= =?UTF-8?q?he=20same=20as=20being=20at=20the=20end.=20=20The=20fix=20is=20?= =?UTF-8?q?to=20=20=20check=20whether=20the=20uncompressed=20buffer=20has?= =?UTF-8?q?=20been=20fully=20filled=20and=20if=20so=20=20=20we=20assume=20?= =?UTF-8?q?we=20have=20reached=20the=20end=20of=20the=20compression=20bloc?= =?UTF-8?q?k.=20=20A=20big=20=20=20thank=20you=20to=20Marcin=20Gibu=C5=82a?= =?UTF-8?q?=20for=20the=20bug=20report,=20the=20assistance=20in=20=20=20tr?= =?UTF-8?q?acking=20down=20the=20bug=20and=20testing=20the=20fix.=20-=20Fi?= =?UTF-8?q?x=20a=20bug=20where=20we=20forgot=20to=20reset=20the=20data=5Fs?= =?UTF-8?q?ize=20and=20initialized=5Fsize=20=20=20in=20two=20error=20code?= =?UTF-8?q?=20paths.=20-=20Fix=20a=20bug=20where=20an=20uncompressed=20blo?= =?UTF-8?q?ck=20could=20be=20misdetected=20as=20a=20=20=20compressed=20one?= =?UTF-8?q?=20if=20it=20was=20made=20up=20of=20multiple=20runs.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (Logical change 1.390) --- libntfs/compress.c | 76 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 66 insertions(+), 10 deletions(-) diff --git a/libntfs/compress.c b/libntfs/compress.c index ed9698bc..e0f101a4 100644 --- a/libntfs/compress.c +++ b/libntfs/compress.c @@ -1,5 +1,5 @@ /* - * compress.c - Compressed attribute handling code. Part of the Linux-NTFS + * compress.c - Compressed attribute handling code. Part of the Linux-NTFS * project. * * Copyright (c) 2004 Anton Altaparmakov @@ -88,8 +88,13 @@ static int ntfs_decompress(u8 *dest, const u32 dest_size, do_next_sb: Dprintf("Beginning sub-block at offset = 0x%x in the cb.\n", cb - cb_start); - /* Have we reached the end of the compression block? */ - if (cb == cb_end || !le16_to_cpup((u16*)cb)) { + /* + * Have we reached the end of the compression block or the end of the + * decompressed data? The latter can happen for example if the current + * position in the compression block is one byte before its end so the + * first two checks do not detect it. + */ + if (cb == cb_end || !le16_to_cpup((u16*)cb) || dest == dest_end) { Dprintf("Completed. Returning success (0).\n"); return 0; } @@ -166,7 +171,7 @@ do_next_tag: /* Continue with the next token. */ continue; } - /* + /* * We have a phrase token. Make sure it is not the first tag in * the sb as this is illegal and would confuse the code below. */ @@ -229,6 +234,53 @@ return_overflow: return -1; } +/** + * ntfs_is_cb_compressed - internal function, do not use + * + * This is a very specialised function determining if a cb is compressed or + * uncompressed. It is assumed that checking for a sparse cb has already been + * performed and that the cb is not sparse. It makes all sorts of other + * assumptions as well and hence it is not useful anywhere other than where it + * is used at the moment. Please, do not make this function available for use + * outside of compress.c as it is bound to confuse people and not do what they + * want. + * + * Return TRUE on errors so that the error will be detected later on in the + * code. Might be a bit confusing to debug but there really should never be + * errors coming from here. + */ +static __inline__ BOOL ntfs_is_cb_compressed(ntfs_attr *na, + runlist_element *rl, VCN cb_start_vcn, int cb_clusters) +{ + /* + * The simplest case: the run starting at @cb_start_vcn contains + * @cb_clusters clusters which are all not sparse, thus the cb is not + * compressed. + */ + if (rl->length - (cb_start_vcn - rl->vcn) >= cb_clusters) + return FALSE; + cb_clusters -= rl->length - (cb_start_vcn - rl->vcn); + do { + /* Go to the next run. */ + rl++; + /* Map the next runlist fragment if it is not mapped. */ + if (rl->lcn < LCN_HOLE || !rl->length) { + rl = ntfs_attr_find_vcn(na, rl->vcn); + if (!rl || rl->lcn < LCN_HOLE || !rl->length) + return TRUE; + } + /* If the current run is sparse, the cb is compressed. */ + if (rl->lcn == LCN_HOLE) + return TRUE; + /* If the whole cb is not sparse, it is not compressed. */ + if (rl->length >= cb_clusters) + return FALSE; + cb_clusters -= rl->length; + } while (cb_clusters > 0); + /* All cb_clusters were not sparse thus the cb is not compressed. */ + return FALSE; +} + /** * ntfs_compressed_attr_pread - read from a compressed attribute * @na: ntfs attribute to read from @@ -361,7 +413,7 @@ do_next_cb: total += to_read; count -= to_read; b = (u8*)b + to_read; - } else if (rl->length - (vcn - rl->vcn) >= cb_clusters) { + } else if (!ntfs_is_cb_compressed(na, rl, vcn, cb_clusters)) { s64 tdata_size, tinitialized_size; /* * Uncompressed cb, read it straight into the destination range @@ -372,8 +424,8 @@ do_next_cb: * Read the uncompressed data into the destination buffer. * NOTE: We cheat a little bit here by marking the attribute as * not compressed in the ntfs_attr structure so that we can - * read the data by simply using ntfs_attr_pread(). (-8 Note, - * Note, we have to modify data_size and initialized_size + * read the data by simply using ntfs_attr_pread(). (-8 + * NOTE: we have to modify data_size and initialized_size * temporarily as well... */ to_read = min(count, cb_size - ofs); @@ -386,6 +438,8 @@ do_next_cb: br = ntfs_attr_pread(na, ofs, to_read, b); if (br < 0) { err = errno; + na->data_size = tdata_size; + na->initialized_size = tinitialized_size; NAttrSetCompressed(na); free(cb); free(dest); @@ -417,8 +471,9 @@ do_next_cb: * NOTE: We cheat a little bit here by marking the attribute as * not compressed in the ntfs_attr structure so that we can * read the raw, compressed data by simply using - * ntfs_attr_pread(). (-8 Note, we have to modify data_size - * and initialized_size temporarily as well... + * ntfs_attr_pread(). (-8 + * NOTE: We have to modify data_size and initialized_size + * temporarily as well... */ to_read = cb_size; NAttrClearCompressed(na); @@ -431,6 +486,8 @@ do_next_cb: (cb_pos - cb), to_read, cb_pos); if (br < 0) { err = errno; + na->data_size = tdata_size; + na->initialized_size = tinitialized_size; NAttrSetCompressed(na); free(cb); free(dest); @@ -474,4 +531,3 @@ do_next_cb: /* Return number of bytes read. */ return total + total2; } -