Author: tthompson
Date: Tue Jul 19 15:31:22 2016
New Revision: 71968

URL: http://svn.reactos.org/svn/reactos?rev=71968&view=rev
Log:
[NTFS]
+FreeClusters(). Fix a DPRINT.

Modified:
    branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/attrib.c
    branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/mft.c
    branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/ntfs.h

Modified: branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/attrib.c
URL: 
http://svn.reactos.org/svn/reactos/branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/attrib.c?rev=71968&r1=71967&r2=71968&view=diff
==============================================================================
--- branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/attrib.c   [iso-8859-1] 
(original)
+++ branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/attrib.c   [iso-8859-1] 
Tue Jul 19 15:31:22 2016
@@ -409,6 +409,208 @@
     return TRUE;
 }
 
+/**
+* @name FreeClusters
+* @implemented
+*
+* Shrinks the allocation size of a non-resident attribute by a given number of 
clusters.
+* Frees the clusters from the volume's $BITMAP file as well as the attribute's 
data runs.
+*
+* @param Vcb
+* Pointer to an NTFS_VCB for the destination volume.
+*
+* @param AttrContext
+* Pointer to an NTFS_ATTR_CONTEXT describing the attribute from which the 
clusters will be freed.
+*
+* @param AttrOffset
+* Byte offset of the destination attribute relative to its file record.
+*
+* @param FileRecord
+* Pointer to a complete copy of the file record containing the attribute. Must 
be at least
+* Vcb->NtfsInfo.BytesPerFileRecord bytes long.
+*
+* @param ClustersToFree
+* Number of clusters that should be freed from the end of the data stream. 
Must be no more
+* Than the number of clusters assigned to the attribute (HighestVCN + 1).
+*
+* @return
+* STATUS_SUCCESS on success. STATUS_INVALID_PARAMETER if AttrContext describes 
a resident attribute,
+* or if the caller requested more clusters be freed than the attribute has 
been allocated.
+* STATUS_INSUFFICIENT_RESOURCES if ConvertDataRunsToLargeMCB() fails.
+* STATUS_BUFFER_TOO_SMALL if ConvertLargeMCBToDataRuns() fails.
+*
+*
+*/
+NTSTATUS
+FreeClusters(PNTFS_VCB Vcb,
+             PNTFS_ATTR_CONTEXT AttrContext,
+             ULONG AttrOffset,
+             PFILE_RECORD_HEADER FileRecord,
+             ULONG ClustersToFree)
+{
+    NTSTATUS Status = STATUS_SUCCESS;
+    ULONG ClustersLeftToFree = ClustersToFree;
+
+    // convert data runs to mcb
+    PUCHAR DataRun = (PUCHAR)&AttrContext->Record + 
AttrContext->Record.NonResident.MappingPairsOffset;
+    PNTFS_ATTR_RECORD DestinationAttribute = 
(PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + AttrOffset);
+    LARGE_MCB DataRunsMCB;
+    ULONG NextAttributeOffset = AttrOffset + AttrContext->Record.Length;
+    PNTFS_ATTR_RECORD NextAttribute = 
(PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + NextAttributeOffset);
+    ULONGLONG NextVBN = AttrContext->Record.NonResident.LowestVCN;
+
+    // Allocate some memory for the RunBuffer
+    PUCHAR RunBuffer = ExAllocatePoolWithTag(NonPagedPool, 
Vcb->NtfsInfo.BytesPerFileRecord, TAG_NTFS);
+    ULONG RunBufferOffset = 0;
+
+    PFILE_RECORD_HEADER BitmapRecord;
+    PNTFS_ATTR_CONTEXT DataContext;
+    ULONGLONG BitmapDataSize;
+    PUCHAR BitmapData;
+    RTL_BITMAP Bitmap;
+    ULONG LengthWritten;
+
+    if (!AttrContext->Record.IsNonResident)
+    {
+        ExFreePoolWithTag(RunBuffer, TAG_NTFS);
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    // Convert the data runs to a map control block
+    Status = ConvertDataRunsToLargeMCB(DataRun, &DataRunsMCB, &NextVBN);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("Unable to convert data runs to MCB (probably ran out of 
memory)!\n");
+        ExFreePoolWithTag(RunBuffer, TAG_NTFS);
+        return Status;
+    }
+
+    BitmapRecord = ExAllocatePoolWithTag(NonPagedPool,
+                                         Vcb->NtfsInfo.BytesPerFileRecord,
+                                         TAG_NTFS);
+    if (BitmapRecord == NULL)
+    {
+        DPRINT1("Error: Unable to allocate memory for bitmap file record!\n");
+        FsRtlUninitializeLargeMcb(&DataRunsMCB);
+        ExFreePoolWithTag(RunBuffer, TAG_NTFS);
+        return STATUS_NO_MEMORY;
+    }
+
+    Status = ReadFileRecord(Vcb, NTFS_FILE_BITMAP, BitmapRecord);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("Error: Unable to read file record for bitmap!\n");
+        FsRtlUninitializeLargeMcb(&DataRunsMCB);
+        ExFreePoolWithTag(BitmapRecord, TAG_NTFS);
+        ExFreePoolWithTag(RunBuffer, TAG_NTFS);
+        return 0;
+    }
+
+    Status = FindAttribute(Vcb, BitmapRecord, AttributeData, L"", 0, 
&DataContext, NULL);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("Error: Unable to find data attribute for bitmap file!\n");
+        FsRtlUninitializeLargeMcb(&DataRunsMCB);
+        ExFreePoolWithTag(BitmapRecord, TAG_NTFS);
+        ExFreePoolWithTag(RunBuffer, TAG_NTFS);
+        return 0;
+    }
+
+    BitmapDataSize = AttributeDataLength(&DataContext->Record);
+    BitmapDataSize = min(BitmapDataSize, 0xffffffff);
+    ASSERT((BitmapDataSize * 8) >= Vcb->NtfsInfo.ClusterCount);
+    BitmapData = ExAllocatePoolWithTag(NonPagedPool, ROUND_UP(BitmapDataSize, 
Vcb->NtfsInfo.BytesPerSector), TAG_NTFS);
+    if (BitmapData == NULL)
+    {
+        DPRINT1("Error: Unable to allocate memory for bitmap file data!\n");
+        ReleaseAttributeContext(DataContext);
+        FsRtlUninitializeLargeMcb(&DataRunsMCB);
+        ExFreePoolWithTag(BitmapRecord, TAG_NTFS);
+        ExFreePoolWithTag(RunBuffer, TAG_NTFS);
+        return 0;
+    }
+
+    ReadAttribute(Vcb, DataContext, 0, (PCHAR)BitmapData, 
(ULONG)BitmapDataSize);
+
+    RtlInitializeBitMap(&Bitmap, (PULONG)BitmapData, 
Vcb->NtfsInfo.ClusterCount);
+    
+    // free clusters in $BITMAP file
+    while (ClustersLeftToFree > 0)
+    {
+        LONGLONG LargeVbn, LargeLbn;
+
+        if (!FsRtlLookupLastLargeMcbEntry(&DataRunsMCB, &LargeVbn, &LargeLbn))
+        {
+            Status = STATUS_INVALID_PARAMETER;
+            DPRINT1("DRIVER ERROR: FreeClusters called to free %lu clusters, 
which is %lu more clusters than are assigned to attribute!",
+                    ClustersToFree,
+                    ClustersLeftToFree);
+            break;
+        }
+
+        if( LargeLbn != -1)
+        {
+            // deallocate this cluster
+            RtlClearBits(&Bitmap, LargeLbn, 1);
+        }
+        FsRtlTruncateLargeMcb(&DataRunsMCB, 
AttrContext->Record.NonResident.HighestVCN);
+        AttrContext->Record.NonResident.HighestVCN = 
min(AttrContext->Record.NonResident.HighestVCN, 
AttrContext->Record.NonResident.HighestVCN - 1);
+        ClustersLeftToFree--;
+    }
+
+    // update $BITMAP file on disk
+    Status = WriteAttribute(Vcb, DataContext, 0, BitmapData, 
(ULONG)BitmapDataSize, &LengthWritten);
+    if (!NT_SUCCESS(Status))
+    {
+        ReleaseAttributeContext(DataContext);
+        FsRtlUninitializeLargeMcb(&DataRunsMCB);
+        ExFreePoolWithTag(BitmapData, TAG_NTFS);
+        ExFreePoolWithTag(BitmapRecord, TAG_NTFS);
+        ExFreePoolWithTag(RunBuffer, TAG_NTFS);
+        return Status;
+    }
+
+    ReleaseAttributeContext(DataContext);
+    ExFreePoolWithTag(BitmapData, TAG_NTFS);
+    ExFreePoolWithTag(BitmapRecord, TAG_NTFS);    
+
+    // Convert the map control block back to encoded data runs
+    ConvertLargeMCBToDataRuns(&DataRunsMCB, RunBuffer, 
Vcb->NtfsInfo.BytesPerCluster, &RunBufferOffset);
+
+    // Update HighestVCN
+    DestinationAttribute->NonResident.HighestVCN = 
AttrContext->Record.NonResident.HighestVCN;
+
+    // Write data runs to destination attribute
+    RtlCopyMemory((PVOID)((ULONG_PTR)DestinationAttribute + 
DestinationAttribute->NonResident.MappingPairsOffset),
+                  RunBuffer,
+                  RunBufferOffset);
+
+    if (NextAttribute->Type == AttributeEnd)
+    {
+        // update attribute length
+        AttrContext->Record.Length = 
ALIGN_UP_BY(AttrContext->Record.NonResident.MappingPairsOffset + 
RunBufferOffset, 8);
+        DestinationAttribute->Length = AttrContext->Record.Length;
+
+        // write end markers
+        NextAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)DestinationAttribute + 
DestinationAttribute->Length);
+        NextAttribute->Type = AttributeEnd;
+        NextAttribute->Length = FILE_RECORD_END;
+
+        // update file record length
+        FileRecord->BytesInUse = AttrOffset + DestinationAttribute->Length + 
(sizeof(ULONG) * 2);
+    }
+
+    // Update the file record
+    Status = UpdateFileRecord(Vcb, AttrContext->FileMFTIndex, FileRecord);
+
+    FsRtlUninitializeLargeMcb(&DataRunsMCB);
+    ExFreePoolWithTag(RunBuffer, TAG_NTFS);
+
+    NtfsDumpDataRuns((PUCHAR)((ULONG_PTR)DestinationAttribute + 
DestinationAttribute->NonResident.MappingPairsOffset), 0);
+
+    return Status;
+}
+
 static
 NTSTATUS
 InternalReadNonResidentAttributes(PFIND_ATTR_CONTXT Context)

