[FASTFAT]
[reactos.git] / reactos / drivers / filesystems / ntfs / fsctl.c
index a9f645b..5550df2 100644 (file)
@@ -167,6 +167,28 @@ ByeBye:
 }
 
 
+static
+ULONG
+NtfsQueryMftZoneReservation(VOID)
+{
+    ULONG ZoneReservation = 1;
+    RTL_QUERY_REGISTRY_TABLE QueryTable[2];
+
+    RtlZeroMemory(QueryTable, sizeof(QueryTable));
+    QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
+    QueryTable[0].Name = L"NtfsMftZoneReservation";
+    QueryTable[0].EntryContext = &ZoneReservation;
+
+    RtlQueryRegistryValues(RTL_REGISTRY_CONTROL,
+                           L"FileSystem",
+                           QueryTable,
+                           NULL,
+                           NULL);
+
+    return ZoneReservation;
+}
+
+
 static
 NTSTATUS
 NtfsGetVolumeData(PDEVICE_OBJECT DeviceObject,
@@ -226,6 +248,7 @@ NtfsGetVolumeData(PDEVICE_OBJECT DeviceObject,
     NtfsInfo->SectorsPerCluster = BootSector->BPB.SectorsPerCluster;
     NtfsInfo->BytesPerCluster = BootSector->BPB.BytesPerSector * BootSector->BPB.SectorsPerCluster;
     NtfsInfo->SectorCount = BootSector->EBPB.SectorCount;
+    NtfsInfo->ClusterCount = DeviceExt->NtfsInfo.SectorCount / (ULONGLONG)DeviceExt->NtfsInfo.SectorsPerCluster;
 
     NtfsInfo->MftStart.QuadPart = BootSector->EBPB.MftLocation;
     NtfsInfo->MftMirrStart.QuadPart = BootSector->EBPB.MftMirrLocation;
@@ -304,10 +327,10 @@ NtfsGetVolumeData(PDEVICE_OBJECT DeviceObject,
     }
 
     /* Enumerate attributes */
-    NtfsDumpFileAttributes(DeviceExt->MasterFileTable);
+    NtfsDumpFileAttributes(DeviceExt, DeviceExt->MasterFileTable);
 
     /* Enumerate attributes */
-    NtfsDumpFileAttributes(VolumeRecord);
+    NtfsDumpFileAttributes(DeviceExt, VolumeRecord);
 
     /* Get volume name */
     Status = FindAttribute(DeviceExt, VolumeRecord, AttributeVolumeName, L"", 0, &AttrCtxt);
@@ -329,7 +352,12 @@ NtfsGetVolumeData(PDEVICE_OBJECT DeviceObject,
         VolumeNameU = L"\0";
     }
 
-    VolumeFcb = NtfsCreateFCB(VolumeNameU, DeviceExt);
+    if (NT_SUCCESS(Status))
+    {
+        ReleaseAttributeContext(AttrCtxt);
+    }
+
+    VolumeFcb = NtfsCreateFCB(VolumeNameU, NULL, DeviceExt);
     if (VolumeFcb == NULL)
     {
         DPRINT1("Failed allocating volume FCB\n");
@@ -359,8 +387,15 @@ NtfsGetVolumeData(PDEVICE_OBJECT DeviceObject,
         NtfsInfo->Flags = VolumeInfo->Flags;
     }
 
+    if (NT_SUCCESS(Status))
+    {
+        ReleaseAttributeContext(AttrCtxt);
+    }
+
     ExFreePool(VolumeRecord);
 
+    NtfsInfo->MftZoneReservation = NtfsQueryMftZoneReservation();
+
     return Status;
 }
 
@@ -431,7 +466,7 @@ NtfsMountVolume(PDEVICE_OBJECT DeviceObject,
 
     InitializeListHead(&Vcb->FcbListHead);
 
-    Fcb = NtfsCreateFCB(NULL, Vcb);
+    Fcb = NtfsCreateFCB(NULL, NULL, Vcb);
     if (Fcb == NULL)
     {
         Status = STATUS_INSUFFICIENT_RESOURCES;
@@ -470,11 +505,20 @@ NtfsMountVolume(PDEVICE_OBJECT DeviceObject,
 //    Fcb->Entry.ExtentLocationL = 0;
 //    Fcb->Entry.DataLengthL = DeviceExt->CdInfo.VolumeSpaceSize * BLOCKSIZE;
 
-    CcInitializeCacheMap(Vcb->StreamFileObject,
-                         (PCC_FILE_SIZES)(&Fcb->RFCB.AllocationSize),
-                         FALSE,
-                         &(NtfsGlobalData->CacheMgrCallbacks),
-                         Fcb);
+    _SEH2_TRY
+    {
+        CcInitializeCacheMap(Vcb->StreamFileObject,
+                             (PCC_FILE_SIZES)(&Fcb->RFCB.AllocationSize),
+                             TRUE,
+                             &(NtfsGlobalData->CacheMgrCallbacks),
+                             Fcb);
+    }
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+    {
+        Status = _SEH2_GetExceptionCode();
+        goto ByeBye;
+    }
+    _SEH2_END;
 
     ExInitializeResourceLite(&Vcb->DirResource);
 
@@ -489,6 +533,8 @@ NtfsMountVolume(PDEVICE_OBJECT DeviceObject,
                   Vcb->NtfsInfo.VolumeLabel,
                   Vcb->NtfsInfo.VolumeLabelLength);
 
+    FsRtlNotifyVolumeEvent(Vcb->StreamFileObject, FSRTL_VOLUME_MOUNT);
+
     Status = STATUS_SUCCESS;
 
 ByeBye:
@@ -499,7 +545,7 @@ ByeBye:
             ObDereferenceObject(Vcb->StreamFileObject);
 
         if (Fcb)
-            ExFreePool(Fcb);
+            NtfsDestroyFCB(Fcb);
 
         if (Ccb)
             ExFreePool(Ccb);
@@ -534,8 +580,10 @@ GetNfsVolumeData(PDEVICE_EXTENSION DeviceExt,
     PIO_STACK_LOCATION Stack;
     PNTFS_VOLUME_DATA_BUFFER DataBuffer;
     PNTFS_ATTR_RECORD Attribute;
+    FIND_ATTR_CONTXT Context;
+    NTSTATUS Status;
 
-    DataBuffer = (PNTFS_VOLUME_DATA_BUFFER)Irp->UserBuffer;
+    DataBuffer = (PNTFS_VOLUME_DATA_BUFFER)Irp->AssociatedIrp.SystemBuffer;
     Stack = IoGetCurrentIrpStackLocation(Irp);
 
     if (Stack->Parameters.FileSystemControl.OutputBufferLength < sizeof(NTFS_VOLUME_DATA_BUFFER) ||
@@ -547,7 +595,7 @@ GetNfsVolumeData(PDEVICE_EXTENSION DeviceExt,
 
     DataBuffer->VolumeSerialNumber.QuadPart = DeviceExt->NtfsInfo.SerialNumber;
     DataBuffer->NumberSectors.QuadPart = DeviceExt->NtfsInfo.SectorCount;
-    DataBuffer->TotalClusters.QuadPart = DeviceExt->NtfsInfo.SectorCount / DeviceExt->NtfsInfo.SectorsPerCluster;
+    DataBuffer->TotalClusters.QuadPart = DeviceExt->NtfsInfo.ClusterCount;
     DataBuffer->FreeClusters.QuadPart = NtfsGetFreeClusters(DeviceExt);
     DataBuffer->TotalReserved.QuadPart = 0LL; // FIXME
     DataBuffer->BytesPerSector = DeviceExt->NtfsInfo.BytesPerSector;
@@ -559,9 +607,8 @@ GetNfsVolumeData(PDEVICE_EXTENSION DeviceExt,
     DataBuffer->MftZoneStart.QuadPart = 0; // FIXME
     DataBuffer->MftZoneEnd.QuadPart = 0; // FIXME
 
-    Attribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)DeviceExt->MasterFileTable + DeviceExt->MasterFileTable->AttributeOffset);
-    while (Attribute < (PNTFS_ATTR_RECORD)((ULONG_PTR)DeviceExt->MasterFileTable + DeviceExt->MasterFileTable->BytesInUse) &&
-           Attribute->Type != AttributeEnd)
+    Status = FindFirstAttribute(&Context, DeviceExt, DeviceExt->MasterFileTable, FALSE, &Attribute);
+    while (NT_SUCCESS(Status))
     {
         if (Attribute->Type == AttributeData)
         {
@@ -571,8 +618,11 @@ GetNfsVolumeData(PDEVICE_EXTENSION DeviceExt,
             break;
         }
 
-        Attribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)Attribute + Attribute->Length);
+        Status = FindNextAttribute(&Context, &Attribute);
     }
+    FindCloseAttribute(&Context);
+
+    Irp->IoStatus.Information = sizeof(NTFS_VOLUME_DATA_BUFFER);
 
     if (Stack->Parameters.FileSystemControl.OutputBufferLength >= sizeof(NTFS_EXTENDED_VOLUME_DATA) + sizeof(NTFS_VOLUME_DATA_BUFFER))
     {
@@ -581,6 +631,7 @@ GetNfsVolumeData(PDEVICE_EXTENSION DeviceExt,
         ExtendedData->ByteCount = sizeof(NTFS_EXTENDED_VOLUME_DATA);
         ExtendedData->MajorVersion = DeviceExt->NtfsInfo.MajorVersion;
         ExtendedData->MinorVersion = DeviceExt->NtfsInfo.MinorVersion;
+        Irp->IoStatus.Information += sizeof(NTFS_EXTENDED_VOLUME_DATA);
     }
 
     return STATUS_SUCCESS;
@@ -656,6 +707,132 @@ GetNtfsFileRecord(PDEVICE_EXTENSION DeviceExt,
 }
 
 
+static
+NTSTATUS
+GetVolumeBitmap(PDEVICE_EXTENSION DeviceExt,
+                PIRP Irp)
+{
+    NTSTATUS Status = STATUS_SUCCESS;
+    PIO_STACK_LOCATION Stack;
+    PVOLUME_BITMAP_BUFFER BitmapBuffer;
+    LONGLONG StartingLcn;
+    PFILE_RECORD_HEADER BitmapRecord;
+    PNTFS_ATTR_CONTEXT DataContext;
+    ULONGLONG TotalClusters;
+    ULONGLONG ToCopy;
+    BOOLEAN Overflow = FALSE;
+
+    DPRINT1("GetVolumeBitmap(%p, %p)\n", DeviceExt, Irp);
+
+    Stack = IoGetCurrentIrpStackLocation(Irp);
+
+    if (Stack->Parameters.FileSystemControl.InputBufferLength < sizeof(STARTING_LCN_INPUT_BUFFER))
+    {
+        DPRINT1("Invalid input! %d\n", Stack->Parameters.FileSystemControl.InputBufferLength);
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    if (Stack->Parameters.FileSystemControl.OutputBufferLength < sizeof(VOLUME_BITMAP_BUFFER))
+    {
+        DPRINT1("Invalid output! %d\n", Stack->Parameters.FileSystemControl.OutputBufferLength);
+        return STATUS_BUFFER_TOO_SMALL;
+    }
+
+    BitmapBuffer = NtfsGetUserBuffer(Irp, FALSE);
+    if (Irp->RequestorMode == UserMode)
+    {
+        _SEH2_TRY
+        {
+            ProbeForRead(Stack->Parameters.FileSystemControl.Type3InputBuffer,
+                         Stack->Parameters.FileSystemControl.InputBufferLength,
+                         sizeof(CHAR));
+            ProbeForWrite(BitmapBuffer, Stack->Parameters.FileSystemControl.OutputBufferLength,
+                          sizeof(CHAR));
+        }
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+        {
+            Status = _SEH2_GetExceptionCode();
+        }
+        _SEH2_END;
+    }
+    else
+    {
+        if (Stack->Parameters.FileSystemControl.Type3InputBuffer == NULL ||
+            BitmapBuffer == NULL)
+        {
+            Status = STATUS_INVALID_PARAMETER;
+        }
+    }
+
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("Invalid buffer! %p %p\n", Stack->Parameters.FileSystemControl.Type3InputBuffer, BitmapBuffer);
+        return Status;
+    }
+
+    StartingLcn = ((PSTARTING_LCN_INPUT_BUFFER)Stack->Parameters.FileSystemControl.Type3InputBuffer)->StartingLcn.QuadPart;
+    if (StartingLcn > DeviceExt->NtfsInfo.ClusterCount)
+    {
+        DPRINT1("Requested bitmap start beyond partition end: %I64x %I64x\n", DeviceExt->NtfsInfo.ClusterCount, StartingLcn);
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    /* Round down to a multiple of 8 */
+    StartingLcn = StartingLcn & ~7;
+    TotalClusters = DeviceExt->NtfsInfo.ClusterCount - StartingLcn;
+    ToCopy = TotalClusters / 8;
+    if ((ToCopy + FIELD_OFFSET(VOLUME_BITMAP_BUFFER, Buffer)) > Stack->Parameters.FileSystemControl.OutputBufferLength)
+    {
+        DPRINT1("Buffer too small: %x, needed: %x\n", Stack->Parameters.FileSystemControl.OutputBufferLength, (ToCopy + FIELD_OFFSET(VOLUME_BITMAP_BUFFER, Buffer)));
+        Overflow = TRUE;
+        ToCopy = Stack->Parameters.FileSystemControl.OutputBufferLength - FIELD_OFFSET(VOLUME_BITMAP_BUFFER, Buffer);
+    }
+
+    BitmapRecord = ExAllocatePoolWithTag(NonPagedPool,
+                                         DeviceExt->NtfsInfo.BytesPerFileRecord,
+                                         TAG_NTFS);
+    if (BitmapRecord == NULL)
+    {
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    Status = ReadFileRecord(DeviceExt, NTFS_FILE_BITMAP, BitmapRecord);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("Failed reading volume bitmap: %lx\n", Status);
+        ExFreePoolWithTag(BitmapRecord, TAG_NTFS);
+        return Status;
+    }
+
+    Status = FindAttribute(DeviceExt, BitmapRecord, AttributeData, L"", 0, &DataContext);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("Failed find $DATA for bitmap: %lx\n", Status);
+        ExFreePoolWithTag(BitmapRecord, TAG_NTFS);
+        return Status;
+    }
+
+    BitmapBuffer->StartingLcn.QuadPart = StartingLcn;
+    BitmapBuffer->BitmapSize.QuadPart = ToCopy * 8;
+
+    Irp->IoStatus.Information = FIELD_OFFSET(VOLUME_BITMAP_BUFFER, Buffer);
+    _SEH2_TRY
+    {
+        Irp->IoStatus.Information += ReadAttribute(DeviceExt, DataContext, StartingLcn / 8, (PCHAR)BitmapBuffer->Buffer, ToCopy);
+        Status = (Overflow ? STATUS_BUFFER_OVERFLOW : STATUS_SUCCESS);
+    }
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+    {
+        Status = _SEH2_GetExceptionCode();
+    }
+    _SEH2_END;
+    ReleaseAttributeContext(DataContext);
+    ExFreePoolWithTag(BitmapRecord, TAG_NTFS);
+
+    return Status;
+}
+
+
 static
 NTSTATUS
 NtfsUserFsRequest(PDEVICE_OBJECT DeviceObject,
@@ -671,6 +848,27 @@ NtfsUserFsRequest(PDEVICE_OBJECT DeviceObject,
     DeviceExt = DeviceObject->DeviceExtension;
     switch (Stack->Parameters.FileSystemControl.FsControlCode)
     {
+        case FSCTL_CREATE_USN_JOURNAL:
+        case FSCTL_DELETE_USN_JOURNAL:
+        case FSCTL_ENUM_USN_DATA:
+        case FSCTL_EXTEND_VOLUME:
+        //case FSCTL_GET_RETRIEVAL_POINTER_BASE:
+        case FSCTL_GET_RETRIEVAL_POINTERS:
+        case FSCTL_LOCK_VOLUME:
+        //case FSCTL_LOOKUP_STREAM_FROM_CLUSTER:
+        case FSCTL_MARK_HANDLE:
+        case FSCTL_MOVE_FILE:
+        case FSCTL_QUERY_USN_JOURNAL:
+        case FSCTL_READ_FILE_USN_DATA:
+        case FSCTL_READ_USN_JOURNAL:
+        //case FSCTL_SHRINK_VOLUME:
+        case FSCTL_UNLOCK_VOLUME:
+        case FSCTL_WRITE_USN_CLOSE_RECORD:
+            UNIMPLEMENTED;
+            DPRINT1("Unimplemented user request: %x\n", Stack->Parameters.FileSystemControl.FsControlCode);
+            Status = STATUS_NOT_IMPLEMENTED;
+            break;
+
         case FSCTL_GET_NTFS_VOLUME_DATA:
             Status = GetNfsVolumeData(DeviceExt, Irp);
             break;
@@ -679,8 +877,12 @@ NtfsUserFsRequest(PDEVICE_OBJECT DeviceObject,
             Status = GetNtfsFileRecord(DeviceExt, Irp);
             break;
 
+        case FSCTL_GET_VOLUME_BITMAP:
+            Status = GetVolumeBitmap(DeviceExt, Irp);
+            break;
+
         default:
-            DPRINT1("Invalid user request: %x\n", Stack->Parameters.FileSystemControl.FsControlCode);
+            DPRINT("Invalid user request: %x\n", Stack->Parameters.FileSystemControl.FsControlCode);
             Status = STATUS_INVALID_DEVICE_REQUEST;
             break;
     }
@@ -690,20 +892,19 @@ NtfsUserFsRequest(PDEVICE_OBJECT DeviceObject,
 
 
 NTSTATUS
-NTAPI
-NtfsFsdFileSystemControl(PDEVICE_OBJECT DeviceObject,
-                         PIRP Irp)
+NtfsFileSystemControl(PNTFS_IRP_CONTEXT IrpContext)
 {
-    PIO_STACK_LOCATION Stack;
     NTSTATUS Status;
+    PIRP Irp;
+    PDEVICE_OBJECT DeviceObject;
 
     DPRINT1("NtfsFileSystemControl() called\n");
 
-    Stack = IoGetCurrentIrpStackLocation(Irp);
-
+    DeviceObject = IrpContext->DeviceObject;
+    Irp = IrpContext->Irp;
     Irp->IoStatus.Information = 0;
 
-    switch (Stack->MinorFunction)
+    switch (IrpContext->MinorFunction)
     {
         case IRP_MN_KERNEL_CALL:
             DPRINT1("NTFS: IRP_MN_USER_FS_REQUEST\n");
@@ -725,15 +926,11 @@ NtfsFsdFileSystemControl(PDEVICE_OBJECT DeviceObject,
             break;
 
         default:
-            DPRINT1("NTFS FSC: MinorFunction %d\n", Stack->MinorFunction);
+            DPRINT1("NTFS FSC: MinorFunction %d\n", IrpContext->MinorFunction);
             Status = STATUS_INVALID_DEVICE_REQUEST;
             break;
     }
 
-    Irp->IoStatus.Status = Status;
-
-    IoCompleteRequest(Irp, IO_NO_INCREMENT);
-
     return Status;
 }