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.8 2003/09/15 16:01:16 ea 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
26 * Updated by Valentin Verkhovsky 2003/09/12
29 /* INCLUDES *****************************************************************/
31 #include <ddk/ntddk.h>
38 /* FUNCTIONS ****************************************************************/
41 NtfsHasFileSystem(PDEVICE_OBJECT DeviceToMount
)
43 * FUNCTION: Tests if the device contains a filesystem that can be mounted
47 PARTITION_INFORMATION PartitionInfo
;
48 DISK_GEOMETRY DiskGeometry
;
50 PBOOT_SECTOR BootSector
;
53 DPRINT("NtfsHasFileSystem() called\n");
55 Size
= sizeof(DISK_GEOMETRY
);
56 Status
= NtfsDeviceIoControl(DeviceToMount
,
57 IOCTL_DISK_GET_DRIVE_GEOMETRY
,
62 if (!NT_SUCCESS(Status
))
64 DPRINT("NtfsDeviceIoControl() failed (Status %lx)\n", Status
);
68 if (DiskGeometry
.MediaType
== FixedMedia
)
70 /* We have found a hard disk */
71 Size
= sizeof(PARTITION_INFORMATION
);
72 Status
= NtfsDeviceIoControl(DeviceToMount
,
73 IOCTL_DISK_GET_PARTITION_INFO
,
78 if (!NT_SUCCESS(Status
))
80 DPRINT("NtfsDeviceIoControl() failed (Status %lx)\n", Status
);
84 if (PartitionInfo
.PartitionType
!= PARTITION_IFS
)
86 return(STATUS_UNRECOGNIZED_VOLUME
);
90 DPRINT("BytesPerSector: %lu\n", DiskGeometry
.BytesPerSector
);
91 BootSector
= ExAllocatePool(NonPagedPool
,
92 DiskGeometry
.BytesPerSector
);
93 if (BootSector
== NULL
)
95 return(STATUS_INSUFFICIENT_RESOURCES
);
98 Status
= NtfsReadRawSectors(DeviceToMount
,
101 DiskGeometry
.BytesPerSector
,
103 if (NT_SUCCESS(Status
))
105 DPRINT("NTFS-identifier: [%.8s]\n", BootSector
->OemName
);
106 if (strncmp(BootSector
->OemName
, "NTFS ", 8) != 0)
108 Status
= STATUS_UNRECOGNIZED_VOLUME
;
112 ExFreePool(BootSector
);
119 NtfsGetVolumeData(PDEVICE_OBJECT DeviceObject
,
120 PDEVICE_EXTENSION Vcb
)
122 DISK_GEOMETRY DiskGeometry
;
126 PBOOT_SECTOR BootSector
;
128 DPRINT("NtfsGetVolumeData() called\n");
130 Size
= sizeof(DISK_GEOMETRY
);
131 Status
= NtfsDeviceIoControl(DeviceObject
,
132 IOCTL_DISK_GET_DRIVE_GEOMETRY
,
137 if (!NT_SUCCESS(Status
))
139 DPRINT("NtfsDeviceIoControl() failed (Status %lx)\n", Status
);
143 DPRINT("BytesPerSector: %lu\n", DiskGeometry
.BytesPerSector
);
144 BootSector
= ExAllocatePool(NonPagedPool
,
145 DiskGeometry
.BytesPerSector
);
146 if (BootSector
== NULL
)
148 return(STATUS_INSUFFICIENT_RESOURCES
);
151 Status
= NtfsReadRawSectors(DeviceObject
,
152 0, /* Partition boot sector */
154 DiskGeometry
.BytesPerSector
,
156 if (NT_SUCCESS(Status
))
158 /* Read data from the bootsector */
159 Vcb
->NtfsInfo
.BytesPerSector
= BootSector
->BytesPerSector
;
160 Vcb
->NtfsInfo
.SectorsPerCluster
= BootSector
->SectorsPerCluster
;
161 Vcb
->NtfsInfo
.BytesPerCluster
= BootSector
->BytesPerSector
* BootSector
->SectorsPerCluster
;
162 Vcb
->NtfsInfo
.SectorCount
= BootSector
->SectorCount
;
164 Vcb
->NtfsInfo
.MftStart
.QuadPart
= BootSector
->MftLocation
;
165 Vcb
->NtfsInfo
.MftMirrStart
.QuadPart
= BootSector
->MftMirrLocation
;
166 Vcb
->NtfsInfo
.SerialNumber
= BootSector
->SerialNumber
;
167 Vcb
->NtfsInfo
.ClustersPerFileRecord
= BootSector
->ClustersPerMftRecord
;
170 DbgPrint("Boot sector information:\n");
171 DbgPrint(" BytesPerSector: %hu\n", BootSector
->BytesPerSector
);
172 DbgPrint(" SectorsPerCluster: %hu\n", BootSector
->SectorsPerCluster
);
174 DbgPrint(" SectorCount: %I64u\n", BootSector
->SectorCount
);
176 DbgPrint(" MftStart: %I64u\n", BootSector
->MftLocation
);
177 DbgPrint(" MftMirrStart: %I64u\n", BootSector
->MftMirrLocation
);
179 DbgPrint(" ClustersPerMftRecord: %lx\n", BootSector
->ClustersPerMftRecord
);
180 DbgPrint(" ClustersPerIndexRecord: %lx\n", BootSector
->ClustersPerIndexRecord
);
182 DbgPrint(" SerialNumber: %I64x\n", BootSector
->SerialNumber
);
185 NtfsOpenMft(DeviceObject
, Vcb
);
189 ExFreePool(BootSector
);
197 NtfsMountVolume(PDEVICE_OBJECT DeviceObject
,
200 PDEVICE_EXTENSION DeviceExt
= NULL
;
201 PDEVICE_OBJECT NewDeviceObject
= NULL
;
202 PDEVICE_OBJECT DeviceToMount
;
203 PIO_STACK_LOCATION Stack
;
209 DPRINT("NtfsMountVolume() called\n");
211 if (DeviceObject
!= NtfsGlobalData
->DeviceObject
)
213 Status
= STATUS_INVALID_DEVICE_REQUEST
;
217 Stack
= IoGetCurrentIrpStackLocation(Irp
);
218 DeviceToMount
= Stack
->Parameters
.MountVolume
.DeviceObject
;
219 Vpb
= Stack
->Parameters
.MountVolume
.Vpb
;
221 Status
= NtfsHasFileSystem(DeviceToMount
);
222 if (!NT_SUCCESS(Status
))
227 Status
= IoCreateDevice(NtfsGlobalData
->DriverObject
,
228 sizeof(DEVICE_EXTENSION
),
230 FILE_DEVICE_FILE_SYSTEM
,
231 // FILE_DEVICE_DISK_FILE_SYSTEM,
235 if (!NT_SUCCESS(Status
))
238 NewDeviceObject
->Flags
= NewDeviceObject
->Flags
| DO_DIRECT_IO
;
239 DeviceExt
= (PVOID
)NewDeviceObject
->DeviceExtension
;
240 RtlZeroMemory(DeviceExt
,
241 sizeof(DEVICE_EXTENSION
));
243 Status
= NtfsGetVolumeData(DeviceToMount
,
245 if (!NT_SUCCESS(Status
))
248 NewDeviceObject
->Vpb
= DeviceToMount
->Vpb
;
250 DeviceExt
->StorageDevice
= DeviceToMount
;
251 DeviceExt
->StorageDevice
->Vpb
->DeviceObject
= NewDeviceObject
;
252 DeviceExt
->StorageDevice
->Vpb
->RealDevice
= DeviceExt
->StorageDevice
;
253 DeviceExt
->StorageDevice
->Vpb
->Flags
|= VPB_MOUNTED
;
254 NewDeviceObject
->StackSize
= DeviceExt
->StorageDevice
->StackSize
+ 1;
255 NewDeviceObject
->Flags
&= ~DO_DEVICE_INITIALIZING
;
257 DeviceExt
->StreamFileObject
= IoCreateStreamFileObject(NULL
,
258 DeviceExt
->StorageDevice
);
261 Fcb
= NtfsCreateFCB(NULL
);
264 Status
= STATUS_INSUFFICIENT_RESOURCES
;
268 Ccb
= ExAllocatePoolWithTag(NonPagedPool
,
273 Status
= STATUS_INSUFFICIENT_RESOURCES
;
279 DeviceExt
->StreamFileObject
->Flags
= DeviceExt
->StreamFileObject
->Flags
| FO_FCB_IS_VALID
| FO_DIRECT_CACHE_PAGING_READ
;
280 DeviceExt
->StreamFileObject
->FsContext
= Fcb
;
281 DeviceExt
->StreamFileObject
->FsContext2
= Ccb
;
282 DeviceExt
->StreamFileObject
->SectionObjectPointer
= &Fcb
->SectionObjectPointers
;
283 DeviceExt
->StreamFileObject
->PrivateCacheMap
= NULL
;
284 DeviceExt
->StreamFileObject
->Vpb
= DeviceExt
->Vpb
;
285 Ccb
->PtrFileObject
= DeviceExt
->StreamFileObject
;
286 Fcb
->FileObject
= DeviceExt
->StreamFileObject
;
287 Fcb
->DevExt
= (PDEVICE_EXTENSION
)DeviceExt
->StorageDevice
;
289 Fcb
->Flags
= FCB_IS_VOLUME_STREAM
;
291 Fcb
->RFCB
.FileSize
.QuadPart
= DeviceExt
->NtfsInfo
.SectorCount
* DeviceExt
->NtfsInfo
.BytesPerSector
;
292 Fcb
->RFCB
.ValidDataLength
.QuadPart
= DeviceExt
->NtfsInfo
.SectorCount
* DeviceExt
->NtfsInfo
.BytesPerSector
;
293 Fcb
->RFCB
.AllocationSize
.QuadPart
= DeviceExt
->NtfsInfo
.SectorCount
* DeviceExt
->NtfsInfo
.BytesPerSector
; /* Correct? */
295 // Fcb->Entry.ExtentLocationL = 0;
296 // Fcb->Entry.DataLengthL = DeviceExt->CdInfo.VolumeSpaceSize * BLOCKSIZE;
298 Status
= CcRosInitializeFileCache(DeviceExt
->StreamFileObject
,
299 CACHEPAGESIZE(DeviceExt
));
300 if (!NT_SUCCESS (Status
))
302 DbgPrint("CcRosInitializeFileCache() failed (Status %lx)\n", Status
);
306 ExInitializeResourceLite(&DeviceExt
->DirResource
);
307 // ExInitializeResourceLite(&DeviceExt->FatResource);
309 KeInitializeSpinLock(&DeviceExt
->FcbListLock
);
310 InitializeListHead(&DeviceExt
->FcbListHead
);
312 /* Read serial number */
313 NewDeviceObject
->Vpb
->SerialNumber
= DeviceExt
->NtfsInfo
.SerialNumber
;
315 /* Read volume label */
316 // NtfsReadVolumeLabel(DeviceExt,
317 // NewDeviceObject->Vpb);
319 Status
= STATUS_SUCCESS
;
322 if (!NT_SUCCESS(Status
))
325 if (DeviceExt
&& DeviceExt
->StreamFileObject
)
326 ObDereferenceObject(DeviceExt
->StreamFileObject
);
332 IoDeleteDevice(NewDeviceObject
);
335 DPRINT("NtfsMountVolume() done (Status: %lx)\n", Status
);
342 NtfsVerifyVolume(PDEVICE_OBJECT DeviceObject
,
346 PDEVICE_OBJECT DeviceToVerify
;
347 PIO_STACK_LOCATION Stack
;
360 DPRINT1("NtfsVerifyVolume() called\n");
363 Stack
= IoGetCurrentIrpStackLocation(Irp
);
364 DeviceToVerify
= Stack
->Parameters
.VerifyVolume
.DeviceObject
;
366 DPRINT("Device object %p Device to verify %p\n", DeviceObject
, DeviceToVerify
);
368 Sector
= CDFS_PRIMARY_DESCRIPTOR_LOCATION
;
370 Buffer
= ExAllocatePool(NonPagedPool
,
374 return(STATUS_INSUFFICIENT_RESOURCES
);
379 /* Read the Primary Volume Descriptor (PVD) */
380 Status
= CdfsReadRawSectors(DeviceToVerify
,
384 DPRINT("CdfsReadRawSectors() status %lx\n", Status
);
385 if (!NT_SUCCESS(Status
))
390 if (Buffer
[0] == 1 &&
402 while (Buffer
[0] != 255);
404 if (Buffer
[0] == 255)
407 Status
= STATUS_WRONG_VOLUME
;
409 /* Calculate the volume serial number */
411 for (i
= 0; i
< 2048; i
+= 4)
413 /* DON'T optimize this to ULONG!!! (breaks overflow) */
414 Serial
.Part
[0] += Buffer
[i
+3];
415 Serial
.Part
[1] += Buffer
[i
+2];
416 Serial
.Part
[2] += Buffer
[i
+1];
417 Serial
.Part
[3] += Buffer
[i
+0];
420 DPRINT("Current serial number %08lx Vpb serial number %08lx\n",
421 Serial
.Value
, DeviceToVerify
->Vpb
->SerialNumber
);
423 if (Serial
.Value
== DeviceToVerify
->Vpb
->SerialNumber
)
424 Status
= STATUS_SUCCESS
;
429 DPRINT("CdfsVerifyVolume() done (Status: %lx)\n", Status
);
433 return(STATUS_UNSUCCESSFUL
);
438 NtfsFileSystemControl(PDEVICE_OBJECT DeviceObject
,
441 PIO_STACK_LOCATION Stack
;
444 DPRINT("NtfsFileSystemControl() called\n");
446 Stack
= IoGetCurrentIrpStackLocation(Irp
);
448 switch (Stack
->MinorFunction
)
450 case IRP_MN_USER_FS_REQUEST
:
451 DPRINT("NTFS: IRP_MN_USER_FS_REQUEST\n");
452 Status
= STATUS_INVALID_DEVICE_REQUEST
;
455 case IRP_MN_MOUNT_VOLUME
:
456 DPRINT("NTFS: IRP_MN_MOUNT_VOLUME\n");
457 Status
= NtfsMountVolume(DeviceObject
, Irp
);
460 case IRP_MN_VERIFY_VOLUME
:
461 DPRINT1("NTFS: IRP_MN_VERIFY_VOLUME\n");
462 Status
= NtfsVerifyVolume(DeviceObject
, Irp
);
466 DPRINT("NTFS FSC: MinorFunction %d\n", Stack
->MinorFunction
);
467 Status
= STATUS_INVALID_DEVICE_REQUEST
;
471 Irp
->IoStatus
.Status
= Status
;
472 Irp
->IoStatus
.Information
= 0;
474 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);