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., 675 Mass Ave, Cambridge, MA 02139, USA.
19 /* $Id: fsctl.c,v 1.7 2003/07/17 13:31:39 chorns Exp $
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS kernel
23 * FILE: services/fs/ntfs/fsctl.c
24 * PURPOSE: NTFS filesystem driver
25 * PROGRAMMER: Eric Kohl
28 /* INCLUDES *****************************************************************/
30 #include <ddk/ntddk.h>
37 /* FUNCTIONS ****************************************************************/
40 NtfsHasFileSystem(PDEVICE_OBJECT DeviceToMount
)
42 * FUNCTION: Tests if the device contains a filesystem that can be mounted
46 PARTITION_INFORMATION PartitionInfo
;
47 DISK_GEOMETRY DiskGeometry
;
49 PBOOT_SECTOR BootSector
;
52 DPRINT("NtfsHasFileSystem() called\n");
54 Size
= sizeof(DISK_GEOMETRY
);
55 Status
= NtfsDeviceIoControl(DeviceToMount
,
56 IOCTL_DISK_GET_DRIVE_GEOMETRY
,
61 if (!NT_SUCCESS(Status
))
63 DPRINT("NtfsDeviceIoControl() failed (Status %lx)\n", Status
);
67 if (DiskGeometry
.MediaType
== FixedMedia
)
69 /* We have found a hard disk */
70 Size
= sizeof(PARTITION_INFORMATION
);
71 Status
= NtfsDeviceIoControl(DeviceToMount
,
72 IOCTL_DISK_GET_PARTITION_INFO
,
77 if (!NT_SUCCESS(Status
))
79 DPRINT("NtfsDeviceIoControl() failed (Status %lx)\n", Status
);
83 if (PartitionInfo
.PartitionType
!= PARTITION_IFS
)
85 return(STATUS_UNRECOGNIZED_VOLUME
);
89 DPRINT("BytesPerSector: %lu\n", DiskGeometry
.BytesPerSector
);
90 BootSector
= ExAllocatePool(NonPagedPool
,
91 DiskGeometry
.BytesPerSector
);
92 if (BootSector
== NULL
)
94 return(STATUS_INSUFFICIENT_RESOURCES
);
97 Status
= NtfsReadRawSectors(DeviceToMount
,
100 DiskGeometry
.BytesPerSector
,
102 if (NT_SUCCESS(Status
))
104 DPRINT("NTFS-identifier: [%.8s]\n", BootSector
->OemName
);
105 if (strncmp(BootSector
->OemName
, "NTFS ", 8) != 0)
107 Status
= STATUS_UNRECOGNIZED_VOLUME
;
111 ExFreePool(BootSector
);
118 NtfsGetVolumeData(PDEVICE_OBJECT DeviceObject
,
119 PDEVICE_EXTENSION Vcb
)
121 DISK_GEOMETRY DiskGeometry
;
125 PBOOT_SECTOR BootSector
;
127 DPRINT("NtfsGetVolumeData() called\n");
129 Size
= sizeof(DISK_GEOMETRY
);
130 Status
= NtfsDeviceIoControl(DeviceObject
,
131 IOCTL_DISK_GET_DRIVE_GEOMETRY
,
136 if (!NT_SUCCESS(Status
))
138 DPRINT("NtfsDeviceIoControl() failed (Status %lx)\n", Status
);
142 DPRINT("BytesPerSector: %lu\n", DiskGeometry
.BytesPerSector
);
143 BootSector
= ExAllocatePool(NonPagedPool
,
144 DiskGeometry
.BytesPerSector
);
145 if (BootSector
== NULL
)
147 return(STATUS_INSUFFICIENT_RESOURCES
);
150 Status
= NtfsReadRawSectors(DeviceObject
,
151 0, /* Partition boot sector */
153 DiskGeometry
.BytesPerSector
,
155 if (NT_SUCCESS(Status
))
157 /* Read data from the bootsector */
158 Vcb
->NtfsInfo
.BytesPerSector
= BootSector
->BytesPerSector
;
159 Vcb
->NtfsInfo
.SectorsPerCluster
= BootSector
->SectorsPerCluster
;
160 Vcb
->NtfsInfo
.BytesPerCluster
= BootSector
->BytesPerSector
* BootSector
->SectorsPerCluster
;
161 Vcb
->NtfsInfo
.SectorCount
= BootSector
->SectorCount
;
163 Vcb
->NtfsInfo
.MftStart
.QuadPart
= BootSector
->MftLocation
;
164 Vcb
->NtfsInfo
.MftMirrStart
.QuadPart
= BootSector
->MftMirrLocation
;
165 Vcb
->NtfsInfo
.SerialNumber
= BootSector
->SerialNumber
;
168 DbgPrint("Boot sector information:\n");
169 DbgPrint(" BytesPerSector: %hu\n", BootSector
->BytesPerSector
);
170 DbgPrint(" SectorsPerCluster: %hu\n", BootSector
->SectorsPerCluster
);
172 DbgPrint(" SectorCount: %I64u\n", BootSector
->SectorCount
);
174 DbgPrint(" MftStart: %I64u\n", BootSector
->MftLocation
);
175 DbgPrint(" MftMirrStart: %I64u\n", BootSector
->MftMirrLocation
);
177 DbgPrint(" ClustersPerMftRecord: %lx\n", BootSector
->ClustersPerMftRecord
);
178 DbgPrint(" ClustersPerIndexRecord: %lx\n", BootSector
->ClustersPerIndexRecord
);
180 DbgPrint(" SerialNumber: %I64x\n", BootSector
->SerialNumber
);
183 NtfsOpenMft(DeviceObject
, Vcb
);
187 ExFreePool(BootSector
);
195 NtfsMountVolume(PDEVICE_OBJECT DeviceObject
,
198 PDEVICE_EXTENSION DeviceExt
= NULL
;
199 PDEVICE_OBJECT NewDeviceObject
= NULL
;
200 PDEVICE_OBJECT DeviceToMount
;
201 PIO_STACK_LOCATION Stack
;
207 DPRINT("NtfsMountVolume() called\n");
209 if (DeviceObject
!= NtfsGlobalData
->DeviceObject
)
211 Status
= STATUS_INVALID_DEVICE_REQUEST
;
215 Stack
= IoGetCurrentIrpStackLocation(Irp
);
216 DeviceToMount
= Stack
->Parameters
.MountVolume
.DeviceObject
;
217 Vpb
= Stack
->Parameters
.MountVolume
.Vpb
;
219 Status
= NtfsHasFileSystem(DeviceToMount
);
220 if (!NT_SUCCESS(Status
))
225 Status
= IoCreateDevice(NtfsGlobalData
->DriverObject
,
226 sizeof(DEVICE_EXTENSION
),
228 FILE_DEVICE_FILE_SYSTEM
,
229 // FILE_DEVICE_DISK_FILE_SYSTEM,
233 if (!NT_SUCCESS(Status
))
236 NewDeviceObject
->Flags
= NewDeviceObject
->Flags
| DO_DIRECT_IO
;
237 DeviceExt
= (PVOID
)NewDeviceObject
->DeviceExtension
;
238 RtlZeroMemory(DeviceExt
,
239 sizeof(DEVICE_EXTENSION
));
241 Status
= NtfsGetVolumeData(DeviceToMount
,
243 if (!NT_SUCCESS(Status
))
246 NewDeviceObject
->Vpb
= DeviceToMount
->Vpb
;
248 DeviceExt
->StorageDevice
= DeviceToMount
;
249 DeviceExt
->StorageDevice
->Vpb
->DeviceObject
= NewDeviceObject
;
250 DeviceExt
->StorageDevice
->Vpb
->RealDevice
= DeviceExt
->StorageDevice
;
251 DeviceExt
->StorageDevice
->Vpb
->Flags
|= VPB_MOUNTED
;
252 NewDeviceObject
->StackSize
= DeviceExt
->StorageDevice
->StackSize
+ 1;
253 NewDeviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
255 DeviceExt
->StreamFileObject
= IoCreateStreamFileObject(NULL
,
256 DeviceExt
->StorageDevice
);
259 Fcb
= NtfsCreateFCB(NULL
);
262 Status
= STATUS_INSUFFICIENT_RESOURCES
;
266 Ccb
= ExAllocatePoolWithTag(NonPagedPool
,
271 Status
= STATUS_INSUFFICIENT_RESOURCES
;
277 DeviceExt
->StreamFileObject
->Flags
= DeviceExt
->StreamFileObject
->Flags
| FO_FCB_IS_VALID
| FO_DIRECT_CACHE_PAGING_READ
;
278 DeviceExt
->StreamFileObject
->FsContext
= Fcb
;
279 DeviceExt
->StreamFileObject
->FsContext2
= Ccb
;
280 DeviceExt
->StreamFileObject
->SectionObjectPointer
= &Fcb
->SectionObjectPointers
;
281 DeviceExt
->StreamFileObject
->PrivateCacheMap
= NULL
;
282 DeviceExt
->StreamFileObject
->Vpb
= DeviceExt
->Vpb
;
283 Ccb
->PtrFileObject
= DeviceExt
->StreamFileObject
;
284 Fcb
->FileObject
= DeviceExt
->StreamFileObject
;
285 Fcb
->DevExt
= (PDEVICE_EXTENSION
)DeviceExt
->StorageDevice
;
287 Fcb
->Flags
= FCB_IS_VOLUME_STREAM
;
289 Fcb
->RFCB
.FileSize
.QuadPart
= DeviceExt
->NtfsInfo
.SectorCount
* DeviceExt
->NtfsInfo
.BytesPerSector
;
290 Fcb
->RFCB
.ValidDataLength
.QuadPart
= DeviceExt
->NtfsInfo
.SectorCount
* DeviceExt
->NtfsInfo
.BytesPerSector
;
291 Fcb
->RFCB
.AllocationSize
.QuadPart
= DeviceExt
->NtfsInfo
.SectorCount
* DeviceExt
->NtfsInfo
.BytesPerSector
; /* Correct? */
293 // Fcb->Entry.ExtentLocationL = 0;
294 // Fcb->Entry.DataLengthL = DeviceExt->CdInfo.VolumeSpaceSize * BLOCKSIZE;
296 Status
= CcRosInitializeFileCache(DeviceExt
->StreamFileObject
,
297 CACHEPAGESIZE(DeviceExt
));
298 if (!NT_SUCCESS (Status
))
300 DbgPrint("CcRosInitializeFileCache() failed (Status %lx)\n", Status
);
304 ExInitializeResourceLite(&DeviceExt
->DirResource
);
305 // ExInitializeResourceLite(&DeviceExt->FatResource);
307 KeInitializeSpinLock(&DeviceExt
->FcbListLock
);
308 InitializeListHead(&DeviceExt
->FcbListHead
);
310 /* Read serial number */
311 NewDeviceObject
->Vpb
->SerialNumber
= DeviceExt
->NtfsInfo
.SerialNumber
;
313 /* Read volume label */
314 // NtfsReadVolumeLabel(DeviceExt,
315 // NewDeviceObject->Vpb);
317 Status
= STATUS_SUCCESS
;
320 if (!NT_SUCCESS(Status
))
323 if (DeviceExt
&& DeviceExt
->StreamFileObject
)
324 ObDereferenceObject(DeviceExt
->StreamFileObject
);
330 IoDeleteDevice(NewDeviceObject
);
333 DPRINT("NtfsMountVolume() done (Status: %lx)\n", Status
);
340 NtfsVerifyVolume(PDEVICE_OBJECT DeviceObject
,
344 PDEVICE_OBJECT DeviceToVerify
;
345 PIO_STACK_LOCATION Stack
;
358 DPRINT1("NtfsVerifyVolume() called\n");
361 Stack
= IoGetCurrentIrpStackLocation(Irp
);
362 DeviceToVerify
= Stack
->Parameters
.VerifyVolume
.DeviceObject
;
364 DPRINT("Device object %p Device to verify %p\n", DeviceObject
, DeviceToVerify
);
366 Sector
= CDFS_PRIMARY_DESCRIPTOR_LOCATION
;
368 Buffer
= ExAllocatePool(NonPagedPool
,
372 return(STATUS_INSUFFICIENT_RESOURCES
);
377 /* Read the Primary Volume Descriptor (PVD) */
378 Status
= CdfsReadRawSectors(DeviceToVerify
,
382 DPRINT("CdfsReadRawSectors() status %lx\n", Status
);
383 if (!NT_SUCCESS(Status
))
388 if (Buffer
[0] == 1 &&
400 while (Buffer
[0] != 255);
402 if (Buffer
[0] == 255)
405 Status
= STATUS_WRONG_VOLUME
;
407 /* Calculate the volume serial number */
409 for (i
= 0; i
< 2048; i
+= 4)
411 /* DON'T optimize this to ULONG!!! (breaks overflow) */
412 Serial
.Part
[0] += Buffer
[i
+3];
413 Serial
.Part
[1] += Buffer
[i
+2];
414 Serial
.Part
[2] += Buffer
[i
+1];
415 Serial
.Part
[3] += Buffer
[i
+0];
418 DPRINT("Current serial number %08lx Vpb serial number %08lx\n",
419 Serial
.Value
, DeviceToVerify
->Vpb
->SerialNumber
);
421 if (Serial
.Value
== DeviceToVerify
->Vpb
->SerialNumber
)
422 Status
= STATUS_SUCCESS
;
427 DPRINT("CdfsVerifyVolume() done (Status: %lx)\n", Status
);
431 return(STATUS_UNSUCCESSFUL
);
436 NtfsFileSystemControl(PDEVICE_OBJECT DeviceObject
,
439 PIO_STACK_LOCATION Stack
;
442 DPRINT("NtfsFileSystemControl() called\n");
444 Stack
= IoGetCurrentIrpStackLocation(Irp
);
446 switch (Stack
->MinorFunction
)
448 case IRP_MN_USER_FS_REQUEST
:
449 DPRINT("NTFS: IRP_MN_USER_FS_REQUEST\n");
450 Status
= STATUS_INVALID_DEVICE_REQUEST
;
453 case IRP_MN_MOUNT_VOLUME
:
454 DPRINT("NTFS: IRP_MN_MOUNT_VOLUME\n");
455 Status
= NtfsMountVolume(DeviceObject
, Irp
);
458 case IRP_MN_VERIFY_VOLUME
:
459 DPRINT1("NTFS: IRP_MN_VERIFY_VOLUME\n");
460 Status
= NtfsVerifyVolume(DeviceObject
, Irp
);
464 DPRINT("NTFS FSC: MinorFunction %d\n", Stack
->MinorFunction
);
465 Status
= STATUS_INVALID_DEVICE_REQUEST
;
469 Irp
->IoStatus
.Status
= Status
;
470 Irp
->IoStatus
.Information
= 0;
472 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);