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