[NTFS]
[reactos.git] / drivers / filesystems / ntfs / volinfo.c
index 7b07312..68a1050 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  ReactOS kernel
- *  Copyright (C) 2002 ReactOS Team
+ *  Copyright (C) 2002, 2014 ReactOS Team
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -20,7 +20,8 @@
  * PROJECT:          ReactOS kernel
  * FILE:             drivers/filesystem/ntfs/volume.c
  * PURPOSE:          NTFS filesystem driver
- * PROGRAMMER:       Eric Kohl
+ * PROGRAMMERS:      Eric Kohl
+ *                   Pierre Schweitzer (pierre@reactos.org)
  */
 
 /* INCLUDES *****************************************************************/
@@ -61,7 +62,7 @@ NtfsGetFreeClusters(PDEVICE_EXTENSION DeviceExt)
         return 0;
     }
 
-    Status = FindAttribute(DeviceExt, BitmapRecord, AttributeData, L"", 0, &DataContext);
+    Status = FindAttribute(DeviceExt, BitmapRecord, AttributeData, L"", 0, &DataContext, NULL);
     if (!NT_SUCCESS(Status))
     {
         ExFreePoolWithTag(BitmapRecord, TAG_NTFS);
@@ -69,8 +70,8 @@ NtfsGetFreeClusters(PDEVICE_EXTENSION DeviceExt)
     }
 
     BitmapDataSize = AttributeDataLength(&DataContext->Record);
-    ASSERT((BitmapDataSize * 8) >= (DeviceExt->NtfsInfo.SectorCount / DeviceExt->NtfsInfo.SectorsPerCluster));
-    BitmapData = ExAllocatePoolWithTag(NonPagedPool, BitmapDataSize, TAG_NTFS);
+    ASSERT((BitmapDataSize * 8) >= DeviceExt->NtfsInfo.ClusterCount);
+    BitmapData = ExAllocatePoolWithTag(NonPagedPool, ROUND_UP(BitmapDataSize, DeviceExt->NtfsInfo.BytesPerSector), TAG_NTFS);
     if (BitmapData == NULL)
     {
         ReleaseAttributeContext(DataContext);
@@ -85,11 +86,11 @@ NtfsGetFreeClusters(PDEVICE_EXTENSION DeviceExt)
     }
     ReleaseAttributeContext(DataContext);
 
-    DPRINT1("Total clusters: %I64x\n", DeviceExt->NtfsInfo.SectorCount / DeviceExt->NtfsInfo.SectorsPerCluster);
+    DPRINT1("Total clusters: %I64x\n", DeviceExt->NtfsInfo.ClusterCount);
     DPRINT1("Total clusters in bitmap: %I64x\n", BitmapDataSize * 8);
-    DPRINT1("Diff in size: %I64d B\n", ((BitmapDataSize * 8) - (DeviceExt->NtfsInfo.SectorCount / DeviceExt->NtfsInfo.SectorsPerCluster)) * DeviceExt->NtfsInfo.SectorsPerCluster * DeviceExt->NtfsInfo.BytesPerSector);
+    DPRINT1("Diff in size: %I64d B\n", ((BitmapDataSize * 8) - DeviceExt->NtfsInfo.ClusterCount) * DeviceExt->NtfsInfo.SectorsPerCluster * DeviceExt->NtfsInfo.BytesPerSector);
 
-    RtlInitializeBitMap(&Bitmap, (PULONG)BitmapData, DeviceExt->NtfsInfo.SectorCount / DeviceExt->NtfsInfo.SectorsPerCluster);
+    RtlInitializeBitMap(&Bitmap, (PULONG)BitmapData, DeviceExt->NtfsInfo.ClusterCount);
     FreeClusters = RtlNumberOfClearBits(&Bitmap);
 
     ExFreePoolWithTag(BitmapData, TAG_NTFS);
@@ -98,6 +99,106 @@ NtfsGetFreeClusters(PDEVICE_EXTENSION DeviceExt)
     return FreeClusters;
 }
 
