[NTFS]
[reactos.git] / drivers / filesystems / ntfs / volinfo.c
index 907256a..df3af49 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 *****************************************************************/
 
 /* FUNCTIONS ****************************************************************/
 
-static NTSTATUS
+ULONGLONG
+NtfsGetFreeClusters(PDEVICE_EXTENSION DeviceExt)
+{
+    NTSTATUS Status;
+    PFILE_RECORD_HEADER BitmapRecord;
+    PNTFS_ATTR_CONTEXT DataContext;
+    ULONGLONG BitmapDataSize;
+    PCHAR BitmapData;
+    ULONGLONG FreeClusters = 0;
+    ULONG Read = 0;
+    RTL_BITMAP Bitmap;
+
+    DPRINT1("NtfsGetFreeClusters(%p)\n", DeviceExt);
+
+    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);
+    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;
+    }
+
+    /* FIXME: Totally underoptimized! */
+    for (; Read < BitmapDataSize; Read += DeviceExt->NtfsInfo.BytesPerSector)
+    {
+        ReadAttribute(DeviceExt, DataContext, Read, (PCHAR)((ULONG_PTR)BitmapData + Read), DeviceExt->NtfsInfo.BytesPerSector);
+    }
+    ReleaseAttributeContext(DataContext);
+
+    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);
+
+    RtlInitializeBitMap(&Bitmap, (PULONG)BitmapData, DeviceExt->NtfsInfo.ClusterCount);
+    FreeClusters = RtlNumberOfClearBits(&Bitmap);
+
+    ExFreePoolWithTag(BitmapData, TAG_NTFS);
+    ExFreePoolWithTag(BitmapRecord, TAG_NTFS);
+
+    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;
+    ULONG Read = 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, Read, (PCHAR)((ULONG_PTR)BitmapData + Read), (ULONG)BitmapDataSize);
+
+    RtlInitializeBitMap(&Bitmap, (PULONG)BitmapData, DeviceExt->NtfsInfo.ClusterCount);
+    FreeClusters = RtlNumberOfClearBits(&Bitmap);
+
+    if (FreeClusters >= DesiredClusters)
+    {
+        // 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);
+    }
+    else
+        Status = STATUS_DISK_FULL;
+
+
+    ReleaseAttributeContext(DataContext);
+
+    ExFreePoolWithTag(BitmapData, TAG_NTFS);
+    ExFreePoolWithTag(BitmapRecord, TAG_NTFS);
+
+    return Status;
+}
+
+static
+NTSTATUS
 NtfsGetFsVolumeInformation(PDEVICE_OBJECT DeviceObject,
                            PFILE_FS_VOLUME_INFORMATION FsVolumeInfo,
                            PULONG BufferLength)
 {
-  DPRINT("NtfsGetFsVolumeInformation() called\n");
-  DPRINT("FsVolumeInfo = %p\n", FsVolumeInfo);
-  DPRINT("BufferLength %lu\n", *BufferLength);
+    DPRINT("NtfsGetFsVolumeInformation() called\n");
+    DPRINT("FsVolumeInfo = %p\n", FsVolumeInfo);
+    DPRINT("BufferLength %lu\n", *BufferLength);
 
-  DPRINT("Vpb %p\n", DeviceObject->Vpb);
+    DPRINT("Vpb %p\n", DeviceObject->Vpb);
 
-  DPRINT("Required length %lu\n",
-         sizeof(FILE_FS_VOLUME_INFORMATION) + DeviceObject->Vpb->VolumeLabelLength);
-  DPRINT("LabelLength %hu\n",
-         DeviceObject->Vpb->VolumeLabelLength);
-  DPRINT("Label %*.S\n",
-         DeviceObject->Vpb->VolumeLabelLength / sizeof(WCHAR),
-         DeviceObject->Vpb->VolumeLabel);
+    DPRINT("Required length %lu\n",
+           sizeof(FILE_FS_VOLUME_INFORMATION) + DeviceObject->Vpb->VolumeLabelLength);
+    DPRINT("LabelLength %hu\n",
+           DeviceObject->Vpb->VolumeLabelLength);
+    DPRINT("Label %.*S\n",
+           DeviceObject->Vpb->VolumeLabelLength / sizeof(WCHAR),
+           DeviceObject->Vpb->VolumeLabel);
 
-  if (*BufferLength < sizeof(FILE_FS_VOLUME_INFORMATION))
-    return STATUS_INFO_LENGTH_MISMATCH;
+    if (*BufferLength < sizeof(FILE_FS_VOLUME_INFORMATION))
+        return STATUS_INFO_LENGTH_MISMATCH;
 
-  if (*BufferLength < (sizeof(FILE_FS_VOLUME_INFORMATION) + DeviceObject->Vpb->VolumeLabelLength))
-    return STATUS_BUFFER_OVERFLOW;
+    if (*BufferLength < (sizeof(FILE_FS_VOLUME_INFORMATION) + DeviceObject->Vpb->VolumeLabelLength))
+        return STATUS_BUFFER_OVERFLOW;
 
-  /* valid entries */
-  FsVolumeInfo->VolumeSerialNumber = DeviceObject->Vpb->SerialNumber;
-  FsVolumeInfo->VolumeLabelLength = DeviceObject->Vpb->VolumeLabelLength;
-  memcpy(FsVolumeInfo->VolumeLabel,
-         DeviceObject->Vpb->VolumeLabel,
-         DeviceObject->Vpb->VolumeLabelLength);
+    /* valid entries */
+    FsVolumeInfo->VolumeSerialNumber = DeviceObject->Vpb->SerialNumber;
+    FsVolumeInfo->VolumeLabelLength = DeviceObject->Vpb->VolumeLabelLength;
+    memcpy(FsVolumeInfo->VolumeLabel,
+           DeviceObject->Vpb->VolumeLabel,
+           DeviceObject->Vpb->VolumeLabelLength);
 
-  /* dummy entries */
-  FsVolumeInfo->VolumeCreationTime.QuadPart = 0;
-  FsVolumeInfo->SupportsObjects = FALSE;
+    /* dummy entries */
+    FsVolumeInfo->VolumeCreationTime.QuadPart = 0;
+    FsVolumeInfo->SupportsObjects = FALSE;
 
-  *BufferLength -= (sizeof(FILE_FS_VOLUME_INFORMATION) + DeviceObject->Vpb->VolumeLabelLength);
+    *BufferLength -= (sizeof(FILE_FS_VOLUME_INFORMATION) + DeviceObject->Vpb->VolumeLabelLength);
 
-  DPRINT("BufferLength %lu\n", *BufferLength);
-  DPRINT("NtfsGetFsVolumeInformation() done\n");
+    DPRINT("BufferLength %lu\n", *BufferLength);
+    DPRINT("NtfsGetFsVolumeInformation() done\n");
 
-  return STATUS_SUCCESS;
+    return STATUS_SUCCESS;
 }
 
 
