:pserver:cvsanon@mok.lvcm.com:/CVS/ReactOS reactos
[reactos.git] / 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$
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 = (PVOID)&Fcb->RFCB;
279   DeviceExt->StreamFileObject->FsContext2 = Ccb;
280   DeviceExt->StreamFileObject->SectionObjectPointers = &Fcb->SectionObjectPointers;
281   DeviceExt->StreamFileObject->PrivateCacheMap = NULL;
282   DeviceExt->StreamFileObject->Vpb = DeviceExt->Vpb;
283   Ccb->Fcb = Fcb;
284   Ccb->PtrFileObject = DeviceExt->StreamFileObject;
285   Fcb->FileObject = DeviceExt->StreamFileObject;
286   Fcb->DevExt = (PDEVICE_EXTENSION)DeviceExt->StorageDevice;
287
288   Fcb->Flags = FCB_IS_VOLUME_STREAM;
289
290   Fcb->RFCB.FileSize.QuadPart = DeviceExt->NtfsInfo.SectorCount * DeviceExt->NtfsInfo.BytesPerSector;
291   Fcb->RFCB.ValidDataLength.QuadPart = DeviceExt->NtfsInfo.SectorCount * DeviceExt->NtfsInfo.BytesPerSector;
292   Fcb->RFCB.AllocationSize.QuadPart = DeviceExt->NtfsInfo.SectorCount * DeviceExt->NtfsInfo.BytesPerSector; /* Correct? */
293
294 //  Fcb->Entry.ExtentLocationL = 0;
295 //  Fcb->Entry.DataLengthL = DeviceExt->CdInfo.VolumeSpaceSize * BLOCKSIZE;
296
297   Status = CcRosInitializeFileCache(DeviceExt->StreamFileObject,
298                                     &Fcb->RFCB.Bcb,
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 */