Alan, Please apply attached ntfs patch for next 2.4.0-ac kernel release. It fixes a long standing bug where values of lengths of runs were considered unsigned when they are in fact signed numbers (both read and write). Also it makes a correction to how negative mft_recordsizes are handled. Thanks go to Yuri Per <[EMAIL PROTECTED]> for the initial patch (which required only a tiny modification). Best regards, Anton -- Anton Altaparmakov <aia21 at cam.ac.uk> (replace at with @) Linux NTFS Maintainer ICQ: 8561279 / WWW: http://www-stu.christs.cam.ac.uk/~aia21/
diff -ur linux-2.4.0-ac11-vanilla/fs/ntfs/inode.c linux/fs/ntfs/inode.c --- linux-2.4.0-ac11-vanilla/fs/ntfs/inode.c Wed Jan 24 23:23:46 2001 +++ linux/fs/ntfs/inode.c Thu Jan 25 23:42:52 2001 @@ -444,16 +444,16 @@ *ctype = 0; switch (type & 0xF) { case 1: - *length = NTFS_GETU8(*data); + *length = NTFS_GETS8(*data); break; case 2: - *length = NTFS_GETU16(*data); + *length = NTFS_GETS16(*data); break; case 3: - *length = NTFS_GETU24(*data); + *length = NTFS_GETS24(*data); break; case 4: - *length = NTFS_GETU32(*data); + *length = NTFS_GETS32(*data); break; /* Note: cases 5-8 are probably pointless to code, since how * many runs > 4GB of length are there? At the most, cases 5 @@ -463,6 +463,11 @@ ntfs_error("Can't decode run type field %x\n", type); return -1; } + if (*length < 0) + { + ntfs_error("Negative run length decoded\n"); + return -1; + } *data += (type & 0xF); switch (type & 0xF0) { case 0: @@ -704,13 +709,14 @@ if (offset + 8 > size) return -E2BIG; /* It might still fit, but this * simplifies testing. */ - if (len < 0x100) { + /* Run length is stored as signed number. */ + if (len <= 0x7F) { NTFS_PUTU8(rec + offset + 1, len); coffs = 1; - } else if (len < 0x10000) { + } else if (len < 0x7FFF) { NTFS_PUTU16(rec + offset + 1, len); coffs = 2; - } else if (len < 0x1000000) { + } else if (len < 0x7FFFFF) { NTFS_PUTU24(rec + offset + 1, len); coffs = 3; } else { @@ -720,21 +726,21 @@ *(rec + offset) |= coffs++; if (rl[i].cluster == MAX_CLUSTER_T) /* Compressed run. */ /* Nothing */; - else if (rclus > -0x80 && rclus < 0x7F) { + else if (rclus >= -0x80 && rclus <= 0x7F) { *(rec + offset) |= 0x10; NTFS_PUTS8(rec + offset + coffs, rclus); coffs += 1; - } else if(rclus > -0x8000 && rclus < 0x7FFF) { + } else if(rclus >= -0x8000 && rclus <= 0x7FFF) { *(rec + offset) |= 0x20; NTFS_PUTS16(rec + offset + coffs, rclus); coffs += 2; - } else if(rclus > -0x800000 && rclus < 0x7FFFFF) { + } else if(rclus >= -0x800000 && rclus <= 0x7FFFFF) { *(rec + offset) |= 0x30; NTFS_PUTS24(rec + offset + coffs, rclus); coffs += 3; } else #if 0 /* In case ntfs_cluster_t ever becomes 64bit. */ - if (rclus > -0x80000000LL && rclus < 0x7FFFFFFF) + if (rclus >= -0x80000000LL && rclus <= 0x7FFFFFFF) #endif { *(rec + offset) |= 0x40; @@ -742,16 +748,17 @@ coffs += 4; } #if 0 /* For 64-bit ntfs_cluster_t */ - else if (rclus > -0x8000000000 && rclus < 0x7FFFFFFFFF) { + else if (rclus >= -0x8000000000 && rclus <= 0x7FFFFFFFFF) { *(rec + offset) |= 0x50; NTFS_PUTS40(rec + offset + coffs, rclus); coffs += 5; - } else if (rclus > -0x800000000000 && rclus < 0x7FFFFFFFFFFF) { + } else if (rclus >= -0x800000000000 && + rclus <= 0x7FFFFFFFFFFF) { *(rec + offset) |= 0x60; NTFS_PUTS48(rec + offset + coffs, rclus); coffs += 6; - } else if (rclus > -0x80000000000000 && - rclus < 0x7FFFFFFFFFFFFF) { + } else if (rclus >= -0x80000000000000 && + rclus <= 0x7FFFFFFFFFFFFF) { *(rec + offset) |= 0x70; NTFS_PUTS56(rec + offset + coffs, rclus); coffs += 7; diff -ur linux-2.4.0-ac11-vanilla/fs/ntfs/super.c linux/fs/ntfs/super.c --- linux-2.4.0-ac11-vanilla/fs/ntfs/super.c Wed Jan 24 23:23:46 2001 +++ linux/fs/ntfs/super.c Thu Jan 25 23:52:43 2001 @@ -89,18 +89,19 @@ should be safe. */ vol->index_clusters_per_record = 1; } - /* In some cases, 0xF6 meant 1024 bytes. Other strange values have not - been observed */ - if (vol->mft_clusters_per_record < 0 && - vol->mft_clusters_per_record != -10) - ntfs_error("Unexpected data #4 in boot block\n"); - vol->clustersize = vol->blocksize << vol->clusterfactorbits; if (vol->mft_clusters_per_record > 0) vol->mft_recordsize = vol->clustersize * vol->mft_clusters_per_record; - else + else { + /* If mft_recordsize < clustersize then mft_clusters_per_record + = -log2(mft_recordsize) bytes. Mft_recordsize normaly equals + 1024 bytes, which is encoded as 0xF6. */ + if (vol->mft_clusters_per_record < -31 || + -9 < vol->mft_clusters_per_record) + ntfs_error("Unexpected data #4 in boot block\n"); vol->mft_recordsize = 1 << (-vol->mft_clusters_per_record); + } vol->index_recordsize = vol->clustersize * vol->index_clusters_per_record; /* FIXME: long long value */