1 /*++
2 
3 Copyright (c) 1989-2000 Microsoft Corporation
4 
5 Module Name:
6 
7     FatInit.c
8 
9 Abstract:
10 
11     This module implements the DRIVER_INITIALIZATION routine for Fat
12 
13 
14 --*/
15 
16 #include "fatprocs.h"
17 
18 DRIVER_INITIALIZE DriverEntry;
19 
20 NTSTATUS
21 NTAPI
22 DriverEntry(
23     _In_ PDRIVER_OBJECT DriverObject,
24     _In_ PUNICODE_STRING RegistryPath
25     );
26 
27 _Function_class_(DRIVER_UNLOAD)
28 VOID
29 NTAPI
30 FatUnload(
31     _In_ _Unreferenced_parameter_ PDRIVER_OBJECT DriverObject
32     );
33 
34 NTSTATUS
35 FatGetCompatibilityModeValue(
36     IN PUNICODE_STRING ValueName,
37     IN OUT PULONG Value
38     );
39 
40 BOOLEAN
41 FatIsFujitsuFMR (
42     );
43 
44 #ifdef ALLOC_PRAGMA
45 #pragma alloc_text(INIT, DriverEntry)
46 #pragma alloc_text(INIT, FatGetCompatibilityModeValue)
47 #pragma alloc_text(INIT, FatIsFujitsuFMR)
48 //#pragma alloc_text(PAGE, FatUnload)
49 #endif
50 
51 #define COMPATIBILITY_MODE_KEY_NAME L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\FileSystem"
52 #define COMPATIBILITY_MODE_VALUE_NAME L"Win31FileSystem"
53 #define CODE_PAGE_INVARIANCE_VALUE_NAME L"FatDisableCodePageInvariance"
54 
55 
56 #define KEY_WORK_AREA ((sizeof(KEY_VALUE_FULL_INFORMATION) + \
57                         sizeof(ULONG)) + 64)
58 
59 #define REGISTRY_HARDWARE_DESCRIPTION_W \
60         L"\\Registry\\Machine\\Hardware\\DESCRIPTION\\System"
61 
62 #define REGISTRY_MACHINE_IDENTIFIER_W   L"Identifier"
63 
64 #define FUJITSU_FMR_NAME_W  L"FUJITSU FMR-"
65 
66 
67 
68 NTSTATUS
69 NTAPI
DriverEntry(_In_ PDRIVER_OBJECT DriverObject,_In_ PUNICODE_STRING RegistryPath)70 DriverEntry(
71     _In_ PDRIVER_OBJECT DriverObject,
72     _In_ PUNICODE_STRING RegistryPath
73     )
74 
75 /*++
76 
77 Routine Description:
78 
79     This is the initialization routine for the Fat file system
80     device driver.  This routine creates the device object for the FileSystem
81     device and performs all other driver initialization.
82 
83 Arguments:
84 
85     DriverObject - Pointer to driver object created by the system.
86 
87 Return Value:
88 
89     NTSTATUS - The function value is the final status from the initialization
90         operation.
91 
92 --*/
93 
94 {
95     USHORT MaxDepth;
96     NTSTATUS Status;
97     UNICODE_STRING UnicodeString;
98     FS_FILTER_CALLBACKS FilterCallbacks;
99     UNICODE_STRING ValueName;
100     ULONG Value;
101 
102     UNREFERENCED_PARAMETER( RegistryPath );
103 
104     //
105     // Create the device object for disks.  To avoid problems with filters who
106     // know this name, we must keep it.
107     //
108 
109     RtlInitUnicodeString( &UnicodeString, L"\\Fat" );
110     Status = IoCreateDevice( DriverObject,
111                              0,
112                              &UnicodeString,
113                              FILE_DEVICE_DISK_FILE_SYSTEM,
114                              0,
115                              FALSE,
116                              &FatDiskFileSystemDeviceObject );
117 
118     if (!NT_SUCCESS( Status )) {
119         return Status;
120     }
121 
122     //
123     // Create the device object for "cdroms".
124     //
125 
126     RtlInitUnicodeString( &UnicodeString, L"\\FatCdrom" );
127     Status = IoCreateDevice( DriverObject,
128                              0,
129                              &UnicodeString,
130                              FILE_DEVICE_CD_ROM_FILE_SYSTEM,
131                              0,
132                              FALSE,
133                              &FatCdromFileSystemDeviceObject );
134 
135     if (!NT_SUCCESS( Status )) {
136         IoDeleteDevice( FatDiskFileSystemDeviceObject);
137         return Status;
138     }
139 
140 #ifdef _MSC_VER
141 #pragma prefast( push )
142 #pragma prefast( disable:28155, "these are all correct" )
143 #pragma prefast( disable:28169, "these are all correct" )
144 #pragma prefast( disable:28175, "this is a filesystem, touching FastIoDispatch is allowed" )
145 #endif
146 
147     DriverObject->DriverUnload = FatUnload;
148 
149     //
150     //  Note that because of the way data caching is done, we set neither
151     //  the Direct I/O or Buffered I/O bit in DeviceObject->Flags.  If
152     //  data is not in the cache, or the request is not buffered, we may,
153     //  set up for Direct I/O by hand.
154     //
155 
156     //
157     // Initialize the driver object with this driver's entry points.
158     //
159 
160     DriverObject->MajorFunction[IRP_MJ_CREATE]                   = (PDRIVER_DISPATCH)FatFsdCreate;
161     DriverObject->MajorFunction[IRP_MJ_CLOSE]                    = (PDRIVER_DISPATCH)FatFsdClose;
162     DriverObject->MajorFunction[IRP_MJ_READ]                     = (PDRIVER_DISPATCH)FatFsdRead;
163     DriverObject->MajorFunction[IRP_MJ_WRITE]                    = (PDRIVER_DISPATCH)FatFsdWrite;
164     DriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION]        = (PDRIVER_DISPATCH)FatFsdQueryInformation;
165     DriverObject->MajorFunction[IRP_MJ_SET_INFORMATION]          = (PDRIVER_DISPATCH)FatFsdSetInformation;
166     DriverObject->MajorFunction[IRP_MJ_QUERY_EA]                 = (PDRIVER_DISPATCH)FatFsdQueryEa;
167     DriverObject->MajorFunction[IRP_MJ_SET_EA]                   = (PDRIVER_DISPATCH)FatFsdSetEa;
168     DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS]            = (PDRIVER_DISPATCH)FatFsdFlushBuffers;
169     DriverObject->MajorFunction[IRP_MJ_QUERY_VOLUME_INFORMATION] = (PDRIVER_DISPATCH)FatFsdQueryVolumeInformation;
170     DriverObject->MajorFunction[IRP_MJ_SET_VOLUME_INFORMATION]   = (PDRIVER_DISPATCH)FatFsdSetVolumeInformation;
171     DriverObject->MajorFunction[IRP_MJ_CLEANUP]                  = (PDRIVER_DISPATCH)FatFsdCleanup;
172     DriverObject->MajorFunction[IRP_MJ_DIRECTORY_CONTROL]        = (PDRIVER_DISPATCH)FatFsdDirectoryControl;
173     DriverObject->MajorFunction[IRP_MJ_FILE_SYSTEM_CONTROL]      = (PDRIVER_DISPATCH)FatFsdFileSystemControl;
174     DriverObject->MajorFunction[IRP_MJ_LOCK_CONTROL]             = (PDRIVER_DISPATCH)FatFsdLockControl;
175     DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL]           = (PDRIVER_DISPATCH)FatFsdDeviceControl;
176     DriverObject->MajorFunction[IRP_MJ_SHUTDOWN]                 = (PDRIVER_DISPATCH)FatFsdShutdown;
177     DriverObject->MajorFunction[IRP_MJ_PNP]                      = (PDRIVER_DISPATCH)FatFsdPnp;
178 
179     DriverObject->FastIoDispatch = &FatFastIoDispatch;
180 
181     RtlZeroMemory(&FatFastIoDispatch, sizeof(FatFastIoDispatch));
182 
183     FatFastIoDispatch.SizeOfFastIoDispatch =    sizeof(FAST_IO_DISPATCH);
184     FatFastIoDispatch.FastIoCheckIfPossible =   FatFastIoCheckIfPossible;  //  CheckForFastIo
185     FatFastIoDispatch.FastIoRead =              FsRtlCopyRead;             //  Read
186     FatFastIoDispatch.FastIoWrite =             FsRtlCopyWrite;            //  Write
187     FatFastIoDispatch.FastIoQueryBasicInfo =    FatFastQueryBasicInfo;     //  QueryBasicInfo
188     FatFastIoDispatch.FastIoQueryStandardInfo = FatFastQueryStdInfo;       //  QueryStandardInfo
189     FatFastIoDispatch.FastIoLock =              FatFastLock;               //  Lock
190     FatFastIoDispatch.FastIoUnlockSingle =      FatFastUnlockSingle;       //  UnlockSingle
191     FatFastIoDispatch.FastIoUnlockAll =         FatFastUnlockAll;          //  UnlockAll
192     FatFastIoDispatch.FastIoUnlockAllByKey =    FatFastUnlockAllByKey;     //  UnlockAllByKey
193     FatFastIoDispatch.FastIoQueryNetworkOpenInfo = FatFastQueryNetworkOpenInfo;
194     FatFastIoDispatch.AcquireForCcFlush =       FatAcquireForCcFlush;
195     FatFastIoDispatch.ReleaseForCcFlush =       FatReleaseForCcFlush;
196     FatFastIoDispatch.MdlRead =                 FsRtlMdlReadDev;
197     FatFastIoDispatch.MdlReadComplete =         FsRtlMdlReadCompleteDev;
198     FatFastIoDispatch.PrepareMdlWrite =         FsRtlPrepareMdlWriteDev;
199     FatFastIoDispatch.MdlWriteComplete =        FsRtlMdlWriteCompleteDev;
200 
201 #ifdef _MSC_VER
202 #pragma prefast( pop )
203 #endif
204 
205     //
206     //  Initialize the filter callbacks we use.
207     //
208 
209     RtlZeroMemory( &FilterCallbacks,
210                    sizeof(FS_FILTER_CALLBACKS) );
211 
212     FilterCallbacks.SizeOfFsFilterCallbacks = sizeof(FS_FILTER_CALLBACKS);
213     FilterCallbacks.PreAcquireForSectionSynchronization = FatFilterCallbackAcquireForCreateSection;
214 
215     Status = FsRtlRegisterFileSystemFilterCallbacks( DriverObject,
216                                                      &FilterCallbacks );
217 
218     if (!NT_SUCCESS( Status )) {
219 
220         IoDeleteDevice( FatDiskFileSystemDeviceObject );
221         IoDeleteDevice( FatCdromFileSystemDeviceObject );
222         return Status;
223     }
224 
225     //
226     //  Initialize the global data structures
227     //
228 
229     //
230     //  The FatData record
231     //
232 
233     RtlZeroMemory( &FatData, sizeof(FAT_DATA));
234 
235     FatData.NodeTypeCode = FAT_NTC_DATA_HEADER;
236     FatData.NodeByteSize = sizeof(FAT_DATA);
237 
238     InitializeListHead(&FatData.VcbQueue);
239 
240     FatData.DriverObject = DriverObject;
241     FatData.DiskFileSystemDeviceObject = FatDiskFileSystemDeviceObject;
242     FatData.CdromFileSystemDeviceObject = FatCdromFileSystemDeviceObject;
243 
244     //
245     //  This list head keeps track of closes yet to be done.
246     //
247 
248     InitializeListHead( &FatData.AsyncCloseList );
249     InitializeListHead( &FatData.DelayedCloseList );
250 
251     FatData.FatCloseItem = IoAllocateWorkItem( FatDiskFileSystemDeviceObject);
252 
253     if (FatData.FatCloseItem == NULL) {
254         IoDeleteDevice (FatDiskFileSystemDeviceObject);
255         IoDeleteDevice (FatCdromFileSystemDeviceObject);
256         return STATUS_INSUFFICIENT_RESOURCES;
257     }
258 
259     //
260     //  Allocate the zero page
261     //
262 
263     FatData.ZeroPage = ExAllocatePoolWithTag( NonPagedPoolNx, PAGE_SIZE, 'ZtaF' );
264     if (FatData.ZeroPage == NULL) {
265         IoDeleteDevice (FatDiskFileSystemDeviceObject);
266         IoDeleteDevice (FatCdromFileSystemDeviceObject);
267         return STATUS_INSUFFICIENT_RESOURCES;
268     }
269     RtlZeroMemory( FatData.ZeroPage, PAGE_SIZE );
270 
271 
272     //
273     //  Now initialize our general purpose spinlock (gag) and figure out how
274     //  deep and wide we want our delayed lists (along with fooling ourselves
275     //  about the lookaside depths).
276     //
277 
278     KeInitializeSpinLock( &FatData.GeneralSpinLock );
279 
280     switch ( MmQuerySystemSize() ) {
281 
282     case MmSmallSystem:
283 
284         MaxDepth = 4;
285         FatMaxDelayedCloseCount = FAT_MAX_DELAYED_CLOSES;
286         break;
287 
288     case MmMediumSystem:
289 
290         MaxDepth = 8;
291         FatMaxDelayedCloseCount = 4 * FAT_MAX_DELAYED_CLOSES;
292         break;
293 
294     case MmLargeSystem:
295     default:
296 
297         MaxDepth = 16;
298         FatMaxDelayedCloseCount = 16 * FAT_MAX_DELAYED_CLOSES;
299         break;
300     }
301 
302 
303     //
304     //  Initialize the cache manager callback routines
305     //
306 
307     FatData.CacheManagerCallbacks.AcquireForLazyWrite  = &FatAcquireFcbForLazyWrite;
308     FatData.CacheManagerCallbacks.ReleaseFromLazyWrite = &FatReleaseFcbFromLazyWrite;
309     FatData.CacheManagerCallbacks.AcquireForReadAhead  = &FatAcquireFcbForReadAhead;
310     FatData.CacheManagerCallbacks.ReleaseFromReadAhead = &FatReleaseFcbFromReadAhead;
311 
312     FatData.CacheManagerNoOpCallbacks.AcquireForLazyWrite  = &FatNoOpAcquire;
313     FatData.CacheManagerNoOpCallbacks.ReleaseFromLazyWrite = &FatNoOpRelease;
314     FatData.CacheManagerNoOpCallbacks.AcquireForReadAhead  = &FatNoOpAcquire;
315     FatData.CacheManagerNoOpCallbacks.ReleaseFromReadAhead = &FatNoOpRelease;
316 
317     //
318     //  Set up global pointer to our process.
319     //
320 
321     FatData.OurProcess = PsGetCurrentProcess();
322 
323     //
324     //  Setup the number of processors we support for statistics as the current number
325     //  running.
326     //
327 
328 #if (NTDDI_VERSION >= NTDDI_VISTA)
329     FatData.NumberProcessors = KeQueryActiveProcessorCount( NULL );
330 #else
331     FatData.NumberProcessors = KeNumberProcessors;
332 #endif
333 
334 
335     //
336     //  Read the registry to determine if we are in ChicagoMode.
337     //
338 
339     ValueName.Buffer = COMPATIBILITY_MODE_VALUE_NAME;
340     ValueName.Length = sizeof(COMPATIBILITY_MODE_VALUE_NAME) - sizeof(WCHAR);
341     ValueName.MaximumLength = sizeof(COMPATIBILITY_MODE_VALUE_NAME);
342 
343     Status = FatGetCompatibilityModeValue( &ValueName, &Value );
344 
345     if (NT_SUCCESS(Status) && FlagOn(Value, 1)) {
346 
347         FatData.ChicagoMode = FALSE;
348 
349     } else {
350 
351         FatData.ChicagoMode = TRUE;
352     }
353 
354     //
355     //  Read the registry to determine if we are going to generate LFNs
356     //  for valid 8.3 names with extended characters.
357     //
358 
359     ValueName.Buffer = CODE_PAGE_INVARIANCE_VALUE_NAME;
360     ValueName.Length = sizeof(CODE_PAGE_INVARIANCE_VALUE_NAME) - sizeof(WCHAR);
361     ValueName.MaximumLength = sizeof(CODE_PAGE_INVARIANCE_VALUE_NAME);
362 
363     Status = FatGetCompatibilityModeValue( &ValueName, &Value );
364 
365     if (NT_SUCCESS(Status) && FlagOn(Value, 1)) {
366 
367         FatData.CodePageInvariant = FALSE;
368 
369     } else {
370 
371         FatData.CodePageInvariant = TRUE;
372     }
373 
374     //
375     //  Initialize our global resource and fire up the lookaside lists.
376     //
377 
378     ExInitializeResourceLite( &FatData.Resource );
379 
380     ExInitializeNPagedLookasideList( &FatIrpContextLookasideList,
381                                      NULL,
382                                      NULL,
383                                      POOL_NX_ALLOCATION | POOL_RAISE_IF_ALLOCATION_FAILURE,
384                                      sizeof(IRP_CONTEXT),
385                                      TAG_IRP_CONTEXT,
386                                      MaxDepth );
387 
388     ExInitializeNPagedLookasideList( &FatNonPagedFcbLookasideList,
389                                      NULL,
390                                      NULL,
391                                      POOL_NX_ALLOCATION | POOL_RAISE_IF_ALLOCATION_FAILURE,
392                                      sizeof(NON_PAGED_FCB),
393                                      TAG_FCB_NONPAGED,
394                                      MaxDepth );
395 
396     ExInitializeNPagedLookasideList( &FatEResourceLookasideList,
397                                      NULL,
398                                      NULL,
399                                      POOL_NX_ALLOCATION | POOL_RAISE_IF_ALLOCATION_FAILURE,
400                                      sizeof(ERESOURCE),
401                                      TAG_ERESOURCE,
402                                      MaxDepth );
403 
404     ExInitializeSListHead( &FatCloseContextSList );
405     ExInitializeFastMutex( &FatCloseQueueMutex );
406     KeInitializeEvent( &FatReserveEvent, SynchronizationEvent, TRUE );
407 
408     //
409     //  Register the file system with the I/O system
410     //
411 
412     IoRegisterFileSystem(FatDiskFileSystemDeviceObject);
413     ObReferenceObject (FatDiskFileSystemDeviceObject);
414     IoRegisterFileSystem(FatCdromFileSystemDeviceObject);
415     ObReferenceObject (FatCdromFileSystemDeviceObject);
416 
417     //
418     //  Find out if we are running an a FujitsuFMR machine.
419     //
420 
421     FatData.FujitsuFMR = FatIsFujitsuFMR();
422 
423 #if (NTDDI_VERSION >= NTDDI_WIN8)
424 
425     //
426     //  Find out global disk accounting state, cache the result
427     //
428 
429     FatDiskAccountingEnabled = PsIsDiskCountersEnabled();
430 
431 #endif
432 
433     //
434     //  And return to our caller
435     //
436 
437     return( STATUS_SUCCESS );
438 }
439 
440 
_Function_class_(DRIVER_UNLOAD)441 _Function_class_(DRIVER_UNLOAD)
442 VOID
443 NTAPI
444 FatUnload(
445     _In_ _Unreferenced_parameter_ PDRIVER_OBJECT DriverObject
446     )
447 
448 /*++
449 
450 Routine Description:
451 
452     This is the unload routine for the filesystem
453 
454 Arguments:
455 
456     DriverObject - Pointer to driver object created by the system.
457 
458 Return Value:
459 
460     None
461 
462 --*/
463 
464 {
465     UNREFERENCED_PARAMETER( DriverObject );
466 
467 
468     ExDeleteNPagedLookasideList (&FatEResourceLookasideList);
469     ExDeleteNPagedLookasideList (&FatNonPagedFcbLookasideList);
470     ExDeleteNPagedLookasideList (&FatIrpContextLookasideList);
471     ExDeleteResourceLite( &FatData.Resource );
472     IoFreeWorkItem (FatData.FatCloseItem);
473     ObDereferenceObject( FatDiskFileSystemDeviceObject);
474     ObDereferenceObject( FatCdromFileSystemDeviceObject);
475 }
476 
477 
478 //
479 //  Local Support routine
480 //
481 
482 NTSTATUS
FatGetCompatibilityModeValue(IN PUNICODE_STRING ValueName,IN OUT PULONG Value)483 FatGetCompatibilityModeValue (
484     IN PUNICODE_STRING ValueName,
485     IN OUT PULONG Value
486     )
487 
488 /*++
489 
490 Routine Description:
491 
492     Given a unicode value name this routine will go into the registry
493     location for the Chicago compatibilitymode information and get the
494     value.
495 
496 Arguments:
497 
498     ValueName - the unicode name for the registry value located in the registry.
499     Value   - a pointer to the ULONG for the result.
500 
501 Return Value:
502 
503     NTSTATUS
504 
505     If STATUS_SUCCESSFUL is returned, the location *Value will be
506     updated with the DWORD value from the registry.  If any failing
507     status is returned, this value is untouched.
508 
509 --*/
510 
511 {
512     HANDLE Handle;
513     NTSTATUS Status;
514     ULONG RequestLength;
515     ULONG ResultLength;
516     UCHAR Buffer[KEY_WORK_AREA];
517     UNICODE_STRING KeyName;
518     OBJECT_ATTRIBUTES ObjectAttributes;
519     PKEY_VALUE_FULL_INFORMATION KeyValueInformation;
520 
521     KeyName.Buffer = COMPATIBILITY_MODE_KEY_NAME;
522     KeyName.Length = sizeof(COMPATIBILITY_MODE_KEY_NAME) - sizeof(WCHAR);
523     KeyName.MaximumLength = sizeof(COMPATIBILITY_MODE_KEY_NAME);
524 
525     InitializeObjectAttributes(&ObjectAttributes,
526                                &KeyName,
527                                OBJ_CASE_INSENSITIVE,
528                                NULL,
529                                NULL);
530 
531     Status = ZwOpenKey(&Handle,
532                        KEY_READ,
533                        &ObjectAttributes);
534 
535     if (!NT_SUCCESS(Status)) {
536 
537         return Status;
538     }
539 
540     RequestLength = KEY_WORK_AREA;
541 
542     KeyValueInformation = (PKEY_VALUE_FULL_INFORMATION)Buffer;
543 
544     while (1) {
545 
546         Status = ZwQueryValueKey(Handle,
547                                  ValueName,
548                                  KeyValueFullInformation,
549                                  KeyValueInformation,
550                                  RequestLength,
551                                  &ResultLength);
552 
553         NT_ASSERT( Status != STATUS_BUFFER_OVERFLOW );
554 
555         if (Status == STATUS_BUFFER_OVERFLOW) {
556 
557             //
558             // Try to get a buffer big enough.
559             //
560 
561             if (KeyValueInformation != (PKEY_VALUE_FULL_INFORMATION)Buffer) {
562 
563                 ExFreePool(KeyValueInformation);
564             }
565 
566             RequestLength += 256;
567 
568             KeyValueInformation = (PKEY_VALUE_FULL_INFORMATION)
569                                   ExAllocatePoolWithTag(PagedPool,
570                                                         RequestLength,
571                                                         ' taF');
572 
573             if (!KeyValueInformation) {
574 
575                 ZwClose(Handle);
576                 return STATUS_NO_MEMORY;
577             }
578 
579         } else {
580 
581             break;
582         }
583     }
584 
585     ZwClose(Handle);
586 
587     if (NT_SUCCESS(Status)) {
588 
589         if (KeyValueInformation->DataLength != 0) {
590 
591             PULONG DataPtr;
592 
593             //
594             // Return contents to the caller.
595             //
596 
597             DataPtr = (PULONG)
598               ((PUCHAR)KeyValueInformation + KeyValueInformation->DataOffset);
599             *Value = *DataPtr;
600 
601         } else {
602 
603             //
604             // Treat as if no value was found
605             //
606 
607             Status = STATUS_OBJECT_NAME_NOT_FOUND;
608         }
609     }
610 
611     if (KeyValueInformation != (PKEY_VALUE_FULL_INFORMATION)Buffer) {
612 
613         ExFreePool(KeyValueInformation);
614     }
615 
616     return Status;
617 }
618 
619 //
620 //  Local Support routine
621 //
622 
623 BOOLEAN
FatIsFujitsuFMR()624 FatIsFujitsuFMR (
625     )
626 
627 /*++
628 
629 Routine Description:
630 
631     This routine tells us if we are running on a FujitsuFMR machine.
632 
633 Arguments:
634 
635 
636 Return Value:
637 
638     BOOLEAN - TRUE if we are and FALSE otherwise
639 
640 --*/
641 
642 {
643     BOOLEAN Result;
644     HANDLE Handle;
645     NTSTATUS Status;
646     ULONG RequestLength;
647     ULONG ResultLength;
648     UCHAR Buffer[KEY_WORK_AREA];
649     UNICODE_STRING KeyName;
650     UNICODE_STRING ValueName;
651     OBJECT_ATTRIBUTES ObjectAttributes;
652     PKEY_VALUE_FULL_INFORMATION KeyValueInformation;
653 
654     //
655     // Set default as PC/AT
656     //
657 
658     KeyName.Buffer = REGISTRY_HARDWARE_DESCRIPTION_W;
659     KeyName.Length = sizeof(REGISTRY_HARDWARE_DESCRIPTION_W) - sizeof(WCHAR);
660     KeyName.MaximumLength = sizeof(REGISTRY_HARDWARE_DESCRIPTION_W);
661 
662     InitializeObjectAttributes(&ObjectAttributes,
663                                &KeyName,
664                                OBJ_CASE_INSENSITIVE,
665                                NULL,
666                                NULL);
667 
668     Status = ZwOpenKey(&Handle,
669                        KEY_READ,
670                        &ObjectAttributes);
671 
672     if (!NT_SUCCESS(Status)) {
673 
674         return FALSE;
675     }
676 
677     ValueName.Buffer = REGISTRY_MACHINE_IDENTIFIER_W;
678     ValueName.Length = sizeof(REGISTRY_MACHINE_IDENTIFIER_W) - sizeof(WCHAR);
679     ValueName.MaximumLength = sizeof(REGISTRY_MACHINE_IDENTIFIER_W);
680 
681     RequestLength = KEY_WORK_AREA;
682 
683     KeyValueInformation = (PKEY_VALUE_FULL_INFORMATION)Buffer;
684 
685     while (1) {
686 
687         Status = ZwQueryValueKey(Handle,
688                                  &ValueName,
689                                  KeyValueFullInformation,
690                                  KeyValueInformation,
691                                  RequestLength,
692                                  &ResultLength);
693 
694         // NT_ASSERT( Status != STATUS_BUFFER_OVERFLOW );
695 
696         if (Status == STATUS_BUFFER_OVERFLOW) {
697 
698             //
699             // Try to get a buffer big enough.
700             //
701 
702             if (KeyValueInformation != (PKEY_VALUE_FULL_INFORMATION)Buffer) {
703 
704                 ExFreePool(KeyValueInformation);
705             }
706 
707             RequestLength += 256;
708 
709             KeyValueInformation = (PKEY_VALUE_FULL_INFORMATION)
710                                   ExAllocatePoolWithTag(PagedPool, RequestLength, ' taF');
711 
712             if (!KeyValueInformation) {
713 
714                 ZwClose(Handle);
715                 return FALSE;
716             }
717 
718         } else {
719 
720             break;
721         }
722     }
723 
724     ZwClose(Handle);
725 
726     if (NT_SUCCESS(Status) &&
727         (KeyValueInformation->DataLength >= sizeof(FUJITSU_FMR_NAME_W)) &&
728         (RtlCompareMemory((PUCHAR)KeyValueInformation + KeyValueInformation->DataOffset,
729                           FUJITSU_FMR_NAME_W,
730                           sizeof(FUJITSU_FMR_NAME_W) - sizeof(WCHAR)) ==
731          sizeof(FUJITSU_FMR_NAME_W) - sizeof(WCHAR))) {
732 
733         Result = TRUE;
734 
735     } else {
736 
737         Result = FALSE;
738     }
739 
740     if (KeyValueInformation != (PKEY_VALUE_FULL_INFORMATION)Buffer) {
741 
742         ExFreePool(KeyValueInformation);
743     }
744 
745     return Result;
746 }
747 
748