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 NtfsGetVolumeData(PDEVICE_OBJECT DeviceObject
,
173 PDEVICE_EXTENSION DeviceExt
)
175 DISK_GEOMETRY DiskGeometry
;
176 PFILE_RECORD_HEADER VolumeRecord
;
177 PVOLINFO_ATTRIBUTE VolumeInfo
;
178 PBOOT_SECTOR BootSector
;
180 PNTFS_INFO NtfsInfo
= &DeviceExt
->NtfsInfo
;
182 PNTFS_ATTR_CONTEXT AttrCtxt
;
183 PNTFS_ATTR_RECORD Attribute
;
187 DPRINT("NtfsGetVolumeData() called\n");
189 Size
= sizeof(DISK_GEOMETRY
);
190 Status
= NtfsDeviceIoControl(DeviceObject
,
191 IOCTL_DISK_GET_DRIVE_GEOMETRY
,
197 if (!NT_SUCCESS(Status
))
199 DPRINT("NtfsDeviceIoControl() failed (Status %lx)\n", Status
);
203 DPRINT("BytesPerSector: %lu\n", DiskGeometry
.BytesPerSector
);
204 BootSector
= ExAllocatePoolWithTag(NonPagedPool
,
205 DiskGeometry
.BytesPerSector
,
207 if (BootSector
== NULL
)
209 return STATUS_INSUFFICIENT_RESOURCES
;
212 Status
= NtfsReadSectors(DeviceObject
,
213 0, /* Partition boot sector */
215 DiskGeometry
.BytesPerSector
,
218 if (!NT_SUCCESS(Status
))
220 ExFreePool(BootSector
);
224 /* Read data from the bootsector */
225 NtfsInfo
->BytesPerSector
= BootSector
->BPB
.BytesPerSector
;
226 NtfsInfo
->SectorsPerCluster
= BootSector
->BPB
.SectorsPerCluster
;
227 NtfsInfo
->BytesPerCluster
= BootSector
->BPB
.BytesPerSector
* BootSector
->BPB
.SectorsPerCluster
;
228 NtfsInfo
->SectorCount
= BootSector
->EBPB
.SectorCount
;
230 NtfsInfo
->MftStart
.QuadPart
= BootSector
->EBPB
.MftLocation
;
231 NtfsInfo
->MftMirrStart
.QuadPart
= BootSector
->EBPB
.MftMirrLocation
;
232 NtfsInfo
->SerialNumber
= BootSector
->EBPB
.SerialNumber
;
233 if (BootSector
->EBPB
.ClustersPerMftRecord
> 0)
234 NtfsInfo
->BytesPerFileRecord
= BootSector
->EBPB
.ClustersPerMftRecord
* NtfsInfo
->BytesPerCluster
;
236 NtfsInfo
->BytesPerFileRecord
= 1 << (-BootSector
->EBPB
.ClustersPerMftRecord
);
237 if (BootSector
->EBPB
.ClustersPerIndexRecord
> 0)
238 NtfsInfo
->BytesPerIndexRecord
= BootSector
->EBPB
.ClustersPerIndexRecord
* NtfsInfo
->BytesPerCluster
;
240 NtfsInfo
->BytesPerIndexRecord
= 1 << (-BootSector
->EBPB
.ClustersPerIndexRecord
);
242 DPRINT("Boot sector information:\n");
243 DPRINT(" BytesPerSector: %hu\n", BootSector
->BPB
.BytesPerSector
);
244 DPRINT(" SectorsPerCluster: %hu\n", BootSector
->BPB
.SectorsPerCluster
);
245 DPRINT(" SectorCount: %I64u\n", BootSector
->EBPB
.SectorCount
);
246 DPRINT(" MftStart: %I64u\n", BootSector
->EBPB
.MftLocation
);
247 DPRINT(" MftMirrStart: %I64u\n", BootSector
->EBPB
.MftMirrLocation
);
248 DPRINT(" ClustersPerMftRecord: %lx\n", BootSector
->EBPB
.ClustersPerMftRecord
);
249 DPRINT(" ClustersPerIndexRecord: %lx\n", BootSector
->EBPB
.ClustersPerIndexRecord
);
250 DPRINT(" SerialNumber: %I64x\n", BootSector
->EBPB
.SerialNumber
);
252 ExFreePool(BootSector
);
254 DeviceExt
->MasterFileTable
= ExAllocatePoolWithTag(NonPagedPool
,
255 NtfsInfo
->BytesPerFileRecord
,
257 if (DeviceExt
->MasterFileTable
== NULL
)
259 return STATUS_INSUFFICIENT_RESOURCES
;
262 Status
= NtfsReadSectors(DeviceObject
,
263 NtfsInfo
->MftStart
.u
.LowPart
* NtfsInfo
->SectorsPerCluster
,
264 NtfsInfo
->BytesPerFileRecord
/ NtfsInfo
->BytesPerSector
,
265 NtfsInfo
->BytesPerSector
,
266 (PVOID
)DeviceExt
->MasterFileTable
,
268 if (!NT_SUCCESS(Status
))
270 DPRINT1("Failed reading MFT.\n");
271 ExFreePool(DeviceExt
->MasterFileTable
);
275 Status
= FindAttribute(DeviceExt
, DeviceExt
->MasterFileTable
, AttributeData
, L
"", 0, &DeviceExt
->MFTContext
);
276 if (!NT_SUCCESS(Status
))
278 DPRINT1("Can't find data attribute for Master File Table.\n");
279 ExFreePool(DeviceExt
->MasterFileTable
);
283 VolumeRecord
= ExAllocatePoolWithTag(NonPagedPool
,
284 NtfsInfo
->BytesPerFileRecord
,
286 if (VolumeRecord
== NULL
)
288 DPRINT1("Allocation failed for volume record\n");
289 ExFreePool(DeviceExt
->MasterFileTable
);
290 return STATUS_INSUFFICIENT_RESOURCES
;
293 /* Read Volume File (MFT index 3) */
294 DeviceExt
->StorageDevice
= DeviceObject
;
295 Status
= ReadFileRecord(DeviceExt
,
298 if (!NT_SUCCESS(Status
))
300 DPRINT1("Failed reading volume file\n");
301 ExFreePool(VolumeRecord
);
302 ExFreePool(DeviceExt
->MasterFileTable
);
306 /* Enumerate attributes */
307 NtfsDumpFileAttributes(DeviceExt
->MasterFileTable
);
309 /* Enumerate attributes */
310 NtfsDumpFileAttributes(VolumeRecord
);
312 /* Get volume name */
313 Status
= FindAttribute(DeviceExt
, VolumeRecord
, AttributeVolumeName
, L
"", 0, &AttrCtxt
);
315 if (NT_SUCCESS(Status
) && AttrCtxt
->Record
.Resident
.ValueLength
!= 0)
317 Attribute
= &AttrCtxt
->Record
;
318 DPRINT("Data length %lu\n", AttributeDataLength(Attribute
));
319 NtfsInfo
->VolumeLabelLength
=
320 min (Attribute
->Resident
.ValueLength
, MAXIMUM_VOLUME_LABEL_LENGTH
);
321 RtlCopyMemory(NtfsInfo
->VolumeLabel
,
322 (PVOID
)((ULONG_PTR
)Attribute
+ Attribute
->Resident
.ValueOffset
),
323 NtfsInfo
->VolumeLabelLength
);
324 VolumeNameU
= NtfsInfo
->VolumeLabel
;
328 NtfsInfo
->VolumeLabelLength
= 0;
332 VolumeFcb
= NtfsCreateFCB(VolumeNameU
, DeviceExt
);
333 if (VolumeFcb
== NULL
)
335 DPRINT1("Failed allocating volume FCB\n");
336 ExFreePool(VolumeRecord
);
337 ExFreePool(DeviceExt
->MasterFileTable
);
338 return STATUS_INSUFFICIENT_RESOURCES
;
341 VolumeFcb
->Flags
= FCB_IS_VOLUME
;
342 VolumeFcb
->RFCB
.FileSize
.QuadPart
= DeviceExt
->NtfsInfo
.SectorCount
* DeviceExt
->NtfsInfo
.BytesPerSector
;
343 VolumeFcb
->RFCB
.ValidDataLength
= VolumeFcb
->RFCB
.FileSize
;
344 VolumeFcb
->RFCB
.AllocationSize
= VolumeFcb
->RFCB
.FileSize
;
345 VolumeFcb
->MFTIndex
= 0;
346 DeviceExt
->VolumeFcb
= VolumeFcb
;
348 /* Get volume information */
349 Status
= FindAttribute(DeviceExt
, VolumeRecord
, AttributeVolumeInformation
, L
"", 0, &AttrCtxt
);
351 if (NT_SUCCESS(Status
) && AttrCtxt
->Record
.Resident
.ValueLength
!= 0)
353 Attribute
= &AttrCtxt
->Record
;
354 DPRINT("Data length %lu\n", AttributeDataLength (Attribute
));
355 VolumeInfo
= (PVOID
)((ULONG_PTR
)Attribute
+ Attribute
->Resident
.ValueOffset
);
357 NtfsInfo
->MajorVersion
= VolumeInfo
->MajorVersion
;
358 NtfsInfo
->MinorVersion
= VolumeInfo
->MinorVersion
;
359 NtfsInfo
->Flags
= VolumeInfo
->Flags
;
362 ExFreePool(VolumeRecord
);
370 NtfsMountVolume(PDEVICE_OBJECT DeviceObject
,
373 PDEVICE_OBJECT NewDeviceObject
= NULL
;
374 PDEVICE_OBJECT DeviceToMount
;
375 PIO_STACK_LOCATION Stack
;
376 PNTFS_FCB Fcb
= NULL
;
377 PNTFS_CCB Ccb
= NULL
;
378 PNTFS_VCB Vcb
= NULL
;
381 DPRINT1("NtfsMountVolume() called\n");
383 if (DeviceObject
!= NtfsGlobalData
->DeviceObject
)
385 Status
= STATUS_INVALID_DEVICE_REQUEST
;
389 Stack
= IoGetCurrentIrpStackLocation(Irp
);
390 DeviceToMount
= Stack
->Parameters
.MountVolume
.DeviceObject
;
392 Status
= NtfsHasFileSystem(DeviceToMount
);
393 if (!NT_SUCCESS(Status
))
398 Status
= IoCreateDevice(NtfsGlobalData
->DriverObject
,
399 sizeof(DEVICE_EXTENSION
),
401 FILE_DEVICE_DISK_FILE_SYSTEM
,
405 if (!NT_SUCCESS(Status
))
408 NewDeviceObject
->Flags
|= DO_DIRECT_IO
;
409 Vcb
= (PVOID
)NewDeviceObject
->DeviceExtension
;
410 RtlZeroMemory(Vcb
, sizeof(NTFS_VCB
));
412 Vcb
->Identifier
.Type
= NTFS_TYPE_VCB
;
413 Vcb
->Identifier
.Size
= sizeof(NTFS_TYPE_VCB
);
415 Status
= NtfsGetVolumeData(DeviceToMount
,
417 if (!NT_SUCCESS(Status
))
420 NewDeviceObject
->Vpb
= DeviceToMount
->Vpb
;
422 Vcb
->StorageDevice
= DeviceToMount
;
423 Vcb
->StorageDevice
->Vpb
->DeviceObject
= NewDeviceObject
;
424 Vcb
->StorageDevice
->Vpb
->RealDevice
= Vcb
->StorageDevice
;
425 Vcb
->StorageDevice
->Vpb
->Flags
|= VPB_MOUNTED
;
426 NewDeviceObject
->StackSize
= Vcb
->StorageDevice
->StackSize
+ 1;
427 NewDeviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
429 Vcb
->StreamFileObject
= IoCreateStreamFileObject(NULL
,
432 InitializeListHead(&Vcb
->FcbListHead
);
434 Fcb
= NtfsCreateFCB(NULL
, Vcb
);
437 Status
= STATUS_INSUFFICIENT_RESOURCES
;
441 Ccb
= ExAllocatePoolWithTag(NonPagedPool
,
446 Status
= STATUS_INSUFFICIENT_RESOURCES
;
450 RtlZeroMemory(Ccb
, sizeof(NTFS_CCB
));
452 Ccb
->Identifier
.Type
= NTFS_TYPE_CCB
;
453 Ccb
->Identifier
.Size
= sizeof(NTFS_TYPE_CCB
);
455 Vcb
->StreamFileObject
->FsContext
= Fcb
;
456 Vcb
->StreamFileObject
->FsContext2
= Ccb
;
457 Vcb
->StreamFileObject
->SectionObjectPointer
= &Fcb
->SectionObjectPointers
;
458 Vcb
->StreamFileObject
->PrivateCacheMap
= NULL
;
459 Vcb
->StreamFileObject
->Vpb
= Vcb
->Vpb
;
460 Ccb
->PtrFileObject
= Vcb
->StreamFileObject
;
461 Fcb
->FileObject
= Vcb
->StreamFileObject
;
462 Fcb
->Vcb
= (PDEVICE_EXTENSION
)Vcb
->StorageDevice
;
464 Fcb
->Flags
= FCB_IS_VOLUME_STREAM
;
466 Fcb
->RFCB
.FileSize
.QuadPart
= Vcb
->NtfsInfo
.SectorCount
* Vcb
->NtfsInfo
.BytesPerSector
;
467 Fcb
->RFCB
.ValidDataLength
.QuadPart
= Vcb
->NtfsInfo
.SectorCount
* Vcb
->NtfsInfo
.BytesPerSector
;
468 Fcb
->RFCB
.AllocationSize
.QuadPart
= Vcb
->NtfsInfo
.SectorCount
* Vcb
->NtfsInfo
.BytesPerSector
; /* Correct? */
470 // Fcb->Entry.ExtentLocationL = 0;
471 // Fcb->Entry.DataLengthL = DeviceExt->CdInfo.VolumeSpaceSize * BLOCKSIZE;
473 CcInitializeCacheMap(Vcb
->StreamFileObject
,
474 (PCC_FILE_SIZES
)(&Fcb
->RFCB
.AllocationSize
),
476 &(NtfsGlobalData
->CacheMgrCallbacks
),
479 ExInitializeResourceLite(&Vcb
->DirResource
);
481 KeInitializeSpinLock(&Vcb
->FcbListLock
);
483 /* Get serial number */
484 NewDeviceObject
->Vpb
->SerialNumber
= Vcb
->NtfsInfo
.SerialNumber
;
486 /* Get volume label */
487 NewDeviceObject
->Vpb
->VolumeLabelLength
= Vcb
->NtfsInfo
.VolumeLabelLength
;
488 RtlCopyMemory(NewDeviceObject
->Vpb
->VolumeLabel
,
489 Vcb
->NtfsInfo
.VolumeLabel
,
490 Vcb
->NtfsInfo
.VolumeLabelLength
);
492 Status
= STATUS_SUCCESS
;
495 if (!NT_SUCCESS(Status
))
498 if (Vcb
&& Vcb
->StreamFileObject
)
499 ObDereferenceObject(Vcb
->StreamFileObject
);
508 IoDeleteDevice(NewDeviceObject
);
511 DPRINT("NtfsMountVolume() done (Status: %lx)\n", Status
);
519 NtfsVerifyVolume(PDEVICE_OBJECT DeviceObject
,
522 UNREFERENCED_PARAMETER(DeviceObject
);
523 UNREFERENCED_PARAMETER(Irp
);
524 DPRINT1("NtfsVerifyVolume() called\n");
525 return STATUS_WRONG_VOLUME
;
531 GetNfsVolumeData(PDEVICE_EXTENSION DeviceExt
,
534 PIO_STACK_LOCATION Stack
;
535 PNTFS_VOLUME_DATA_BUFFER DataBuffer
;
536 PNTFS_ATTR_RECORD Attribute
;
538 DataBuffer
= (PNTFS_VOLUME_DATA_BUFFER
)Irp
->UserBuffer
;
539 Stack
= IoGetCurrentIrpStackLocation(Irp
);
541 if (Stack
->Parameters
.FileSystemControl
.OutputBufferLength
< sizeof(NTFS_VOLUME_DATA_BUFFER
) ||
542 Irp
->UserBuffer
== NULL
)
544 DPRINT1("Invalid output! %d %p\n", Stack
->Parameters
.FileSystemControl
.OutputBufferLength
, Irp
->UserBuffer
);
545 return STATUS_INVALID_PARAMETER
;
548 DataBuffer
->VolumeSerialNumber
.QuadPart
= DeviceExt
->NtfsInfo
.SerialNumber
;
549 DataBuffer
->NumberSectors
.QuadPart
= DeviceExt
->NtfsInfo
.SectorCount
;
550 DataBuffer
->TotalClusters
.QuadPart
= DeviceExt
->NtfsInfo
.SectorCount
/ DeviceExt
->NtfsInfo
.SectorsPerCluster
;
551 DataBuffer
->FreeClusters
.QuadPart
= NtfsGetFreeClusters(DeviceExt
);
552 DataBuffer
->TotalReserved
.QuadPart
= 0LL; // FIXME
553 DataBuffer
->BytesPerSector
= DeviceExt
->NtfsInfo
.BytesPerSector
;
554 DataBuffer
->BytesPerCluster
= DeviceExt
->NtfsInfo
.BytesPerCluster
;
555 DataBuffer
->BytesPerFileRecordSegment
= DeviceExt
->NtfsInfo
.BytesPerFileRecord
;
556 DataBuffer
->ClustersPerFileRecordSegment
= DeviceExt
->NtfsInfo
.BytesPerFileRecord
/ DeviceExt
->NtfsInfo
.BytesPerCluster
;
557 DataBuffer
->MftStartLcn
.QuadPart
= DeviceExt
->NtfsInfo
.MftStart
.QuadPart
;
558 DataBuffer
->Mft2StartLcn
.QuadPart
= DeviceExt
->NtfsInfo
.MftMirrStart
.QuadPart
;
559 DataBuffer
->MftZoneStart
.QuadPart
= 0; // FIXME
560 DataBuffer
->MftZoneEnd
.QuadPart
= 0; // FIXME
562 Attribute
= (PNTFS_ATTR_RECORD
)((ULONG_PTR
)DeviceExt
->MasterFileTable
+ DeviceExt
->MasterFileTable
->AttributeOffset
);
563 while (Attribute
< (PNTFS_ATTR_RECORD
)((ULONG_PTR
)DeviceExt
->MasterFileTable
+ DeviceExt
->MasterFileTable
->BytesInUse
) &&
564 Attribute
->Type
!= AttributeEnd
)
566 if (Attribute
->Type
== AttributeData
)
568 ASSERT(Attribute
->IsNonResident
);
569 DataBuffer
->MftValidDataLength
.QuadPart
= Attribute
->NonResident
.DataSize
;
574 Attribute
= (PNTFS_ATTR_RECORD
)((ULONG_PTR
)Attribute
+ Attribute
->Length
);
577 if (Stack
->Parameters
.FileSystemControl
.OutputBufferLength
>= sizeof(NTFS_EXTENDED_VOLUME_DATA
) + sizeof(NTFS_VOLUME_DATA_BUFFER
))
579 PNTFS_EXTENDED_VOLUME_DATA ExtendedData
= (PNTFS_EXTENDED_VOLUME_DATA
)((ULONG_PTR
)Irp
->UserBuffer
+ sizeof(NTFS_VOLUME_DATA_BUFFER
));
581 ExtendedData
->ByteCount
= sizeof(NTFS_EXTENDED_VOLUME_DATA
);
582 ExtendedData
->MajorVersion
= DeviceExt
->NtfsInfo
.MajorVersion
;
583 ExtendedData
->MinorVersion
= DeviceExt
->NtfsInfo
.MinorVersion
;
586 return STATUS_SUCCESS
;
592 GetNtfsFileRecord(PDEVICE_EXTENSION DeviceExt
,
596 PIO_STACK_LOCATION Stack
;
597 PNTFS_FILE_RECORD_INPUT_BUFFER InputBuffer
;
598 PFILE_RECORD_HEADER FileRecord
;
599 PNTFS_FILE_RECORD_OUTPUT_BUFFER OutputBuffer
;
602 Stack
= IoGetCurrentIrpStackLocation(Irp
);
604 if (Stack
->Parameters
.FileSystemControl
.InputBufferLength
< sizeof(NTFS_FILE_RECORD_INPUT_BUFFER
) ||
605 Irp
->AssociatedIrp
.SystemBuffer
== NULL
)
607 DPRINT1("Invalid input! %d %p\n", Stack
->Parameters
.FileSystemControl
.InputBufferLength
, Irp
->AssociatedIrp
.SystemBuffer
);
608 return STATUS_INVALID_PARAMETER
;
611 if (Stack
->Parameters
.FileSystemControl
.OutputBufferLength
< (FIELD_OFFSET(NTFS_FILE_RECORD_OUTPUT_BUFFER
, FileRecordBuffer
) + DeviceExt
->NtfsInfo
.BytesPerFileRecord
) ||
612 Irp
->AssociatedIrp
.SystemBuffer
== NULL
)
614 DPRINT1("Invalid output! %d %p\n", Stack
->Parameters
.FileSystemControl
.OutputBufferLength
, Irp
->AssociatedIrp
.SystemBuffer
);
615 return STATUS_BUFFER_TOO_SMALL
;
618 FileRecord
= ExAllocatePoolWithTag(NonPagedPool
,
619 DeviceExt
->NtfsInfo
.BytesPerFileRecord
,
621 if (FileRecord
== NULL
)
623 return STATUS_INSUFFICIENT_RESOURCES
;
626 InputBuffer
= (PNTFS_FILE_RECORD_INPUT_BUFFER
)Irp
->AssociatedIrp
.SystemBuffer
;
628 MFTRecord
= InputBuffer
->FileReferenceNumber
.QuadPart
;
629 DPRINT1("Requesting: %I64x\n", MFTRecord
);
633 Status
= ReadFileRecord(DeviceExt
, MFTRecord
, FileRecord
);
634 if (NT_SUCCESS(Status
))
636 if (FileRecord
->Flags
& FRH_IN_USE
)
645 DPRINT1("Returning: %I64x\n", MFTRecord
);
646 OutputBuffer
= (PNTFS_FILE_RECORD_OUTPUT_BUFFER
)Irp
->AssociatedIrp
.SystemBuffer
;
647 OutputBuffer
->FileReferenceNumber
.QuadPart
= MFTRecord
;
648 OutputBuffer
->FileRecordLength
= DeviceExt
->NtfsInfo
.BytesPerFileRecord
;
649 RtlCopyMemory(OutputBuffer
->FileRecordBuffer
, FileRecord
, DeviceExt
->NtfsInfo
.BytesPerFileRecord
);
651 ExFreePoolWithTag(FileRecord
, TAG_NTFS
);
653 Irp
->IoStatus
.Information
= FIELD_OFFSET(NTFS_FILE_RECORD_OUTPUT_BUFFER
, FileRecordBuffer
) + DeviceExt
->NtfsInfo
.BytesPerFileRecord
;
655 return STATUS_SUCCESS
;
661 GetVolumeBitmap(PDEVICE_EXTENSION DeviceExt
,
664 DPRINT1("GetVolumeBitmap(%p, %p)\n", DeviceExt
, Irp
);
667 return STATUS_NOT_IMPLEMENTED
;
673 NtfsUserFsRequest(PDEVICE_OBJECT DeviceObject
,
677 PIO_STACK_LOCATION Stack
;
678 PDEVICE_EXTENSION DeviceExt
;
680 DPRINT1("NtfsUserFsRequest(%p, %p)\n", DeviceObject
, Irp
);
682 Stack
= IoGetCurrentIrpStackLocation(Irp
);
683 DeviceExt
= DeviceObject
->DeviceExtension
;
684 switch (Stack
->Parameters
.FileSystemControl
.FsControlCode
)
686 case FSCTL_GET_NTFS_VOLUME_DATA
:
687 Status
= GetNfsVolumeData(DeviceExt
, Irp
);
690 case FSCTL_GET_NTFS_FILE_RECORD
:
691 Status
= GetNtfsFileRecord(DeviceExt
, Irp
);
694 case FSCTL_GET_VOLUME_BITMAP
:
695 Status
= GetVolumeBitmap(DeviceExt
, Irp
);
699 DPRINT1("Invalid user request: %x\n", Stack
->Parameters
.FileSystemControl
.FsControlCode
);
700 Status
= STATUS_INVALID_DEVICE_REQUEST
;
710 NtfsFsdFileSystemControl(PDEVICE_OBJECT DeviceObject
,
713 PIO_STACK_LOCATION Stack
;
716 DPRINT1("NtfsFileSystemControl() called\n");
718 Stack
= IoGetCurrentIrpStackLocation(Irp
);
720 Irp
->IoStatus
.Information
= 0;
722 switch (Stack
->MinorFunction
)
724 case IRP_MN_KERNEL_CALL
:
725 DPRINT1("NTFS: IRP_MN_USER_FS_REQUEST\n");
726 Status
= STATUS_INVALID_DEVICE_REQUEST
;
729 case IRP_MN_USER_FS_REQUEST
:
730 Status
= NtfsUserFsRequest(DeviceObject
, Irp
);
733 case IRP_MN_MOUNT_VOLUME
:
734 DPRINT("NTFS: IRP_MN_MOUNT_VOLUME\n");
735 Status
= NtfsMountVolume(DeviceObject
, Irp
);
738 case IRP_MN_VERIFY_VOLUME
:
739 DPRINT1("NTFS: IRP_MN_VERIFY_VOLUME\n");
740 Status
= NtfsVerifyVolume(DeviceObject
, Irp
);
744 DPRINT1("NTFS FSC: MinorFunction %d\n", Stack
->MinorFunction
);
745 Status
= STATUS_INVALID_DEVICE_REQUEST
;
749 Irp
->IoStatus
.Status
= Status
;
751 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);