- Fix comparison of $MFT and $MFTMirr to not bail out when there are
          unused, invalid mft records which are the same in both $MFT and
          $MFTMirr.
+       - Add support for sparse files which have a compression unit of 0.
 
 2.1.26 - Minor bug fixes and updates.
 
 
                        a->data.non_resident.initialized_size =
                        cpu_to_sle64(attr_size);
        if (NInoSparse(ni) || NInoCompressed(ni)) {
-               a->data.non_resident.compression_unit = 4;
+               a->data.non_resident.compression_unit = 0;
+               if (NInoCompressed(ni) || vol->major_ver < 3)
+                       a->data.non_resident.compression_unit = 4;
                a->data.non_resident.compressed_size =
                                a->data.non_resident.allocated_size;
        } else
        ni->allocated_size = new_size;
        if (NInoSparse(ni) || NInoCompressed(ni)) {
                ni->itype.compressed.size = ni->allocated_size;
-               ni->itype.compressed.block_size = 1U <<
-                               (a->data.non_resident.compression_unit +
-                               vol->cluster_size_bits);
-               ni->itype.compressed.block_size_bits =
-                               ffs(ni->itype.compressed.block_size) - 1;
-               ni->itype.compressed.block_clusters = 1U <<
-                               a->data.non_resident.compression_unit;
+               if (a->data.non_resident.compression_unit) {
+                       ni->itype.compressed.block_size = 1U << (a->data.
+                                       non_resident.compression_unit +
+                                       vol->cluster_size_bits);
+                       ni->itype.compressed.block_size_bits =
+                                       ffs(ni->itype.compressed.block_size) -
+                                       1;
+                       ni->itype.compressed.block_clusters = 1U <<
+                                       a->data.non_resident.compression_unit;
+               } else {
+                       ni->itype.compressed.block_size = 0;
+                       ni->itype.compressed.block_size_bits = 0;
+                       ni->itype.compressed.block_clusters = 0;
+               }
                vi->i_blocks = ni->itype.compressed.size >> 9;
        } else
                vi->i_blocks = ni->allocated_size >> 9;
 
 /**
  * inode.c - NTFS kernel inode handling. Part of the Linux-NTFS project.
  *
- * Copyright (c) 2001-2005 Anton Altaparmakov
+ * Copyright (c) 2001-2006 Anton Altaparmakov
  *
  * 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
 #include <linux/smp_lock.h>
 #include <linux/quotaops.h>
 #include <linux/mount.h>
+#include <linux/mutex.h>
 
 #include "aops.h"
+#include "attrib.h"
 #include "dir.h"
 #include "debug.h"
 #include "inode.h"
                if (a->non_resident) {
                        NInoSetNonResident(ni);
                        if (NInoCompressed(ni) || NInoSparse(ni)) {
-                               if (a->data.non_resident.compression_unit !=
-                                               4) {
+                               if (NInoCompressed(ni) && a->data.non_resident.
+                                               compression_unit != 4) {
                                        ntfs_error(vi->i_sb, "Found "
-                                                       "nonstandard "
+                                                       "non-standard "
                                                        "compression unit (%u "
                                                        "instead of 4).  "
                                                        "Cannot handle this.",
                                        err = -EOPNOTSUPP;
                                        goto unm_err_out;
                                }
-                               ni->itype.compressed.block_clusters = 1U <<
-                                               a->data.non_resident.
-                                               compression_unit;
-                               ni->itype.compressed.block_size = 1U << (
-                                               a->data.non_resident.
-                                               compression_unit +
-                                               vol->cluster_size_bits);
-                               ni->itype.compressed.block_size_bits = ffs(
-                                               ni->itype.compressed.
-                                               block_size) - 1;
+                               if (a->data.non_resident.compression_unit) {
+                                       ni->itype.compressed.block_size = 1U <<
+                                                       (a->data.non_resident.
+                                                       compression_unit +
+                                                       vol->cluster_size_bits);
+                                       ni->itype.compressed.block_size_bits =
+                                                       ffs(ni->itype.
+                                                       compressed.
+                                                       block_size) - 1;
+                                       ni->itype.compressed.block_clusters =
+                                                       1U << a->data.
+                                                       non_resident.
+                                                       compression_unit;
+                               } else {
+                                       ni->itype.compressed.block_size = 0;
+                                       ni->itype.compressed.block_size_bits =
+                                                       0;
+                                       ni->itype.compressed.block_clusters =
+                                                       0;
+                               }
                                ni->itype.compressed.size = sle64_to_cpu(
                                                a->data.non_resident.
                                                compressed_size);
                        goto unm_err_out;
                }
                if (NInoCompressed(ni) || NInoSparse(ni)) {
-                       if (a->data.non_resident.compression_unit != 4) {
-                               ntfs_error(vi->i_sb, "Found nonstandard "
+                       if (NInoCompressed(ni) && a->data.non_resident.
+                                       compression_unit != 4) {
+                               ntfs_error(vi->i_sb, "Found non-standard "
                                                "compression unit (%u instead "
                                                "of 4).  Cannot handle this.",
                                                a->data.non_resident.
                                err = -EOPNOTSUPP;
                                goto unm_err_out;
                        }
-                       ni->itype.compressed.block_clusters = 1U <<
-                                       a->data.non_resident.compression_unit;
-                       ni->itype.compressed.block_size = 1U << (
-                                       a->data.non_resident.compression_unit +
-                                       vol->cluster_size_bits);
-                       ni->itype.compressed.block_size_bits = ffs(
-                                       ni->itype.compressed.block_size) - 1;
+                       if (a->data.non_resident.compression_unit) {
+                               ni->itype.compressed.block_size = 1U <<
+                                               (a->data.non_resident.
+                                               compression_unit +
+                                               vol->cluster_size_bits);
+                               ni->itype.compressed.block_size_bits =
+                                               ffs(ni->itype.compressed.
+                                               block_size) - 1;
+                               ni->itype.compressed.block_clusters = 1U <<
+                                               a->data.non_resident.
+                                               compression_unit;
+                       } else {
+                               ni->itype.compressed.block_size = 0;
+                               ni->itype.compressed.block_size_bits = 0;
+                               ni->itype.compressed.block_clusters = 0;
+                       }
                        ni->itype.compressed.size = sle64_to_cpu(
                                        a->data.non_resident.compressed_size);
                }
 
                                compressed.  (This effectively limits the
                                compression unit size to be a power of two
                                clusters.)  WinNT4 only uses a value of 4.
-                               Sparse files also have this set to 4. */
+                               Sparse files have this set to 0 on XPSP2. */
 /* 35*/                        u8 reserved[5];         /* Align to 8-byte boundary. */
 /* The sizes below are only used when lowest_vcn is zero, as otherwise it would
    be difficult to keep them up-to-date.*/
 /* 20*/        sle64 last_access_time;         /* Time this mft record was last
                                           accessed. */
 /* 28*/        sle64 allocated_size;           /* Byte size of on-disk allocated space
-                                          for the data attribute.  So for
-                                          normal $DATA, this is the
+                                          for the unnamed data attribute.  So
+                                          for normal $DATA, this is the
                                           allocated_size from the unnamed
                                           $DATA attribute and for compressed
                                           and/or sparse $DATA, this is the
                                           compressed_size from the unnamed
-                                          $DATA attribute.  NOTE: This is a
-                                          multiple of the cluster size. */
-/* 30*/        sle64 data_size;                /* Byte size of actual data in data
-                                          attribute. */
+                                          $DATA attribute.  For a directory or
+                                          other inode without an unnamed $DATA
+                                          attribute, this is always 0.  NOTE:
+                                          This is a multiple of the cluster
+                                          size. */
+/* 30*/        sle64 data_size;                /* Byte size of actual data in unnamed
+                                          data attribute.  For a directory or
+                                          other inode without an unnamed $DATA
+                                          attribute, this is always 0. */
 /* 38*/        FILE_ATTR_FLAGS file_attributes;        /* Flags describing the file. */
 /* 3c*/        union {
        /* 3c*/ struct {