xref: /reactos/drivers/filesystems/ext2/src/init.c (revision aaeb131b)
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
DriverUnload(IN PDRIVER_OBJECT DriverObject)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
Ext2RegistryQueryCallback(IN PWSTR ValueName,IN ULONG ValueType,IN PVOID ValueData,IN ULONG ValueLength,IN PVOID Context,IN PVOID EntryContext)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
Ext2QueryGlobalParameters(IN PUNICODE_STRING RegistryPath)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
Ext2QueryRegistrySettings(IN PUNICODE_STRING RegistryPath)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
Ext2EresourceAlignmentChecking()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
DriverEntry(IN PDRIVER_OBJECT DriverObject,IN PUNICODE_STRING RegistryPath)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