- NDK 0.98, now with versionned headers. Too many changes to list, see the TinyKRNL...
[reactos.git] / reactos / ntoskrnl / io / fs.c
1 /* $Id$
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/io/fs.c
6 * PURPOSE: Filesystem functions
7 *
8 * PROGRAMMERS: David Welch (welch@mcmail.com)
9 */
10
11 /* INCLUDES *****************************************************************/
12
13 #include <ntoskrnl.h>
14 #define NDEBUG
15 #include <internal/debug.h>
16
17 #if defined (ALLOC_PRAGMA)
18 #pragma alloc_text(INIT, IoInitFileSystemImplementation)
19 #endif
20
21 /* TYPES *******************************************************************/
22
23 typedef struct _FILE_SYSTEM_OBJECT
24 {
25 PDEVICE_OBJECT DeviceObject;
26 LIST_ENTRY Entry;
27 } FILE_SYSTEM_OBJECT, *PFILE_SYSTEM_OBJECT;
28
29 typedef struct _FS_CHANGE_NOTIFY_ENTRY
30 {
31 LIST_ENTRY FsChangeNotifyList;
32 PDRIVER_OBJECT DriverObject;
33 PDRIVER_FS_NOTIFICATION FSDNotificationProc;
34 } FS_CHANGE_NOTIFY_ENTRY, *PFS_CHANGE_NOTIFY_ENTRY;
35
36 /* GLOBALS ******************************************************************/
37
38 static ERESOURCE FileSystemListLock;
39 static LIST_ENTRY FileSystemListHead;
40
41 static KGUARDED_MUTEX FsChangeNotifyListLock;
42 static LIST_ENTRY FsChangeNotifyListHead;
43
44 static VOID
45 IopNotifyFileSystemChange(PDEVICE_OBJECT DeviceObject,
46 BOOLEAN DriverActive);
47
48
49 /* FUNCTIONS *****************************************************************/
50
51 /*
52 * @unimplemented
53 */
54 VOID
55 STDCALL
56 IoCancelFileOpen(
57 IN PDEVICE_OBJECT DeviceObject,
58 IN PFILE_OBJECT FileObject
59 )
60 {
61 UNIMPLEMENTED;
62 }
63
64 VOID INIT_FUNCTION
65 IoInitFileSystemImplementation(VOID)
66 {
67 InitializeListHead(&FileSystemListHead);
68 ExInitializeResourceLite(&FileSystemListLock);
69
70 InitializeListHead(&FsChangeNotifyListHead);
71 KeInitializeGuardedMutex(&FsChangeNotifyListLock);
72 }
73
74
75 VOID
76 IoShutdownRegisteredFileSystems(VOID)
77 {
78 FILE_SYSTEM_OBJECT* current;
79 PIRP Irp;
80 KEVENT Event;
81 IO_STATUS_BLOCK IoStatusBlock;
82 NTSTATUS Status;
83
84 DPRINT("IoShutdownRegisteredFileSystems()\n");
85
86 KeEnterCriticalRegion();
87 ExAcquireResourceSharedLite(&FileSystemListLock,TRUE);
88 KeInitializeEvent(&Event,
89 NotificationEvent,
90 FALSE);
91
92 LIST_FOR_EACH(current, &FileSystemListHead, FILE_SYSTEM_OBJECT,Entry)
93 {
94 /* send IRP_MJ_SHUTDOWN */
95 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_SHUTDOWN,
96 current->DeviceObject,
97 NULL,
98 0,
99 0,
100 &Event,
101 &IoStatusBlock);
102
103 Status = IoCallDriver(current->DeviceObject,Irp);
104 if (Status == STATUS_PENDING)
105 {
106 KeWaitForSingleObject(&Event,
107 Executive,
108 KernelMode,
109 FALSE,
110 NULL);
111 }
112 }
113
114 ExReleaseResourceLite(&FileSystemListLock);
115 KeLeaveCriticalRegion();
116 }
117
118
119 static NTSTATUS
120 IopMountFileSystem(PDEVICE_OBJECT DeviceObject,
121 PDEVICE_OBJECT DeviceToMount)
122 {
123 IO_STATUS_BLOCK IoStatusBlock;
124 PIO_STACK_LOCATION StackPtr;
125 KEVENT Event;
126 PIRP Irp;
127 NTSTATUS Status;
128
129 DPRINT("IopMountFileSystem(DeviceObject 0x%p, DeviceToMount 0x%p)\n",
130 DeviceObject,DeviceToMount);
131
132 ASSERT_IRQL(PASSIVE_LEVEL);
133
134 KeInitializeEvent(&Event, NotificationEvent, FALSE);
135 Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
136 if (Irp==NULL)
137 {
138 return(STATUS_INSUFFICIENT_RESOURCES);
139 }
140
141 Irp->UserIosb = &IoStatusBlock;
142 DPRINT("Irp->UserIosb 0x%p\n", Irp->UserIosb);
143 Irp->UserEvent = &Event;
144 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
145
146 StackPtr = IoGetNextIrpStackLocation(Irp);
147 StackPtr->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL;
148 StackPtr->MinorFunction = IRP_MN_MOUNT_VOLUME;
149 StackPtr->Flags = 0;
150 StackPtr->Control = 0;
151 StackPtr->DeviceObject = DeviceObject;
152 StackPtr->FileObject = NULL;
153 StackPtr->CompletionRoutine = NULL;
154
155 StackPtr->Parameters.MountVolume.Vpb = DeviceToMount->Vpb;
156 StackPtr->Parameters.MountVolume.DeviceObject = DeviceToMount;
157
158 Status = IoCallDriver(DeviceObject,Irp);
159 if (Status==STATUS_PENDING)
160 {
161 KeWaitForSingleObject(&Event,Executive,KernelMode,FALSE,NULL);
162 Status = IoStatusBlock.Status;
163 }
164
165 return(Status);
166 }
167
168
169 static NTSTATUS
170 IopLoadFileSystem(IN PDEVICE_OBJECT DeviceObject)
171 {
172 IO_STATUS_BLOCK IoStatusBlock;
173 PIO_STACK_LOCATION StackPtr;
174 KEVENT Event;
175 PIRP Irp;
176 NTSTATUS Status;
177
178 DPRINT("IopLoadFileSystem(DeviceObject 0x%p)\n", DeviceObject);
179
180 ASSERT_IRQL(PASSIVE_LEVEL);
181
182 KeInitializeEvent(&Event, NotificationEvent, FALSE);
183 Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
184 if (Irp==NULL)
185 {
186 return(STATUS_INSUFFICIENT_RESOURCES);
187 }
188
189 Irp->UserIosb = &IoStatusBlock;
190 DPRINT("Irp->UserIosb 0x%p\n", Irp->UserIosb);
191 Irp->UserEvent = &Event;
192 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
193
194 StackPtr = IoGetNextIrpStackLocation(Irp);
195 StackPtr->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL;
196 StackPtr->MinorFunction = IRP_MN_LOAD_FILE_SYSTEM;
197 StackPtr->Flags = 0;
198 StackPtr->Control = 0;
199 StackPtr->DeviceObject = DeviceObject;
200 StackPtr->FileObject = NULL;
201 StackPtr->CompletionRoutine = NULL;
202
203 Status = IoCallDriver(DeviceObject,Irp);
204 if (Status==STATUS_PENDING)
205 {
206 KeWaitForSingleObject(&Event,Executive,KernelMode,FALSE,NULL);
207 Status = IoStatusBlock.Status;
208 }
209
210 return(Status);
211 }
212
213
214 NTSTATUS
215 IoMountVolume(IN PDEVICE_OBJECT DeviceObject,
216 IN BOOLEAN AllowRawMount)
217 /*
218 * FUNCTION: Mounts a logical volume
219 * ARGUMENTS:
220 * DeviceObject = Device to mount
221 * RETURNS: Status
222 */
223 {
224 PFILE_SYSTEM_OBJECT current;
225 NTSTATUS Status;
226 DEVICE_TYPE MatchingDeviceType;
227 PDEVICE_OBJECT DevObject;
228
229 ASSERT_IRQL(PASSIVE_LEVEL);
230
231 DPRINT("IoMountVolume(DeviceObject 0x%p AllowRawMount %x)\n",
232 DeviceObject, AllowRawMount);
233
234 switch (DeviceObject->DeviceType)
235 {
236 case FILE_DEVICE_DISK:
237 case FILE_DEVICE_VIRTUAL_DISK: /* ?? */
238 MatchingDeviceType = FILE_DEVICE_DISK_FILE_SYSTEM;
239 break;
240
241 case FILE_DEVICE_CD_ROM:
242 MatchingDeviceType = FILE_DEVICE_CD_ROM_FILE_SYSTEM;
243 break;
244
245 case FILE_DEVICE_NETWORK:
246 MatchingDeviceType = FILE_DEVICE_NETWORK_FILE_SYSTEM;
247 break;
248
249 case FILE_DEVICE_TAPE:
250 MatchingDeviceType = FILE_DEVICE_TAPE_FILE_SYSTEM;
251 break;
252
253 default:
254 CPRINT("No matching file system type found for device type: %x\n",
255 DeviceObject->DeviceType);
256 return(STATUS_UNRECOGNIZED_VOLUME);
257 }
258
259 KeEnterCriticalRegion();
260 ExAcquireResourceSharedLite(&FileSystemListLock,TRUE);
261
262 restart:
263 LIST_FOR_EACH(current,&FileSystemListHead, FILE_SYSTEM_OBJECT, Entry)
264 {
265 if (current->DeviceObject->DeviceType != MatchingDeviceType)
266 {
267 continue;
268 }
269 /* If we are not allowed to mount this volume as a raw filesystem volume
270 then don't try this */
271 if (!AllowRawMount && RawFsIsRawFileSystemDeviceObject(current->DeviceObject))
272 {
273 Status = STATUS_UNRECOGNIZED_VOLUME;
274 }
275 else
276 {
277 Status = IopMountFileSystem(current->DeviceObject,
278 DeviceObject);
279 }
280 switch (Status)
281 {
282 case STATUS_FS_DRIVER_REQUIRED:
283 DevObject = current->DeviceObject;
284 ExReleaseResourceLite(&FileSystemListLock);
285 Status = IopLoadFileSystem(DevObject);
286 if (!NT_SUCCESS(Status))
287 {
288 KeLeaveCriticalRegion();
289 return(Status);
290 }
291 ExAcquireResourceSharedLite(&FileSystemListLock,TRUE);
292 goto restart;
293
294 case STATUS_SUCCESS:
295 DeviceObject->Vpb->Flags = DeviceObject->Vpb->Flags |
296 VPB_MOUNTED;
297 ExReleaseResourceLite(&FileSystemListLock);
298 KeLeaveCriticalRegion();
299 return(STATUS_SUCCESS);
300
301 case STATUS_UNRECOGNIZED_VOLUME:
302 default:
303 /* do nothing */
304 break;
305 }
306 }
307 ExReleaseResourceLite(&FileSystemListLock);
308 KeLeaveCriticalRegion();
309
310 return(STATUS_UNRECOGNIZED_VOLUME);
311 }
312
313
314 /**********************************************************************
315 * NAME EXPORTED
316 * IoVerifyVolume
317 *
318 * DESCRIPTION
319 * Verify the file system type and volume information or mount
320 * a file system.
321 *
322 * ARGUMENTS
323 * DeviceObject
324 * Device to verify or mount
325 *
326 * AllowRawMount
327 * ...
328 *
329 * RETURN VALUE
330 * Status
331 *
332 * @implemented
333 */
334 NTSTATUS STDCALL
335 IoVerifyVolume(IN PDEVICE_OBJECT DeviceObject,
336 IN BOOLEAN AllowRawMount)
337 {
338 IO_STATUS_BLOCK IoStatusBlock;
339 PIO_STACK_LOCATION StackPtr;
340 KEVENT Event;
341 PIRP Irp;
342 NTSTATUS Status;
343 PDEVICE_OBJECT DevObject;
344
345 DPRINT("IoVerifyVolume(DeviceObject 0x%p AllowRawMount %x)\n",
346 DeviceObject, AllowRawMount);
347
348 Status = STATUS_SUCCESS;
349
350 KeWaitForSingleObject(&DeviceObject->DeviceLock,
351 Executive,
352 KernelMode,
353 FALSE,
354 NULL);
355
356 if (DeviceObject->Vpb->Flags & VPB_MOUNTED)
357 {
358 /* Issue verify request to the FSD */
359 DevObject = DeviceObject->Vpb->DeviceObject;
360
361 KeInitializeEvent(&Event,
362 NotificationEvent,
363 FALSE);
364
365 Irp = IoAllocateIrp(DevObject->StackSize, TRUE);
366 if (Irp==NULL)
367 {
368 return(STATUS_INSUFFICIENT_RESOURCES);
369 }
370
371 Irp->UserIosb = &IoStatusBlock;
372 Irp->UserEvent = &Event;
373 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
374
375 StackPtr = IoGetNextIrpStackLocation(Irp);
376 StackPtr->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL;
377 StackPtr->MinorFunction = IRP_MN_VERIFY_VOLUME;
378 StackPtr->Flags = 0;
379 StackPtr->Control = 0;
380 StackPtr->DeviceObject = DevObject;
381 StackPtr->FileObject = NULL;
382 StackPtr->CompletionRoutine = NULL;
383
384 StackPtr->Parameters.VerifyVolume.Vpb = DeviceObject->Vpb;
385 StackPtr->Parameters.VerifyVolume.DeviceObject = DeviceObject;
386
387 Status = IoCallDriver(DevObject,
388 Irp);
389 if (Status==STATUS_PENDING)
390 {
391 KeWaitForSingleObject(&Event,Executive,KernelMode,FALSE,NULL);
392 Status = IoStatusBlock.Status;
393 }
394
395 if (NT_SUCCESS(Status))
396 {
397 KeSetEvent(&DeviceObject->DeviceLock,
398 IO_NO_INCREMENT,
399 FALSE);
400 return(STATUS_SUCCESS);
401 }
402 }
403
404 if (Status == STATUS_WRONG_VOLUME)
405 {
406 /* Clean existing VPB. This unmounts the filesystem. */
407 DPRINT("Wrong volume!\n");
408
409 DeviceObject->Vpb->DeviceObject = NULL;
410 DeviceObject->Vpb->Flags &= ~VPB_MOUNTED;
411 }
412
413 /* Start mount sequence */
414 Status = IoMountVolume(DeviceObject,
415 AllowRawMount);
416
417 KeSetEvent(&DeviceObject->DeviceLock,
418 IO_NO_INCREMENT,
419 FALSE);
420
421 return(Status);
422 }
423
424
425 /*
426 * @implemented
427 */
428 PDEVICE_OBJECT STDCALL
429 IoGetDeviceToVerify(IN PETHREAD Thread)
430 /*
431 * FUNCTION: Returns a pointer to the device, representing a removable-media
432 * device, that is the target of the given thread's I/O request
433 */
434 {
435 return(Thread->DeviceToVerify);
436 }
437
438
439 /*
440 * @implemented
441 */
442 VOID STDCALL
443 IoSetDeviceToVerify(IN PETHREAD Thread,
444 IN PDEVICE_OBJECT DeviceObject)
445 {
446 Thread->DeviceToVerify = DeviceObject;
447 }
448
449
450 /*
451 * @implemented
452 */
453 VOID STDCALL
454 IoSetHardErrorOrVerifyDevice(IN PIRP Irp,
455 IN PDEVICE_OBJECT DeviceObject)
456 {
457 Irp->Tail.Overlay.Thread->DeviceToVerify = DeviceObject;
458 }
459
460
461 /*
462 * @implemented
463 */
464 VOID STDCALL
465 IoRegisterFileSystem(IN PDEVICE_OBJECT DeviceObject)
466 {
467 PFILE_SYSTEM_OBJECT Fs;
468
469 DPRINT("IoRegisterFileSystem(DeviceObject 0x%p)\n", DeviceObject);
470
471 Fs = ExAllocatePoolWithTag(NonPagedPool,
472 sizeof(FILE_SYSTEM_OBJECT),
473 TAG_FILE_SYSTEM);
474 ASSERT(Fs!=NULL);
475
476 Fs->DeviceObject = DeviceObject;
477 KeEnterCriticalRegion();
478 ExAcquireResourceExclusiveLite(&FileSystemListLock, TRUE);
479
480 /* The RAW filesystem device objects must be last in the list so the
481 raw filesystem driver is the last filesystem driver asked to mount
482 a volume. It is always the first filesystem driver registered so
483 we use InsertHeadList() here as opposed to the other alternative
484 InsertTailList(). */
485 InsertHeadList(&FileSystemListHead,
486 &Fs->Entry);
487
488 ExReleaseResourceLite(&FileSystemListLock);
489 KeLeaveCriticalRegion();
490
491 IopNotifyFileSystemChange(DeviceObject,
492 TRUE);
493 }
494
495
496 /*
497 * @implemented
498 */
499 VOID STDCALL
500 IoUnregisterFileSystem(IN PDEVICE_OBJECT DeviceObject)
501 {
502 PFILE_SYSTEM_OBJECT current;
503
504 DPRINT("IoUnregisterFileSystem(DeviceObject 0x%p)\n", DeviceObject);
505
506 KeEnterCriticalRegion();
507 ExAcquireResourceExclusiveLite(&FileSystemListLock, TRUE);
508
509 LIST_FOR_EACH(current,&FileSystemListHead, FILE_SYSTEM_OBJECT,Entry)
510 {
511 if (current->DeviceObject == DeviceObject)
512 {
513 RemoveEntryList(&current->Entry);
514 ExFreePoolWithTag(current, TAG_FILE_SYSTEM);
515 ExReleaseResourceLite(&FileSystemListLock);
516 KeLeaveCriticalRegion();
517 IopNotifyFileSystemChange(DeviceObject, FALSE);
518 return;
519 }
520 }
521
522 ExReleaseResourceLite(&FileSystemListLock);
523 KeLeaveCriticalRegion();
524 }
525
526
527 /**********************************************************************
528 * NAME EXPORTED
529 * IoGetBaseFileSystemDeviceObject@4
530 *
531 * DESCRIPTION
532 * Get the DEVICE_OBJECT associated to
533 * a FILE_OBJECT.
534 *
535 * ARGUMENTS
536 * FileObject
537 *
538 * RETURN VALUE
539 *
540 * NOTE
541 * From Bo Branten's ntifs.h v13.
542 *
543 * @implemented
544 */
545 PDEVICE_OBJECT STDCALL
546 IoGetBaseFileSystemDeviceObject(IN PFILE_OBJECT FileObject)
547 {
548 PDEVICE_OBJECT DeviceObject = NULL;
549 PVPB Vpb = NULL;
550
551 /*
552 * If the FILE_OBJECT's VPB is defined,
553 * get the device from it.
554 */
555 if (NULL != (Vpb = FileObject->Vpb))
556 {
557 if (NULL != (DeviceObject = Vpb->DeviceObject))
558 {
559 /* Vpb->DeviceObject DEFINED! */
560 return DeviceObject;
561 }
562 }
563 /*
564 * If that failed, try the VPB
565 * in the FILE_OBJECT's DeviceObject.
566 */
567 DeviceObject = FileObject->DeviceObject;
568 if (NULL == (Vpb = DeviceObject->Vpb))
569 {
570 /* DeviceObject->Vpb UNDEFINED! */
571 return DeviceObject;
572 }
573 /*
574 * If that pointer to the VPB is again
575 * undefined, return directly the
576 * device object from the FILE_OBJECT.
577 */
578 return (
579 (NULL == Vpb->DeviceObject)
580 ? DeviceObject
581 : Vpb->DeviceObject
582 );
583 }
584
585
586 static VOID
587 IopNotifyFileSystemChange(PDEVICE_OBJECT DeviceObject,
588 BOOLEAN DriverActive)
589 {
590 PFS_CHANGE_NOTIFY_ENTRY ChangeEntry;
591
592 KeAcquireGuardedMutex(&FsChangeNotifyListLock);
593 LIST_FOR_EACH(ChangeEntry, &FsChangeNotifyListHead,FS_CHANGE_NOTIFY_ENTRY, FsChangeNotifyList)
594 {
595 (ChangeEntry->FSDNotificationProc)(DeviceObject, DriverActive);
596 }
597 KeReleaseGuardedMutex(&FsChangeNotifyListLock);
598 }
599
600
601 /*
602 * @implemented
603 */
604 NTSTATUS STDCALL
605 IoRegisterFsRegistrationChange(IN PDRIVER_OBJECT DriverObject,
606 IN PDRIVER_FS_NOTIFICATION FSDNotificationProc)
607 {
608 PFS_CHANGE_NOTIFY_ENTRY Entry;
609
610 Entry = ExAllocatePoolWithTag(NonPagedPool,
611 sizeof(FS_CHANGE_NOTIFY_ENTRY),
612 TAG_FS_CHANGE_NOTIFY);
613 if (Entry == NULL)
614 return(STATUS_INSUFFICIENT_RESOURCES);
615
616 Entry->DriverObject = DriverObject;
617 Entry->FSDNotificationProc = FSDNotificationProc;
618
619 KeAcquireGuardedMutex(&FsChangeNotifyListLock);
620 InsertHeadList(&FsChangeNotifyListHead,
621 &Entry->FsChangeNotifyList);
622 KeReleaseGuardedMutex(&FsChangeNotifyListLock);
623
624 return(STATUS_SUCCESS);
625 }
626
627
628 /*
629 * @implemented
630 */
631 VOID STDCALL
632 IoUnregisterFsRegistrationChange(IN PDRIVER_OBJECT DriverObject,
633 IN PDRIVER_FS_NOTIFICATION FSDNotificationProc)
634 {
635 PFS_CHANGE_NOTIFY_ENTRY ChangeEntry;
636
637 LIST_FOR_EACH(ChangeEntry, &FsChangeNotifyListHead, FS_CHANGE_NOTIFY_ENTRY, FsChangeNotifyList)
638 {
639 if (ChangeEntry->DriverObject == DriverObject &&
640 ChangeEntry->FSDNotificationProc == FSDNotificationProc)
641 {
642 KeAcquireGuardedMutex(&FsChangeNotifyListLock);
643 RemoveEntryList(&ChangeEntry->FsChangeNotifyList);
644 KeReleaseGuardedMutex(&FsChangeNotifyListLock);
645
646 ExFreePoolWithTag(ChangeEntry, TAG_FS_CHANGE_NOTIFY);
647 return;
648 }
649
650 }
651 }
652
653 /* EOF */