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