text: /*
   * Copyright (c) 2015 Egor Tensin <Egor.Tensin@gmail.com>
   * This file is part of the "Windows 7 drivers" project.
   * For details, see https://github.com/egor-tensin/windows7-drivers.
   * Distributed under the MIT License.
   */
  
  #include <ntifs.h>
  
  #include "nt2dos.h"
  
  static NTSTATUS get_object_name_info(
      void *object,
      OBJECT_NAME_INFORMATION **object_name_info)
  {
      unsigned long nbneeded;
      NTSTATUS status = STATUS_SUCCESS;
  
      status = ObQueryNameString(object, NULL, 0, &nbneeded);
  
      if (status != STATUS_INFO_LENGTH_MISMATCH)
          return status;
  
      *object_name_info = ExAllocatePoolWithTag(PagedPool, nbneeded, '1l');
  
      if (*object_name_info == NULL)
          return STATUS_INSUFFICIENT_RESOURCES;
  
      status = ObQueryNameString(object, *object_name_info, nbneeded, &nbneeded);
  
      if (!NT_SUCCESS(status))
          goto free_object_name_info;
  
      return status;
  
  free_object_name_info:
      ExFreePool(*object_name_info);
  
      return status;
  }
  
  NTSTATUS nt2dos(UNICODE_STRING *u_resolved, UNICODE_STRING *u_unresolved)
  {
      IO_STATUS_BLOCK io_status_block;
      DEVICE_OBJECT *volume_object;
      FILE_OBJECT *file_object;
      HANDLE file;
      OBJECT_ATTRIBUTES file_attrs;
      OBJECT_NAME_INFORMATION *file_name_info, *volume_name_info;
      UNICODE_STRING u_dos_name;
      USHORT u_resolved_size;
      NTSTATUS status = STATUS_SUCCESS;
  
      InitializeObjectAttributes(
          &file_attrs,
          u_unresolved,
          OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
          NULL,
          NULL);
  
      status = ZwCreateFile(
          &file,
          FILE_READ_ATTRIBUTES,
          &file_attrs,
          &io_status_block,
          NULL,
          FILE_ATTRIBUTE_NORMAL,
          FILE_SHARE_READ | FILE_SHARE_WRITE,
          FILE_OPEN,
          FILE_SYNCHRONOUS_IO_NONALERT,
          NULL,
          0);
  
      if (!NT_SUCCESS(status))
          return status;
  
      status = ObReferenceObjectByHandle(
          file,
          FILE_READ_ATTRIBUTES,
          *IoFileObjectType,
          KernelMode,
          &file_object,
          NULL);
  
      if (!NT_SUCCESS(status))
          goto close_file;
  
      status = get_object_name_info(file_object, &file_name_info);
  
      if (!NT_SUCCESS(status))
          goto close_file;
  
      if (file_object->Vpb == NULL)
      {
          u_resolved->Buffer = ExAllocatePoolWithTag(
              PagedPool, file_name_info->Name.Length, '1l');
  
          if (u_resolved->Buffer == NULL)
          {
              status = STATUS_INSUFFICIENT_RESOURCES;
              goto free_file_name_info;
          }
  
          RtlInitEmptyUnicodeString(
              u_resolved, u_resolved->Buffer, file_name_info->Name.Length);
          RtlCopyUnicodeString(u_resolved, &file_name_info->Name);
          goto free_file_name_info;
      }
  
      volume_object = file_object->Vpb->RealDevice;
      status = get_object_name_info(volume_object, &volume_name_info);
  
      if (!NT_SUCCESS(status))
          goto free_file_name_info;
  
      status = IoVolumeDeviceToDosName(volume_object, &u_dos_name);
  
      if (!NT_SUCCESS(status))
          goto free_volume_name_info;
  
      u_resolved_size = file_name_info->Name.Length - volume_name_info->Name.Length + u_dos_name.Length;
  
      u_resolved->Buffer = ExAllocatePoolWithTag(PagedPool, u_resolved_size, '1l');
  
      if (u_resolved->Buffer == NULL)
      {
          status = STATUS_INSUFFICIENT_RESOURCES;
          goto free_dos_name;
      }
  
      RtlInitEmptyUnicodeString(u_resolved, u_resolved->Buffer, u_resolved_size);
  
      RtlCopyUnicodeString(u_resolved, &u_dos_name);
      file_name_info->Name.Buffer += volume_name_info->Name.Length / sizeof(wchar_t);
      file_name_info->Name.Length -= volume_name_info->Name.Length;
      RtlUnicodeStringCat(u_resolved, &file_name_info->Name);
  
  free_dos_name:
      ExFreePool(u_dos_name.Buffer);
  
  free_volume_name_info:
      ExFreePool(volume_name_info);
  
  free_file_name_info:
      ExFreePool(file_name_info);
  
  close_file:
      ZwClose(file);
  
      return status;
  }
  