-static NTSTATUS
+static
+NTSTATUS
 NtfsGetFsAttributeInformation(PDEVICE_EXTENSION DeviceExt,
                               PFILE_FS_ATTRIBUTE_INFORMATION FsAttributeInfo,
                               PULONG BufferLength)
 {
-  DPRINT("NtfsGetFsAttributeInformation()\n");
-  DPRINT("FsAttributeInfo = %p\n", FsAttributeInfo);
-  DPRINT("BufferLength %lu\n", *BufferLength);
-  DPRINT("Required length %lu\n", (sizeof(FILE_FS_ATTRIBUTE_INFORMATION) + 8));
+    UNREFERENCED_PARAMETER(DeviceExt);
 
-  if (*BufferLength < sizeof (FILE_FS_ATTRIBUTE_INFORMATION))
-    return(STATUS_INFO_LENGTH_MISMATCH);
+    DPRINT("NtfsGetFsAttributeInformation()\n");
+    DPRINT("FsAttributeInfo = %p\n", FsAttributeInfo);
+    DPRINT("BufferLength %lu\n", *BufferLength);
+    DPRINT("Required length %lu\n", (sizeof(FILE_FS_ATTRIBUTE_INFORMATION) + 8));
 
-  if (*BufferLength < (sizeof(FILE_FS_ATTRIBUTE_INFORMATION) + 8))
-    return(STATUS_BUFFER_OVERFLOW);
+    if (*BufferLength < sizeof (FILE_FS_ATTRIBUTE_INFORMATION))
+        return STATUS_INFO_LENGTH_MISMATCH;
 
-  FsAttributeInfo->FileSystemAttributes =
-    FILE_CASE_PRESERVED_NAMES | FILE_UNICODE_ON_DISK;
-  FsAttributeInfo->MaximumComponentNameLength = 255;
-  FsAttributeInfo->FileSystemNameLength = 8;
+    if (*BufferLength < (sizeof(FILE_FS_ATTRIBUTE_INFORMATION) + 8))
+        return STATUS_BUFFER_OVERFLOW;
 
-  memcpy(FsAttributeInfo->FileSystemName, L"NTFS", 8);
+    FsAttributeInfo->FileSystemAttributes =
+        FILE_CASE_PRESERVED_NAMES | FILE_UNICODE_ON_DISK | FILE_READ_ONLY_VOLUME;
+    FsAttributeInfo->MaximumComponentNameLength = 255;
+    FsAttributeInfo->FileSystemNameLength = 8;
 
-  DPRINT("Finished NtfsGetFsAttributeInformation()\n");
+    memcpy(FsAttributeInfo->FileSystemName, L"NTFS", 8);
 
-  *BufferLength -= (sizeof(FILE_FS_ATTRIBUTE_INFORMATION) + 8);
-  DPRINT("BufferLength %lu\n", *BufferLength);
+    DPRINT("Finished NtfsGetFsAttributeInformation()\n");
 
-  return(STATUS_SUCCESS);
+    *BufferLength -= (sizeof(FILE_FS_ATTRIBUTE_INFORMATION) + 8);
+    DPRINT("BufferLength %lu\n", *BufferLength);
+
+    return STATUS_SUCCESS;
 }
 
 