Modified: branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/mft.c
URL: 
http://svn.reactos.org/svn/reactos/branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/mft.c?rev=71968&r1=71967&r2=71968&view=diff
==============================================================================
--- branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/mft.c      [iso-8859-1] 
(original)
+++ branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/mft.c      [iso-8859-1] 
Tue Jul 19 15:31:22 2016
@@ -225,6 +225,7 @@
                        PLARGE_INTEGER DataSize)
 {
     NTSTATUS Status = STATUS_SUCCESS;
+    ULONG BytesPerCluster = Fcb->Vcb->NtfsInfo.BytesPerCluster;
 
     // are we truncating the file?
     if (DataSize->QuadPart < AttributeDataLength(&AttrContext->Record))
@@ -238,14 +239,13 @@
 
     if (AttrContext->Record.IsNonResident)
     {
-        ULONG BytesPerCluster = Fcb->Vcb->NtfsInfo.BytesPerCluster;
         ULONGLONG AllocationSize = ROUND_UP(DataSize->QuadPart, 
BytesPerCluster);
         PNTFS_ATTR_RECORD DestinationAttribute = 
(PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + AttrOffset);
+        ULONG ExistingClusters = AttrContext->Record.NonResident.AllocatedSize 
/ BytesPerCluster;
 
         // do we need to increase the allocation size?
         if (AttrContext->Record.NonResident.AllocatedSize < AllocationSize)
         {              
-            ULONG ExistingClusters = 
AttrContext->Record.NonResident.AllocatedSize / BytesPerCluster;
             ULONG ClustersNeeded = (AllocationSize / BytesPerCluster) - 
ExistingClusters;
             LARGE_INTEGER LastClusterInDataRun;
             ULONG NextAssignedCluster;
@@ -284,15 +284,9 @@
         }
         else if (AttrContext->Record.NonResident.AllocatedSize > 
AllocationSize)
         {
-            // shrink allocation size (TODO)
-            if (AllocationSize == 0)
-            {
-                // hack for notepad.exe
-                PUCHAR DataRuns = (PUCHAR)((ULONG_PTR)DestinationAttribute + 
DestinationAttribute->NonResident.MappingPairsOffset);
-                *DataRuns = 0;
-                DestinationAttribute->NonResident.HighestVCN = 
-                AttrContext->Record.NonResident.HighestVCN = 0;
-            }
+            // shrink allocation size
+            ULONG ClustersToFree = ExistingClusters - (AllocationSize / 
BytesPerCluster);
+            Status = FreeClusters(Fcb->Vcb, AttrContext, AttrOffset, 
FileRecord, ClustersToFree);
         }
 
         // TODO: is the file compressed, encrypted, or sparse?
@@ -1098,7 +1092,7 @@
 
     if (!NT_SUCCESS(Status))
     {
-        DPRINT1("UpdateFileRecord failed: %I64u written, %u expected\n", 
BytesWritten, Vcb->NtfsInfo.BytesPerFileRecord);
+        DPRINT1("UpdateFileRecord failed: %I64u written, %lu expected\n", 
BytesWritten, Vcb->NtfsInfo.BytesPerFileRecord);
     }
 
     // remove the fixup array (so the file record pointer can still be used)

Modified: branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/ntfs.h
URL: 
http://svn.reactos.org/svn/reactos/branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/ntfs.h?rev=71968&r1=71967&r2=71968&view=diff
==============================================================================
--- branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/ntfs.h     [iso-8859-1] 
(original)
+++ branches/GSoC_2016/NTFS/drivers/filesystems/ntfs/ntfs.h     [iso-8859-1] 
Tue Jul 19 15:31:22 2016
@@ -584,6 +584,13 @@
 VOID
 FindCloseAttribute(PFIND_ATTR_CONTXT Context);
 
+NTSTATUS
+FreeClusters(PNTFS_VCB Vcb,
+             PNTFS_ATTR_CONTEXT AttrContext,
+             ULONG AttrOffset,
+             PFILE_RECORD_HEADER FileRecord,
+             ULONG ClustersToFree);
+
 /* blockdev.c */
 
 NTSTATUS


Reply via email to