+/** 
+* NtfsAllocateClusters 
+* Allocates a run of clusters. The run allocated might be smaller than DesiredClusters.
+*/
+NTSTATUS
+NtfsAllocateClusters(PDEVICE_EXTENSION DeviceExt,
+                     ULONG FirstDesiredCluster,
+                     ULONG DesiredClusters, 
+                     PULONG FirstAssignedCluster, 
+                     PULONG AssignedClusters)
+{
+    NTSTATUS Status;
+    PFILE_RECORD_HEADER BitmapRecord;
+    PNTFS_ATTR_CONTEXT DataContext;
+    ULONGLONG BitmapDataSize;
+    PCHAR BitmapData;
+    ULONGLONG FreeClusters = 0;
+    RTL_BITMAP Bitmap;
+
+    DPRINT1("NtfsAllocateClusters(%p, %lu, %lu, %p, %p)\n", DeviceExt, FirstDesiredCluster, DesiredClusters, FirstAssignedCluster, AssignedClusters);
+
+    BitmapRecord = ExAllocatePoolWithTag(NonPagedPool,
+                                         DeviceExt->NtfsInfo.BytesPerFileRecord,
+                                         TAG_NTFS);
+    if (BitmapRecord == NULL)
+    {
+        return 0;
+    }
+
+    Status = ReadFileRecord(DeviceExt, NTFS_FILE_BITMAP, BitmapRecord);
+    if (!NT_SUCCESS(Status))
+    {
+        ExFreePoolWithTag(BitmapRecord, TAG_NTFS);
+        return 0;
+    }
+
+    Status = FindAttribute(DeviceExt, BitmapRecord, AttributeData, L"", 0, &DataContext, NULL);
+    if (!NT_SUCCESS(Status))
+    {
+        ExFreePoolWithTag(BitmapRecord, TAG_NTFS);
+        return 0;
+    }
+
+    BitmapDataSize = AttributeDataLength(&DataContext->Record);
+    BitmapDataSize = min(BitmapDataSize, 0xffffffff);
+    ASSERT((BitmapDataSize * 8) >= DeviceExt->NtfsInfo.ClusterCount);
+    BitmapData = ExAllocatePoolWithTag(NonPagedPool, ROUND_UP(BitmapDataSize, DeviceExt->NtfsInfo.BytesPerSector), TAG_NTFS);
+    if (BitmapData == NULL)
+    {
+        ReleaseAttributeContext(DataContext);
+        ExFreePoolWithTag(BitmapRecord, TAG_NTFS);
+        return 0;
+    }
+
+    DPRINT1("Total clusters: %I64x\n", DeviceExt->NtfsInfo.ClusterCount);
+    DPRINT1("Total clusters in bitmap: %I64x\n", BitmapDataSize * 8);
+    DPRINT1("Diff in size: %I64d B\n", ((BitmapDataSize * 8) - DeviceExt->NtfsInfo.ClusterCount) * DeviceExt->NtfsInfo.SectorsPerCluster * DeviceExt->NtfsInfo.BytesPerSector);
+
+    ReadAttribute(DeviceExt, DataContext, 0, (PCHAR)BitmapData, (ULONG)BitmapDataSize);
+
+    RtlInitializeBitMap(&Bitmap, (PULONG)BitmapData, DeviceExt->NtfsInfo.ClusterCount);
+    FreeClusters = RtlNumberOfClearBits(&Bitmap);
+
+    if( FreeClusters < DesiredClusters )
+        Status = STATUS_DISK_FULL;
+    
+    // TODO: Observe MFT reservation zone
+
+    // Can we get one contiguous run?
+    ULONG AssignedRun = RtlFindClearBitsAndSet(&Bitmap, DesiredClusters, FirstDesiredCluster);
+    ULONG LengthWritten;
+
+    if (AssignedRun != 0xFFFFFFFF)
+    {
+        *FirstAssignedCluster = AssignedRun;
+        *AssignedClusters = DesiredClusters;
+    }
+    else
+    {
+        // we can't get one contiguous run
+        *AssignedClusters = RtlFindNextForwardRunClear(&Bitmap, FirstDesiredCluster, FirstAssignedCluster);
+        
+        if (*AssignedClusters == 0)
+        {
+            // we couldn't find any runs starting at DesiredFirstCluster
+            *AssignedClusters = RtlFindLongestRunClear(&Bitmap, FirstAssignedCluster);
+        }
+            
+    }
+                
+    Status = WriteAttribute(DeviceExt, DataContext, 0, BitmapData, (ULONG)BitmapDataSize, &LengthWritten);
+    
+    ReleaseAttributeContext(DataContext);
+
+    ExFreePoolWithTag(BitmapData, TAG_NTFS);
+    ExFreePoolWithTag(BitmapRecord, TAG_NTFS);
+
+    return Status;
+}
+
 static
 NTSTATUS
 NtfsGetFsVolumeInformation(PDEVICE_OBJECT DeviceObject,
@@ -114,7 +215,7 @@ NtfsGetFsVolumeInformation(PDEVICE_OBJECT DeviceObject,
            sizeof(FILE_FS_VOLUME_INFORMATION) + DeviceObject->Vpb->VolumeLabelLength);
     DPRINT("LabelLength %hu\n",
            DeviceObject->Vpb->VolumeLabelLength);
-    DPRINT("Label %*.S\n",
+    DPRINT("Label %.*S\n",
            DeviceObject->Vpb->VolumeLabelLength / sizeof(WCHAR),
            DeviceObject->Vpb->VolumeLabel);
 
@@ -164,7 +265,7 @@ NtfsGetFsAttributeInformation(PDEVICE_EXTENSION DeviceExt,
         return STATUS_BUFFER_OVERFLOW;
 
     FsAttributeInfo->FileSystemAttributes =
-        FILE_CASE_PRESERVED_NAMES | FILE_UNICODE_ON_DISK;
+        FILE_CASE_PRESERVED_NAMES | FILE_UNICODE_ON_DISK | FILE_READ_ONLY_VOLUME;
     FsAttributeInfo->MaximumComponentNameLength = 255;
     FsAttributeInfo->FileSystemNameLength = 8;
 
@@ -197,7 +298,7 @@ NtfsGetFsSizeInformation(PDEVICE_OBJECT DeviceObject,
     DeviceExt = DeviceObject->DeviceExtension;
 
     FsSizeInfo->AvailableAllocationUnits.QuadPart = NtfsGetFreeClusters(DeviceExt);
-    FsSizeInfo->TotalAllocationUnits.QuadPart = DeviceExt->NtfsInfo.SectorCount / DeviceExt->NtfsInfo.SectorsPerCluster;
+    FsSizeInfo->TotalAllocationUnits.QuadPart = DeviceExt->NtfsInfo.ClusterCount;
     FsSizeInfo->SectorsPerAllocationUnit = DeviceExt->NtfsInfo.SectorsPerCluster;
     FsSizeInfo->BytesPerSector = DeviceExt->NtfsInfo.BytesPerSector;
 
@@ -245,6 +346,7 @@ NtfsQueryVolumeInformation(PNTFS_IRP_CONTEXT IrpContext)
     NTSTATUS Status = STATUS_SUCCESS;
     PVOID SystemBuffer;
     ULONG BufferLength;
+    PDEVICE_EXTENSION DeviceExt;
 
     DPRINT("NtfsQueryVolumeInformation() called\n");
 
@@ -252,7 +354,15 @@ NtfsQueryVolumeInformation(PNTFS_IRP_CONTEXT IrpContext)
 
     Irp = IrpContext->Irp;
     DeviceObject = IrpContext->DeviceObject;
-    Stack = IoGetCurrentIrpStackLocation(Irp);
+    DeviceExt = DeviceObject->DeviceExtension;
+    Stack = IrpContext->Stack;
+
+    if (!ExAcquireResourceSharedLite(&DeviceExt->DirResource,
+                                     BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_CANWAIT)))
+    {
+        return NtfsMarkIrpContextForQueue(IrpContext);
+    }
+
     FsInformationClass = Stack->Parameters.QueryVolume.FsInformationClass;
     BufferLength = Stack->Parameters.QueryVolume.Length;
     SystemBuffer = Irp->AssociatedIrp.SystemBuffer;
@@ -291,6 +401,8 @@ NtfsQueryVolumeInformation(PNTFS_IRP_CONTEXT IrpContext)
             Status = STATUS_NOT_SUPPORTED;
     }
 
+    ExReleaseResourceLite(&DeviceExt->DirResource);
+
     if (NT_SUCCESS(Status))
         Irp->IoStatus.Information =
             Stack->Parameters.QueryVolume.Length - BufferLength;