Error reading compressed file

Feb 25, 2010 at 7:39 PM

This error occurs on about 3 files on my file system:

System.ArgumentOutOfRangeException occurred
  Message="Index was out of range. Must be non-negative and less than the size of the collection.\r\nParameter name: index"
       at System.ThrowHelper.ThrowArgumentOutOfRangeException()
       at System.Collections.Generic.List`1.get_Item(Int32 index)
       at DiscUtils.Ntfs.NonResidentAttributeExtentStream.IsBlockCompressed(Int32 startDataRunIdx, Int32 compressionUnitSize)
       at DiscUtils.Ntfs.NonResidentAttributeExtentStream.DoReadCompressed(Byte[] buffer, Int32 offset, Int32 count)
       at DiscUtils.Ntfs.NonResidentAttributeExtentStream.Read(Byte[] buffer, Int32 offset, Int32 count)
       at DiscUtils.Ntfs.NonResidentAttributeStream.Read(Byte[] buffer, Int32 offset, Int32 count)
       at DiscUtils.Ntfs.File.FileStream.Read(Byte[] buffer, Int32 offset, Int32 count)
       at DiscUtils.Ntfs.NtfsFileStream.Read(Byte[] buffer, Int32 offset, Int32 count)
       at Test.Program.CopyFile(NtfsFileSystem sourceNtfs, NtfsFileSystem destNtfs, String path) in C:\Users\Bill Sobel.SOBEL\Documents\Visual Studio 2008\Projects\Test\Program.cs:line 216

Any ideas?

Feb 25, 2010 at 10:48 PM
Edited Feb 25, 2010 at 10:48 PM

Ok, it looks like IsBlockCompressed does not handle the case of a non-compressed run (which is shorter than the compression unit size) at the end of a file.  The original while loop does not exit even if dataRunIdx is larger than the valid # of runs.  I suggest the two bolded changes below...

        private bool IsBlockCompressed(int startDataRunIdx, int compressionUnitSize)
            var runs = _record.CookedDataRuns;
            int clustersRemaining = compressionUnitSize;
            int dataRunIdx = startDataRunIdx;
            int dataRunMax = runs.Count;

            while (clustersRemaining > 0 && dataRunIdx < dataRunMax)
                // We're looking for this - a sparse record within compressionUnit Virtual Clusters
                // from the start of the compression unit.  If we don't find it, then the compression
                // unit is not actually compressed.
                if (runs[dataRunIdx].IsSparse)
                    return true;
                if (runs[dataRunIdx].Length > clustersRemaining)
                    return false;
                clustersRemaining -= (int)runs[dataRunIdx].Length;

            return false;

Feb 26, 2010 at 7:08 PM

Hi Bill,

Thanks for tracking this down.  I've uploaded a change - it's slightly different to the one you proposed, but should have the same effect.