-static NTSTATUS
+static
+NTSTATUS
 NtfsGetFsSizeInformation(PDEVICE_OBJECT DeviceObject,
                          PFILE_FS_SIZE_INFORMATION FsSizeInfo,
                          PULONG BufferLength)
 {
-  PDEVICE_EXTENSION DeviceExt;
-  NTSTATUS Status = STATUS_SUCCESS;
+    PDEVICE_EXTENSION DeviceExt;
+    NTSTATUS Status = STATUS_SUCCESS;
 
-  DPRINT("NtfsGetFsSizeInformation()\n");
-  DPRINT("FsSizeInfo = %p\n", FsSizeInfo);
+    DPRINT("NtfsGetFsSizeInformation()\n");
+    DPRINT("FsSizeInfo = %p\n", FsSizeInfo);
 
-  if (*BufferLength < sizeof(FILE_FS_SIZE_INFORMATION))
-    return(STATUS_BUFFER_OVERFLOW);
+    if (*BufferLength < sizeof(FILE_FS_SIZE_INFORMATION))
+        return STATUS_BUFFER_OVERFLOW;
 
-  DeviceExt = DeviceObject->DeviceExtension;
+    DeviceExt = DeviceObject->DeviceExtension;
 
-  FsSizeInfo->AvailableAllocationUnits.QuadPart = 0;
-  FsSizeInfo->TotalAllocationUnits.QuadPart = DeviceExt->NtfsInfo.SectorCount; /* ?? */
-  FsSizeInfo->SectorsPerAllocationUnit = DeviceExt->NtfsInfo.SectorsPerCluster;
-  FsSizeInfo->BytesPerSector = DeviceExt->NtfsInfo.BytesPerSector;
+    FsSizeInfo->AvailableAllocationUnits.QuadPart = NtfsGetFreeClusters(DeviceExt);
+    FsSizeInfo->TotalAllocationUnits.QuadPart = DeviceExt->NtfsInfo.ClusterCount;
+    FsSizeInfo->SectorsPerAllocationUnit = DeviceExt->NtfsInfo.SectorsPerCluster;
+    FsSizeInfo->BytesPerSector = DeviceExt->NtfsInfo.BytesPerSector;
 
-  DPRINT("Finished NtfsGetFsSizeInformation()\n");
-  if (NT_SUCCESS(Status))
-    *BufferLength -= sizeof(FILE_FS_SIZE_INFORMATION);
+    DPRINT("Finished NtfsGetFsSizeInformation()\n");
+    if (NT_SUCCESS(Status))
+        *BufferLength -= sizeof(FILE_FS_SIZE_INFORMATION);
 
-  return(Status);
+    return Status;
 }
 
 
