text: /*++
  
  Copyright (c) 1989-2000 Microsoft Corporation
  
  Module Name:
  
      FatInit.c
  
  Abstract:
  
      This module implements the DRIVER_INITIALIZATION routine for Fat
  
  
  --*/
  
  #include "FatProcs.h"
  
  DRIVER_INITIALIZE DriverEntry;
  
  NTSTATUS
  DriverEntry(
      _In_ PDRIVER_OBJECT DriverObject,
      _In_ PUNICODE_STRING RegistryPath
      );
  
  _Function_class_(DRIVER_UNLOAD)
  VOID
  FatUnload(
      _In_ _Unreferenced_parameter_ PDRIVER_OBJECT DriverObject
      );
  
  NTSTATUS
  FatGetCompatibilityModeValue(
      IN PUNICODE_STRING ValueName,
      IN OUT PULONG Value
      );
  
  BOOLEAN
  FatIsFujitsuFMR (
      );
  
  #ifdef ALLOC_PRAGMA
  #pragma alloc_text(INIT, DriverEntry)
  #pragma alloc_text(INIT, FatGetCompatibilityModeValue)
  #pragma alloc_text(INIT, FatIsFujitsuFMR)
  //#pragma alloc_text(PAGE, FatUnload)
  #endif
  
  #define COMPATIBILITY_MODE_KEY_NAME L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\FileSystem"
  #define COMPATIBILITY_MODE_VALUE_NAME L"Win31FileSystem"
  #define CODE_PAGE_INVARIANCE_VALUE_NAME L"FatDisableCodePageInvariance"
  
  
  #define KEY_WORK_AREA ((sizeof(KEY_VALUE_FULL_INFORMATION) + \
                          sizeof(ULONG)) + 64)
  
  #define REGISTRY_HARDWARE_DESCRIPTION_W \
          L"\\Registry\\Machine\\Hardware\\DESCRIPTION\\System"
  
  #define REGISTRY_MACHINE_IDENTIFIER_W   L"Identifier"
  
  #define FUJITSU_FMR_NAME_W  L"FUJITSU FMR-"
  
  
  
  NTSTATUS
  DriverEntry(
      _In_ PDRIVER_OBJECT DriverObject,
      _In_ PUNICODE_STRING RegistryPath
      )
  
  /*++
  
  Routine Description:
  
      This is the initialization routine for the Fat file system
      device driver.  This routine creates the device object for the FileSystem
      device and performs all other driver initialization.
  
  Arguments:
  
      DriverObject - Pointer to driver object created by the system.
  
  Return Value:
  
      NTSTATUS - The function value is the final status from the initialization
          operation.
  
  --*/
  
  {
      USHORT MaxDepth;
      NTSTATUS Status;
      UNICODE_STRING UnicodeString;
      FS_FILTER_CALLBACKS FilterCallbacks;
      UNICODE_STRING ValueName;
      ULONG Value;
  
      UNREFERENCED_PARAMETER( RegistryPath );
  
      //
      // Create the device object for disks.  To avoid problems with filters who
      // know this name, we must keep it.
      //
  
      RtlInitUnicodeString( &UnicodeString, L"\\Fat" );
      Status = IoCreateDevice( DriverObject,
                               0,
                               &UnicodeString,
                               FILE_DEVICE_DISK_FILE_SYSTEM,
                               0,
                               FALSE,
                               &FatDiskFileSystemDeviceObject );
  
      if (!NT_SUCCESS( Status )) {
          return Status;
      }
  
      //
      // Create the device object for "cdroms".
      //
  
      RtlInitUnicodeString( &UnicodeString, L"\\FatCdrom" );
      Status = IoCreateDevice( DriverObject,
                               0,
                               &UnicodeString,
                               FILE_DEVICE_CD_ROM_FILE_SYSTEM,
                               0,
                               FALSE,
                               &FatCdromFileSystemDeviceObject );
  
      if (!NT_SUCCESS( Status )) {
          IoDeleteDevice( FatDiskFileSystemDeviceObject);
          return Status;
      }
  
  #pragma prefast( push )
  #pragma prefast( disable:28155, "these are all correct" )
  #pragma prefast( disable:28169, "these are all correct" )
  #pragma prefast( disable:28175, "this is a filesystem, touching FastIoDispatch is allowed" )
  
      DriverObject->DriverUnload = FatUnload;
  
      //
      //  Note that because of the way data caching is done, we set neither
      //  the Direct I/O or Buffered I/O bit in DeviceObject->Flags.  If
      //  data is not in the cache, or the request is not buffered, we may,
      //  set up for Direct I/O by hand.
      //
  
      //
      // Initialize the driver object with this driver's entry points.
      //
  
      DriverObject->MajorFunction[IRP_MJ_CREATE]                   = (PDRIVER_DISPATCH)FatFsdCreate;
      DriverObject->MajorFunction[IRP_MJ_CLOSE]                    = (PDRIVER_DISPATCH)FatFsdClose;
      DriverObject->MajorFunction[IRP_MJ_READ]                     = (PDRIVER_DISPATCH)FatFsdRead;
      DriverObject->MajorFunction[IRP_MJ_WRITE]                    = (PDRIVER_DISPATCH)FatFsdWrite;
      DriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION]        = (PDRIVER_DISPATCH)FatFsdQueryInformation;
      DriverObject->MajorFunction[IRP_MJ_SET_INFORMATION]          = (PDRIVER_DISPATCH)FatFsdSetInformation;
      DriverObject->MajorFunction[IRP_MJ_QUERY_EA]                 = (PDRIVER_DISPATCH)FatFsdQueryEa;
      DriverObject->MajorFunction[IRP_MJ_SET_EA]                   = (PDRIVER_DISPATCH)FatFsdSetEa;
      DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS]            = (PDRIVER_DISPATCH)FatFsdFlushBuffers;
      DriverObject->MajorFunction[IRP_MJ_QUERY_VOLUME_INFORMATION] = (PDRIVER_DISPATCH)FatFsdQueryVolumeInformation;
      DriverObject->MajorFunction[IRP_MJ_SET_VOLUME_INFORMATION]   = (PDRIVER_DISPATCH)FatFsdSetVolumeInformation;
      DriverObject->MajorFunction[IRP_MJ_CLEANUP]                  = (PDRIVER_DISPATCH)FatFsdCleanup;
      DriverObject->MajorFunction[IRP_MJ_DIRECTORY_CONTROL]        = (PDRIVER_DISPATCH)FatFsdDirectoryControl;
      DriverObject->MajorFunction[IRP_MJ_FILE_SYSTEM_CONTROL]      = (PDRIVER_DISPATCH)FatFsdFileSystemControl;
      DriverObject->MajorFunction[IRP_MJ_LOCK_CONTROL]             = (PDRIVER_DISPATCH)FatFsdLockControl;
      DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL]           = (PDRIVER_DISPATCH)FatFsdDeviceControl;
      DriverObject->MajorFunction[IRP_MJ_SHUTDOWN]                 = (PDRIVER_DISPATCH)FatFsdShutdown;
      DriverObject->MajorFunction[IRP_MJ_PNP]                      = (PDRIVER_DISPATCH)FatFsdPnp;
  
      DriverObject->FastIoDispatch = &FatFastIoDispatch;
  
      RtlZeroMemory(&FatFastIoDispatch, sizeof(FatFastIoDispatch));
  
      FatFastIoDispatch.SizeOfFastIoDispatch =    sizeof(FAST_IO_DISPATCH);
      FatFastIoDispatch.FastIoCheckIfPossible =   FatFastIoCheckIfPossible;  //  CheckForFastIo
      FatFastIoDispatch.FastIoRead =              FsRtlCopyRead;             //  Read
      FatFastIoDispatch.FastIoWrite =             FsRtlCopyWrite;            //  Write
      FatFastIoDispatch.FastIoQueryBasicInfo =    FatFastQueryBasicInfo;     //  QueryBasicInfo
      FatFastIoDispatch.FastIoQueryStandardInfo = FatFastQueryStdInfo;       //  QueryStandardInfo
      FatFastIoDispatch.FastIoLock =              FatFastLock;               //  Lock
      FatFastIoDispatch.FastIoUnlockSingle =      FatFastUnlockSingle;       //  UnlockSingle
      FatFastIoDispatch.FastIoUnlockAll =         FatFastUnlockAll;          //  UnlockAll
      FatFastIoDispatch.FastIoUnlockAllByKey =    FatFastUnlockAllByKey;     //  UnlockAllByKey
      FatFastIoDispatch.FastIoQueryNetworkOpenInfo = FatFastQueryNetworkOpenInfo;
      FatFastIoDispatch.AcquireForCcFlush =       FatAcquireForCcFlush;
      FatFastIoDispatch.ReleaseForCcFlush =       FatReleaseForCcFlush;
      FatFastIoDispatch.MdlRead =                 FsRtlMdlReadDev;
      FatFastIoDispatch.MdlReadComplete =         FsRtlMdlReadCompleteDev;
      FatFastIoDispatch.PrepareMdlWrite =         FsRtlPrepareMdlWriteDev;
      FatFastIoDispatch.MdlWriteComplete =        FsRtlMdlWriteCompleteDev;
  
  #pragma prefast( pop )
      
      //
      //  Initialize the filter callbacks we use.
      //
  
      RtlZeroMemory( &FilterCallbacks,
                     sizeof(FS_FILTER_CALLBACKS) );
  
      FilterCallbacks.SizeOfFsFilterCallbacks = sizeof(FS_FILTER_CALLBACKS);
      FilterCallbacks.PreAcquireForSectionSynchronization = FatFilterCallbackAcquireForCreateSection;
  
      Status = FsRtlRegisterFileSystemFilterCallbacks( DriverObject,
                                                       &FilterCallbacks );
  
      if (!NT_SUCCESS( Status )) {
  
          IoDeleteDevice( FatDiskFileSystemDeviceObject );
          IoDeleteDevice( FatCdromFileSystemDeviceObject );
          return Status;
      }
  
      //
      //  Initialize the global data structures
      //
  
      //
      //  The FatData record
      //
  
      RtlZeroMemory( &FatData, sizeof(FAT_DATA));
  
      FatData.NodeTypeCode = FAT_NTC_DATA_HEADER;
      FatData.NodeByteSize = sizeof(FAT_DATA);
  
      InitializeListHead(&FatData.VcbQueue);
  
      FatData.DriverObject = DriverObject;
      FatData.DiskFileSystemDeviceObject = FatDiskFileSystemDeviceObject;
      FatData.CdromFileSystemDeviceObject = FatCdromFileSystemDeviceObject;
  
      //
      //  This list head keeps track of closes yet to be done.
      //
  
      InitializeListHead( &FatData.AsyncCloseList );
      InitializeListHead( &FatData.DelayedCloseList );
      
      FatData.FatCloseItem = IoAllocateWorkItem( FatDiskFileSystemDeviceObject);
  
      if (FatData.FatCloseItem == NULL) {
          IoDeleteDevice (FatDiskFileSystemDeviceObject);
          IoDeleteDevice (FatCdromFileSystemDeviceObject);
          return STATUS_INSUFFICIENT_RESOURCES;
      }
  
      //
      //  Allocate the zero page
      //
  
      FatData.ZeroPage = ExAllocatePoolWithTag( NonPagedPoolNx, PAGE_SIZE, 'ZtaF' );
      if (FatData.ZeroPage == NULL) {
          IoDeleteDevice (FatDiskFileSystemDeviceObject);
          IoDeleteDevice (FatCdromFileSystemDeviceObject);        
          return STATUS_INSUFFICIENT_RESOURCES;
      }
      RtlZeroMemory( FatData.ZeroPage, PAGE_SIZE );
  
  
      //
      //  Now initialize our general purpose spinlock (gag) and figure out how
      //  deep and wide we want our delayed lists (along with fooling ourselves
      //  about the lookaside depths).
      //
  
      KeInitializeSpinLock( &FatData.GeneralSpinLock );
  
      switch ( MmQuerySystemSize() ) {
  
      case MmSmallSystem:
  
          MaxDepth = 4;
          FatMaxDelayedCloseCount = FAT_MAX_DELAYED_CLOSES;
          break;
  
      case MmMediumSystem:
  
          MaxDepth = 8;
          FatMaxDelayedCloseCount = 4 * FAT_MAX_DELAYED_CLOSES;
          break;
  
      case MmLargeSystem:
      default:
          
          MaxDepth = 16;
          FatMaxDelayedCloseCount = 16 * FAT_MAX_DELAYED_CLOSES;
          break;
      }
  
  
      //
      //  Initialize the cache manager callback routines
      //
  
      FatData.CacheManagerCallbacks.AcquireForLazyWrite  = &FatAcquireFcbForLazyWrite;
      FatData.CacheManagerCallbacks.ReleaseFromLazyWrite = &FatReleaseFcbFromLazyWrite;
      FatData.CacheManagerCallbacks.AcquireForReadAhead  = &FatAcquireFcbForReadAhead;
      FatData.CacheManagerCallbacks.ReleaseFromReadAhead = &FatReleaseFcbFromReadAhead;
  
      FatData.CacheManagerNoOpCallbacks.AcquireForLazyWrite  = &FatNoOpAcquire;
      FatData.CacheManagerNoOpCallbacks.ReleaseFromLazyWrite = &FatNoOpRelease;
      FatData.CacheManagerNoOpCallbacks.AcquireForReadAhead  = &FatNoOpAcquire;
      FatData.CacheManagerNoOpCallbacks.ReleaseFromReadAhead = &FatNoOpRelease;
  
      //
      //  Set up global pointer to our process.
      //
  
      FatData.OurProcess = PsGetCurrentProcess();
  
      // 
      //  Setup the number of processors we support for statistics as the current number 
      //  running.
      //
  
  #if (NTDDI_VERSION >= NTDDI_VISTA)
      FatData.NumberProcessors = KeQueryActiveProcessorCount( NULL );
  #else
      FatData.NumberProcessors = KeNumberProcessors;
  #endif
  
  
      //
      //  Read the registry to determine if we are in ChicagoMode.
      //
  
      ValueName.Buffer = COMPATIBILITY_MODE_VALUE_NAME;
      ValueName.Length = sizeof(COMPATIBILITY_MODE_VALUE_NAME) - sizeof(WCHAR);
      ValueName.MaximumLength = sizeof(COMPATIBILITY_MODE_VALUE_NAME);
  
      Status = FatGetCompatibilityModeValue( &ValueName, &Value );
  
      if (NT_SUCCESS(Status) && FlagOn(Value, 1)) {
  
          FatData.ChicagoMode = FALSE;
  
      } else {
  
          FatData.ChicagoMode = TRUE;
      }
  
      //
      //  Read the registry to determine if we are going to generate LFNs
      //  for valid 8.3 names with extended characters.
      //
  
      ValueName.Buffer = CODE_PAGE_INVARIANCE_VALUE_NAME;
      ValueName.Length = sizeof(CODE_PAGE_INVARIANCE_VALUE_NAME) - sizeof(WCHAR);
      ValueName.MaximumLength = sizeof(CODE_PAGE_INVARIANCE_VALUE_NAME);
  
      Status = FatGetCompatibilityModeValue( &ValueName, &Value );
  
      if (NT_SUCCESS(Status) && FlagOn(Value, 1)) {
  
          FatData.CodePageInvariant = FALSE;
  
      } else {
  
          FatData.CodePageInvariant = TRUE;
      }
  
      //
      //  Initialize our global resource and fire up the lookaside lists.
      //
  
      ExInitializeResourceLite( &FatData.Resource );
  
      ExInitializeNPagedLookasideList( &FatIrpContextLookasideList,
                                       NULL,
                                       NULL,
                                       POOL_NX_ALLOCATION | POOL_RAISE_IF_ALLOCATION_FAILURE,
                                       sizeof(IRP_CONTEXT),
                                       TAG_IRP_CONTEXT,
                                       MaxDepth );
  
      ExInitializeNPagedLookasideList( &FatNonPagedFcbLookasideList,
                                       NULL,
                                       NULL,
                                       POOL_NX_ALLOCATION | POOL_RAISE_IF_ALLOCATION_FAILURE,
                                       sizeof(NON_PAGED_FCB),
                                       TAG_FCB_NONPAGED,
                                       MaxDepth );
  
      ExInitializeNPagedLookasideList( &FatEResourceLookasideList,
                                       NULL,
                                       NULL,
                                       POOL_NX_ALLOCATION | POOL_RAISE_IF_ALLOCATION_FAILURE,
                                       sizeof(ERESOURCE),
                                       TAG_ERESOURCE,
                                       MaxDepth );
  
      ExInitializeSListHead( &FatCloseContextSList );
      ExInitializeFastMutex( &FatCloseQueueMutex );
      KeInitializeEvent( &FatReserveEvent, SynchronizationEvent, TRUE );
  
      //
      //  Register the file system with the I/O system
      //
  
      IoRegisterFileSystem(FatDiskFileSystemDeviceObject);
      ObReferenceObject (FatDiskFileSystemDeviceObject);
      IoRegisterFileSystem(FatCdromFileSystemDeviceObject);
      ObReferenceObject (FatCdromFileSystemDeviceObject);
  
      //
      //  Find out if we are running an a FujitsuFMR machine.
      //
  
      FatData.FujitsuFMR = FatIsFujitsuFMR();
  
  #if (NTDDI_VERSION >= NTDDI_WIN8)
  
      //
      //  Find out global disk accounting state, cache the result
      //
  
      FatDiskAccountingEnabled = PsIsDiskCountersEnabled();
  
  #endif
  
      //
      //  And return to our caller
      //
  
      return( STATUS_SUCCESS );
  }
  
  
  _Function_class_(DRIVER_UNLOAD)
  VOID
  FatUnload(
      _In_ _Unreferenced_parameter_ PDRIVER_OBJECT DriverObject
      )
  
  /*++
  
  Routine Description:
  
      This is the unload routine for the filesystem
  
  Arguments:
  
      DriverObject - Pointer to driver object created by the system.
  
  Return Value:
  
      None
  
  --*/
  
  {
      UNREFERENCED_PARAMETER( DriverObject );
  
  
      ExDeleteNPagedLookasideList (&FatEResourceLookasideList);
      ExDeleteNPagedLookasideList (&FatNonPagedFcbLookasideList);
      ExDeleteNPagedLookasideList (&FatIrpContextLookasideList);
      ExDeleteResourceLite( &FatData.Resource );
      IoFreeWorkItem (FatData.FatCloseItem);
      ObDereferenceObject( FatDiskFileSystemDeviceObject);
      ObDereferenceObject( FatCdromFileSystemDeviceObject);
  }
  
  
  //
  //  Local Support routine
  //
  
  NTSTATUS
  FatGetCompatibilityModeValue (
      IN PUNICODE_STRING ValueName,
      IN OUT PULONG Value
      )
  
  /*++
  
  Routine Description:
  
      Given a unicode value name this routine will go into the registry
      location for the Chicago compatibilitymode information and get the
      value.
  
  Arguments:
  
      ValueName - the unicode name for the registry value located in the registry.
      Value   - a pointer to the ULONG for the result.
  
  Return Value:
  
      NTSTATUS
  
      If STATUS_SUCCESSFUL is returned, the location *Value will be
      updated with the DWORD value from the registry.  If any failing
      status is returned, this value is untouched.
  
  --*/
  
  {
      HANDLE Handle;
      NTSTATUS Status;
      ULONG RequestLength;
      ULONG ResultLength;
      UCHAR Buffer[KEY_WORK_AREA];
      UNICODE_STRING KeyName;
      OBJECT_ATTRIBUTES ObjectAttributes;
      PKEY_VALUE_FULL_INFORMATION KeyValueInformation;
  
      KeyName.Buffer = COMPATIBILITY_MODE_KEY_NAME;
      KeyName.Length = sizeof(COMPATIBILITY_MODE_KEY_NAME) - sizeof(WCHAR);
      KeyName.MaximumLength = sizeof(COMPATIBILITY_MODE_KEY_NAME);
  
      InitializeObjectAttributes(&ObjectAttributes,
                                 &KeyName,
                                 OBJ_CASE_INSENSITIVE,
                                 NULL,
                                 NULL);
  
      Status = ZwOpenKey(&Handle,
                         KEY_READ,
                         &ObjectAttributes);
  
      if (!NT_SUCCESS(Status)) {
  
          return Status;
      }
  
      RequestLength = KEY_WORK_AREA;
  
      KeyValueInformation = (PKEY_VALUE_FULL_INFORMATION)Buffer;
  
      while (1) {
  
          Status = ZwQueryValueKey(Handle,
                                   ValueName,
                                   KeyValueFullInformation,
                                   KeyValueInformation,
                                   RequestLength,
                                   &ResultLength);
  
          NT_ASSERT( Status != STATUS_BUFFER_OVERFLOW );
  
          if (Status == STATUS_BUFFER_OVERFLOW) {
  
              //
              // Try to get a buffer big enough.
              //
  
              if (KeyValueInformation != (PKEY_VALUE_FULL_INFORMATION)Buffer) {
  
                  ExFreePool(KeyValueInformation);
              }
  
              RequestLength += 256;
  
              KeyValueInformation = (PKEY_VALUE_FULL_INFORMATION)
                                    ExAllocatePoolWithTag(PagedPool,
                                                          RequestLength,
                                                          ' taF');
  
              if (!KeyValueInformation) {
  
                  ZwClose(Handle);
                  return STATUS_NO_MEMORY;
              }
  
          } else {
  
              break;
          }
      }
  
      ZwClose(Handle);
  
      if (NT_SUCCESS(Status)) {
  
          if (KeyValueInformation->DataLength != 0) {
  
              PULONG DataPtr;
  
              //
              // Return contents to the caller.
              //
  
              DataPtr = (PULONG)
                ((PUCHAR)KeyValueInformation + KeyValueInformation->DataOffset);
              *Value = *DataPtr;
  
          } else {
  
              //
              // Treat as if no value was found
              //
  
              Status = STATUS_OBJECT_NAME_NOT_FOUND;
          }
      }
  
      if (KeyValueInformation != (PKEY_VALUE_FULL_INFORMATION)Buffer) {
  
          ExFreePool(KeyValueInformation);
      }
  
      return Status;
  }
  
  //
  //  Local Support routine
  //
  
  BOOLEAN
  FatIsFujitsuFMR (
      )
  
  /*++
  
  Routine Description:
  
      This routine tells us if we are running on a FujitsuFMR machine.
  
  Arguments:
  
  
  Return Value:
  
      BOOLEAN - TRUE if we are and FALSE otherwise
  
  --*/
  
  {
      BOOLEAN Result;
      HANDLE Handle;
      NTSTATUS Status;
      ULONG RequestLength;
      ULONG ResultLength;
      UCHAR Buffer[KEY_WORK_AREA];
      UNICODE_STRING KeyName;
      UNICODE_STRING ValueName;
      OBJECT_ATTRIBUTES ObjectAttributes;
      PKEY_VALUE_FULL_INFORMATION KeyValueInformation;
  
      //
      // Set default as PC/AT
      //
  
      KeyName.Buffer = REGISTRY_HARDWARE_DESCRIPTION_W;
      KeyName.Length = sizeof(REGISTRY_HARDWARE_DESCRIPTION_W) - sizeof(WCHAR);
      KeyName.MaximumLength = sizeof(REGISTRY_HARDWARE_DESCRIPTION_W);
  
      InitializeObjectAttributes(&ObjectAttributes,
                                 &KeyName,
                                 OBJ_CASE_INSENSITIVE,
                                 NULL,
                                 NULL);
  
      Status = ZwOpenKey(&Handle,
                         KEY_READ,
                         &ObjectAttributes);
  
      if (!NT_SUCCESS(Status)) {
  
          return FALSE;
      }
  
      ValueName.Buffer = REGISTRY_MACHINE_IDENTIFIER_W;
      ValueName.Length = sizeof(REGISTRY_MACHINE_IDENTIFIER_W) - sizeof(WCHAR);
      ValueName.MaximumLength = sizeof(REGISTRY_MACHINE_IDENTIFIER_W);
  
      RequestLength = KEY_WORK_AREA;
  
      KeyValueInformation = (PKEY_VALUE_FULL_INFORMATION)Buffer;
  
      while (1) {
  
          Status = ZwQueryValueKey(Handle,
                                   &ValueName,
                                   KeyValueFullInformation,
                                   KeyValueInformation,
                                   RequestLength,
                                   &ResultLength);
  
          // NT_ASSERT( Status != STATUS_BUFFER_OVERFLOW );
  
          if (Status == STATUS_BUFFER_OVERFLOW) {
  
              //
              // Try to get a buffer big enough.
              //
  
              if (KeyValueInformation != (PKEY_VALUE_FULL_INFORMATION)Buffer) {
  
                  ExFreePool(KeyValueInformation);
              }
  
              RequestLength += 256;
  
              KeyValueInformation = (PKEY_VALUE_FULL_INFORMATION)
                                    ExAllocatePoolWithTag(PagedPool, RequestLength, ' taF');
  
              if (!KeyValueInformation) {
  
                  ZwClose(Handle);
                  return FALSE;
              }
  
          } else {
  
              break;
          }
      }
  
      ZwClose(Handle);
  
      if (NT_SUCCESS(Status) &&
          (KeyValueInformation->DataLength >= sizeof(FUJITSU_FMR_NAME_W)) &&
          (RtlCompareMemory((PUCHAR)KeyValueInformation + KeyValueInformation->DataOffset,
                            FUJITSU_FMR_NAME_W,
                            sizeof(FUJITSU_FMR_NAME_W) - sizeof(WCHAR)) ==
           sizeof(FUJITSU_FMR_NAME_W) - sizeof(WCHAR))) {
  
          Result = TRUE;
  
      } else {
  
          Result = FALSE;
      }
  
      if (KeyValueInformation != (PKEY_VALUE_FULL_INFORMATION)Buffer) {
  
          ExFreePool(KeyValueInformation);
      }
  
      return Result;
  }
  
  