b471989c5f99c200028f43ccbccf62e05dae53d3
[reactos.git] / reactos / drivers / fs / ntfs / fsctl.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 2002 ReactOS Team
4 *
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.
9 *
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.
14 *
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.
18 */
19 /* $Id: fsctl.c,v 1.7 2003/07/17 13:31:39 chorns Exp $
20 *
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 */
27
28 /* INCLUDES *****************************************************************/
29
30 #include <ddk/ntddk.h>
31
32 //#define NDEBUG
33 #include <debug.h>
34
35 #include "ntfs.h"
36
37 /* FUNCTIONS ****************************************************************/
38
39 static NTSTATUS
40 NtfsHasFileSystem(PDEVICE_OBJECT DeviceToMount)
41 /*
42 * FUNCTION: Tests if the device contains a filesystem that can be mounted
43 * by this fsd
44 */
45 {
46 PARTITION_INFORMATION PartitionInfo;
47 DISK_GEOMETRY DiskGeometry;
48 ULONG Size;
49 PBOOT_SECTOR BootSector;
50 NTSTATUS Status;
51
52 DPRINT("NtfsHasFileSystem() called\n");
53
54 Size = sizeof(DISK_GEOMETRY);
55 Status = NtfsDeviceIoControl(DeviceToMount,
56 IOCTL_DISK_GET_DRIVE_GEOMETRY,
57 NULL,
58 0,
59 &DiskGeometry,
60 &Size);
61 if (!NT_SUCCESS(Status))
62 {
63 DPRINT("NtfsDeviceIoControl() failed (Status %lx)\n", Status);
64 return(Status);
65 }
66
67 if (DiskGeometry.MediaType == FixedMedia)
68 {
69 /* We have found a hard disk */
70 Size = sizeof(PARTITION_INFORMATION);
71 Status = NtfsDeviceIoControl(DeviceToMount,
72 IOCTL_DISK_GET_PARTITION_INFO,
73 NULL,
74 0,
75 &PartitionInfo,
76 &Size);
77 if (!NT_SUCCESS(Status))
78 {
79 DPRINT("NtfsDeviceIoControl() failed (Status %lx)\n", Status);
80 return(Status);
81 }
82
83 if (PartitionInfo.PartitionType != PARTITION_IFS)
84 {
85 return(STATUS_UNRECOGNIZED_VOLUME);
86 }
87 }
88
89 DPRINT("BytesPerSector: %lu\n", DiskGeometry.BytesPerSector);
90 BootSector = ExAllocatePool(NonPagedPool,
91 DiskGeometry.BytesPerSector);
92 if (BootSector == NULL)
93 {
94 return(STATUS_INSUFFICIENT_RESOURCES);
95 }
96
97 Status = NtfsReadRawSectors(DeviceToMount,
98 0,
99 1,
100 DiskGeometry.BytesPerSector,
101 (PVOID)BootSector);
102 if (NT_SUCCESS(Status))
103 {
104 DPRINT("NTFS-identifier: [%.8s]\n", BootSector->OemName);
105 if (strncmp(BootSector->OemName, "NTFS ", 8) != 0)
106 {
107 Status = STATUS_UNRECOGNIZED_VOLUME;
108 }
109 }
110
111 ExFreePool(BootSector);
112
113 return(Status);
114 }
115
116
117 static NTSTATUS
118 NtfsGetVolumeData(PDEVICE_OBJECT DeviceObject,
119 PDEVICE_EXTENSION Vcb)
120 {
121 DISK_GEOMETRY DiskGeometry;
122 // PUCHAR Buffer;
123 ULONG Size;
124 NTSTATUS Status;
125 PBOOT_SECTOR BootSector;
126
127 DPRINT("NtfsGetVolumeData() called\n");
128
129 Size = sizeof(DISK_GEOMETRY);
130 Status = NtfsDeviceIoControl(DeviceObject,
131 IOCTL_DISK_GET_DRIVE_GEOMETRY,
132 NULL,
133 0,
134 &DiskGeometry,
135 &Size);
136 if (!NT_SUCCESS(Status))
137 {
138 DPRINT("NtfsDeviceIoControl() failed (Status %lx)\n", Status);
139 return(Status);
140 }
141
142 DPRINT("BytesPerSector: %lu\n", DiskGeometry.BytesPerSector);
143 BootSector = ExAllocatePool(NonPagedPool,
144 DiskGeometry.BytesPerSector);
145 if (BootSector == NULL)
146 {
147 return(STATUS_INSUFFICIENT_RESOURCES);
148 }
149
150 Status = NtfsReadRawSectors(DeviceObject,
151 0, /* Partition boot sector */
152 1,
153 DiskGeometry.BytesPerSector,
154 (PVOID)BootSector);
155 if (NT_SUCCESS(Status))
156 {
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;
162
163 Vcb->NtfsInfo.MftStart.QuadPart = BootSector->MftLocation;
164 Vcb->NtfsInfo.MftMirrStart.QuadPart = BootSector->MftMirrLocation;
165 Vcb->NtfsInfo.SerialNumber = BootSector->SerialNumber;
166
167 //#indef NDEBUG
168 DbgPrint("Boot sector information:\n");
169 DbgPrint(" BytesPerSector: %hu\n", BootSector->BytesPerSector);
170 DbgPrint(" SectorsPerCluster: %hu\n", BootSector->SectorsPerCluster);
171
172 DbgPrint(" SectorCount: %I64u\n", BootSector->SectorCount);
173
174 DbgPrint(" MftStart: %I64u\n", BootSector->MftLocation);
175 DbgPrint(" MftMirrStart: %I64u\n", BootSector->MftMirrLocation);
176
177 DbgPrint(" ClustersPerMftRecord: %lx\n", BootSector->ClustersPerMftRecord);
178 DbgPrint(" ClustersPerIndexRecord: %lx\n", BootSector->ClustersPerIndexRecord);
179
180 DbgPrint(" SerialNumber: %I64x\n", BootSector->SerialNumber);
181 //#endif
182
183 NtfsOpenMft(DeviceObject, Vcb);
184
185 }
186
187 ExFreePool(BootSector);
188
189 return(Status);
190 }
191
192
193
194 static NTSTATUS
195 NtfsMountVolume(PDEVICE_OBJECT DeviceObject,
196 PIRP Irp)
197 {
198 PDEVICE_EXTENSION DeviceExt = NULL;
199 PDEVICE_OBJECT NewDeviceObject = NULL;
200 PDEVICE_OBJECT DeviceToMount;
201 PIO_STACK_LOCATION Stack;
202 PFCB Fcb = NULL;
203 PCCB Ccb = NULL;
204 PVPB Vpb;
205 NTSTATUS Status;
206
207 DPRINT("NtfsMountVolume() called\n");
208
209 if (DeviceObject != NtfsGlobalData->DeviceObject)
210 {
211 Status = STATUS_INVALID_DEVICE_REQUEST;
212 goto ByeBye;
213 }
214
215 Stack = IoGetCurrentIrpStackLocation(Irp);
216 DeviceToMount = Stack->Parameters.MountVolume.DeviceObject;
217 Vpb = Stack->Parameters.MountVolume.Vpb;
218
219 Status = NtfsHasFileSystem(DeviceToMount);
220 if (!NT_SUCCESS(Status))
221 {
222 goto ByeBye;
223 }
224
225 Status = IoCreateDevice(NtfsGlobalData->DriverObject,
226 sizeof(DEVICE_EXTENSION),
227 NULL,
228 FILE_DEVICE_FILE_SYSTEM,
229 // FILE_DEVICE_DISK_FILE_SYSTEM,
230 0,
231 FALSE,
232 &NewDeviceObject);
233 if (!NT_SUCCESS(Status))
234 goto ByeBye;
235
236 NewDeviceObject->Flags = NewDeviceObject->Flags | DO_DIRECT_IO;
237 DeviceExt = (PVOID)NewDeviceObject->DeviceExtension;
238 RtlZeroMemory(DeviceExt,
239 sizeof(DEVICE_EXTENSION));
240
241 Status = NtfsGetVolumeData(DeviceToMount,
242 DeviceExt);
243 if (!NT_SUCCESS(Status))
244 goto ByeBye;
245
246 NewDeviceObject->Vpb = DeviceToMount->Vpb;
247
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;
254
255 DeviceExt->StreamFileObject = IoCreateStreamFileObject(NULL,
256 DeviceExt->StorageDevice);
257
258
259 Fcb = NtfsCreateFCB(NULL);
260 if (Fcb == NULL)
261 {
262 Status = STATUS_INSUFFICIENT_RESOURCES;
263 goto ByeBye;
264 }
265
266 Ccb = ExAllocatePoolWithTag(NonPagedPool,
267 sizeof(CCB),
268 TAG_CCB);
269 if (Ccb == NULL)
270 {
271 Status = STATUS_INSUFFICIENT_RESOURCES;
272 goto ByeBye;
273 }
274 RtlZeroMemory(Ccb,
275 sizeof(CCB));
276
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;
286
287 Fcb->Flags = FCB_IS_VOLUME_STREAM;
288
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? */
292
293 // Fcb->Entry.ExtentLocationL = 0;
294 // Fcb->Entry.DataLengthL = DeviceExt->CdInfo.VolumeSpaceSize * BLOCKSIZE;
295
296 Status = CcRosInitializeFileCache(DeviceExt->StreamFileObject,
297 CACHEPAGESIZE(DeviceExt));
298 if (!NT_SUCCESS (Status))
299 {
300 DbgPrint("CcRosInitializeFileCache() failed (Status %lx)\n", Status);
301 goto ByeBye;
302 }
303
304 ExInitializeResourceLite(&DeviceExt->DirResource);
305 // ExInitializeResourceLite(&DeviceExt->FatResource);
306
307 KeInitializeSpinLock(&DeviceExt->FcbListLock);
308 InitializeListHead(&DeviceExt->FcbListHead);
309
310 /* Read serial number */
311 NewDeviceObject->Vpb->SerialNumber = DeviceExt->NtfsInfo.SerialNumber;
312
313 /* Read volume label */
314 // NtfsReadVolumeLabel(DeviceExt,
315 // NewDeviceObject->Vpb);
316
317 Status = STATUS_SUCCESS;
318
319 ByeBye:
320 if (!NT_SUCCESS(Status))
321 {
322 /* Cleanup */
323 if (DeviceExt && DeviceExt->StreamFileObject)
324 ObDereferenceObject(DeviceExt->StreamFileObject);
325 if (Fcb)
326 ExFreePool(Fcb);
327 if (Ccb)
328 ExFreePool(Ccb);
329 if (NewDeviceObject)
330 IoDeleteDevice(NewDeviceObject);
331 }
332
333 DPRINT("NtfsMountVolume() done (Status: %lx)\n", Status);
334
335 return(Status);
336 }
337
338
339 static NTSTATUS
340 NtfsVerifyVolume(PDEVICE_OBJECT DeviceObject,
341 PIRP Irp)
342 {
343 #if 0
344 PDEVICE_OBJECT DeviceToVerify;
345 PIO_STACK_LOCATION Stack;
346 PUCHAR Buffer;
347 ULONG Sector;
348 ULONG i;
349 NTSTATUS Status;
350
351 union
352 {
353 ULONG Value;
354 UCHAR Part[4];
355 } Serial;
356 #endif
357
358 DPRINT1("NtfsVerifyVolume() called\n");
359
360 #if 0
361 Stack = IoGetCurrentIrpStackLocation(Irp);
362 DeviceToVerify = Stack->Parameters.VerifyVolume.DeviceObject;
363
364 DPRINT("Device object %p Device to verify %p\n", DeviceObject, DeviceToVerify);
365
366 Sector = CDFS_PRIMARY_DESCRIPTOR_LOCATION;
367
368 Buffer = ExAllocatePool(NonPagedPool,
369 CDFS_BASIC_SECTOR);
370 if (Buffer == NULL)
371 {
372 return(STATUS_INSUFFICIENT_RESOURCES);
373 }
374
375 do
376 {
377 /* Read the Primary Volume Descriptor (PVD) */
378 Status = CdfsReadRawSectors(DeviceToVerify,
379 Sector,
380 1,
381 Buffer);
382 DPRINT("CdfsReadRawSectors() status %lx\n", Status);
383 if (!NT_SUCCESS(Status))
384 {
385 goto ByeBye;
386 }
387
388 if (Buffer[0] == 1 &&
389 Buffer[1] == 'C' &&
390 Buffer[2] == 'D' &&
391 Buffer[3] == '0' &&
392 Buffer[4] == '0' &&
393 Buffer[5] == '1')
394 {
395 break;
396 }
397
398 Sector++;
399 }
400 while (Buffer[0] != 255);
401
402 if (Buffer[0] == 255)
403 goto ByeBye;
404
405 Status = STATUS_WRONG_VOLUME;
406
407 /* Calculate the volume serial number */
408 Serial.Value = 0;
409 for (i = 0; i < 2048; i += 4)
410 {
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];
416 }
417
418 DPRINT("Current serial number %08lx Vpb serial number %08lx\n",
419 Serial.Value, DeviceToVerify->Vpb->SerialNumber);
420
421 if (Serial.Value == DeviceToVerify->Vpb->SerialNumber)
422 Status = STATUS_SUCCESS;
423
424 ByeBye:
425 ExFreePool(Buffer);
426
427 DPRINT("CdfsVerifyVolume() done (Status: %lx)\n", Status);
428
429 return(Status);
430 #endif
431 return(STATUS_UNSUCCESSFUL);
432 }
433
434
435 NTSTATUS STDCALL
436 NtfsFileSystemControl(PDEVICE_OBJECT DeviceObject,
437 PIRP Irp)
438 {
439 PIO_STACK_LOCATION Stack;
440 NTSTATUS Status;
441
442 DPRINT("NtfsFileSystemControl() called\n");
443
444 Stack = IoGetCurrentIrpStackLocation(Irp);
445
446 switch (Stack->MinorFunction)
447 {
448 case IRP_MN_USER_FS_REQUEST:
449 DPRINT("NTFS: IRP_MN_USER_FS_REQUEST\n");
450 Status = STATUS_INVALID_DEVICE_REQUEST;
451 break;
452
453 case IRP_MN_MOUNT_VOLUME:
454 DPRINT("NTFS: IRP_MN_MOUNT_VOLUME\n");
455 Status = NtfsMountVolume(DeviceObject, Irp);
456 break;
457
458 case IRP_MN_VERIFY_VOLUME:
459 DPRINT1("NTFS: IRP_MN_VERIFY_VOLUME\n");
460 Status = NtfsVerifyVolume(DeviceObject, Irp);
461 break;
462
463 default:
464 DPRINT("NTFS FSC: MinorFunction %d\n", Stack->MinorFunction);
465 Status = STATUS_INVALID_DEVICE_REQUEST;
466 break;
467 }
468
469 Irp->IoStatus.Status = Status;
470 Irp->IoStatus.Information = 0;
471
472 IoCompleteRequest(Irp, IO_NO_INCREMENT);
473
474 return(Status);
475 }
476
477 /* EOF */