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 */