-static NTSTATUS
-NtfsGetFsDeviceInformation(PFILE_FS_DEVICE_INFORMATION FsDeviceInfo,
+static
+NTSTATUS
+NtfsGetFsDeviceInformation(PDEVICE_OBJECT DeviceObject,
+                           PFILE_FS_DEVICE_INFORMATION FsDeviceInfo,
                            PULONG BufferLength)
 {
-  DPRINT("NtfsGetFsDeviceInformation()\n");
-  DPRINT("FsDeviceInfo = %p\n", FsDeviceInfo);
-  DPRINT("BufferLength %lu\n", *BufferLength);
-  DPRINT("Required length %lu\n", sizeof(FILE_FS_DEVICE_INFORMATION));
+    DPRINT("NtfsGetFsDeviceInformation()\n");
+    DPRINT("FsDeviceInfo = %p\n", FsDeviceInfo);
+    DPRINT("BufferLength %lu\n", *BufferLength);
+    DPRINT("Required length %lu\n", sizeof(FILE_FS_DEVICE_INFORMATION));
 
-  if (*BufferLength < sizeof(FILE_FS_DEVICE_INFORMATION))
-    return(STATUS_BUFFER_OVERFLOW);
+    if (*BufferLength < sizeof(FILE_FS_DEVICE_INFORMATION))
+        return STATUS_BUFFER_OVERFLOW;
 
-  FsDeviceInfo->DeviceType = FILE_DEVICE_DISK;
-  FsDeviceInfo->Characteristics = 0; /* FIXME: fix this !! */
+    FsDeviceInfo->DeviceType = FILE_DEVICE_DISK;
+    FsDeviceInfo->Characteristics = DeviceObject->Characteristics;
 
-  DPRINT("NtfsGetFsDeviceInformation() finished.\n");
+    DPRINT("NtfsGetFsDeviceInformation() finished.\n");
 
-  *BufferLength -= sizeof(FILE_FS_DEVICE_INFORMATION);
-  DPRINT("BufferLength %lu\n", *BufferLength);
+    *BufferLength -= sizeof(FILE_FS_DEVICE_INFORMATION);
+    DPRINT("BufferLength %lu\n", *BufferLength);
 
-  return(STATUS_SUCCESS);
+    return STATUS_SUCCESS;
 }
 
 
-
 NTSTATUS
 NtfsQueryVolumeInformation(PNTFS_IRP_CONTEXT IrpContext)
 {
-  PIRP Irp;
-  PDEVICE_OBJECT DeviceObject;
-  FS_INFORMATION_CLASS FsInformationClass;
-  PIO_STACK_LOCATION Stack;
-  NTSTATUS Status = STATUS_SUCCESS;
-  PVOID SystemBuffer;
-  ULONG BufferLength;
-
-  DPRINT("NtfsQueryVolumeInformation() called\n");
-
-  ASSERT(IrpContext);
-
-  Irp = IrpContext->Irp;
-  DeviceObject = IrpContext->DeviceObject;
-  Stack = IoGetCurrentIrpStackLocation(Irp);
-  FsInformationClass = Stack->Parameters.QueryVolume.FsInformationClass;
-  BufferLength = Stack->Parameters.QueryVolume.Length;
-  SystemBuffer = Irp->AssociatedIrp.SystemBuffer;
-  RtlZeroMemory(SystemBuffer, BufferLength);
-
-  DPRINT("FsInformationClass %d\n", FsInformationClass);
-  DPRINT("SystemBuffer %p\n", SystemBuffer);
-
-  switch (FsInformationClass)
-  {
-    case FileFsVolumeInformation:
-      Status = NtfsGetFsVolumeInformation(DeviceObject,
-                                          SystemBuffer,
-                                          &BufferLength);
-      break;
-
-    case FileFsAttributeInformation:
-      Status = NtfsGetFsAttributeInformation(DeviceObject->DeviceExtension,
-                                             SystemBuffer,
-                                             &BufferLength);
-      break;
-
-    case FileFsSizeInformation:
-      Status = NtfsGetFsSizeInformation(DeviceObject,
-                                        SystemBuffer,
-                                        &BufferLength);
-      break;
-
-    case FileFsDeviceInformation:
-      Status = NtfsGetFsDeviceInformation(SystemBuffer,
-                                          &BufferLength);
-      break;
-
-    default:
-      Status = STATUS_NOT_SUPPORTED;
-  }
-
-  if (NT_SUCCESS(Status))
-    Irp->IoStatus.Information =
-      Stack->Parameters.QueryVolume.Length - BufferLength;
-  else
-    Irp->IoStatus.Information = 0;
-
-  return Status;
+    PIRP Irp;
+    PDEVICE_OBJECT DeviceObject;
+    FS_INFORMATION_CLASS FsInformationClass;
+    PIO_STACK_LOCATION Stack;
+    NTSTATUS Status = STATUS_SUCCESS;
+    PVOID SystemBuffer;
+    ULONG BufferLength;
+    PDEVICE_EXTENSION DeviceExt;
+
+    DPRINT("NtfsQueryVolumeInformation() called\n");
+
+    ASSERT(IrpContext);
+
+    Irp = IrpContext->Irp;
+    DeviceObject = IrpContext->DeviceObject;
+    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;
+    RtlZeroMemory(SystemBuffer, BufferLength);
+
+    DPRINT("FsInformationClass %d\n", FsInformationClass);
+    DPRINT("SystemBuffer %p\n", SystemBuffer);
+
+    switch (FsInformationClass)
+    {
+        case FileFsVolumeInformation:
+            Status = NtfsGetFsVolumeInformation(DeviceObject,
+                                                SystemBuffer,
+                                                &BufferLength);
+            break;
+
+        case FileFsAttributeInformation:
+            Status = NtfsGetFsAttributeInformation(DeviceObject->DeviceExtension,
+                                                   SystemBuffer,
+                                                   &BufferLength);
+            break;
+
+        case FileFsSizeInformation:
+            Status = NtfsGetFsSizeInformation(DeviceObject,
+                                              SystemBuffer,
+                                              &BufferLength);
+            break;
+
+        case FileFsDeviceInformation:
+            Status = NtfsGetFsDeviceInformation(DeviceObject,
+                                                SystemBuffer,
+                                                &BufferLength);
+            break;
+
+        default:
+            Status = STATUS_NOT_SUPPORTED;
+    }
+
+    ExReleaseResourceLite(&DeviceExt->DirResource);
+
+    if (NT_SUCCESS(Status))
+        Irp->IoStatus.Information =
+            Stack->Parameters.QueryVolume.Length - BufferLength;
+    else
+        Irp->IoStatus.Information = 0;
+
+    return Status;
 }
 
 
 NTSTATUS
 NtfsSetVolumeInformation(PNTFS_IRP_CONTEXT IrpContext)
 {
-  PIRP Irp;
-  
-  DPRINT("NtfsSetVolumeInformation() called\n");
+    PIRP Irp;
 
-  ASSERT(IrpContext);
+    DPRINT("NtfsSetVolumeInformation() called\n");
 
-  Irp = IrpContext->Irp;
-  Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
-  Irp->IoStatus.Information = 0;
+    ASSERT(IrpContext);
+
+    Irp = IrpContext->Irp;
+    Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
+    Irp->IoStatus.Information = 0;
 
-  return STATUS_NOT_SUPPORTED;
+    return STATUS_NOT_SUPPORTED;
 }
 
 /* EOF */