3 * Copyright (C) 2002 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
19 * COPYRIGHT: See COPYING in the top level directory
20 * PROJECT: ReactOS kernel
21 * FILE: drivers/filesystems/ntfs/fsctl.c
22 * PURPOSE: NTFS filesystem driver
23 * PROGRAMMER: Eric Kohl
28 /* INCLUDES *****************************************************************/
37 /* FUNCTIONS ****************************************************************/
40 * FUNCTION: Tests if the device contains a filesystem that can be mounted
45 NtfsHasFileSystem(PDEVICE_OBJECT DeviceToMount
)
47 PARTITION_INFORMATION PartitionInfo
;
48 DISK_GEOMETRY DiskGeometry
;
49 ULONG ClusterSize
, Size
, k
;
50 PBOOT_SECTOR BootSector
;
53 DPRINT1("NtfsHasFileSystem() called\n");
55 Size
= sizeof(DISK_GEOMETRY
);
56 Status
= NtfsDeviceIoControl(DeviceToMount
,
57 IOCTL_DISK_GET_DRIVE_GEOMETRY
,
63 if (!NT_SUCCESS(Status
))
65 DPRINT1("NtfsDeviceIoControl() failed (Status %lx)\n", Status
);
69 if (DiskGeometry
.MediaType
== FixedMedia
)
71 /* We have found a hard disk */
72 Size
= sizeof(PARTITION_INFORMATION
);
73 Status
= NtfsDeviceIoControl(DeviceToMount
,
74 IOCTL_DISK_GET_PARTITION_INFO
,
80 if (!NT_SUCCESS(Status
))
82 DPRINT1("NtfsDeviceIoControl() failed (Status %lx)\n", Status
);
86 if (PartitionInfo
.PartitionType
!= PARTITION_IFS
)
88 DPRINT1("Invalid partition type\n");
89 return STATUS_UNRECOGNIZED_VOLUME
;
93 DPRINT1("BytesPerSector: %lu\n", DiskGeometry
.BytesPerSector
);
94 BootSector
= ExAllocatePoolWithTag(NonPagedPool
,
95 DiskGeometry
.BytesPerSector
,
97 if (BootSector
== NULL
)
99 return STATUS_INSUFFICIENT_RESOURCES
;
102 Status
= NtfsReadSectors(DeviceToMount
,
105 DiskGeometry
.BytesPerSector
,
108 if (!NT_SUCCESS(Status
))
114 * Check values of different fields. If those fields have not expected
115 * values, we fail, to avoid mounting partitions that Windows won't mount.
118 /* OEMID: this field must be NTFS */
119 if (RtlCompareMemory(BootSector
->OEMID
, "NTFS ", 8) != 8)
121 DPRINT1("Failed with NTFS-identifier: [%.8s]\n", BootSector
->OEMID
);
122 Status
= STATUS_UNRECOGNIZED_VOLUME
;
126 /* Unused0: this field must be COMPLETELY null */
127 for (k
= 0; k
< 7; k
++)
129 if (BootSector
->BPB
.Unused0
[k
] != 0)
131 DPRINT1("Failed in field Unused0: [%.7s]\n", BootSector
->BPB
.Unused0
);
132 Status
= STATUS_UNRECOGNIZED_VOLUME
;
137 /* Unused3: this field must be COMPLETELY null */
138 for (k
= 0; k
< 4; k
++)
140 if (BootSector
->BPB
.Unused3
[k
] != 0)
142 DPRINT1("Failed in field Unused3: [%.4s]\n", BootSector
->BPB
.Unused3
);
143 Status
= STATUS_UNRECOGNIZED_VOLUME
;
148 /* Check cluster size */
149 ClusterSize
= BootSector
->BPB
.BytesPerSector
* BootSector
->BPB
.SectorsPerCluster
;
150 if (ClusterSize
!= 512 && ClusterSize
!= 1024 &&
151 ClusterSize
!= 2048 && ClusterSize
!= 4096 &&
152 ClusterSize
!= 8192 && ClusterSize
!= 16384 &&
153 ClusterSize
!= 32768 && ClusterSize
!= 65536)
155 DPRINT1("Cluster size failed: %hu, %hu, %hu\n",
156 BootSector
->BPB
.BytesPerSector
,
157 BootSector
->BPB
.SectorsPerCluster
,
159 Status
= STATUS_UNRECOGNIZED_VOLUME
;
164 ExFreePool(BootSector
);
172 NtfsQueryMftZoneReservation(VOID
)
174 ULONG ZoneReservation
= 1;
175 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
177 RtlZeroMemory(QueryTable
, sizeof(QueryTable
));
178 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
179 QueryTable
[0].Name
= L
"NtfsMftZoneReservation";
180 QueryTable
[0].EntryContext
= &ZoneReservation
;
182 RtlQueryRegistryValues(RTL_REGISTRY_CONTROL
,
188 return ZoneReservation
;
194 NtfsGetVolumeData(PDEVICE_OBJECT DeviceObject
,
195 PDEVICE_EXTENSION DeviceExt
)
197 DISK_GEOMETRY DiskGeometry
;
198 PFILE_RECORD_HEADER VolumeRecord
;
199 PVOLINFO_ATTRIBUTE VolumeInfo
;
200 PBOOT_SECTOR BootSector
;
202 PNTFS_INFO NtfsInfo
= &DeviceExt
->NtfsInfo
;
204 PNTFS_ATTR_CONTEXT AttrCtxt
;
205 PNTFS_ATTR_RECORD Attribute
;
209 DPRINT("NtfsGetVolumeData() called\n");
211 Size
= sizeof(DISK_GEOMETRY
);
212 Status
= NtfsDeviceIoControl(DeviceObject
,
213 IOCTL_DISK_GET_DRIVE_GEOMETRY
,
219 if (!NT_SUCCESS(Status
))
221 DPRINT("NtfsDeviceIoControl() failed (Status %lx)\n", Status
);
225 DPRINT("BytesPerSector: %lu\n", DiskGeometry
.BytesPerSector
);
226 BootSector
= ExAllocatePoolWithTag(NonPagedPool
,
227 DiskGeometry
.BytesPerSector
,
229 if (BootSector
== NULL
)
231 return STATUS_INSUFFICIENT_RESOURCES
;
234 Status
= NtfsReadSectors(DeviceObject
,
235 0, /* Partition boot sector */
237 DiskGeometry
.BytesPerSector
,
240 if (!NT_SUCCESS(Status
))
242 ExFreePool(BootSector
);
246 /* Read data from the bootsector */
247 NtfsInfo
->BytesPerSector
= BootSector
->BPB
.BytesPerSector
;
248 NtfsInfo
->SectorsPerCluster
= BootSector
->BPB
.SectorsPerCluster
;
249 NtfsInfo
->BytesPerCluster
= BootSector
->BPB
.BytesPerSector
* BootSector
->BPB
.SectorsPerCluster
;
250 NtfsInfo
->SectorCount
= BootSector
->EBPB
.SectorCount
;
251 NtfsInfo
->ClusterCount
= DeviceExt
->NtfsInfo
.SectorCount
/ (ULONGLONG
)DeviceExt
->NtfsInfo
.SectorsPerCluster
;
253 NtfsInfo
->MftStart
.QuadPart
= BootSector
->EBPB
.MftLocation
;
254 NtfsInfo
->MftMirrStart
.QuadPart
= BootSector
->EBPB
.MftMirrLocation
;
255 NtfsInfo
->SerialNumber
= BootSector
->EBPB
.SerialNumber
;
256 if (BootSector
->EBPB
.ClustersPerMftRecord
> 0)
257 NtfsInfo
->BytesPerFileRecord
= BootSector
->EBPB
.ClustersPerMftRecord
* NtfsInfo
->BytesPerCluster
;
259 NtfsInfo
->BytesPerFileRecord
= 1 << (-BootSector
->EBPB
.ClustersPerMftRecord
);
260 if (BootSector
->EBPB
.ClustersPerIndexRecord
> 0)
261 NtfsInfo
->BytesPerIndexRecord
= BootSector
->EBPB
.ClustersPerIndexRecord
* NtfsInfo
->BytesPerCluster
;
263 NtfsInfo
->BytesPerIndexRecord
= 1 << (-BootSector
->EBPB
.ClustersPerIndexRecord
);
265 DPRINT("Boot sector information:\n");
266 DPRINT(" BytesPerSector: %hu\n", BootSector
->BPB
.BytesPerSector
);
267 DPRINT(" SectorsPerCluster: %hu\n", BootSector
->BPB
.SectorsPerCluster
);
268 DPRINT(" SectorCount: %I64u\n", BootSector
->EBPB
.SectorCount
);
269 DPRINT(" MftStart: %I64u\n", BootSector
->EBPB
.MftLocation
);
270 DPRINT(" MftMirrStart: %I64u\n", BootSector
->EBPB
.MftMirrLocation
);
271 DPRINT(" ClustersPerMftRecord: %lx\n", BootSector
->EBPB
.ClustersPerMftRecord
);
272 DPRINT(" ClustersPerIndexRecord: %lx\n", BootSector
->EBPB
.ClustersPerIndexRecord
);
273 DPRINT(" SerialNumber: %I64x\n", BootSector
->EBPB
.SerialNumber
);
275 ExFreePool(BootSector
);
277 ExInitializeNPagedLookasideList(&DeviceExt
->FileRecLookasideList
,
278 NULL
, NULL
, 0, NtfsInfo
->BytesPerFileRecord
, TAG_FILE_REC
, 0);
280 DeviceExt
->MasterFileTable
= ExAllocateFromNPagedLookasideList(&DeviceExt
->FileRecLookasideList
);
281 if (DeviceExt
->MasterFileTable
== NULL
)
283 ExDeleteNPagedLookasideList(&DeviceExt
->FileRecLookasideList
);
284 return STATUS_INSUFFICIENT_RESOURCES
;
287 Status
= NtfsReadSectors(DeviceObject
,
288 NtfsInfo
->MftStart
.u
.LowPart
* NtfsInfo
->SectorsPerCluster
,
289 NtfsInfo
->BytesPerFileRecord
/ NtfsInfo
->BytesPerSector
,
290 NtfsInfo
->BytesPerSector
,
291 (PVOID
)DeviceExt
->MasterFileTable
,
293 if (!NT_SUCCESS(Status
))
295 DPRINT1("Failed reading MFT.\n");
296 ExFreeToNPagedLookasideList(&DeviceExt
->FileRecLookasideList
, DeviceExt
->MasterFileTable
);
297 ExDeleteNPagedLookasideList(&DeviceExt
->FileRecLookasideList
);
301 Status
= FindAttribute(DeviceExt
,
302 DeviceExt
->MasterFileTable
,
306 &DeviceExt
->MFTContext
,
307 &DeviceExt
->MftDataOffset
);
308 if (!NT_SUCCESS(Status
))
310 DPRINT1("Can't find data attribute for Master File Table.\n");
311 ExFreeToNPagedLookasideList(&DeviceExt
->FileRecLookasideList
, DeviceExt
->MasterFileTable
);
312 ExDeleteNPagedLookasideList(&DeviceExt
->FileRecLookasideList
);
316 VolumeRecord
= ExAllocateFromNPagedLookasideList(&DeviceExt
->FileRecLookasideList
);
317 if (VolumeRecord
== NULL
)
319 DPRINT1("Allocation failed for volume record\n");
320 ExFreeToNPagedLookasideList(&DeviceExt
->FileRecLookasideList
, DeviceExt
->MasterFileTable
);
321 ExDeleteNPagedLookasideList(&DeviceExt
->FileRecLookasideList
);
322 return STATUS_INSUFFICIENT_RESOURCES
;
325 /* Read Volume File (MFT index 3) */
326 DeviceExt
->StorageDevice
= DeviceObject
;
327 Status
= ReadFileRecord(DeviceExt
,
330 if (!NT_SUCCESS(Status
))
332 DPRINT1("Failed reading volume file\n");
333 ExFreeToNPagedLookasideList(&DeviceExt
->FileRecLookasideList
, VolumeRecord
);
334 ExFreeToNPagedLookasideList(&DeviceExt
->FileRecLookasideList
, DeviceExt
->MasterFileTable
);
335 ExDeleteNPagedLookasideList(&DeviceExt
->FileRecLookasideList
);
339 /* Enumerate attributes */
340 NtfsDumpFileAttributes(DeviceExt
, DeviceExt
->MasterFileTable
);
342 /* Enumerate attributes */
343 NtfsDumpFileAttributes(DeviceExt
, VolumeRecord
);
345 /* Get volume name */
346 Status
= FindAttribute(DeviceExt
, VolumeRecord
, AttributeVolumeName
, L
"", 0, &AttrCtxt
, NULL
);
348 if (NT_SUCCESS(Status
) && AttrCtxt
->pRecord
->Resident
.ValueLength
!= 0)
350 Attribute
= AttrCtxt
->pRecord
;
351 DPRINT("Data length %lu\n", AttributeDataLength(Attribute
));
352 NtfsInfo
->VolumeLabelLength
=
353 min (Attribute
->Resident
.ValueLength
, MAXIMUM_VOLUME_LABEL_LENGTH
);
354 RtlCopyMemory(NtfsInfo
->VolumeLabel
,
355 (PVOID
)((ULONG_PTR
)Attribute
+ Attribute
->Resident
.ValueOffset
),
356 NtfsInfo
->VolumeLabelLength
);
357 VolumeNameU
= NtfsInfo
->VolumeLabel
;
361 NtfsInfo
->VolumeLabelLength
= 0;
365 if (NT_SUCCESS(Status
))
367 ReleaseAttributeContext(AttrCtxt
);
370 VolumeFcb
= NtfsCreateFCB(VolumeNameU
, NULL
, DeviceExt
);
371 if (VolumeFcb
== NULL
)
373 DPRINT1("Failed allocating volume FCB\n");
374 ExFreeToNPagedLookasideList(&DeviceExt
->FileRecLookasideList
, VolumeRecord
);
375 ExFreeToNPagedLookasideList(&DeviceExt
->FileRecLookasideList
, DeviceExt
->MasterFileTable
);
376 ExDeleteNPagedLookasideList(&DeviceExt
->FileRecLookasideList
);
377 return STATUS_INSUFFICIENT_RESOURCES
;
380 VolumeFcb
->Flags
= FCB_IS_VOLUME
;
381 VolumeFcb
->RFCB
.FileSize
.QuadPart
= DeviceExt
->NtfsInfo
.SectorCount
* DeviceExt
->NtfsInfo
.BytesPerSector
;
382 VolumeFcb
->RFCB
.ValidDataLength
= VolumeFcb
->RFCB
.FileSize
;
383 VolumeFcb
->RFCB
.AllocationSize
= VolumeFcb
->RFCB
.FileSize
;
384 VolumeFcb
->MFTIndex
= 0;
385 DeviceExt
->VolumeFcb
= VolumeFcb
;
387 /* Get volume information */
388 Status
= FindAttribute(DeviceExt
, VolumeRecord
, AttributeVolumeInformation
, L
"", 0, &AttrCtxt
, NULL
);
390 if (NT_SUCCESS(Status
) && AttrCtxt
->pRecord
->Resident
.ValueLength
!= 0)
392 Attribute
= AttrCtxt
->pRecord
;
393 DPRINT("Data length %lu\n", AttributeDataLength (Attribute
));
394 VolumeInfo
= (PVOID
)((ULONG_PTR
)Attribute
+ Attribute
->Resident
.ValueOffset
);
396 NtfsInfo
->MajorVersion
= VolumeInfo
->MajorVersion
;
397 NtfsInfo
->MinorVersion
= VolumeInfo
->MinorVersion
;
398 NtfsInfo
->Flags
= VolumeInfo
->Flags
;
401 if (NT_SUCCESS(Status
))
403 ReleaseAttributeContext(AttrCtxt
);
406 ExFreeToNPagedLookasideList(&DeviceExt
->FileRecLookasideList
, VolumeRecord
);
408 NtfsInfo
->MftZoneReservation
= NtfsQueryMftZoneReservation();
416 NtfsMountVolume(PDEVICE_OBJECT DeviceObject
,
419 PDEVICE_OBJECT NewDeviceObject
= NULL
;
420 PDEVICE_OBJECT DeviceToMount
;
421 PIO_STACK_LOCATION Stack
;
422 PNTFS_FCB Fcb
= NULL
;
423 PNTFS_CCB Ccb
= NULL
;
424 PNTFS_VCB Vcb
= NULL
;
426 BOOLEAN Lookaside
= FALSE
;
428 DPRINT1("NtfsMountVolume() called\n");
430 if (DeviceObject
!= NtfsGlobalData
->DeviceObject
)
432 Status
= STATUS_INVALID_DEVICE_REQUEST
;
436 Stack
= IoGetCurrentIrpStackLocation(Irp
);
437 DeviceToMount
= Stack
->Parameters
.MountVolume
.DeviceObject
;
439 Status
= NtfsHasFileSystem(DeviceToMount
);
440 if (!NT_SUCCESS(Status
))
445 Status
= IoCreateDevice(NtfsGlobalData
->DriverObject
,
446 sizeof(DEVICE_EXTENSION
),
448 FILE_DEVICE_DISK_FILE_SYSTEM
,
452 if (!NT_SUCCESS(Status
))
457 NewDeviceObject
->Flags
|= DO_DIRECT_IO
;
458 Vcb
= (PVOID
)NewDeviceObject
->DeviceExtension
;
459 RtlZeroMemory(Vcb
, sizeof(NTFS_VCB
));
461 Vcb
->Identifier
.Type
= NTFS_TYPE_VCB
;
462 Vcb
->Identifier
.Size
= sizeof(NTFS_TYPE_VCB
);
464 Status
= NtfsGetVolumeData(DeviceToMount
,
466 if (!NT_SUCCESS(Status
))
469 NewDeviceObject
->Vpb
= DeviceToMount
->Vpb
;
471 Vcb
->StorageDevice
= DeviceToMount
;
472 Vcb
->StorageDevice
->Vpb
->DeviceObject
= NewDeviceObject
;
473 Vcb
->StorageDevice
->Vpb
->RealDevice
= Vcb
->StorageDevice
;
474 Vcb
->StorageDevice
->Vpb
->Flags
|= VPB_MOUNTED
;
475 NewDeviceObject
->StackSize
= Vcb
->StorageDevice
->StackSize
+ 1;
476 NewDeviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
478 Vcb
->StreamFileObject
= IoCreateStreamFileObject(NULL
,
481 InitializeListHead(&Vcb
->FcbListHead
);
483 Fcb
= NtfsCreateFCB(NULL
, NULL
, Vcb
);
486 Status
= STATUS_INSUFFICIENT_RESOURCES
;
490 Ccb
= ExAllocatePoolWithTag(NonPagedPool
,
495 Status
= STATUS_INSUFFICIENT_RESOURCES
;
499 RtlZeroMemory(Ccb
, sizeof(NTFS_CCB
));
501 Ccb
->Identifier
.Type
= NTFS_TYPE_CCB
;
502 Ccb
->Identifier
.Size
= sizeof(NTFS_TYPE_CCB
);
504 Vcb
->StreamFileObject
->FsContext
= Fcb
;
505 Vcb
->StreamFileObject
->FsContext2
= Ccb
;
506 Vcb
->StreamFileObject
->SectionObjectPointer
= &Fcb
->SectionObjectPointers
;
507 Vcb
->StreamFileObject
->PrivateCacheMap
= NULL
;
508 Vcb
->StreamFileObject
->Vpb
= Vcb
->Vpb
;
509 Ccb
->PtrFileObject
= Vcb
->StreamFileObject
;
510 Fcb
->FileObject
= Vcb
->StreamFileObject
;
511 Fcb
->Vcb
= (PDEVICE_EXTENSION
)Vcb
->StorageDevice
;
513 Fcb
->Flags
= FCB_IS_VOLUME_STREAM
;
515 Fcb
->RFCB
.FileSize
.QuadPart
= Vcb
->NtfsInfo
.SectorCount
* Vcb
->NtfsInfo
.BytesPerSector
;
516 Fcb
->RFCB
.ValidDataLength
.QuadPart
= Vcb
->NtfsInfo
.SectorCount
* Vcb
->NtfsInfo
.BytesPerSector
;
517 Fcb
->RFCB
.AllocationSize
.QuadPart
= Vcb
->NtfsInfo
.SectorCount
* Vcb
->NtfsInfo
.BytesPerSector
; /* Correct? */
519 // Fcb->Entry.ExtentLocationL = 0;
520 // Fcb->Entry.DataLengthL = DeviceExt->CdInfo.VolumeSpaceSize * BLOCKSIZE;
524 CcInitializeCacheMap(Vcb
->StreamFileObject
,
525 (PCC_FILE_SIZES
)(&Fcb
->RFCB
.AllocationSize
),
527 &(NtfsGlobalData
->CacheMgrCallbacks
),
530 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
532 Status
= _SEH2_GetExceptionCode();
537 ExInitializeResourceLite(&Vcb
->DirResource
);
539 KeInitializeSpinLock(&Vcb
->FcbListLock
);
541 /* Get serial number */
542 NewDeviceObject
->Vpb
->SerialNumber
= Vcb
->NtfsInfo
.SerialNumber
;
544 /* Get volume label */
545 NewDeviceObject
->Vpb
->VolumeLabelLength
= Vcb
->NtfsInfo
.VolumeLabelLength
;
546 RtlCopyMemory(NewDeviceObject
->Vpb
->VolumeLabel
,
547 Vcb
->NtfsInfo
.VolumeLabel
,
548 Vcb
->NtfsInfo
.VolumeLabelLength
);
550 FsRtlNotifyVolumeEvent(Vcb
->StreamFileObject
, FSRTL_VOLUME_MOUNT
);
552 Status
= STATUS_SUCCESS
;
555 if (!NT_SUCCESS(Status
))
558 if (Vcb
&& Vcb
->StreamFileObject
)
559 ObDereferenceObject(Vcb
->StreamFileObject
);
568 IoDeleteDevice(NewDeviceObject
);
571 ExDeleteNPagedLookasideList(&Vcb
->FileRecLookasideList
);
574 DPRINT("NtfsMountVolume() done (Status: %lx)\n", Status
);
582 NtfsVerifyVolume(PDEVICE_OBJECT DeviceObject
,
585 UNREFERENCED_PARAMETER(DeviceObject
);
586 UNREFERENCED_PARAMETER(Irp
);
587 DPRINT1("NtfsVerifyVolume() called\n");
588 return STATUS_WRONG_VOLUME
;
594 GetNfsVolumeData(PDEVICE_EXTENSION DeviceExt
,
597 PIO_STACK_LOCATION Stack
;
598 PNTFS_VOLUME_DATA_BUFFER DataBuffer
;
599 PNTFS_ATTR_RECORD Attribute
;
600 FIND_ATTR_CONTXT Context
;
603 DataBuffer
= (PNTFS_VOLUME_DATA_BUFFER
)Irp
->AssociatedIrp
.SystemBuffer
;
604 Stack
= IoGetCurrentIrpStackLocation(Irp
);
606 if (Stack
->Parameters
.FileSystemControl
.OutputBufferLength
< sizeof(NTFS_VOLUME_DATA_BUFFER
) ||
607 Irp
->UserBuffer
== NULL
)
609 DPRINT1("Invalid output! %d %p\n", Stack
->Parameters
.FileSystemControl
.OutputBufferLength
, Irp
->UserBuffer
);
610 return STATUS_INVALID_PARAMETER
;
613 DataBuffer
->VolumeSerialNumber
.QuadPart
= DeviceExt
->NtfsInfo
.SerialNumber
;
614 DataBuffer
->NumberSectors
.QuadPart
= DeviceExt
->NtfsInfo
.SectorCount
;
615 DataBuffer
->TotalClusters
.QuadPart
= DeviceExt
->NtfsInfo
.ClusterCount
;
616 DataBuffer
->FreeClusters
.QuadPart
= NtfsGetFreeClusters(DeviceExt
);
617 DataBuffer
->TotalReserved
.QuadPart
= 0LL; // FIXME
618 DataBuffer
->BytesPerSector
= DeviceExt
->NtfsInfo
.BytesPerSector
;
619 DataBuffer
->BytesPerCluster
= DeviceExt
->NtfsInfo
.BytesPerCluster
;
620 DataBuffer
->BytesPerFileRecordSegment
= DeviceExt
->NtfsInfo
.BytesPerFileRecord
;
621 DataBuffer
->ClustersPerFileRecordSegment
= DeviceExt
->NtfsInfo
.BytesPerFileRecord
/ DeviceExt
->NtfsInfo
.BytesPerCluster
;
622 DataBuffer
->MftStartLcn
.QuadPart
= DeviceExt
->NtfsInfo
.MftStart
.QuadPart
;
623 DataBuffer
->Mft2StartLcn
.QuadPart
= DeviceExt
->NtfsInfo
.MftMirrStart
.QuadPart
;
624 DataBuffer
->MftZoneStart
.QuadPart
= 0; // FIXME
625 DataBuffer
->MftZoneEnd
.QuadPart
= 0; // FIXME
627 Status
= FindFirstAttribute(&Context
, DeviceExt
, DeviceExt
->MasterFileTable
, FALSE
, &Attribute
);
628 while (NT_SUCCESS(Status
))
630 if (Attribute
->Type
== AttributeData
)
632 ASSERT(Attribute
->IsNonResident
);
633 DataBuffer
->MftValidDataLength
.QuadPart
= Attribute
->NonResident
.DataSize
;
638 Status
= FindNextAttribute(&Context
, &Attribute
);
640 FindCloseAttribute(&Context
);
642 Irp
->IoStatus
.Information
= sizeof(NTFS_VOLUME_DATA_BUFFER
);
644 if (Stack
->Parameters
.FileSystemControl
.OutputBufferLength
>= sizeof(NTFS_EXTENDED_VOLUME_DATA
) + sizeof(NTFS_VOLUME_DATA_BUFFER
))
646 PNTFS_EXTENDED_VOLUME_DATA ExtendedData
= (PNTFS_EXTENDED_VOLUME_DATA
)((ULONG_PTR
)Irp
->UserBuffer
+ sizeof(NTFS_VOLUME_DATA_BUFFER
));
648 ExtendedData
->ByteCount
= sizeof(NTFS_EXTENDED_VOLUME_DATA
);
649 ExtendedData
->MajorVersion
= DeviceExt
->NtfsInfo
.MajorVersion
;
650 ExtendedData
->MinorVersion
= DeviceExt
->NtfsInfo
.MinorVersion
;
651 Irp
->IoStatus
.Information
+= sizeof(NTFS_EXTENDED_VOLUME_DATA
);
654 return STATUS_SUCCESS
;
660 GetNtfsFileRecord(PDEVICE_EXTENSION DeviceExt
,
664 PIO_STACK_LOCATION Stack
;
665 PNTFS_FILE_RECORD_INPUT_BUFFER InputBuffer
;
666 PFILE_RECORD_HEADER FileRecord
;
667 PNTFS_FILE_RECORD_OUTPUT_BUFFER OutputBuffer
;
670 Stack
= IoGetCurrentIrpStackLocation(Irp
);
672 if (Stack
->Parameters
.FileSystemControl
.InputBufferLength
< sizeof(NTFS_FILE_RECORD_INPUT_BUFFER
) ||
673 Irp
->AssociatedIrp
.SystemBuffer
== NULL
)
675 DPRINT1("Invalid input! %d %p\n", Stack
->Parameters
.FileSystemControl
.InputBufferLength
, Irp
->AssociatedIrp
.SystemBuffer
);
676 return STATUS_INVALID_PARAMETER
;
679 if (Stack
->Parameters
.FileSystemControl
.OutputBufferLength
< (FIELD_OFFSET(NTFS_FILE_RECORD_OUTPUT_BUFFER
, FileRecordBuffer
) + DeviceExt
->NtfsInfo
.BytesPerFileRecord
) ||
680 Irp
->AssociatedIrp
.SystemBuffer
== NULL
)
682 DPRINT1("Invalid output! %d %p\n", Stack
->Parameters
.FileSystemControl
.OutputBufferLength
, Irp
->AssociatedIrp
.SystemBuffer
);
683 return STATUS_BUFFER_TOO_SMALL
;
686 FileRecord
= ExAllocateFromNPagedLookasideList(&DeviceExt
->FileRecLookasideList
);
687 if (FileRecord
== NULL
)
689 return STATUS_INSUFFICIENT_RESOURCES
;
692 InputBuffer
= (PNTFS_FILE_RECORD_INPUT_BUFFER
)Irp
->AssociatedIrp
.SystemBuffer
;
694 MFTRecord
= InputBuffer
->FileReferenceNumber
.QuadPart
;
695 DPRINT1("Requesting: %I64x\n", MFTRecord
);
699 Status
= ReadFileRecord(DeviceExt
, MFTRecord
, FileRecord
);
700 if (NT_SUCCESS(Status
))
702 if (FileRecord
->Flags
& FRH_IN_USE
)
711 DPRINT1("Returning: %I64x\n", MFTRecord
);
712 OutputBuffer
= (PNTFS_FILE_RECORD_OUTPUT_BUFFER
)Irp
->AssociatedIrp
.SystemBuffer
;
713 OutputBuffer
->FileReferenceNumber
.QuadPart
= MFTRecord
;
714 OutputBuffer
->FileRecordLength
= DeviceExt
->NtfsInfo
.BytesPerFileRecord
;
715 RtlCopyMemory(OutputBuffer
->FileRecordBuffer
, FileRecord
, DeviceExt
->NtfsInfo
.BytesPerFileRecord
);
717 ExFreeToNPagedLookasideList(&DeviceExt
->FileRecLookasideList
, FileRecord
);
719 Irp
->IoStatus
.Information
= FIELD_OFFSET(NTFS_FILE_RECORD_OUTPUT_BUFFER
, FileRecordBuffer
) + DeviceExt
->NtfsInfo
.BytesPerFileRecord
;
721 return STATUS_SUCCESS
;
727 GetVolumeBitmap(PDEVICE_EXTENSION DeviceExt
,
730 NTSTATUS Status
= STATUS_SUCCESS
;
731 PIO_STACK_LOCATION Stack
;
732 PVOLUME_BITMAP_BUFFER BitmapBuffer
;
733 LONGLONG StartingLcn
;
734 PFILE_RECORD_HEADER BitmapRecord
;
735 PNTFS_ATTR_CONTEXT DataContext
;
736 ULONGLONG TotalClusters
;
738 BOOLEAN Overflow
= FALSE
;
740 DPRINT1("GetVolumeBitmap(%p, %p)\n", DeviceExt
, Irp
);
742 Stack
= IoGetCurrentIrpStackLocation(Irp
);
744 if (Stack
->Parameters
.FileSystemControl
.InputBufferLength
< sizeof(STARTING_LCN_INPUT_BUFFER
))
746 DPRINT1("Invalid input! %d\n", Stack
->Parameters
.FileSystemControl
.InputBufferLength
);
747 return STATUS_INVALID_PARAMETER
;
750 if (Stack
->Parameters
.FileSystemControl
.OutputBufferLength
< sizeof(VOLUME_BITMAP_BUFFER
))
752 DPRINT1("Invalid output! %d\n", Stack
->Parameters
.FileSystemControl
.OutputBufferLength
);
753 return STATUS_BUFFER_TOO_SMALL
;
756 BitmapBuffer
= NtfsGetUserBuffer(Irp
, FALSE
);
757 if (Irp
->RequestorMode
== UserMode
)
761 ProbeForRead(Stack
->Parameters
.FileSystemControl
.Type3InputBuffer
,
762 Stack
->Parameters
.FileSystemControl
.InputBufferLength
,
764 ProbeForWrite(BitmapBuffer
, Stack
->Parameters
.FileSystemControl
.OutputBufferLength
,
767 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
769 Status
= _SEH2_GetExceptionCode();
775 if (Stack
->Parameters
.FileSystemControl
.Type3InputBuffer
== NULL
||
776 BitmapBuffer
== NULL
)
778 Status
= STATUS_INVALID_PARAMETER
;
782 if (!NT_SUCCESS(Status
))
784 DPRINT1("Invalid buffer! %p %p\n", Stack
->Parameters
.FileSystemControl
.Type3InputBuffer
, BitmapBuffer
);
788 StartingLcn
= ((PSTARTING_LCN_INPUT_BUFFER
)Stack
->Parameters
.FileSystemControl
.Type3InputBuffer
)->StartingLcn
.QuadPart
;
789 if (StartingLcn
> DeviceExt
->NtfsInfo
.ClusterCount
)
791 DPRINT1("Requested bitmap start beyond partition end: %I64x %I64x\n", DeviceExt
->NtfsInfo
.ClusterCount
, StartingLcn
);
792 return STATUS_INVALID_PARAMETER
;
795 /* Round down to a multiple of 8 */
796 StartingLcn
= StartingLcn
& ~7;
797 TotalClusters
= DeviceExt
->NtfsInfo
.ClusterCount
- StartingLcn
;
798 ToCopy
= TotalClusters
/ 8;
799 if ((ToCopy
+ FIELD_OFFSET(VOLUME_BITMAP_BUFFER
, Buffer
)) > Stack
->Parameters
.FileSystemControl
.OutputBufferLength
)
801 DPRINT1("Buffer too small: %x, needed: %x\n", Stack
->Parameters
.FileSystemControl
.OutputBufferLength
, (ToCopy
+ FIELD_OFFSET(VOLUME_BITMAP_BUFFER
, Buffer
)));
803 ToCopy
= Stack
->Parameters
.FileSystemControl
.OutputBufferLength
- FIELD_OFFSET(VOLUME_BITMAP_BUFFER
, Buffer
);
806 BitmapRecord
= ExAllocateFromNPagedLookasideList(&DeviceExt
->FileRecLookasideList
);
807 if (BitmapRecord
== NULL
)
809 return STATUS_INSUFFICIENT_RESOURCES
;
812 Status
= ReadFileRecord(DeviceExt
, NTFS_FILE_BITMAP
, BitmapRecord
);
813 if (!NT_SUCCESS(Status
))
815 DPRINT1("Failed reading volume bitmap: %lx\n", Status
);
816 ExFreeToNPagedLookasideList(&DeviceExt
->FileRecLookasideList
, BitmapRecord
);
820 Status
= FindAttribute(DeviceExt
, BitmapRecord
, AttributeData
, L
"", 0, &DataContext
, NULL
);
821 if (!NT_SUCCESS(Status
))
823 DPRINT1("Failed find $DATA for bitmap: %lx\n", Status
);
824 ExFreeToNPagedLookasideList(&DeviceExt
->FileRecLookasideList
, BitmapRecord
);
828 BitmapBuffer
->StartingLcn
.QuadPart
= StartingLcn
;
829 BitmapBuffer
->BitmapSize
.QuadPart
= ToCopy
* 8;
831 Irp
->IoStatus
.Information
= FIELD_OFFSET(VOLUME_BITMAP_BUFFER
, Buffer
);
834 Irp
->IoStatus
.Information
+= ReadAttribute(DeviceExt
, DataContext
, StartingLcn
/ 8, (PCHAR
)BitmapBuffer
->Buffer
, ToCopy
);
835 Status
= (Overflow
? STATUS_BUFFER_OVERFLOW
: STATUS_SUCCESS
);
837 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
839 Status
= _SEH2_GetExceptionCode();
842 ReleaseAttributeContext(DataContext
);
843 ExFreeToNPagedLookasideList(&DeviceExt
->FileRecLookasideList
, BitmapRecord
);
851 LockOrUnlockVolume(PDEVICE_EXTENSION DeviceExt
,
855 PFILE_OBJECT FileObject
;
857 PIO_STACK_LOCATION Stack
;
859 DPRINT("LockOrUnlockVolume(%p, %p, %d)\n", DeviceExt
, Irp
, Lock
);
861 Stack
= IoGetCurrentIrpStackLocation(Irp
);
862 FileObject
= Stack
->FileObject
;
863 Fcb
= FileObject
->FsContext
;
865 /* Only allow locking with the volume open */
866 if (!(Fcb
->Flags
& FCB_IS_VOLUME
))
868 return STATUS_ACCESS_DENIED
;
871 /* Bail out if it's already in the demanded state */
872 if (((DeviceExt
->Flags
& VCB_VOLUME_LOCKED
) && Lock
) ||
873 (!(DeviceExt
->Flags
& VCB_VOLUME_LOCKED
) && !Lock
))
875 return STATUS_ACCESS_DENIED
;
878 /* Deny locking if we're not alone */
879 if (Lock
&& DeviceExt
->OpenHandleCount
!= 1)
881 return STATUS_ACCESS_DENIED
;
884 /* Finally, proceed */
887 DeviceExt
->Flags
|= VCB_VOLUME_LOCKED
;
891 DeviceExt
->Flags
&= ~VCB_VOLUME_LOCKED
;
894 return STATUS_SUCCESS
;
900 NtfsUserFsRequest(PDEVICE_OBJECT DeviceObject
,
904 PIO_STACK_LOCATION Stack
;
905 PDEVICE_EXTENSION DeviceExt
;
907 DPRINT1("NtfsUserFsRequest(%p, %p)\n", DeviceObject
, Irp
);
909 Stack
= IoGetCurrentIrpStackLocation(Irp
);
910 DeviceExt
= DeviceObject
->DeviceExtension
;
911 switch (Stack
->Parameters
.FileSystemControl
.FsControlCode
)
913 case FSCTL_CREATE_USN_JOURNAL
:
914 case FSCTL_DELETE_USN_JOURNAL
:
915 case FSCTL_ENUM_USN_DATA
:
916 case FSCTL_EXTEND_VOLUME
:
917 //case FSCTL_GET_RETRIEVAL_POINTER_BASE:
918 case FSCTL_GET_RETRIEVAL_POINTERS
:
919 //case FSCTL_LOOKUP_STREAM_FROM_CLUSTER:
920 case FSCTL_MARK_HANDLE
:
921 case FSCTL_MOVE_FILE
:
922 case FSCTL_QUERY_USN_JOURNAL
:
923 case FSCTL_READ_FILE_USN_DATA
:
924 case FSCTL_READ_USN_JOURNAL
:
925 //case FSCTL_SHRINK_VOLUME:
926 case FSCTL_WRITE_USN_CLOSE_RECORD
:
928 DPRINT1("Unimplemented user request: %x\n", Stack
->Parameters
.FileSystemControl
.FsControlCode
);
929 Status
= STATUS_NOT_IMPLEMENTED
;
932 case FSCTL_LOCK_VOLUME
:
933 Status
= LockOrUnlockVolume(DeviceExt
, Irp
, TRUE
);
936 case FSCTL_UNLOCK_VOLUME
:
937 Status
= LockOrUnlockVolume(DeviceExt
, Irp
, FALSE
);
940 case FSCTL_GET_NTFS_VOLUME_DATA
:
941 Status
= GetNfsVolumeData(DeviceExt
, Irp
);
944 case FSCTL_GET_NTFS_FILE_RECORD
:
945 Status
= GetNtfsFileRecord(DeviceExt
, Irp
);
948 case FSCTL_GET_VOLUME_BITMAP
:
949 Status
= GetVolumeBitmap(DeviceExt
, Irp
);
953 DPRINT("Invalid user request: %x\n", Stack
->Parameters
.FileSystemControl
.FsControlCode
);
954 Status
= STATUS_INVALID_DEVICE_REQUEST
;
963 NtfsFileSystemControl(PNTFS_IRP_CONTEXT IrpContext
)
967 PDEVICE_OBJECT DeviceObject
;
969 DPRINT1("NtfsFileSystemControl() called\n");
971 DeviceObject
= IrpContext
->DeviceObject
;
972 Irp
= IrpContext
->Irp
;
973 Irp
->IoStatus
.Information
= 0;
975 switch (IrpContext
->MinorFunction
)
977 case IRP_MN_KERNEL_CALL
:
978 DPRINT1("NTFS: IRP_MN_USER_FS_REQUEST\n");
979 Status
= STATUS_INVALID_DEVICE_REQUEST
;
982 case IRP_MN_USER_FS_REQUEST
:
983 Status
= NtfsUserFsRequest(DeviceObject
, Irp
);
986 case IRP_MN_MOUNT_VOLUME
:
987 DPRINT("NTFS: IRP_MN_MOUNT_VOLUME\n");
988 Status
= NtfsMountVolume(DeviceObject
, Irp
);
991 case IRP_MN_VERIFY_VOLUME
:
992 DPRINT1("NTFS: IRP_MN_VERIFY_VOLUME\n");
993 Status
= NtfsVerifyVolume(DeviceObject
, Irp
);
997 DPRINT1("NTFS FSC: MinorFunction %d\n", IrpContext
->MinorFunction
);
998 Status
= STATUS_INVALID_DEVICE_REQUEST
;