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