[FASTFAT] Implement delayed close
[reactos.git] / drivers / filesystems / udfs / udfinit.cpp
1 ////////////////////////////////////////////////////////////////////
2 // Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine
3 // All rights reserved
4 // This file was released under the GPLv2 on June 2015.
5 ////////////////////////////////////////////////////////////////////
6 /*************************************************************************
7 *
8 * File: UDFinit.cpp
9 *
10 * Module: UDF File System Driver (Kernel mode execution only)
11 *
12 * Description:
13 * This file contains the initialization code for the kernel mode
14 * UDF FSD module. The DriverEntry() routine is called by the I/O
15 * sub-system to initialize the FSD.
16 *
17 *************************************************************************/
18
19 #include "udffs.h"
20
21 // define the file specific bug-check id
22 #define UDF_BUG_CHECK_ID UDF_FILE_INIT
23
24 // global variables are declared here
25 UDFData UDFGlobalData;
26
27 #define KD_PREFIX
28
29 struct UDF_MEDIA_CLASS_NAMES UDFMediaClassName[] = {
30 {MediaUnknown, REG_DEFAULT_UNKNOWN},
31 {MediaHdd , REG_DEFAULT_HDD},
32 {MediaCdr , REG_DEFAULT_CDR},
33 {MediaCdrw , REG_DEFAULT_CDRW},
34 {MediaCdrom , REG_DEFAULT_CDROM},
35 {MediaZip , REG_DEFAULT_ZIP},
36 {MediaFloppy , REG_DEFAULT_FLOPPY},
37 {MediaDvdr , REG_DEFAULT_DVDR},
38 {MediaDvdrw , REG_DEFAULT_DVDRW}
39 };
40 /*
41 ULONG MajorVersion = 0;
42 ULONG MinorVersion = 0;
43 ULONG BuildNumber = 0;
44 */
45 ULONG FsRegistered = FALSE;
46
47 WORK_QUEUE_ITEM RemountWorkQueueItem;
48
49 //ptrFsRtlNotifyVolumeEvent FsRtlNotifyVolumeEvent = NULL;
50
51 HANDLE FsNotification_ThreadId = (HANDLE)(-1);
52
53 NTSTATUS
54 UDFCreateFsDeviceObject(
55 PCWSTR FsDeviceName,
56 PDRIVER_OBJECT DriverObject,
57 DEVICE_TYPE DeviceType,
58 PDEVICE_OBJECT *DeviceObject);
59
60 NTSTATUS
61 UDFDismountDevice(
62 PUNICODE_STRING unicodeCdRomDeviceName);
63
64 VOID
65 UDFRemountAll(
66 IN PVOID Context);
67
68 /*************************************************************************
69 *
70 * Function: DriverEntry()
71 *
72 * Description:
73 * This routine is the standard entry point for all kernel mode drivers.
74 * The routine is invoked at IRQL PASSIVE_LEVEL in the context of a
75 * system worker thread.
76 * All FSD specific data structures etc. are initialized here.
77 *
78 * Expected Interrupt Level (for execution) :
79 *
80 * IRQL_PASSIVE_LEVEL
81 *
82 * Return Value: STATUS_SUCCESS/Error (will cause driver to be unloaded).
83 *
84 *************************************************************************/
85 NTSTATUS
86 NTAPI
87 DriverEntry(
88 PDRIVER_OBJECT DriverObject, // created by the I/O sub-system
89 PUNICODE_STRING RegistryPath // path to the registry key
90 )
91 {
92 NTSTATUS RC = STATUS_SUCCESS;
93 UNICODE_STRING DriverDeviceName;
94 UNICODE_STRING unicodeDeviceName;
95 // BOOLEAN RegisteredShutdown = FALSE;
96 BOOLEAN InternalMMInitialized = FALSE;
97 // BOOLEAN DLDetectInitialized = FALSE;
98 // ULONG CdRomNumber;
99 // CCHAR deviceNameBuffer[MAXIMUM_FILENAME_LENGTH];
100 // ANSI_STRING deviceName;
101 // UNICODE_STRING unicodeCdRomDeviceName;
102 PUDFFS_DEV_EXTENSION FSDevExt;
103 HKEY hUdfRootKey;
104 LARGE_INTEGER delay;
105
106 // UDFPrint(("UDF: Entered " VER_STR_PRODUCT_NAME " UDF DriverEntry \n"));
107 // UDFPrint((KD_PREFIX "Build " VER_STR_PRODUCT "\n"));
108
109 _SEH2_TRY {
110 _SEH2_TRY {
111
112 /*
113 CrNtInit(DriverObject, RegistryPath);
114
115 //PsGetVersion(&MajorVersion, &MinorVersion, &BuildNumber, NULL);
116 UDFPrint(("UDF: OS Version Major: %x, Minor: %x, Build number: %d\n",
117 MajorVersion, MinorVersion, BuildNumber));
118 */
119 #ifdef __REACTOS__
120 UDFPrint(("UDF Init: OS should be ReactOS\n"));
121 #endif
122
123 // initialize the global data structure
124 RtlZeroMemory(&UDFGlobalData, sizeof(UDFGlobalData));
125
126 // initialize some required fields
127 UDFGlobalData.NodeIdentifier.NodeType = UDF_NODE_TYPE_GLOBAL_DATA;
128 UDFGlobalData.NodeIdentifier.NodeSize = sizeof(UDFGlobalData);
129
130 // initialize the global data resource and remember the fact that
131 // the resource has been initialized
132 RC = UDFInitializeResourceLite(&(UDFGlobalData.GlobalDataResource));
133 ASSERT(NT_SUCCESS(RC));
134 UDFSetFlag(UDFGlobalData.UDFFlags, UDF_DATA_FLAGS_RESOURCE_INITIALIZED);
135
136 RC = UDFInitializeResourceLite(&(UDFGlobalData.DelayedCloseResource));
137 ASSERT(NT_SUCCESS(RC));
138 // UDFSetFlag(UDFGlobalData.UDFFlags, UDF_DATA_FLAGS_RESOURCE_INITIALIZED);
139
140 // keep a ptr to the driver object sent to us by the I/O Mgr
141 UDFGlobalData.DriverObject = DriverObject;
142
143 //SeEnableAccessToExports();
144
145 // initialize the mounted logical volume list head
146 InitializeListHead(&(UDFGlobalData.VCBQueue));
147
148 UDFPrint(("UDF: Init memory manager\n"));
149 // Initialize internal memory management
150 if(!MyAllocInit()) {
151 try_return(RC = STATUS_INSUFFICIENT_RESOURCES);
152 }
153 InternalMMInitialized = TRUE;
154
155 #ifdef USE_DLD
156 // Initialize Deadlock Detector
157 DLDInit(1280);
158 DLDetectInitialized = TRUE;
159 #endif
160 // before we proceed with any more initialization, read in
161 // user supplied configurable values ...
162
163 // Save RegistryPath
164 RtlCopyMemory(&(UDFGlobalData.SavedRegPath), RegistryPath, sizeof(UNICODE_STRING));
165
166 UDFGlobalData.SavedRegPath.Buffer = (PWSTR)MyAllocatePool__(NonPagedPool, RegistryPath->Length + 2);
167 if(!UDFGlobalData.SavedRegPath.Buffer) try_return (RC = STATUS_INSUFFICIENT_RESOURCES);
168 RtlCopyMemory(UDFGlobalData.SavedRegPath.Buffer, RegistryPath->Buffer, RegistryPath->Length + 2);
169
170 RegTGetKeyHandle(NULL, UDFGlobalData.SavedRegPath.Buffer, &hUdfRootKey);
171
172 RtlInitUnicodeString(&UDFGlobalData.UnicodeStrRoot, L"\\");
173 RtlInitUnicodeString(&UDFGlobalData.UnicodeStrSDir, L":");
174 RtlInitUnicodeString(&UDFGlobalData.AclName, UDF_SN_NT_ACL);
175
176 UDFPrint(("UDF: Init delayed close queues\n"));
177 #ifdef UDF_DELAYED_CLOSE
178 InitializeListHead( &UDFGlobalData.DelayedCloseQueue );
179 InitializeListHead( &UDFGlobalData.DirDelayedCloseQueue );
180
181 ExInitializeWorkItem( &UDFGlobalData.CloseItem,
182 UDFDelayedClose,
183 NULL );
184
185 UDFGlobalData.DelayedCloseCount = 0;
186 UDFGlobalData.DirDelayedCloseCount = 0;
187 #endif //UDF_DELAYED_CLOSE
188
189 // we should have the registry data (if any), allocate zone memory ...
190 // This is an example of when FSD implementations __try to pre-allocate
191 // some fixed amount of memory to avoid internal fragmentation and/or waiting
192 // later during run-time ...
193
194 UDFGlobalData.DefaultZoneSizeInNumStructs=10;
195
196 UDFPrint(("UDF: Init zones\n"));
197 if (!NT_SUCCESS(RC = UDFInitializeZones()))
198 try_return(RC);
199
200 UDFPrint(("UDF: Init pointers\n"));
201 // initialize the IRP major function table, and the fast I/O table
202 UDFInitializeFunctionPointers(DriverObject);
203
204 UDFGlobalData.CPU_Count = KeNumberProcessors;
205
206 // create a device object representing the driver itself
207 // so that requests can be targeted to the driver ...
208 // e.g. for a disk-based FSD, "mount" requests will be sent to
209 // this device object by the I/O Manager.
210 // For a redirector/server, you may have applications
211 // send "special" IOCTL's using this device object ...
212
213 RtlInitUnicodeString(&DriverDeviceName, UDF_FS_NAME);
214
215 UDFPrint(("UDF: Create Driver dev obj\n"));
216 if (!NT_SUCCESS(RC = IoCreateDevice(
217 DriverObject, // our driver object
218 sizeof(UDFFS_DEV_EXTENSION), // don't need an extension for this object
219 &DriverDeviceName, // name - can be used to "open" the driver
220 // see the book for alternate choices
221 FILE_DEVICE_CD_ROM_FILE_SYSTEM,
222 0, // no special characteristics
223 // do not want this as an exclusive device, though you might
224 FALSE,
225 &(UDFGlobalData.UDFDeviceObject)))) {
226 // failed to create a device object, leave ...
227 try_return(RC);
228 }
229
230 FSDevExt = (PUDFFS_DEV_EXTENSION)((UDFGlobalData.UDFDeviceObject)->DeviceExtension);
231 // Zero it out (typically this has already been done by the I/O
232 // Manager but it does not hurt to do it again)!
233 RtlZeroMemory(FSDevExt, sizeof(UDFFS_DEV_EXTENSION));
234
235 // Initialize the signature fields
236 FSDevExt->NodeIdentifier.NodeType = UDF_NODE_TYPE_UDFFS_DRVOBJ;
237 FSDevExt->NodeIdentifier.NodeSize = sizeof(UDFFS_DEV_EXTENSION);
238
239 RtlInitUnicodeString(&unicodeDeviceName, UDF_DOS_FS_NAME);
240 IoCreateSymbolicLink(&unicodeDeviceName, &DriverDeviceName);
241
242 UDFPrint(("UDF: Create CD dev obj\n"));
243 if (!NT_SUCCESS(RC = UDFCreateFsDeviceObject(UDF_FS_NAME_CD,
244 DriverObject,
245 FILE_DEVICE_CD_ROM_FILE_SYSTEM,
246 &(UDFGlobalData.UDFDeviceObject_CD)))) {
247 // failed to create a device object, leave ...
248 try_return(RC);
249 }
250 #ifdef UDF_HDD_SUPPORT
251 UDFPrint(("UDF: Create HDD dev obj\n"));
252 if (!NT_SUCCESS(RC = UDFCreateFsDeviceObject(UDF_FS_NAME_HDD,
253 DriverObject,
254 FILE_DEVICE_DISK_FILE_SYSTEM,
255 &(UDFGlobalData.UDFDeviceObject_HDD)))) {
256 // failed to create a device object, leave ...
257 try_return(RC);
258 }
259 #endif //UDF_HDD_SUPPORT
260
261 /* RtlInitUnicodeString(&DriverDeviceName, UDF_FS_NAME_OTHER);
262
263 if (!NT_SUCCESS(RC = IoCreateDevice(
264 DriverObject, // our driver object
265 0, // don't need an extension for this object
266 &DriverDeviceName, // name - can be used to "open" the driver
267 // see the book for alternate choices
268 FILE_DEVICE_FILE_SYSTEM,
269 0, // no special characteristics
270 // do not want this as an exclusive device, though you might
271 FALSE,
272 &(UDFGlobalData.UDFDeviceObject_OTHER)))) {
273 // failed to create a device object, leave ...
274 try_return(RC);
275 }
276 // register the driver with the I/O Manager, pretend as if this is
277 // a physical disk based FSD (or in order words, this FSD manages
278 // logical volumes residing on physical disk drives)
279 IoRegisterFileSystem(UDFGlobalData.UDFDeviceObject_OTHER);
280
281 RtlInitUnicodeString(&DriverDeviceName, UDF_FS_NAME_TAPE);
282
283 if (!NT_SUCCESS(RC = IoCreateDevice(
284 DriverObject, // our driver object
285 0, // don't need an extension for this object
286 &DriverDeviceName, // name - can be used to "open" the driver
287 // see the book for alternate choices
288 FILE_DEVICE_TAPE_FILE_SYSTEM,
289 0, // no special characteristics
290 // do not want this as an exclusive device, though you might
291 FALSE,
292 &(UDFGlobalData.UDFDeviceObject_TAPE)))) {
293 // failed to create a device object, leave ...
294 try_return(RC);
295 }
296 // register the driver with the I/O Manager, pretend as if this is
297 // a physical disk based FSD (or in order words, this FSD manages
298 // logical volumes residing on physical disk drives)
299 IoRegisterFileSystem(UDFGlobalData.UDFDeviceObject_TAPE);
300 */
301
302 if (UDFGlobalData.UDFDeviceObject_CD) {
303 UDFPrint(("UDFCreateFsDeviceObject: IoRegisterFileSystem() for CD\n"));
304 IoRegisterFileSystem(UDFGlobalData.UDFDeviceObject_CD);
305 }
306 #ifdef UDF_HDD_SUPPORT
307 if (UDFGlobalData.UDFDeviceObject_HDD) {
308 UDFPrint(("UDFCreateFsDeviceObject: IoRegisterFileSystem() for HDD\n"));
309 IoRegisterFileSystem(UDFGlobalData.UDFDeviceObject_HDD);
310 }
311 #endif // UDF_HDD_SUPPORT
312 FsRegistered = TRUE;
313
314 UDFPrint(("UDF: IoRegisterFsRegistrationChange()\n"));
315 IoRegisterFsRegistrationChange( DriverObject, UDFFsNotification );
316
317 // delay.QuadPart = -10000000;
318 // KeDelayExecutionThread(KernelMode, FALSE, &delay); //10 microseconds
319
320 delay.QuadPart = -10000000; // 1 sec
321 KeDelayExecutionThread(KernelMode, FALSE, &delay);
322
323 #if 0
324 if(!WinVer_IsNT) {
325 /*ExInitializeWorkItem(&RemountWorkQueueItem, UDFRemountAll, NULL);
326 UDFPrint(("UDFDriverEntry: create remount thread\n"));
327 ExQueueWorkItem(&RemountWorkQueueItem, DelayedWorkQueue);*/
328
329 for(CdRomNumber = 0;true;CdRomNumber++) {
330 sprintf(deviceNameBuffer, "\\Device\\CdRom%d", CdRomNumber);
331 UDFPrint(( "UDF: DriverEntry : dismount %s\n", deviceNameBuffer));
332 RtlInitString(&deviceName, deviceNameBuffer);
333 RC = RtlAnsiStringToUnicodeString(&unicodeCdRomDeviceName, &deviceName, TRUE);
334
335 if (!NT_SUCCESS(RC)) {
336 RtlFreeUnicodeString(&unicodeCdRomDeviceName);
337 break;
338 }
339
340 RC = UDFDismountDevice(&unicodeCdRomDeviceName);
341 RtlFreeUnicodeString(&unicodeCdRomDeviceName);
342
343 if (!NT_SUCCESS(RC)) break;
344
345 }
346
347 PVOID ModuleBase = NULL;
348
349 // get NTOSKRNL.EXE exports
350 ModuleBase = CrNtGetModuleBase("NTOSKRNL.EXE");
351 if(ModuleBase) {
352 FsRtlNotifyVolumeEvent = (ptrFsRtlNotifyVolumeEvent)CrNtGetProcAddress(ModuleBase, "FsRtlNotifyVolumeEvent");
353 }
354
355 }
356 #endif
357 RC = STATUS_SUCCESS;
358
359 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
360 // we encountered an exception somewhere, eat it up
361 UDFPrint(("UDF: exception\n"));
362 RC = _SEH2_GetExceptionCode();
363 } _SEH2_END;
364
365 InternalMMInitialized = FALSE;
366
367 try_exit: NOTHING;
368 } _SEH2_FINALLY {
369 // start unwinding if we were unsuccessful
370 if (!NT_SUCCESS(RC)) {
371 UDFPrint(("UDF: failed with status %x\n", RC));
372 // Now, delete any device objects, etc. we may have created
373 /* if (UDFGlobalData.UDFDeviceObject) {
374 IoDeleteDevice(UDFGlobalData.UDFDeviceObject);
375 UDFGlobalData.UDFDeviceObject = NULL;
376 }*/
377 #ifdef USE_DLD
378 if (DLDetectInitialized) DLDFree();
379 #endif
380 if (InternalMMInitialized) {
381 MyAllocRelease();
382 }
383 if (UDFGlobalData.UDFDeviceObject_CD) {
384 IoDeleteDevice(UDFGlobalData.UDFDeviceObject_CD);
385 UDFGlobalData.UDFDeviceObject_CD = NULL;
386 }
387 #ifdef UDF_HDD_SUPPORT
388
389 if (UDFGlobalData.UDFDeviceObject_HDD) {
390 IoDeleteDevice(UDFGlobalData.UDFDeviceObject_HDD);
391 UDFGlobalData.UDFDeviceObject_HDD = NULL;
392 }
393 #endif // UDF_HDD_SUPPORT
394
395 /*
396 if (UDFGlobalData.UDFDeviceObject_OTHER) {
397 IoDeleteDevice(UDFGlobalData.UDFDeviceObject_CD);
398 UDFGlobalData.UDFDeviceObject_CD = NULL;
399 }
400
401 if (UDFGlobalData.UDFDeviceObject_TAPE) {
402 IoDeleteDevice(UDFGlobalData.UDFDeviceObject_CD);
403 UDFGlobalData.UDFDeviceObject_CD = NULL;
404 }
405 */
406 // free up any memory we might have reserved for zones/lookaside
407 // lists
408 if (UDFGlobalData.UDFFlags & UDF_DATA_FLAGS_ZONES_INITIALIZED) {
409 UDFDestroyZones();
410 }
411
412 // delete the resource we may have initialized
413 if (UDFGlobalData.UDFFlags & UDF_DATA_FLAGS_RESOURCE_INITIALIZED) {
414 // un-initialize this resource
415 UDFDeleteResource(&(UDFGlobalData.GlobalDataResource));
416 UDFClearFlag(UDFGlobalData.UDFFlags, UDF_DATA_FLAGS_RESOURCE_INITIALIZED);
417 }
418 // } else {
419 }
420 } _SEH2_END;
421
422 return(RC);
423 } // end DriverEntry()
424
425
426
427 /*************************************************************************
428 *
429 * Function: UDFInitializeFunctionPointers()
430 *
431 * Description:
432 * Initialize the IRP... function pointer array in the driver object
433 * structure. Also initialize the fast-io function ptr array ...
434 *
435 * Expected Interrupt Level (for execution) :
436 *
437 * IRQL_PASSIVE_LEVEL
438 *
439 * Return Value: None
440 *
441 *************************************************************************/
442 VOID
443 NTAPI
444 UDFInitializeFunctionPointers(
445 PDRIVER_OBJECT DriverObject // created by the I/O sub-system
446 )
447 {
448 PFAST_IO_DISPATCH PtrFastIoDispatch = NULL;
449
450 // initialize the function pointers for the IRP major
451 // functions that this FSD is prepared to handle ...
452 // NT Version 4.0 has 28 possible functions that a
453 // kernel mode driver can handle.
454 // NT Version 3.51 and before has only 22 such functions,
455 // of which 18 are typically interesting to most FSD's.
456
457 // The only interesting new functions that a FSD might
458 // want to respond to beginning with Version 4.0 are the
459 // IRP_MJ_QUERY_QUOTA and the IRP_MJ_SET_QUOTA requests.
460
461 // The code below does not handle quota manipulation, neither
462 // does the NT Version 4.0 operating system (or I/O Manager).
463 // However, you should be on the lookout for any such new
464 // functionality that the FSD might have to implement in
465 // the near future.
466
467 DriverObject->MajorFunction[IRP_MJ_CREATE] = UDFCreate;
468 DriverObject->MajorFunction[IRP_MJ_CLOSE] = UDFClose;
469 DriverObject->MajorFunction[IRP_MJ_READ] = UDFRead;
470 #ifndef UDF_READ_ONLY_BUILD
471 DriverObject->MajorFunction[IRP_MJ_WRITE] = UDFWrite;
472 #endif //UDF_READ_ONLY_BUILD
473
474 DriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION] = UDFFileInfo;
475 #ifndef UDF_READ_ONLY_BUILD
476 DriverObject->MajorFunction[IRP_MJ_SET_INFORMATION] = UDFFileInfo;
477 #endif //UDF_READ_ONLY_BUILD
478
479 #ifndef UDF_READ_ONLY_BUILD
480 DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = UDFFlush;
481 #endif //UDF_READ_ONLY_BUILD
482 // To implement support for querying and modifying volume attributes
483 // (volume information query/set operations), enable initialization
484 // of the following two function pointers and then implement the supporting
485 // functions.
486 DriverObject->MajorFunction[IRP_MJ_QUERY_VOLUME_INFORMATION] = UDFQueryVolInfo;
487 #ifndef UDF_READ_ONLY_BUILD
488 DriverObject->MajorFunction[IRP_MJ_SET_VOLUME_INFORMATION] = UDFSetVolInfo;
489 #endif //UDF_READ_ONLY_BUILD
490 DriverObject->MajorFunction[IRP_MJ_DIRECTORY_CONTROL] = UDFDirControl;
491 // To implement support for file system IOCTL calls, enable initialization
492 // of the following function pointer and implement appropriate support.
493 DriverObject->MajorFunction[IRP_MJ_FILE_SYSTEM_CONTROL] = UDFFSControl;
494 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = UDFDeviceControl;
495 DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = UDFShutdown;
496 // For byte-range lock support, enable initialization of the following
497 // function pointer and implement appropriate support.
498 DriverObject->MajorFunction[IRP_MJ_LOCK_CONTROL] = UDFLockControl;
499 DriverObject->MajorFunction[IRP_MJ_CLEANUP] = UDFCleanup;
500 #ifdef UDF_HANDLE_EAS
501 DriverObject->MajorFunction[IRP_MJ_QUERY_EA] = UDFQuerySetEA;
502 #ifndef UDF_READ_ONLY_BUILD
503 DriverObject->MajorFunction[IRP_MJ_SET_EA] = UDFQuerySetEA;
504 #endif //UDF_READ_ONLY_BUILD
505 #endif //UDF_HANDLE_EAS
506 // If the FSD supports security attributes, we should provide appropriate
507 // dispatch entry points and initialize the function pointers as given below.
508
509 #ifdef UDF_ENABLE_SECURITY
510 DriverObject->MajorFunction[IRP_MJ_QUERY_SECURITY] = UDFGetSecurity;
511 #ifndef UDF_READ_ONLY_BUILD
512 DriverObject->MajorFunction[IRP_MJ_SET_SECURITY] = UDFSetSecurity;
513 #endif //UDF_READ_ONLY_BUILD
514 #endif //UDF_ENABLE_SECURITY
515
516 // if(MajorVersion >= 0x05) {
517 // w2k and higher
518 // DriverObject->MajorFunction[IRP_MJ_PNP] = UDFPnp;
519 // }
520
521 // Now, it is time to initialize the fast-io stuff ...
522 PtrFastIoDispatch = DriverObject->FastIoDispatch = &(UDFGlobalData.UDFFastIoDispatch);
523
524 // initialize the global fast-io structure
525 // NOTE: The fast-io structure has undergone a substantial revision
526 // in Windows NT Version 4.0. The structure has been extensively expanded.
527 // Therefore, if the driver needs to work on both V3.51 and V4.0+,
528 // we will have to be able to distinguish between the two versions at compile time.
529
530 RtlZeroMemory(PtrFastIoDispatch, sizeof(FAST_IO_DISPATCH));
531
532 PtrFastIoDispatch->SizeOfFastIoDispatch = sizeof(FAST_IO_DISPATCH);
533 PtrFastIoDispatch->FastIoCheckIfPossible = UDFFastIoCheckIfPossible;
534 PtrFastIoDispatch->FastIoRead = FsRtlCopyRead;
535 #ifndef UDF_READ_ONLY_BUILD
536 PtrFastIoDispatch->FastIoWrite = UDFFastIoCopyWrite /*FsRtlCopyWrite*/;
537 #endif //UDF_READ_ONLY_BUILD
538 PtrFastIoDispatch->FastIoQueryBasicInfo = UDFFastIoQueryBasicInfo;
539 PtrFastIoDispatch->FastIoQueryStandardInfo = UDFFastIoQueryStdInfo;
540 PtrFastIoDispatch->FastIoLock = UDFFastLock; // Lock
541 PtrFastIoDispatch->FastIoUnlockSingle = UDFFastUnlockSingle; // UnlockSingle
542 PtrFastIoDispatch->FastIoUnlockAll = UDFFastUnlockAll; // UnlockAll
543 PtrFastIoDispatch->FastIoUnlockAllByKey = (unsigned char (__stdcall *)(struct _FILE_OBJECT *,
544 PVOID ,unsigned long,struct _IO_STATUS_BLOCK *,struct _DEVICE_OBJECT *))UDFFastUnlockAllByKey; // UnlockAllByKey
545
546 PtrFastIoDispatch->AcquireFileForNtCreateSection = UDFFastIoAcqCreateSec;
547 PtrFastIoDispatch->ReleaseFileForNtCreateSection = UDFFastIoRelCreateSec;
548
549 // PtrFastIoDispatch->FastIoDeviceControl = UDFFastIoDeviceControl;
550
551 // the remaining are only valid under NT Version 4.0 and later
552 #if(_WIN32_WINNT >= 0x0400)
553
554 PtrFastIoDispatch->FastIoQueryNetworkOpenInfo = UDFFastIoQueryNetInfo;
555
556 PtrFastIoDispatch->AcquireForModWrite = UDFFastIoAcqModWrite;
557 PtrFastIoDispatch->ReleaseForModWrite = UDFFastIoRelModWrite;
558 PtrFastIoDispatch->AcquireForCcFlush = UDFFastIoAcqCcFlush;
559 PtrFastIoDispatch->ReleaseForCcFlush = UDFFastIoRelCcFlush;
560
561 /* // MDL functionality
562
563 PtrFastIoDispatch->MdlRead = UDFFastIoMdlRead;
564 PtrFastIoDispatch->MdlReadComplete = UDFFastIoMdlReadComplete;
565 PtrFastIoDispatch->PrepareMdlWrite = UDFFastIoPrepareMdlWrite;
566 PtrFastIoDispatch->MdlWriteComplete = UDFFastIoMdlWriteComplete;*/
567
568 // this FSD does not support compressed read/write functionality,
569 // NTFS does, and if we design a FSD that can provide such functionality,
570 // we should consider initializing the fast io entry points for reading
571 // and/or writing compressed data ...
572 #endif // (_WIN32_WINNT >= 0x0400)
573
574 // last but not least, initialize the Cache Manager callback functions
575 // which are used in CcInitializeCacheMap()
576
577 UDFGlobalData.CacheMgrCallBacks.AcquireForLazyWrite = UDFAcqLazyWrite;
578 UDFGlobalData.CacheMgrCallBacks.ReleaseFromLazyWrite = UDFRelLazyWrite;
579 UDFGlobalData.CacheMgrCallBacks.AcquireForReadAhead = UDFAcqReadAhead;
580 UDFGlobalData.CacheMgrCallBacks.ReleaseFromReadAhead = UDFRelReadAhead;
581
582 DriverObject->DriverUnload = UDFDriverUnload;
583
584 return;
585 } // end UDFInitializeFunctionPointers()
586
587 NTSTATUS
588 UDFCreateFsDeviceObject(
589 PCWSTR FsDeviceName,
590 PDRIVER_OBJECT DriverObject,
591 DEVICE_TYPE DeviceType,
592 PDEVICE_OBJECT *DeviceObject
593 )
594 {
595 NTSTATUS RC = STATUS_SUCCESS;
596 UNICODE_STRING DriverDeviceName;
597 PUDFFS_DEV_EXTENSION FSDevExt;
598 RtlInitUnicodeString(&DriverDeviceName, FsDeviceName);
599 *DeviceObject = NULL;
600
601 UDFPrint(("UDFCreateFsDeviceObject: create dev\n"));
602
603 if (!NT_SUCCESS(RC = IoCreateDevice(
604 DriverObject, // our driver object
605 sizeof(UDFFS_DEV_EXTENSION), // don't need an extension for this object
606 &DriverDeviceName, // name - can be used to "open" the driver
607 // see the book for alternate choices
608 DeviceType,
609 0, // no special characteristics
610 // do not want this as an exclusive device, though you might
611 FALSE,
612 DeviceObject))) {
613 // failed to create a device object, leave ...
614 return(RC);
615 }
616 FSDevExt = (PUDFFS_DEV_EXTENSION)((*DeviceObject)->DeviceExtension);
617 // Zero it out (typically this has already been done by the I/O
618 // Manager but it does not hurt to do it again)!
619 RtlZeroMemory(FSDevExt, sizeof(UDFFS_DEV_EXTENSION));
620
621 // Initialize the signature fields
622 FSDevExt->NodeIdentifier.NodeType = UDF_NODE_TYPE_UDFFS_DEVOBJ;
623 FSDevExt->NodeIdentifier.NodeSize = sizeof(UDFFS_DEV_EXTENSION);
624 // register the driver with the I/O Manager, pretend as if this is
625 // a physical disk based FSD (or in order words, this FSD manages
626 // logical volumes residing on physical disk drives)
627 /* UDFPrint(("UDFCreateFsDeviceObject: IoRegisterFileSystem()\n"));
628 IoRegisterFileSystem(*DeviceObject);*/
629 return(RC);
630 } // end UDFCreateFsDeviceObject()
631
632
633 NTSTATUS
634 UDFDismountDevice(
635 PUNICODE_STRING unicodeCdRomDeviceName
636 )
637 {
638 NTSTATUS RC;
639 IO_STATUS_BLOCK IoStatus;
640 HANDLE NtFileHandle = (HANDLE)-1;
641 OBJECT_ATTRIBUTES ObjectAttributes;
642 NOTIFY_MEDIA_CHANGE_USER_IN buffer = { 0 };
643 PFILE_FS_ATTRIBUTE_INFORMATION Buffer;
644
645 _SEH2_TRY {
646
647 Buffer = (PFILE_FS_ATTRIBUTE_INFORMATION)MyAllocatePool__(NonPagedPool,sizeof(FILE_FS_ATTRIBUTE_INFORMATION)+2*sizeof(UDF_FS_TITLE_DVDRAM));
648 if (!Buffer) try_return(RC = STATUS_INSUFFICIENT_RESOURCES);
649
650 InitializeObjectAttributes ( &ObjectAttributes,
651 unicodeCdRomDeviceName,
652 OBJ_CASE_INSENSITIVE,
653 NULL,
654 NULL );
655
656 UDFPrint(("\n*** UDFDismountDevice: Create\n"));
657 RC = ZwCreateFile( &NtFileHandle,
658 GENERIC_READ,
659 &ObjectAttributes,
660 &IoStatus,
661 NULL,
662 FILE_ATTRIBUTE_NORMAL,
663 FILE_SHARE_READ,
664 FILE_OPEN,
665 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
666 NULL,
667 0 );
668
669
670 if (!NT_SUCCESS(RC)) try_return(RC);
671
672 UDFPrint(("\n*** UDFDismountDevice: QueryVolInfo\n"));
673 RC = ZwQueryVolumeInformationFile( NtFileHandle,
674 &IoStatus,
675 Buffer,
676 sizeof(FILE_FS_ATTRIBUTE_INFORMATION)+2*sizeof(UDF_FS_TITLE_DVDRAM),
677 FileFsAttributeInformation);
678
679 #define UDF_CHECK_FS_NAME(name) \
680 (Buffer->FileSystemNameLength+sizeof(WCHAR) == sizeof(name) && \
681 DbgCompareMemory(&Buffer->FileSystemName[0],name , sizeof(name)) == sizeof(name))
682
683 if (NT_SUCCESS(RC) &&
684 (UDF_CHECK_FS_NAME((PVOID)UDF_FS_TITLE_CDR) ||
685 UDF_CHECK_FS_NAME((PVOID)UDF_FS_TITLE_CDRW) ||
686 UDF_CHECK_FS_NAME((PVOID)UDF_FS_TITLE_DVDR) ||
687 UDF_CHECK_FS_NAME((PVOID)UDF_FS_TITLE_DVDRW) ||
688 UDF_CHECK_FS_NAME((PVOID)UDF_FS_TITLE_DVDpR) ||
689 UDF_CHECK_FS_NAME((PVOID)UDF_FS_TITLE_DVDpRW) ||
690 UDF_CHECK_FS_NAME((PVOID)UDF_FS_TITLE_DVDRAM) )) try_return(STATUS_SUCCESS);
691
692 UDFPrint(("\n*** UDFDismountDevice: LockVolume\n"));
693 RC = ZwFsControlFile(NtFileHandle,
694 NULL,
695 NULL,
696 NULL,
697 &IoStatus,
698 FSCTL_LOCK_VOLUME,
699 NULL,
700 NULL,
701 NULL,
702 NULL);
703
704 if (!NT_SUCCESS(RC)) try_return(RC);
705
706 UDFPrint(("\n*** UDFDismountDevice: DismountVolume\n"));
707 RC = ZwFsControlFile(NtFileHandle,
708 NULL,
709 NULL,
710 NULL,
711 &IoStatus,
712 FSCTL_DISMOUNT_VOLUME,
713 NULL,
714 NULL,
715 NULL,
716 NULL);
717
718 if (!NT_SUCCESS(RC)) try_return(RC);
719
720 UDFPrint(("\n*** UDFDismountDevice: NotifyMediaChange\n"));
721 RC = ZwDeviceIoControlFile(NtFileHandle,
722 NULL,
723 NULL,
724 NULL,
725 &IoStatus,
726 IOCTL_CDRW_NOTIFY_MEDIA_CHANGE,
727 &buffer,
728 sizeof(buffer),
729 &buffer,
730 sizeof(buffer));
731
732 if (!NT_SUCCESS(RC)) try_return(RC);
733
734
735 UDFPrint(("\n*** UDFDismountDevice: UnlockVolume\n"));
736 RC = ZwFsControlFile(NtFileHandle,
737 NULL,
738 NULL,
739 NULL,
740 &IoStatus,
741 FSCTL_UNLOCK_VOLUME,
742 NULL,
743 NULL,
744 NULL,
745 NULL);
746
747 UDFPrint(("\n*** UDFDismountDevice: Close\n"));
748 ZwClose( NtFileHandle );
749
750 NtFileHandle = (HANDLE)-1;
751
752 UDFPrint(("\n*** UDFDismountDevice: Create 2\n"));
753 RC = ZwCreateFile( &NtFileHandle,
754 GENERIC_READ,
755 &ObjectAttributes,
756 &IoStatus,
757 NULL,
758 FILE_ATTRIBUTE_NORMAL,
759 FILE_SHARE_READ,
760 FILE_OPEN,
761 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
762 NULL,
763 0 );
764
765 try_exit: NOTHING;
766
767 } _SEH2_FINALLY {
768 if (Buffer) MyFreePool__(Buffer);
769 if (NtFileHandle != (HANDLE)-1) ZwClose( NtFileHandle );
770 } _SEH2_END;
771
772 UDFPrint(("\n*** UDFDismountDevice: RC=%x\n",RC));
773 return RC;
774 }
775
776
777 VOID
778 NTAPI
779 UDFFsNotification(
780 IN PDEVICE_OBJECT DeviceObject,
781 IN BOOLEAN FsActive
782 )
783
784 /*
785
786 Routine Description:
787
788 This routine is invoked whenever a file system has either registered or
789 unregistered itself as an active file system.
790
791 For the former case, this routine creates a device object and attaches it
792 to the specified file system's device object. This allows this driver
793 to filter all requests to that file system.
794
795 For the latter case, this file system's device object is located,
796 detached, and deleted. This removes this file system as a filter for
797 the specified file system.
798
799 Arguments:
800
801 DeviceObject - Pointer to the file system's device object.
802
803 FsActive - bolean indicating whether the file system has registered
804 (TRUE) or unregistered (FALSE) itself as an active file system.
805
806 Return Value:
807
808 None.
809
810 */
811
812 {
813 // Begin by determine whether or not the file system is a cdrom-based file
814 // system. If not, then this driver is not concerned with it.
815 if (!FsRegistered ||
816 DeviceObject->DeviceType != FILE_DEVICE_CD_ROM_FILE_SYSTEM) {
817 return;
818 }
819
820 // Begin by determining whether this file system is registering or
821 // unregistering as an active file system.
822 if (FsActive
823 && UDFGlobalData.UDFDeviceObject_CD != DeviceObject
824 #ifdef UDF_HDD_SUPPORT
825 && UDFGlobalData.UDFDeviceObject_HDD != DeviceObject
826 #endif // UDF_HDD_SUPPORT
827 ) {
828 UDFPrint(("\n*** UDFFSNotification \n\n"));
829
830 // Acquire GlobalDataResource
831 UDFAcquireResourceExclusive(&(UDFGlobalData.GlobalDataResource), TRUE);
832
833 if(FsNotification_ThreadId != PsGetCurrentThreadId()) {
834
835 FsNotification_ThreadId = PsGetCurrentThreadId();
836
837 IoUnregisterFileSystem(UDFGlobalData.UDFDeviceObject_CD);
838 IoRegisterFileSystem(UDFGlobalData.UDFDeviceObject_CD);
839
840 #ifdef UDF_HDD_SUPPORT
841 IoUnregisterFileSystem(UDFGlobalData.UDFDeviceObject_HDD);
842 IoRegisterFileSystem(UDFGlobalData.UDFDeviceObject_HDD);
843 #endif // UDF_HDD_SUPPORT
844
845 FsNotification_ThreadId = (HANDLE)(-1);
846
847 } else {
848 UDFPrint(("\n*** recursive UDFFSNotification call,\n can't become top-level UDF FSD \n\n"));
849 }
850
851 // Release the global resource.
852 UDFReleaseResource( &(UDFGlobalData.GlobalDataResource) );
853
854
855 }
856 }
857 /*VOID
858 UDFRemountAll(
859 IN PVOID Context
860 )
861 {
862 NTSTATUS RC = STATUS_SUCCESS;
863 ULONG CdRomNumber;
864 CCHAR deviceNameBuffer[MAXIMUM_FILENAME_LENGTH];
865 ANSI_STRING deviceName;
866 UNICODE_STRING unicodeCdRomDeviceName;
867 LARGE_INTEGER delay;
868
869 */
870 /* delay.QuadPart = -80*10000000;
871 KeDelayExecutionThread(KernelMode, FALSE, &delay); //10 seconds*/
872
873 /* for(CdRomNumber = 0;true;CdRomNumber++) {
874 sprintf(deviceNameBuffer, "\\Device\\CdRom%d", CdRomNumber);
875 UDFPrint(( "UDF: UDFRemountAll : dismount %s\n", deviceNameBuffer));
876 RtlInitString(&deviceName, deviceNameBuffer);
877 RC = RtlAnsiStringToUnicodeString(&unicodeCdRomDeviceName, &deviceName, TRUE);
878
879 if (!NT_SUCCESS(RC)) {
880 RtlFreeUnicodeString(&unicodeCdRomDeviceName);
881 break;
882 }
883
884 RC = UDFDismountDevice(&unicodeCdRomDeviceName);
885 RtlFreeUnicodeString(&unicodeCdRomDeviceName);
886
887 if (!NT_SUCCESS(RC)) break;
888 }
889 }*/