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

Reply via email to