Added ObGetObjectHandleCount().
[reactos.git] / reactos / ntoskrnl / io / fs.c
1 /* $Id: fs.c,v 1.20 2001/12/05 12:14:13 ekohl Exp $
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 * PROGRAMMER: David Welch (welch@mcmail.com)
8 * UPDATE HISTORY:
9 * Created 22/05/98
10 */
11
12 /* INCLUDES *****************************************************************/
13
14 #include <ddk/ntddk.h>
15 #include <internal/io.h>
16 #include <internal/pool.h>
17
18 #define NDEBUG
19 #include <internal/debug.h>
20
21 /* TYPES *******************************************************************/
22
23 typedef struct
24 {
25 PDEVICE_OBJECT DeviceObject;
26 LIST_ENTRY Entry;
27 } FILE_SYSTEM_OBJECT;
28
29 typedef struct
30 {
31 LIST_ENTRY FsChangeNotifyList;
32 PDRIVER_OBJECT DriverObject;
33 PFSDNOTIFICATIONPROC FSDNotificationProc;
34 } FS_CHANGE_NOTIFY_ENTRY, *PFS_CHANGE_NOTIFY_ENTRY;
35
36 /* GLOBALS ******************************************************************/
37
38 static KSPIN_LOCK FileSystemListLock;
39 static LIST_ENTRY FileSystemListHead;
40
41 static KSPIN_LOCK FsChangeNotifyListLock;
42 static LIST_ENTRY FsChangeNotifyListHead;
43
44 #define TAG_FILE_SYSTEM TAG('F', 'S', 'Y', 'S')
45 #define TAG_FS_CHANGE_NOTIFY TAG('F', 'S', 'C', 'N')
46
47
48 static VOID IopNotifyFileSystemChange(PDEVICE_OBJECT DeviceObject,
49 BOOLEAN DriverActive);
50
51 /* FUNCTIONS *****************************************************************/
52
53 NTSTATUS STDCALL
54 NtFsControlFile (
55 IN HANDLE DeviceHandle,
56 IN HANDLE EventHandle OPTIONAL,
57 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
58 IN PVOID ApcContext OPTIONAL,
59 OUT PIO_STATUS_BLOCK IoStatusBlock,
60 IN ULONG IoControlCode,
61 IN PVOID InputBuffer,
62 IN ULONG InputBufferSize,
63 OUT PVOID OutputBuffer,
64 IN ULONG OutputBufferSize
65 )
66 {
67 NTSTATUS Status;
68 PFILE_OBJECT FileObject;
69 PDEVICE_OBJECT DeviceObject;
70 PIRP Irp;
71 PIO_STACK_LOCATION StackPtr;
72 KEVENT KEvent;
73 IO_STATUS_BLOCK IoSB;
74
75 DPRINT("NtFsControlFile(DeviceHandle %x EventHandle %x ApcRoutine %x "
76 "ApcContext %x IoStatusBlock %x IoControlCode %x "
77 "InputBuffer %x InputBufferSize %x OutputBuffer %x "
78 "OutputBufferSize %x)\n",
79 DeviceHandle,EventHandle,ApcRoutine,ApcContext,IoStatusBlock,
80 IoControlCode,InputBuffer,InputBufferSize,OutputBuffer,
81 OutputBufferSize);
82
83 Status = ObReferenceObjectByHandle(DeviceHandle,
84 FILE_READ_DATA | FILE_WRITE_DATA,
85 NULL,
86 KernelMode,
87 (PVOID *) &FileObject,
88 NULL);
89
90 if (!NT_SUCCESS(Status))
91 {
92 return(Status);
93 }
94
95 DeviceObject = FileObject->DeviceObject;
96
97 KeInitializeEvent(&KEvent,NotificationEvent,TRUE);
98
99 Irp = IoBuildDeviceIoControlRequest(IoControlCode,
100 DeviceObject,
101 InputBuffer,
102 InputBufferSize,
103 OutputBuffer,
104 OutputBufferSize,
105 FALSE,
106 &KEvent,
107 &IoSB);
108
109 Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
110 Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;
111
112 StackPtr = IoGetNextIrpStackLocation(Irp);
113 StackPtr->FileObject = FileObject;
114 StackPtr->DeviceObject = DeviceObject;
115 StackPtr->Parameters.FileSystemControl.InputBufferLength = InputBufferSize;
116 StackPtr->Parameters.FileSystemControl.OutputBufferLength =
117 OutputBufferSize;
118 StackPtr->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL;
119
120 Status = IoCallDriver(DeviceObject,Irp);
121 if (Status == STATUS_PENDING && !(FileObject->Flags & FO_SYNCHRONOUS_IO))
122 {
123 KeWaitForSingleObject(&KEvent,Executive,KernelMode,FALSE,NULL);
124 Status = IoSB.Status;
125 }
126 if (IoStatusBlock)
127 {
128 *IoStatusBlock = IoSB;
129 }
130 return(Status);
131 }
132
133 VOID IoInitFileSystemImplementation(VOID)
134 {
135 InitializeListHead(&FileSystemListHead);
136 KeInitializeSpinLock(&FileSystemListLock);
137
138 InitializeListHead(&FsChangeNotifyListHead);
139 KeInitializeSpinLock(&FsChangeNotifyListLock);
140 }
141
142 VOID IoShutdownRegisteredFileSystems(VOID)
143 {
144 KIRQL oldlvl;
145 PLIST_ENTRY current_entry;
146 FILE_SYSTEM_OBJECT* current;
147 PIRP Irp;
148 KEVENT Event;
149 IO_STATUS_BLOCK IoStatusBlock;
150 NTSTATUS Status;
151
152 DPRINT("IoShutdownRegisteredFileSystems()\n");
153
154 KeAcquireSpinLock(&FileSystemListLock,&oldlvl);
155 KeInitializeEvent(&Event,NotificationEvent,FALSE);
156
157 current_entry = FileSystemListHead.Flink;
158 while (current_entry!=(&FileSystemListHead))
159 {
160 current = CONTAINING_RECORD(current_entry,FILE_SYSTEM_OBJECT,Entry);
161
162 /* send IRP_MJ_SHUTDOWN */
163 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_SHUTDOWN,
164 current->DeviceObject,
165 NULL,
166 0,
167 0,
168 &Event,
169 &IoStatusBlock);
170
171 Status = IoCallDriver(current->DeviceObject,Irp);
172 if (Status==STATUS_PENDING)
173 {
174 KeWaitForSingleObject(&Event,Executive,KernelMode,FALSE,NULL);
175 }
176
177 current_entry = current_entry->Flink;
178 }
179
180 KeReleaseSpinLock(&FileSystemListLock,oldlvl);
181 }
182
183 NTSTATUS IoAskFileSystemToMountDevice(PDEVICE_OBJECT DeviceObject,
184 PDEVICE_OBJECT DeviceToMount)
185 {
186 PIRP Irp;
187 KEVENT Event;
188 IO_STATUS_BLOCK IoStatusBlock;
189 NTSTATUS Status;
190
191 DPRINT("IoAskFileSystemToMountDevice(DeviceObject %x, DeviceToMount %x)\n",
192 DeviceObject,DeviceToMount);
193
194 assert_irql(PASSIVE_LEVEL);
195
196 KeInitializeEvent(&Event,NotificationEvent,FALSE);
197 Irp = IoBuildFilesystemControlRequest(IRP_MN_MOUNT_VOLUME,
198 DeviceObject,
199 &Event,
200 &IoStatusBlock,
201 DeviceToMount);
202 Status = IoCallDriver(DeviceObject,Irp);
203 if (Status==STATUS_PENDING)
204 {
205 KeWaitForSingleObject(&Event,Executive,KernelMode,FALSE,NULL);
206 Status = IoStatusBlock.Status;
207 }
208 return(Status);
209 }
210
211 NTSTATUS IoAskFileSystemToLoad(PDEVICE_OBJECT DeviceObject)
212 {
213 UNIMPLEMENTED;
214 }
215
216 NTSTATUS IoTryToMountStorageDevice(PDEVICE_OBJECT DeviceObject)
217 /*
218 * FUNCTION: Trys to mount a storage device
219 * ARGUMENTS:
220 * DeviceObject = Device to try and mount
221 * RETURNS: Status
222 */
223 {
224 KIRQL oldlvl;
225 PLIST_ENTRY current_entry;
226 FILE_SYSTEM_OBJECT* current;
227 NTSTATUS Status;
228
229 assert_irql(PASSIVE_LEVEL);
230
231 DPRINT("IoTryToMountStorageDevice(DeviceObject %x)\n",DeviceObject);
232
233 KeAcquireSpinLock(&FileSystemListLock,&oldlvl);
234 current_entry = FileSystemListHead.Flink;
235 while (current_entry!=(&FileSystemListHead))
236 {
237 current = CONTAINING_RECORD(current_entry,FILE_SYSTEM_OBJECT,Entry);
238 KeReleaseSpinLock(&FileSystemListLock,oldlvl);
239 Status = IoAskFileSystemToMountDevice(current->DeviceObject,
240 DeviceObject);
241 KeAcquireSpinLock(&FileSystemListLock,&oldlvl);
242 switch (Status)
243 {
244 case STATUS_FS_DRIVER_REQUIRED:
245 KeReleaseSpinLock(&FileSystemListLock,oldlvl);
246 (void)IoAskFileSystemToLoad(DeviceObject);
247 KeAcquireSpinLock(&FileSystemListLock,&oldlvl);
248 current_entry = FileSystemListHead.Flink;
249 break;
250
251 case STATUS_SUCCESS:
252 DeviceObject->Vpb->Flags = DeviceObject->Vpb->Flags |
253 VPB_MOUNTED;
254 KeReleaseSpinLock(&FileSystemListLock,oldlvl);
255 return(STATUS_SUCCESS);
256
257 case STATUS_UNRECOGNIZED_VOLUME:
258 default:
259 current_entry = current_entry->Flink;
260 }
261 }
262 KeReleaseSpinLock(&FileSystemListLock,oldlvl);
263 return(STATUS_UNRECOGNIZED_VOLUME);
264 }
265
266 VOID STDCALL
267 IoRegisterFileSystem(PDEVICE_OBJECT DeviceObject)
268 {
269 FILE_SYSTEM_OBJECT* fs;
270
271 DPRINT("IoRegisterFileSystem(DeviceObject %x)\n",DeviceObject);
272
273 fs = ExAllocatePoolWithTag(NonPagedPool, sizeof(FILE_SYSTEM_OBJECT),
274 TAG_FILE_SYSTEM);
275 assert(fs!=NULL);
276
277 fs->DeviceObject = DeviceObject;
278 ExInterlockedInsertTailList(&FileSystemListHead,&fs->Entry,
279 &FileSystemListLock);
280 IopNotifyFileSystemChange(DeviceObject, TRUE);
281 }
282
283 VOID STDCALL
284 IoUnregisterFileSystem(PDEVICE_OBJECT DeviceObject)
285 {
286 KIRQL oldlvl;
287 PLIST_ENTRY current_entry;
288 FILE_SYSTEM_OBJECT* current;
289
290 DPRINT("IoUnregisterFileSystem(DeviceObject %x)\n",DeviceObject);
291
292 KeAcquireSpinLock(&FileSystemListLock,&oldlvl);
293 current_entry = FileSystemListHead.Flink;
294 while (current_entry!=(&FileSystemListHead))
295 {
296 current = CONTAINING_RECORD(current_entry,FILE_SYSTEM_OBJECT,Entry);
297 if (current->DeviceObject == DeviceObject)
298 {
299 RemoveEntryList(current_entry);
300 ExFreePool(current);
301 KeReleaseSpinLock(&FileSystemListLock,oldlvl);
302 IopNotifyFileSystemChange(DeviceObject, FALSE);
303 return;
304 }
305 current_entry = current_entry->Flink;
306 }
307 KeReleaseSpinLock(&FileSystemListLock,oldlvl);
308 }
309
310
311 /**********************************************************************
312 * NAME EXPORTED
313 * IoGetBaseFileSystemDeviceObject@4
314 *
315 * DESCRIPTION
316 * Get the DEVICE_OBJECT associated to
317 * a FILE_OBJECT.
318 *
319 * ARGUMENTS
320 * FileObject
321 *
322 * RETURN VALUE
323 *
324 * NOTE
325 * From Bo Branten's ntifs.h v13.
326 */
327 PDEVICE_OBJECT STDCALL
328 IoGetBaseFileSystemDeviceObject(IN PFILE_OBJECT FileObject)
329 {
330 PDEVICE_OBJECT DeviceObject = NULL;
331 PVPB Vpb = NULL;
332
333 /*
334 * If the FILE_OBJECT's VPB is defined,
335 * get the device from it.
336 */
337 if (NULL != (Vpb = FileObject->Vpb))
338 {
339 if (NULL != (DeviceObject = Vpb->DeviceObject))
340 {
341 /* Vpb->DeviceObject DEFINED! */
342 return DeviceObject;
343 }
344 }
345 /*
346 * If that failed, try the VPB
347 * in the FILE_OBJECT's DeviceObject.
348 */
349 DeviceObject = FileObject->DeviceObject;
350 if (NULL == (Vpb = DeviceObject->Vpb))
351 {
352 /* DeviceObject->Vpb UNDEFINED! */
353 return DeviceObject;
354 }
355 /*
356 * If that pointer to the VPB is again
357 * undefined, return directly the
358 * device object from the FILE_OBJECT.
359 */
360 return (
361 (NULL == Vpb->DeviceObject)
362 ? DeviceObject
363 : Vpb->DeviceObject
364 );
365 }
366
367
368 static VOID
369 IopNotifyFileSystemChange(PDEVICE_OBJECT DeviceObject,
370 BOOLEAN DriverActive)
371 {
372 PFS_CHANGE_NOTIFY_ENTRY ChangeEntry;
373 PLIST_ENTRY Entry;
374 KIRQL oldlvl;
375
376 KeAcquireSpinLock(&FsChangeNotifyListLock,&oldlvl);
377 Entry = FsChangeNotifyListHead.Flink;
378 while (Entry != &FsChangeNotifyListHead)
379 {
380 ChangeEntry = CONTAINING_RECORD(Entry, FS_CHANGE_NOTIFY_ENTRY, FsChangeNotifyList);
381
382 (ChangeEntry->FSDNotificationProc)(DeviceObject, DriverActive);
383
384 Entry = Entry->Flink;
385 }
386 KeReleaseSpinLock(&FsChangeNotifyListLock,oldlvl);
387 }
388
389
390 NTSTATUS STDCALL
391 IoRegisterFsRegistrationChange(IN PDRIVER_OBJECT DriverObject,
392 IN PFSDNOTIFICATIONPROC FSDNotificationProc)
393 {
394 PFS_CHANGE_NOTIFY_ENTRY Entry;
395
396 Entry = ExAllocatePoolWithTag(NonPagedPool,
397 sizeof(FS_CHANGE_NOTIFY_ENTRY),
398 TAG_FS_CHANGE_NOTIFY);
399 if (Entry == NULL)
400 return(STATUS_INSUFFICIENT_RESOURCES);
401
402 Entry->DriverObject = DriverObject;
403 Entry->FSDNotificationProc = FSDNotificationProc;
404
405 ExInterlockedInsertHeadList(&FsChangeNotifyListHead,
406 &Entry->FsChangeNotifyList,
407 &FsChangeNotifyListLock);
408
409 return(STATUS_SUCCESS);
410 }
411
412
413 VOID STDCALL
414 IoUnregisterFsRegistrationChange(IN PDRIVER_OBJECT DriverObject,
415 IN PFSDNOTIFICATIONPROC FSDNotificationProc)
416 {
417 PFS_CHANGE_NOTIFY_ENTRY ChangeEntry;
418 PLIST_ENTRY Entry;
419 KIRQL oldlvl;
420
421 Entry = FsChangeNotifyListHead.Flink;
422 while (Entry != &FsChangeNotifyListHead)
423 {
424 ChangeEntry = CONTAINING_RECORD(Entry, FS_CHANGE_NOTIFY_ENTRY, FsChangeNotifyList);
425 if (ChangeEntry->DriverObject == DriverObject &&
426 ChangeEntry->FSDNotificationProc == FSDNotificationProc)
427 {
428 KeAcquireSpinLock(&FsChangeNotifyListLock,&oldlvl);
429 RemoveEntryList(Entry);
430 KeReleaseSpinLock(&FsChangeNotifyListLock,oldlvl);
431
432 ExFreePool(Entry);
433 return;
434 }
435
436 Entry = Entry->Flink;
437 }
438 }
439
440 /* EOF */