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.
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->SectionObjectPointers = &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);