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