xref: /reactos/drivers/filesystems/ext2/src/init.c (revision b99f0b49)
1 /*
2  * COPYRIGHT:        See COPYRIGHT.TXT
3  * PROJECT:          Ext2 File System Driver for WinNT/2K/XP
4  * FILE:             init.c
5  * PROGRAMMER:       Matt Wu <mattwu@163.com>
6  * HOMEPAGE:         http://www.ext2fsd.com
7  * UPDATE HISTORY:
8  */
9 
10 /* INCLUDES *****************************************************************/
11 
12 #include "ext2fs.h"
13 
14 /* GLOBALS ***************************************************************/
15 
16 PEXT2_GLOBAL    Ext2Global   = NULL;
17 
18 /*
19  *   Ext2Fsd version, building date/time
20  */
21 
22 CHAR            gVersion[]   = EXT2FSD_VERSION;
23 CHAR            gTime[] = __TIME__;
24 CHAR            gDate[] = __DATE__;
25 
26 
27 /* DEFINITIONS ***********************************************************/
28 
29 NTSTATUS NTAPI
30 DriverEntry(
31     IN PDRIVER_OBJECT DriverObject,
32     IN PUNICODE_STRING RegistryPath   );
33 
34 #ifdef ALLOC_PRAGMA
35 #pragma alloc_text(INIT, Ext2QueryGlobalParameters)
36 #pragma alloc_text(INIT, Ext2QueryRegistrySettings)
37 #pragma alloc_text(INIT, DriverEntry)
38 #if EXT2_UNLOAD
39 #pragma alloc_text(PAGE, DriverUnload)
40 #endif
41 #endif
42 
43 /* FUNCTIONS ***************************************************************/
44 
45 DECLARE_INIT(journal_init);
46 DECLARE_EXIT(journal_exit);
47 
48 #if EXT2_UNLOAD
49 
50 /*
51  * FUNCTION: Called by the system to unload the driver
52  * ARGUMENTS:
53  *           DriverObject = object describing this driver
54  * RETURNS:  None
55  */
56 
57 VOID NTAPI
58 DriverUnload (IN PDRIVER_OBJECT DriverObject)
59 {
60 
61     UNICODE_STRING              DosDeviceName;
62 
63     DEBUG(DL_FUN, ( "Ext2Fsd: Unloading routine.\n"));
64 
65     /*
66      *  stop reaper thread ...
67      */
68 
69 
70     /*
71      *  removing memory allocations and  objects
72      */
73 
74     RtlInitUnicodeString(&DosDeviceName, DOS_DEVICE_NAME);
75     IoDeleteSymbolicLink(&DosDeviceName);
76 
77     Ext2UnloadAllNls();
78 
79     ExDeleteResourceLite(&Ext2Global->Resource);
80 
81     ExDeleteNPagedLookasideList(&(Ext2Global->Ext2DentryLookasideList));
82     ExDeleteNPagedLookasideList(&(Ext2Global->Ext2ExtLookasideList));
83     ExDeleteNPagedLookasideList(&(Ext2Global->Ext2McbLookasideList));
84     ExDeleteNPagedLookasideList(&(Ext2Global->Ext2CcbLookasideList));
85     ExDeleteNPagedLookasideList(&(Ext2Global->Ext2FcbLookasideList));
86     ExDeleteNPagedLookasideList(&(Ext2Global->Ext2IrpContextLookasideList));
87 
88     ObDereferenceObject(Ext2Global->DiskdevObject);
89     ObDereferenceObject(Ext2Global->CdromdevObject);
90 
91     /* cleanup journal related caches */
92     UNLOAD_MODULE(journal_exit);
93 
94     /* cleanup linux lib */
95     ext2_destroy_linux();
96 
97     Ext2FreePool(Ext2Global, 'LG2E');
98     Ext2Global = NULL;
99 }
100 
101 #endif
102 
103 NTSTATUS NTAPI
104 Ext2RegistryQueryCallback(
105     IN PWSTR ValueName,
106     IN ULONG ValueType,
107     IN PVOID ValueData,
108     IN ULONG ValueLength,
109     IN PVOID Context,
110     IN PVOID EntryContext
111     )
112 {
113     ULONG  i = 0;
114     BYTE   *s, *t;
115 
116     if (NULL == ValueName || NULL == ValueData)
117         return STATUS_SUCCESS;
118 
119     if (ValueType == REG_DWORD && wcslen(ValueName) == wcslen(WRITING_SUPPORT) &&
120         _wcsnicmp(ValueName, WRITING_SUPPORT, wcslen(WRITING_SUPPORT)) == 0) {
121 
122         if (ValueData && ValueLength == sizeof(DWORD)) {
123             if (*((PULONG)ValueData)) {
124                 SetLongFlag(Ext2Global->Flags, EXT2_SUPPORT_WRITING);
125             } else {
126                 ClearLongFlag(Ext2Global->Flags, EXT2_SUPPORT_WRITING);
127             }
128         }
129     } else if (ValueType == REG_DWORD && wcslen(ValueName) == wcslen(CHECKING_BITMAP) &&
130         _wcsnicmp(ValueName, CHECKING_BITMAP, wcslen(CHECKING_BITMAP)) == 0) {
131 
132         if (ValueData && ValueLength == sizeof(DWORD)) {
133             if (*((PULONG)ValueData)) {
134                 SetLongFlag(Ext2Global->Flags, EXT2_CHECKING_BITMAP);
135             } else {
136                 ClearLongFlag(Ext2Global->Flags, EXT2_CHECKING_BITMAP);
137             }
138         }
139     } else if (ValueType == REG_DWORD && wcslen(ValueName) == wcslen(EXT3_FORCEWRITING) &&
140         _wcsnicmp(ValueName, EXT3_FORCEWRITING, wcslen(EXT3_FORCEWRITING)) == 0) {
141 
142         if (ValueData && ValueLength == sizeof(DWORD)) {
143             if (*((PULONG)ValueData)) {
144                 SetLongFlag(Ext2Global->Flags, EXT3_FORCE_WRITING);
145                 SetLongFlag(Ext2Global->Flags, EXT2_SUPPORT_WRITING);
146             } else {
147                 ClearLongFlag(Ext2Global->Flags, EXT3_FORCE_WRITING);
148             }
149         }
150     } else if (ValueType == REG_DWORD && wcslen(ValueName) == wcslen(AUTO_MOUNT) &&
151         _wcsnicmp(ValueName, AUTO_MOUNT, wcslen(AUTO_MOUNT)) == 0) {
152 
153         if (ValueData && ValueLength == sizeof(DWORD)) {
154             if (*((PULONG)ValueData)) {
155                 SetLongFlag(Ext2Global->Flags, EXT2_AUTO_MOUNT);
156             } else {
157                 ClearLongFlag(Ext2Global->Flags, EXT2_AUTO_MOUNT);
158             }
159         }
160     } else if (ValueType == REG_SZ && wcslen(ValueName) == wcslen(CODEPAGE_NAME) &&
161         _wcsnicmp(ValueName, CODEPAGE_NAME, wcslen(CODEPAGE_NAME)) == 0) {
162 
163         if (ValueData && ValueLength <= sizeof(WCHAR) * CODEPAGE_MAXLEN) {
164             RtlCopyMemory(&Ext2Global->Codepage.PageName[0],
165                           ValueData, ValueLength);
166         }
167     } else if (ValueType == REG_SZ && wcslen(ValueName) == wcslen(HIDING_PREFIX) &&
168         _wcsnicmp(ValueName, HIDING_PREFIX, wcslen(HIDING_PREFIX)) == 0) {
169 
170         if (ValueData && ValueLength <= sizeof(WCHAR) * HIDINGPAT_LEN) {
171             RtlCopyMemory(&Ext2Global->wHidingPrefix[0],
172                           ValueData, ValueLength);
173         }
174     } else  if (ValueType == REG_SZ && wcslen(ValueName) == wcslen(HIDING_SUFFIX) &&
175         _wcsnicmp(ValueName, HIDING_SUFFIX, wcslen(HIDING_SUFFIX)) == 0) {
176 
177         if (ValueData && ValueLength <= sizeof(WCHAR) * HIDINGPAT_LEN) {
178             RtlCopyMemory(&Ext2Global->wHidingSuffix[0],
179                           ValueData, ValueLength);
180         }
181     }
182 
183 
184     return STATUS_SUCCESS;
185 }
186 
187 NTSTATUS
188 Ext2QueryGlobalParameters(IN PUNICODE_STRING RegistryPath)
189 {
190     RTL_QUERY_REGISTRY_TABLE    QueryTable[8];
191     int                         i = 0;
192     NTSTATUS                    Status;
193 
194     RtlZeroMemory(&QueryTable[0], sizeof(RTL_QUERY_REGISTRY_TABLE) * 8);
195 
196     /*
197      * 1 writing support
198      */
199     QueryTable[i].Flags = 0;
200     QueryTable[i].Name = WRITING_SUPPORT;
201     QueryTable[i].DefaultType = REG_NONE;
202     QueryTable[i].DefaultLength = 0;
203     QueryTable[i].DefaultData = NULL;
204     QueryTable[i].EntryContext = NULL;
205     QueryTable[i].QueryRoutine = Ext2RegistryQueryCallback;
206     i++;
207 
208     /*
209      * 2 checking bitmap
210      */
211     QueryTable[i].Flags = 0;
212     QueryTable[i].Name = CHECKING_BITMAP;
213     QueryTable[i].DefaultType = REG_NONE;
214     QueryTable[i].DefaultLength = 0;
215     QueryTable[i].DefaultData = NULL;
216     QueryTable[i].EntryContext = NULL;
217     QueryTable[i].QueryRoutine = Ext2RegistryQueryCallback;
218     i++;
219 
220     /*
221      * 3 force writing
222      */
223     QueryTable[i].Flags = 0;
224     QueryTable[i].Name = EXT3_FORCEWRITING;
225     QueryTable[i].DefaultType = REG_NONE;
226     QueryTable[i].DefaultLength = 0;
227     QueryTable[i].DefaultData = NULL;
228     QueryTable[i].EntryContext = NULL;
229     QueryTable[i].QueryRoutine = Ext2RegistryQueryCallback;
230     i++;
231 
232     /*
233      * 4 automount
234      */
235     QueryTable[i].Flags = 0;
236     QueryTable[i].Name = AUTO_MOUNT;
237     QueryTable[i].DefaultType = REG_NONE;
238     QueryTable[i].DefaultLength = 0;
239     QueryTable[i].DefaultData = NULL;
240     QueryTable[i].EntryContext = NULL;
241     QueryTable[i].QueryRoutine = Ext2RegistryQueryCallback;
242     i++;
243 
244     /*
245      * 5 codepage
246      */
247     QueryTable[i].Flags = 0;
248     QueryTable[i].Name = CODEPAGE_NAME;
249     QueryTable[i].DefaultType = REG_NONE;
250     QueryTable[i].DefaultLength = 0;
251     QueryTable[i].DefaultData = NULL;
252     QueryTable[i].EntryContext = NULL;
253     QueryTable[i].QueryRoutine = Ext2RegistryQueryCallback;
254     i++;
255 
256     /*
257      * 6 hidden prefix
258      */
259     QueryTable[i].Flags = 0;
260     QueryTable[i].Name = HIDING_PREFIX;
261     QueryTable[i].DefaultType = REG_NONE;
262     QueryTable[i].DefaultLength = 0;
263     QueryTable[i].DefaultData = NULL;
264     QueryTable[i].EntryContext = NULL;
265     QueryTable[i].QueryRoutine = Ext2RegistryQueryCallback;
266     i++;
267 
268 
269     /*
270      * 7 hidden suffix
271      */
272     QueryTable[i].Flags = 0;
273     QueryTable[i].Name = HIDING_SUFFIX;
274     QueryTable[i].DefaultType = REG_NONE;
275     QueryTable[i].DefaultLength = 0;
276     QueryTable[i].DefaultData = NULL;
277     QueryTable[i].EntryContext = NULL;
278     QueryTable[i].QueryRoutine = Ext2RegistryQueryCallback;
279     i++;
280 
281     Status = RtlQueryRegistryValues(
282                  RTL_REGISTRY_ABSOLUTE,
283                  RegistryPath->Buffer,
284                  &QueryTable[0],
285                  NULL,
286                  NULL
287             );
288 
289     return NT_SUCCESS(Status);
290 }
291 
292 
293 BOOLEAN
294 Ext2QueryRegistrySettings(IN PUNICODE_STRING  RegistryPath)
295 {
296     UNICODE_STRING              ParameterPath;
297     UNICODE_STRING              UniName;
298     ANSI_STRING                 AnsiName;
299 
300     ULONG                       WritingSupport = 0;
301     ULONG                       CheckingBitmap = 0;
302     ULONG                       Ext3ForceWriting = 0;
303     ULONG                       AutoMount = 0;
304 
305     WCHAR                       UniBuffer[CODEPAGE_MAXLEN];
306     USHORT                      Buffer[HIDINGPAT_LEN];
307 
308     NTSTATUS                    Status;
309 
310     ParameterPath.Length = 0;
311     ParameterPath.MaximumLength =
312         RegistryPath->Length + sizeof(PARAMETERS_KEY) + sizeof(WCHAR);
313     ParameterPath.Buffer =
314         (PWSTR) Ext2AllocatePool(
315             PagedPool,
316             ParameterPath.MaximumLength,
317             'LG2E'
318         );
319     if (!ParameterPath.Buffer) {
320         DbgBreak();
321         DEBUG(DL_ERR, ( "Ex2QueryParameters: failed to allocate Parameters...\n"));
322         return FALSE;
323     }
324 
325     RtlCopyUnicodeString(&ParameterPath, RegistryPath);
326     RtlAppendUnicodeToString(&ParameterPath, PARAMETERS_KEY);
327 
328     /* enable automount of ext2/3/4 volumes */
329     SetLongFlag(Ext2Global->Flags, EXT2_AUTO_MOUNT);
330 
331     /* query parameter settings from registry */
332     Ext2QueryGlobalParameters(&ParameterPath);
333 
334     /* set global codepage settings */
335     if (wcslen(&Ext2Global->Codepage.PageName[0])) {
336         UniName.Length = sizeof(WCHAR) * wcslen(&Ext2Global->Codepage.PageName[0]);
337         UniName.MaximumLength = CODEPAGE_MAXLEN * sizeof(WCHAR);
338         UniName.Buffer = &Ext2Global->Codepage.PageName[0];
339         AnsiName.MaximumLength = CODEPAGE_MAXLEN;
340         AnsiName.Length = 0;
341         AnsiName.Buffer = &Ext2Global->Codepage.AnsiName[0];
342         Status = RtlUnicodeStringToAnsiString(
343                      &AnsiName,
344                      &UniName,
345                      FALSE);
346         if (!NT_SUCCESS(Status)) {
347             DEBUG(DL_ERR, ( "Ext2QueryParameters: Wrong CodePage %wZ ...\n", &UniName));
348             RtlCopyMemory(&(Ext2Global->Codepage.AnsiName[0]),"default\0", 8);
349         }
350     } else {
351         DEBUG(DL_ERR, ( "Ext2QueryParameters: CodePage not specified.\n"));
352         RtlCopyMemory(&(Ext2Global->Codepage.AnsiName[0]),"default\0", 8);
353     }
354     Ext2Global->Codepage.AnsiName[CODEPAGE_MAXLEN - 1] = 0;
355 
356 
357     /* set global hidden prefix pattern */
358     if (wcslen(&Ext2Global->wHidingPrefix[0])) {
359         UniName.Length = sizeof(WCHAR) * wcslen(&Ext2Global->wHidingPrefix[0]);
360         UniName.MaximumLength = HIDINGPAT_LEN * sizeof(WCHAR);
361         UniName.Buffer = &Ext2Global->wHidingPrefix[0];
362         AnsiName.MaximumLength = HIDINGPAT_LEN;
363         AnsiName.Length = 0;
364         AnsiName.Buffer = &(Ext2Global->sHidingPrefix[0]);
365 
366         Status = RtlUnicodeStringToAnsiString(
367                      &AnsiName,
368                      &UniName,
369                      FALSE);
370         if (NT_SUCCESS(Status)) {
371             Ext2Global->bHidingPrefix = TRUE;
372         } else {
373             DEBUG(DL_ERR, ( "Ext2QueryParameters: Wrong HidingPrefix ...\n"));
374         }
375     } else {
376         DEBUG(DL_ERR, ( "Ext2QueryParameters: HidingPrefix not specified.\n"));
377     }
378     Ext2Global->sHidingPrefix[HIDINGPAT_LEN - 1] = 0;
379 
380 
381     /* set global hidden suffix pattern */
382     if (wcslen(&Ext2Global->wHidingSuffix[0])) {
383         UniName.Length = sizeof(WCHAR) * wcslen(&Ext2Global->wHidingSuffix[0]);
384         UniName.MaximumLength = HIDINGPAT_LEN * sizeof(WCHAR);
385         UniName.Buffer = &Ext2Global->wHidingSuffix[0];
386         AnsiName.MaximumLength = HIDINGPAT_LEN;
387         AnsiName.Length = 0;
388         AnsiName.Buffer = &(Ext2Global->sHidingSuffix[0]);
389 
390         Status = RtlUnicodeStringToAnsiString(
391                      &AnsiName,
392                      &UniName,
393                      FALSE);
394         if (NT_SUCCESS(Status)) {
395             Ext2Global->bHidingSuffix = TRUE;
396         } else {
397             DEBUG(DL_ERR, ( "Ext2QueryParameters: Wrong HidingSuffix ...\n"));
398         }
399     } else {
400         DEBUG(DL_ERR, ( "Ext2QueryParameters: HidingSuffix not specified.\n"));
401     }
402     Ext2Global->sHidingPrefix[HIDINGPAT_LEN - 1] = 0;
403 
404     Ext2Global->RegistryPath.Buffer = ParameterPath.Buffer;
405     Ext2Global->RegistryPath.Length = 0;
406     Ext2Global->RegistryPath.MaximumLength = ParameterPath.MaximumLength;
407     RtlCopyUnicodeString(&Ext2Global->RegistryPath, RegistryPath);
408     RtlAppendUnicodeToString(&Ext2Global->RegistryPath, VOLUMES_KEY);
409 
410     return TRUE;
411 }
412 
413 
414 #define NLS_OEM_LEAD_BYTE_INFO            (*NlsOemLeadByteInfo)
415 
416 #ifndef __REACTOS__
417 #define FsRtlIsLeadDbcsCharacter(DBCS_CHAR) (                      \
418     (BOOLEAN)((UCHAR)(DBCS_CHAR) < 0x80 ? FALSE :                  \
419               (NLS_MB_CODE_PAGE_TAG &&                             \
420                (NLS_OEM_LEAD_BYTE_INFO[(UCHAR)(DBCS_CHAR)] != 0))) \
421 )
422 #endif
423 
424 VOID
425 Ext2EresourceAlignmentChecking()
426 {
427     /* Verify ERESOURCE alignment in structures */
428     CL_ASSERT((FIELD_OFFSET(EXT2_GLOBAL, Resource) & 7) == 0);
429     CL_ASSERT((FIELD_OFFSET(EXT2_VCB, MainResource) & 7) == 0);
430     CL_ASSERT((FIELD_OFFSET(EXT2_VCB, PagingIoResource) & 7) == 0);
431     CL_ASSERT((FIELD_OFFSET(EXT2_VCB, MetaInode) & 7) == 0);
432     CL_ASSERT((FIELD_OFFSET(EXT2_VCB, MetaBlock) & 7) == 0);
433     CL_ASSERT((FIELD_OFFSET(EXT2_VCB, McbLock) & 7) == 0);
434     CL_ASSERT((FIELD_OFFSET(EXT2_VCB, FcbLock) & 7) == 0);
435     CL_ASSERT((FIELD_OFFSET(EXT2_VCB, bd.bd_bh_lock) & 7) == 0);
436     CL_ASSERT((FIELD_OFFSET(EXT2_VCB, sbi.s_gd_lock) & 7) == 0);
437     CL_ASSERT((FIELD_OFFSET(EXT2_FCBVCB, MainResource) & 7) == 0);
438     CL_ASSERT((FIELD_OFFSET(EXT2_FCBVCB, PagingIoResource) & 7) == 0);
439     CL_ASSERT((FIELD_OFFSET(EXT2_FCB, MainResource) & 7) == 0);
440     CL_ASSERT((FIELD_OFFSET(EXT2_FCB, PagingIoResource) & 7) == 0);
441 }
442 
443 /*
444  * NAME: DriverEntry
445  * FUNCTION: Called by the system to initalize the driver
446  *
447  * ARGUMENTS:
448  *           DriverObject = object describing this driver
449  *           RegistryPath = path to our configuration entries
450  * RETURNS: Success or failure
451  */
452 NTSTATUS NTAPI
453 DriverEntry (
454     IN PDRIVER_OBJECT   DriverObject,
455     IN PUNICODE_STRING  RegistryPath
456 )
457 {
458     PDEVICE_OBJECT              DiskdevObject = NULL;
459     PDEVICE_OBJECT              CdromdevObject = NULL;
460     UNICODE_STRING              DeviceName;
461     UNICODE_STRING              DosDeviceName;
462 
463     PFAST_IO_DISPATCH           FastIoDispatch;
464     PCACHE_MANAGER_CALLBACKS    CacheManagerCallbacks;
465 
466     NTSTATUS                    Status;
467 
468     int                         rc = 0;
469     BOOLEAN                     linux_lib_inited = FALSE;
470     BOOLEAN                     journal_module_inited = FALSE;
471 
472     /* Verity super block ... */
473     ASSERT(sizeof(EXT2_SUPER_BLOCK) == 1024);
474     ASSERT(FIELD_OFFSET(EXT2_SUPER_BLOCK, s_magic) == 56);
475 
476     DbgPrint(
477         "Ext2Fsd --"
478 #ifdef _WIN2K_TARGET_
479         " Win2k --"
480 #endif
481         " Version "
482         EXT2FSD_VERSION
483 #if EXT2_DEBUG
484         " Checked"
485 #else
486         " Free"
487 #endif
488         " -- "
489         __DATE__ " "
490         __TIME__ ".\n");
491 
492     DEBUG(DL_FUN, ( "Ext2 DriverEntry ...\n"));
493 
494     /* initialize winlib structures */
495     if (ext2_init_linux()) {
496         Status = STATUS_INSUFFICIENT_RESOURCES;
497         goto errorout;
498     }
499     linux_lib_inited = TRUE;
500 
501     /* initialize journal module structures */
502     LOAD_MODULE(journal_init);
503     if (rc != 0) {
504         Status = STATUS_INSUFFICIENT_RESOURCES;
505         goto errorout;
506     }
507     journal_module_inited = TRUE;
508 
509     /* allocate memory for Ext2Global */
510     Ext2Global = Ext2AllocatePool(NonPagedPool, sizeof(EXT2_GLOBAL), 'LG2E');
511     if (!Ext2Global) {
512         Status = STATUS_INSUFFICIENT_RESOURCES;
513         goto errorout;
514     }
515 
516     /* initialize Ext2Global */
517     RtlZeroMemory(Ext2Global, sizeof(EXT2_GLOBAL));
518     Ext2Global->Identifier.Type = EXT2FGD;
519     Ext2Global->Identifier.Size = sizeof(EXT2_GLOBAL);
520 
521     InitializeListHead(&(Ext2Global->VcbList));
522     ExInitializeResourceLite(&(Ext2Global->Resource));
523 
524     /* query registry settings */
525     Ext2QueryRegistrySettings(RegistryPath);
526 
527     /* create Ext2Fsd cdrom fs deivce */
528     RtlInitUnicodeString(&DeviceName, CDROM_NAME);
529     Status = IoCreateDevice(
530                  DriverObject,
531                  0,
532                  &DeviceName,
533                  FILE_DEVICE_CD_ROM_FILE_SYSTEM,
534                  0,
535                  FALSE,
536                  &CdromdevObject );
537 
538     if (!NT_SUCCESS(Status)) {
539         DEBUG(DL_ERR, ( "IoCreateDevice cdrom device object error.\n"));
540         goto errorout;
541     }
542 
543     /* create Ext2Fsd disk fs deivce */
544     RtlInitUnicodeString(&DeviceName, DEVICE_NAME);
545     Status = IoCreateDevice(
546                  DriverObject,
547                  0,
548                  &DeviceName,
549                  FILE_DEVICE_DISK_FILE_SYSTEM,
550                  0,
551                  FALSE,
552                  &DiskdevObject );
553 
554     if (!NT_SUCCESS(Status)) {
555         DEBUG(DL_ERR, ( "IoCreateDevice disk device object error.\n"));
556         goto errorout;
557     }
558 
559     Status= Ext2StartReaper(
560                 &Ext2Global->FcbReaper,
561                 Ext2FcbReaperThread);
562     if (!NT_SUCCESS(Status)) {
563         goto errorout;
564     }
565 
566     /* start resource reaper thread */
567     Status= Ext2StartReaper(
568                 &Ext2Global->McbReaper,
569                 Ext2McbReaperThread);
570     if (!NT_SUCCESS(Status)) {
571         Ext2StopReaper(&Ext2Global->FcbReaper);
572         goto errorout;
573     }
574 
575     Status= Ext2StartReaper(
576                 &Ext2Global->bhReaper,
577                 Ext2bhReaperThread);
578     if (!NT_SUCCESS(Status)) {
579         Ext2StopReaper(&Ext2Global->FcbReaper);
580         Ext2StopReaper(&Ext2Global->McbReaper);
581         goto errorout;
582     }
583 
584 #ifdef _PNP_POWER_
585     DiskdevObject->DeviceObjectExtension->PowerControlNeeded = FALSE;
586     CdromdevObject->DeviceObjectExtension->PowerControlNeeded = FALSE;
587 #endif
588 
589     /* initializing */
590     Ext2Global->DiskdevObject  = DiskdevObject;
591     Ext2Global->CdromdevObject = CdromdevObject;
592 
593     DriverObject->MajorFunction[IRP_MJ_CREATE]              = Ext2BuildRequest;
594     DriverObject->MajorFunction[IRP_MJ_CLOSE]               = Ext2BuildRequest;
595     DriverObject->MajorFunction[IRP_MJ_READ]                = Ext2BuildRequest;
596     DriverObject->MajorFunction[IRP_MJ_WRITE]               = Ext2BuildRequest;
597 
598     DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS]       = Ext2BuildRequest;
599     DriverObject->MajorFunction[IRP_MJ_SHUTDOWN]            = Ext2BuildRequest;
600 
601     DriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION]   = Ext2BuildRequest;
602     DriverObject->MajorFunction[IRP_MJ_SET_INFORMATION]     = Ext2BuildRequest;
603 
604     DriverObject->MajorFunction[IRP_MJ_QUERY_VOLUME_INFORMATION]    = Ext2BuildRequest;
605     DriverObject->MajorFunction[IRP_MJ_SET_VOLUME_INFORMATION]      = Ext2BuildRequest;
606 
607     DriverObject->MajorFunction[IRP_MJ_DIRECTORY_CONTROL]   = Ext2BuildRequest;
608     DriverObject->MajorFunction[IRP_MJ_FILE_SYSTEM_CONTROL] = Ext2BuildRequest;
609     DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL]      = Ext2BuildRequest;
610     DriverObject->MajorFunction[IRP_MJ_LOCK_CONTROL]        = Ext2BuildRequest;
611 
612     DriverObject->MajorFunction[IRP_MJ_QUERY_EA] = Ext2BuildRequest;
613     DriverObject->MajorFunction[IRP_MJ_SET_EA] = Ext2BuildRequest;
614 
615     DriverObject->MajorFunction[IRP_MJ_CLEANUP]             = Ext2BuildRequest;
616 
617 #if (_WIN32_WINNT >= 0x0500)
618     DriverObject->MajorFunction[IRP_MJ_PNP]                 = Ext2BuildRequest;
619 #endif //(_WIN32_WINNT >= 0x0500)
620 
621 #if EXT2_UNLOAD
622     DriverObject->DriverUnload                              = DriverUnload;
623 #else
624     DriverObject->DriverUnload                              = NULL;
625 #endif
626 
627     //
628     // Initialize the fast I/O entry points
629     //
630 
631     FastIoDispatch = &(Ext2Global->FastIoDispatch);
632 
633     FastIoDispatch->SizeOfFastIoDispatch          = sizeof(FAST_IO_DISPATCH);
634     FastIoDispatch->FastIoCheckIfPossible         = Ext2FastIoCheckIfPossible;
635     FastIoDispatch->FastIoRead                    = Ext2FastIoRead;
636     FastIoDispatch->FastIoWrite                   = Ext2FastIoWrite;
637     FastIoDispatch->FastIoQueryBasicInfo          = Ext2FastIoQueryBasicInfo;
638     FastIoDispatch->FastIoQueryStandardInfo       = Ext2FastIoQueryStandardInfo;
639     FastIoDispatch->FastIoLock                    = Ext2FastIoLock;
640     FastIoDispatch->FastIoUnlockSingle            = Ext2FastIoUnlockSingle;
641     FastIoDispatch->FastIoUnlockAll               = Ext2FastIoUnlockAll;
642     FastIoDispatch->FastIoUnlockAllByKey          = Ext2FastIoUnlockAllByKey;
643     FastIoDispatch->FastIoQueryNetworkOpenInfo    = Ext2FastIoQueryNetworkOpenInfo;
644 
645     FastIoDispatch->AcquireForModWrite            = Ext2AcquireFileForModWrite;
646     FastIoDispatch->ReleaseForModWrite            = Ext2ReleaseFileForModWrite;
647     FastIoDispatch->AcquireForModWrite            = Ext2AcquireFileForModWrite;
648     FastIoDispatch->ReleaseForModWrite            = Ext2ReleaseFileForModWrite;
649     FastIoDispatch->AcquireForCcFlush             = Ext2AcquireFileForCcFlush;
650     FastIoDispatch->ReleaseForCcFlush             = Ext2ReleaseFileForCcFlush;
651     FastIoDispatch->AcquireFileForNtCreateSection = Ext2AcquireForCreateSection;
652     FastIoDispatch->ReleaseFileForNtCreateSection = Ext2ReleaseForCreateSection;
653 
654     DriverObject->FastIoDispatch = FastIoDispatch;
655 
656     //
657     //  initializing structure sizes for statistics
658     //  1 means flexible/not fixed for all allocations (for different volumes).
659     //
660     Ext2Global->PerfStat.Magic   = EXT2_PERF_STAT_MAGIC;
661     Ext2Global->PerfStat.Version = EXT2_PERF_STAT_VER2;
662     Ext2Global->PerfStat.Length  = sizeof(EXT2_PERF_STATISTICS_V2);
663 
664     Ext2Global->PerfStat.Unit.Slot[PS_IRP_CONTEXT] = sizeof(EXT2_IRP_CONTEXT);  /* 0 */
665     Ext2Global->PerfStat.Unit.Slot[PS_VCB] = sizeof(EXT2_VCB);                  /* 1 */
666     Ext2Global->PerfStat.Unit.Slot[PS_FCB] = sizeof(EXT2_FCB);                  /* 2 */
667     Ext2Global->PerfStat.Unit.Slot[PS_CCB] = sizeof(EXT2_CCB);                  /* 3 */
668     Ext2Global->PerfStat.Unit.Slot[PS_MCB] = sizeof(EXT2_MCB);                  /* 4 */
669     Ext2Global->PerfStat.Unit.Slot[PS_EXTENT] = sizeof(EXT2_EXTENT);            /* 5 */
670     Ext2Global->PerfStat.Unit.Slot[PS_RW_CONTEXT] = sizeof(EXT2_RW_CONTEXT);    /* 6 */
671     Ext2Global->PerfStat.Unit.Slot[PS_VPB] = sizeof(VPB);                       /* 7 */
672     Ext2Global->PerfStat.Unit.Slot[PS_FILE_NAME] = 1;                           /* 8 */
673     Ext2Global->PerfStat.Unit.Slot[PS_MCB_NAME] = 1;                            /* 9 */
674     Ext2Global->PerfStat.Unit.Slot[PS_INODE_NAME] = 1;                          /* a */
675     Ext2Global->PerfStat.Unit.Slot[PS_DIR_ENTRY] = sizeof(EXT2_DIR_ENTRY2);     /* b */
676     Ext2Global->PerfStat.Unit.Slot[PS_DIR_PATTERN] = 1;                         /* c */
677     Ext2Global->PerfStat.Unit.Slot[PS_DISK_EVENT] = sizeof(KEVENT);             /* d */
678     Ext2Global->PerfStat.Unit.Slot[PS_DISK_BUFFER] = 1;                         /* e */
679     Ext2Global->PerfStat.Unit.Slot[PS_BLOCK_DATA] = 1;                          /* f */
680     Ext2Global->PerfStat.Unit.Slot[PS_EXT2_INODE] = 1;                          /* 10 */
681     Ext2Global->PerfStat.Unit.Slot[PS_DENTRY] = sizeof(struct dentry);          /* 11 */
682     Ext2Global->PerfStat.Unit.Slot[PS_BUFF_HEAD] = sizeof(struct buffer_head);  /* 12 */
683 
684     switch ( MmQuerySystemSize() ) {
685 
686     case MmSmallSystem:
687 
688         Ext2Global->MaxDepth = 64;
689         break;
690 
691     case MmMediumSystem:
692 
693         Ext2Global->MaxDepth = 128;
694         break;
695 
696     case MmLargeSystem:
697 
698         Ext2Global->MaxDepth = 256;
699         break;
700     }
701 
702     //
703     // Initialize the Cache Manager callbacks
704     //
705 
706     CacheManagerCallbacks = &(Ext2Global->CacheManagerCallbacks);
707     CacheManagerCallbacks->AcquireForLazyWrite  = Ext2AcquireForLazyWrite;
708     CacheManagerCallbacks->ReleaseFromLazyWrite = Ext2ReleaseFromLazyWrite;
709     CacheManagerCallbacks->AcquireForReadAhead  = Ext2AcquireForReadAhead;
710     CacheManagerCallbacks->ReleaseFromReadAhead = Ext2ReleaseFromReadAhead;
711 
712     Ext2Global->CacheManagerNoOpCallbacks.AcquireForLazyWrite  = Ext2NoOpAcquire;
713     Ext2Global->CacheManagerNoOpCallbacks.ReleaseFromLazyWrite = Ext2NoOpRelease;
714     Ext2Global->CacheManagerNoOpCallbacks.AcquireForReadAhead  = Ext2NoOpAcquire;
715     Ext2Global->CacheManagerNoOpCallbacks.ReleaseFromReadAhead = Ext2NoOpRelease;
716 
717 
718 #ifndef _WIN2K_TARGET_
719     //
720     // Initialize FS Filter callbacks
721     //
722 
723     RtlZeroMemory(&Ext2Global->FilterCallbacks,  sizeof(FS_FILTER_CALLBACKS));
724     Ext2Global->FilterCallbacks.SizeOfFsFilterCallbacks = sizeof(FS_FILTER_CALLBACKS);
725     Ext2Global->FilterCallbacks.PreAcquireForSectionSynchronization = Ext2PreAcquireForCreateSection;
726     FsRtlRegisterFileSystemFilterCallbacks(DriverObject,  &Ext2Global->FilterCallbacks );
727 
728 #endif
729 
730     //
731     // Initialize the global data
732     //
733 
734     ExInitializeNPagedLookasideList( &(Ext2Global->Ext2IrpContextLookasideList),
735                                      NULL,
736                                      NULL,
737                                      0,
738                                      sizeof(EXT2_IRP_CONTEXT),
739                                      'PRIE',
740                                      0 );
741 
742     ExInitializeNPagedLookasideList( &(Ext2Global->Ext2FcbLookasideList),
743                                      NULL,
744                                      NULL,
745                                      0,
746                                      sizeof(EXT2_FCB),
747                                      'BCFE',
748                                      0 );
749 
750     ExInitializeNPagedLookasideList( &(Ext2Global->Ext2CcbLookasideList),
751                                     NULL,
752                                     NULL,
753                                     0,
754                                     sizeof(EXT2_CCB),
755                                     'BCCE',
756                                     0 );
757 
758     ExInitializeNPagedLookasideList( &(Ext2Global->Ext2McbLookasideList),
759                                     NULL,
760                                     NULL,
761                                     0,
762                                     sizeof(EXT2_MCB),
763                                     'BCME',
764                                     0 );
765 
766     ExInitializeNPagedLookasideList( &(Ext2Global->Ext2ExtLookasideList),
767                                     NULL,
768                                     NULL,
769                                     0,
770                                     sizeof(EXT2_EXTENT),
771                                     'STXE',
772                                     0 );
773 
774     ExInitializeNPagedLookasideList( &(Ext2Global->Ext2DentryLookasideList),
775                                     NULL,
776                                     NULL,
777                                     0,
778                                     sizeof(struct dentry),
779                                     'TNED',
780                                     0 );
781 
782     RtlInitUnicodeString(&DosDeviceName, DOS_DEVICE_NAME);
783     IoCreateSymbolicLink(&DosDeviceName, &DeviceName);
784 
785 #if EXT2_DEBUG
786     ProcessNameOffset = Ext2GetProcessNameOffset();
787 #endif
788 
789     Ext2LoadAllNls();
790 
791     Ext2Global->Codepage.PageTable =
792         load_nls(Ext2Global->Codepage.AnsiName);
793 
794     /* register file system devices for disk and cdrom */
795     IoRegisterFileSystem(DiskdevObject);
796     ObReferenceObject(DiskdevObject);
797 
798     IoRegisterFileSystem(CdromdevObject);
799     ObReferenceObject(CdromdevObject);
800 
801 errorout:
802 
803     if (!NT_SUCCESS(Status)) {
804 
805         /*
806          *  stop reaper thread ...
807          */
808 
809 
810         /*
811          *  cleanup resources ...
812          */
813 
814         if (Ext2Global) {
815             ExDeleteResourceLite(&Ext2Global->Resource);
816             Ext2FreePool(Ext2Global, 'LG2E');
817         }
818 
819         if (CdromdevObject) {
820             IoDeleteDevice(CdromdevObject);
821         }
822 
823         if (DiskdevObject) {
824             IoDeleteDevice(DiskdevObject);
825         }
826 
827         if (journal_module_inited) {
828             /* cleanup journal related caches */
829             UNLOAD_MODULE(journal_exit);
830         }
831 
832         if (linux_lib_inited) {
833             /* cleanup linux lib */
834             ext2_destroy_linux();
835         }
836     }
837 
838     return Status;
839 }
840