Fix bunch of bugs in GetVolumeNameForVolumeMountPointW. Thanks to w3seek.
[reactos.git] / reactos / lib / kernel32 / file / volume.c
index 8642f75..d0cf382 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: volume.c,v 1.26 2002/09/08 10:22:42 chorns Exp $
+/* $Id$
  *
  * COPYRIGHT:       See COPYING in the top level directory
  * PROJECT:         ReactOS system libraries
  */
 //WINE copyright notice:
 /*
- * DOS drives handling functions 
+ * DOS drives handling functions
  *
  * Copyright 1993 Erik Bos
  * Copyright 1996 Alexandre Julliard
  */
 
-#include <ddk/ntddk.h>
-#include <windows.h>
-#include <ntos/minmax.h>
+#include <k32.h>
 
 #define NDEBUG
-#include <kernel32/kernel32.h>
-#include <kernel32/error.h>
+#include "../include/debug.h"
 
 
 #define MAX_DOS_DRIVES 26
 
-HANDLE InternalOpenDirW(PWCHAR DirName, BOOLEAN Write)
-{
-    UNICODE_STRING NtPathU;
-    OBJECT_ATTRIBUTES ObjectAttributes;
-    NTSTATUS errCode;
-    IO_STATUS_BLOCK IoStatusBlock;
-    HANDLE hFile;
 
-    if (!RtlDosPathNameToNtPathName_U ((LPWSTR)DirName,
-                                      &NtPathU,
-                                      NULL,
-                                      NULL))
+static HANDLE
+InternalOpenDirW(LPCWSTR DirName,
+                BOOLEAN Write)
+{
+  UNICODE_STRING NtPathU;
+  OBJECT_ATTRIBUTES ObjectAttributes;
+  NTSTATUS errCode;
+  IO_STATUS_BLOCK IoStatusBlock;
+  HANDLE hFile;
+
+  if (!RtlDosPathNameToNtPathName_U((LPWSTR)DirName,
+                                   &NtPathU,
+                                   NULL,
+                                   NULL))
     {
        DPRINT("Invalid path\n");
        SetLastError(ERROR_BAD_PATHNAME);
@@ -76,6 +76,10 @@ HANDLE InternalOpenDirW(PWCHAR DirName, BOOLEAN Write)
     return hFile;
 }
 
+
+/*
+ * @implemented
+ */
 DWORD STDCALL
 GetLogicalDriveStringsA(DWORD nBufferLength,
                        LPSTR lpBuffer)
@@ -83,7 +87,7 @@ GetLogicalDriveStringsA(DWORD nBufferLength,
    DWORD drive, count;
    DWORD dwDriveMap;
 
-   dwDriveMap = SharedUserData->DosDeviceMap;
+   dwDriveMap = GetLogicalDrives();
 
    for (drive = count = 0; drive < MAX_DOS_DRIVES; drive++)
      {
@@ -110,6 +114,9 @@ GetLogicalDriveStringsA(DWORD nBufferLength,
 }
 
 
+/*
+ * @implemented
+ */
 DWORD STDCALL
 GetLogicalDriveStringsW(DWORD nBufferLength,
                        LPWSTR lpBuffer)
@@ -117,7 +124,7 @@ GetLogicalDriveStringsW(DWORD nBufferLength,
    DWORD drive, count;
    DWORD dwDriveMap;
 
-   dwDriveMap = SharedUserData->DosDeviceMap;
+   dwDriveMap = GetLogicalDrives();
 
    for (drive = count = 0; drive < MAX_DOS_DRIVES; drive++)
      {
@@ -142,14 +149,37 @@ GetLogicalDriveStringsW(DWORD nBufferLength,
 }
 
 
+/*
+ * @implemented
+ */
 DWORD STDCALL
 GetLogicalDrives(VOID)
 {
-  return(SharedUserData->DosDeviceMap);
+       NTSTATUS Status;
+       PROCESS_DEVICEMAP_INFORMATION ProcessDeviceMapInfo;
+
+       /* Get the Device Map for this Process */
+       Status = NtQueryInformationProcess(NtCurrentProcess(),
+                                          ProcessDeviceMap,
+                                          &ProcessDeviceMapInfo,
+                                          sizeof(ProcessDeviceMapInfo),
+                                          NULL);
+
+       /* Return the Drive Map */
+       if (!NT_SUCCESS(Status))
+       {
+               SetLastErrorByStatus(Status);
+               return 0;
+       }
+
+        return ProcessDeviceMapInfo.Query.DriveMap;
 }
 
 
-WINBOOL STDCALL
+/*
+ * @implemented
+ */
+BOOL STDCALL
 GetDiskFreeSpaceA (
        LPCSTR  lpRootPathName,
        LPDWORD lpSectorsPerCluster,
@@ -158,47 +188,26 @@ GetDiskFreeSpaceA (
        LPDWORD lpTotalNumberOfClusters
        )
 {
-       UNICODE_STRING RootPathNameU;
-       ANSI_STRING RootPathName;
-       WINBOOL Result;
+   PWCHAR RootPathNameW=NULL;
 
-       RtlInitAnsiString (&RootPathName,
-                          (LPSTR)lpRootPathName);
-
-       RtlInitUnicodeString (&RootPathNameU,
-                             NULL);
-
-       if (lpRootPathName)
-       {
-               /* convert ansi (or oem) string to unicode */
-               if (bIsFileApiAnsi)
-                       RtlAnsiStringToUnicodeString (&RootPathNameU,
-                                                     &RootPathName,
-                                                     TRUE);
-               else
-                       RtlOemStringToUnicodeString (&RootPathNameU,
-                                                    &RootPathName,
-                                                    TRUE);
-       }
+   if (lpRootPathName)
+   {
+      if (!(RootPathNameW = FilenameA2W(lpRootPathName, FALSE)))
+         return FALSE;
+   }
 
-       Result = GetDiskFreeSpaceW (RootPathNameU.Buffer,
+       return GetDiskFreeSpaceW (RootPathNameW,
                                    lpSectorsPerCluster,
                                    lpBytesPerSector,
                                    lpNumberOfFreeClusters,
                                    lpTotalNumberOfClusters);
-
-       if (lpRootPathName)
-       {
-               RtlFreeHeap (RtlGetProcessHeap (),
-                            0,
-                            RootPathNameU.Buffer);
-       }
-
-       return Result;
 }
 
 
-WINBOOL STDCALL
+/*
+ * @implemented
+ */
+BOOL STDCALL
 GetDiskFreeSpaceW(
     LPCWSTR lpRootPathName,
     LPDWORD lpSectorsPerCluster,
@@ -220,14 +229,15 @@ GetDiskFreeSpaceW(
     else
     {
         GetCurrentDirectoryW (MAX_PATH, RootPathName);
-        RootPathName[3] = 0;
     }
-       
-    if (INVALID_HANDLE_VALUE == (hFile = InternalOpenDirW((PWCHAR)lpRootPathName, FALSE)))
+    RootPathName[3] = 0;
+
+  hFile = InternalOpenDirW(RootPathName, FALSE);
+  if (INVALID_HANDLE_VALUE == hFile)
     {
-        return FALSE;
+      SetLastError(ERROR_PATH_NOT_FOUND);
+      return FALSE;
     }
-   
 
     errCode = NtQueryVolumeInformationFile(hFile,
                                            &IoStatusBlock,
@@ -246,60 +256,43 @@ GetDiskFreeSpaceW(
     *lpNumberOfFreeClusters = FileFsSize.AvailableAllocationUnits.u.LowPart;
     *lpTotalNumberOfClusters = FileFsSize.TotalAllocationUnits.u.LowPart;
     CloseHandle(hFile);
+
     return TRUE;
 }
 
 
-WINBOOL STDCALL
+/*
+ * @implemented
+ */
+BOOL STDCALL
 GetDiskFreeSpaceExA (
-       LPCSTR          lpDirectoryName,
+       LPCSTR lpDirectoryName   OPTIONAL,
        PULARGE_INTEGER lpFreeBytesAvailableToCaller,
        PULARGE_INTEGER lpTotalNumberOfBytes,
        PULARGE_INTEGER lpTotalNumberOfFreeBytes
        )
 {
-       UNICODE_STRING DirectoryNameU;
-       ANSI_STRING DirectoryName;
-       WINBOOL Result;
-
-       RtlInitAnsiString (&DirectoryName,
-                          (LPSTR)lpDirectoryName);
-
-       RtlInitUnicodeString (&DirectoryNameU,
-                             NULL);
+   PWCHAR DirectoryNameW=NULL;
 
        if (lpDirectoryName)
        {
-               /* convert ansi (or oem) string to unicode */
-               if (bIsFileApiAnsi)
-                       RtlAnsiStringToUnicodeString (&DirectoryNameU,
-                                                     &DirectoryName,
-                                                     TRUE);
-               else
-                       RtlOemStringToUnicodeString (&DirectoryNameU,
-                                                    &DirectoryName,
-                                                    TRUE);
+      if (!(DirectoryNameW = FilenameA2W(lpDirectoryName, FALSE)))
+         return FALSE;
        }
 
-       Result = GetDiskFreeSpaceExW (DirectoryNameU.Buffer,
+   return GetDiskFreeSpaceExW (DirectoryNameW ,
                                      lpFreeBytesAvailableToCaller,
                                      lpTotalNumberOfBytes,
                                      lpTotalNumberOfFreeBytes);
-
-       if (lpDirectoryName)
-       {
-               RtlFreeHeap (RtlGetProcessHeap (),
-                            0,
-                            DirectoryNameU.Buffer);
-       }
-
-       return Result;
 }
 
 
-WINBOOL STDCALL
+/*
+ * @implemented
+ */
+BOOL STDCALL
 GetDiskFreeSpaceExW(
-    LPCWSTR lpDirectoryName,
+    LPCWSTR lpDirectoryName OPTIONAL,
     PULARGE_INTEGER lpFreeBytesAvailableToCaller,
     PULARGE_INTEGER lpTotalNumberOfBytes,
     PULARGE_INTEGER lpTotalNumberOfFreeBytes
@@ -312,6 +305,10 @@ GetDiskFreeSpaceExW(
     HANDLE hFile;
     NTSTATUS errCode;
 
+    /*
+    FIXME: this is obviously wrong for UNC paths, symbolic directories etc.
+    -Gunnar
+    */
     if (lpDirectoryName)
     {
         wcsncpy (RootPathName, lpDirectoryName, 3);
@@ -319,14 +316,15 @@ GetDiskFreeSpaceExW(
     else
     {
         GetCurrentDirectoryW (MAX_PATH, RootPathName);
-        RootPathName[3] = 0;
     }
-       
-    if (INVALID_HANDLE_VALUE == (hFile = InternalOpenDirW(lpDirectoryName, FALSE)))
+    RootPathName[3] = 0;
+
+    hFile = InternalOpenDirW(RootPathName, FALSE);
+    if (INVALID_HANDLE_VALUE == hFile)
     {
         return FALSE;
     }
-   
+
     errCode = NtQueryVolumeInformationFile(hFile,
                                            &IoStatusBlock,
                                            &FileFsSize,
@@ -346,7 +344,7 @@ GetDiskFreeSpaceExW(
        if (lpFreeBytesAvailableToCaller)
         lpFreeBytesAvailableToCaller->QuadPart =
             BytesPerCluster.QuadPart * FileFsSize.AvailableAllocationUnits.QuadPart;
-       
+
        if (lpTotalNumberOfBytes)
         lpTotalNumberOfBytes->QuadPart =
             BytesPerCluster.QuadPart * FileFsSize.TotalAllocationUnits.QuadPart;
@@ -355,39 +353,29 @@ GetDiskFreeSpaceExW(
             BytesPerCluster.QuadPart * FileFsSize.AvailableAllocationUnits.QuadPart;
 
     CloseHandle(hFile);
+
     return TRUE;
 }
 
 
+/*
+ * @implemented
+ */
 UINT STDCALL
 GetDriveTypeA(LPCSTR lpRootPathName)
 {
-       UNICODE_STRING RootPathNameU;
-       ANSI_STRING RootPathName;
-       UINT Result;
+   PWCHAR RootPathNameW;
 
-       RtlInitAnsiString (&RootPathName,
-                          (LPSTR)lpRootPathName);
+   if (!(RootPathNameW = FilenameA2W(lpRootPathName, FALSE)))
+      return DRIVE_UNKNOWN;
 
-       /* convert ansi (or oem) string to unicode */
-       if (bIsFileApiAnsi)
-               RtlAnsiStringToUnicodeString (&RootPathNameU,
-                                             &RootPathName,
-                                             TRUE);
-       else
-               RtlOemStringToUnicodeString (&RootPathNameU,
-                                            &RootPathName,
-                                            TRUE);
-
-       Result = GetDriveTypeW (RootPathNameU.Buffer);
-
-       RtlFreeHeap (RtlGetProcessHeap (),
-                    0,
-                    RootPathNameU.Buffer);
-
-       return Result;
+   return GetDriveTypeW(RootPathNameW);
 }
 
+
+/*
+ * @implemented
+ */
 UINT STDCALL
 GetDriveTypeW(LPCWSTR lpRootPathName)
 {
@@ -400,7 +388,7 @@ GetDriveTypeW(LPCWSTR lpRootPathName)
        hFile = InternalOpenDirW(lpRootPathName, FALSE);
        if (hFile == INVALID_HANDLE_VALUE)
        {
-           return 0;
+           return DRIVE_NO_ROOT_DIR;   /* According to WINE regression tests */
        }
 
        errCode = NtQueryVolumeInformationFile (hFile,
@@ -415,11 +403,35 @@ GetDriveTypeW(LPCWSTR lpRootPathName)
                return 0;
        }
        CloseHandle(hFile);
-       return (UINT)FileFsDevice.DeviceType;
+
+        switch (FileFsDevice.DeviceType)
+        {
+               case FILE_DEVICE_CD_ROM:
+               case FILE_DEVICE_CD_ROM_FILE_SYSTEM:
+                       return DRIVE_CDROM;
+               case FILE_DEVICE_VIRTUAL_DISK:
+                       return DRIVE_RAMDISK;
+               case FILE_DEVICE_NETWORK_FILE_SYSTEM:
+                       return DRIVE_REMOTE;
+               case FILE_DEVICE_DISK:
+               case FILE_DEVICE_DISK_FILE_SYSTEM:
+                       if (FileFsDevice.Characteristics & FILE_REMOTE_DEVICE)
+                               return DRIVE_REMOTE;
+                       if (FileFsDevice.Characteristics & FILE_REMOVABLE_MEDIA)
+                               return DRIVE_REMOVABLE;
+                       return DRIVE_FIXED;
+        }
+
+        DPRINT1("Returning DRIVE_UNKNOWN for device type %d\n", FileFsDevice.DeviceType);
+
+       return DRIVE_UNKNOWN;
 }
 
 
-WINBOOL STDCALL
+/*
+ * @implemented
+ */
+BOOL STDCALL
 GetVolumeInformationA(
        LPCSTR  lpRootPathName,
        LPSTR   lpVolumeNameBuffer,
@@ -431,103 +443,134 @@ GetVolumeInformationA(
        DWORD   nFileSystemNameSize
        )
 {
-       UNICODE_STRING RootPathNameU;
-       UNICODE_STRING FileSystemNameU;
-       UNICODE_STRING VolumeNameU;
-       ANSI_STRING RootPathName;
-       ANSI_STRING VolumeName;
-       ANSI_STRING FileSystemName;
-       WINBOOL Result;
-
-       RtlInitAnsiString (&RootPathName,
-                          (LPSTR)lpRootPathName);
-
-       /* convert ansi (or oem) string to unicode */
-       if (bIsFileApiAnsi)
-               RtlAnsiStringToUnicodeString (&RootPathNameU,
-                                             &RootPathName,
-                                             TRUE);
-       else
-               RtlOemStringToUnicodeString (&RootPathNameU,
-                                            &RootPathName,
-                                            TRUE);
-
-       VolumeNameU.Length = 0;
-       VolumeNameU.MaximumLength = nVolumeNameSize * sizeof(WCHAR);
-       VolumeNameU.Buffer = RtlAllocateHeap (RtlGetProcessHeap (),
-                                             0,
-                                             VolumeNameU.MaximumLength);
-
-       FileSystemNameU.Length = 0;
-       FileSystemNameU.MaximumLength = nFileSystemNameSize * sizeof(WCHAR);
-       FileSystemNameU.Buffer = RtlAllocateHeap (RtlGetProcessHeap (),
-                                                 0,
-                                                 FileSystemNameU.MaximumLength);
-
-       Result = GetVolumeInformationW (RootPathNameU.Buffer,
-                                       VolumeNameU.Buffer,
-                                       nVolumeNameSize,
-                                       lpVolumeSerialNumber,
-                                       lpMaximumComponentLength,
-                                       lpFileSystemFlags,
-                                       FileSystemNameU.Buffer,
-                                       nFileSystemNameSize);
-
-       if (Result)
-       {
-                VolumeNameU.Length = wcslen(VolumeNameU.Buffer) * sizeof(WCHAR);
-               VolumeName.Length = 0;
-               VolumeName.MaximumLength = nVolumeNameSize;
-               VolumeName.Buffer = lpVolumeNameBuffer;
-
-                FileSystemNameU.Length = wcslen(FileSystemNameU.Buffer) * sizeof(WCHAR);
-               FileSystemName.Length = 0;
-               FileSystemName.MaximumLength = nFileSystemNameSize;
-               FileSystemName.Buffer = lpFileSystemNameBuffer;
-
-               /* convert unicode strings to ansi (or oem) */
-               if (bIsFileApiAnsi)
-               {
-                       RtlUnicodeStringToAnsiString (&VolumeName,
-                                                     &VolumeNameU,
-                                                     FALSE);
-                       RtlUnicodeStringToAnsiString (&FileSystemName,
-                                                     &FileSystemNameU,
-                                                     FALSE);
-               }
-               else
-               {
-                       RtlUnicodeStringToOemString (&VolumeName,
-                                                    &VolumeNameU,
-                                                    FALSE);
-                       RtlUnicodeStringToOemString (&FileSystemName,
-                                                    &FileSystemNameU,
-                                                    FALSE);
-               }
-       }
+  UNICODE_STRING FileSystemNameU;
+  UNICODE_STRING VolumeNameU = {0};
+  ANSI_STRING VolumeName;
+  ANSI_STRING FileSystemName;
+  PWCHAR RootPathNameW;
+  BOOL Result;
 
-       RtlFreeHeap (RtlGetProcessHeap (),
-                    0,
-                    RootPathNameU.Buffer);
-       RtlFreeHeap (RtlGetProcessHeap (),
-                    0,
-                    VolumeNameU.Buffer);
-       RtlFreeHeap (RtlGetProcessHeap (),
-                    0,
-                    FileSystemNameU.Buffer);
+  if (!(RootPathNameW = FilenameA2W(lpRootPathName, FALSE)))
+     return FALSE;
 
-       return Result;
-}
+  if (lpVolumeNameBuffer)
+    {
+      VolumeNameU.MaximumLength = nVolumeNameSize * sizeof(WCHAR);
+      VolumeNameU.Buffer = RtlAllocateHeap (RtlGetProcessHeap (),
+                                           0,
+                                           VolumeNameU.MaximumLength);
+      if (VolumeNameU.Buffer == NULL)
+      {
+          goto FailNoMem;
+      }
+    }
 
+  if (lpFileSystemNameBuffer)
+    {
+      FileSystemNameU.Length = 0;
+      FileSystemNameU.MaximumLength = nFileSystemNameSize * sizeof(WCHAR);
+      FileSystemNameU.Buffer = RtlAllocateHeap (RtlGetProcessHeap (),
+                                               0,
+                                               FileSystemNameU.MaximumLength);
+      if (FileSystemNameU.Buffer == NULL)
+      {
+          if (VolumeNameU.Buffer != NULL)
+          {
+              RtlFreeHeap(RtlGetProcessHeap(),
+                          0,
+                          VolumeNameU.Buffer);
+          }
+
+FailNoMem:
+          SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+          return FALSE;
+      }
+    }
+
+  Result = GetVolumeInformationW (RootPathNameW,
+                                 lpVolumeNameBuffer ? VolumeNameU.Buffer : NULL,
+                                 nVolumeNameSize,
+                                 lpVolumeSerialNumber,
+                                 lpMaximumComponentLength,
+                                 lpFileSystemFlags,
+                                 lpFileSystemNameBuffer ? FileSystemNameU.Buffer : NULL,
+                                 nFileSystemNameSize);
+
+  if (Result)
+    {
+      if (lpVolumeNameBuffer)
+        {
+          VolumeNameU.Length = wcslen(VolumeNameU.Buffer) * sizeof(WCHAR);
+         VolumeName.Length = 0;
+         VolumeName.MaximumLength = nVolumeNameSize;
+         VolumeName.Buffer = lpVolumeNameBuffer;
+       }
 
+      if (lpFileSystemNameBuffer)
+       {
+         FileSystemNameU.Length = wcslen(FileSystemNameU.Buffer) * sizeof(WCHAR);
+         FileSystemName.Length = 0;
+         FileSystemName.MaximumLength = nFileSystemNameSize;
+         FileSystemName.Buffer = lpFileSystemNameBuffer;
+       }
+
+      /* convert unicode strings to ansi (or oem) */
+      if (bIsFileApiAnsi)
+        {
+         if (lpVolumeNameBuffer)
+           {
+             RtlUnicodeStringToAnsiString (&VolumeName,
+                                           &VolumeNameU,
+                                           FALSE);
+           }
+         if (lpFileSystemNameBuffer)
+           {
+             RtlUnicodeStringToAnsiString (&FileSystemName,
+                                           &FileSystemNameU,
+                                           FALSE);
+           }
+       }
+      else
+        {
+         if (lpVolumeNameBuffer)
+           {
+             RtlUnicodeStringToOemString (&VolumeName,
+                                          &VolumeNameU,
+                                          FALSE);
+           }
+          if (lpFileSystemNameBuffer)
+           {
+             RtlUnicodeStringToOemString (&FileSystemName,
+                                          &FileSystemNameU,
+                                          FALSE);
+           }
+       }
+    }
 
+  if (lpVolumeNameBuffer)
+    {
+      RtlFreeHeap (RtlGetProcessHeap (),
+                  0,
+                  VolumeNameU.Buffer);
+    }
+  if (lpFileSystemNameBuffer)
+    {
+      RtlFreeHeap (RtlGetProcessHeap (),
+                  0,
+                  FileSystemNameU.Buffer);
+    }
 
-#define FS_VOLUME_BUFFER_SIZE (MAX_PATH + sizeof(FILE_FS_VOLUME_INFORMATION))
+  return Result;
+}
 
-#define FS_ATTRIBUTE_BUFFER_SIZE (MAX_PATH + sizeof(FILE_FS_ATTRIBUTE_INFORMATION))
+#define FS_VOLUME_BUFFER_SIZE (MAX_PATH * sizeof(WCHAR) + sizeof(FILE_FS_VOLUME_INFORMATION))
 
+#define FS_ATTRIBUTE_BUFFER_SIZE (MAX_PATH * sizeof(WCHAR) + sizeof(FILE_FS_ATTRIBUTE_INFORMATION))
 
-WINBOOL STDCALL
+/*
+ * @implemented
+ */
+BOOL STDCALL
 GetVolumeInformationW(
     LPCWSTR lpRootPathName,
     LPWSTR lpVolumeNameBuffer,
@@ -539,150 +582,183 @@ GetVolumeInformationW(
     DWORD nFileSystemNameSize
     )
 {
-       PFILE_FS_VOLUME_INFORMATION FileFsVolume;
-       PFILE_FS_ATTRIBUTE_INFORMATION FileFsAttribute;
-       IO_STATUS_BLOCK IoStatusBlock;
-        OBJECT_ATTRIBUTES ObjectAttributes;
-       USHORT Buffer[FS_VOLUME_BUFFER_SIZE];
-       USHORT Buffer2[FS_ATTRIBUTE_BUFFER_SIZE];
-
-       HANDLE hFile;
-       NTSTATUS errCode;
+  PFILE_FS_VOLUME_INFORMATION FileFsVolume;
+  PFILE_FS_ATTRIBUTE_INFORMATION FileFsAttribute;
+  IO_STATUS_BLOCK IoStatusBlock;
+  WCHAR RootPathName[MAX_PATH];
+  UCHAR Buffer[max(FS_VOLUME_BUFFER_SIZE, FS_ATTRIBUTE_BUFFER_SIZE)];
+
+  HANDLE hFile;
+  NTSTATUS errCode;
+
+  FileFsVolume = (PFILE_FS_VOLUME_INFORMATION)Buffer;
+  FileFsAttribute = (PFILE_FS_ATTRIBUTE_INFORMATION)Buffer;
+
+  DPRINT("FileFsVolume %p\n", FileFsVolume);
+  DPRINT("FileFsAttribute %p\n", FileFsAttribute);
+
+  if (!lpRootPathName || !wcscmp(lpRootPathName, L""))
+  {
+      GetCurrentDirectoryW (MAX_PATH, RootPathName);
+  }
+  else
+  {
+      wcsncpy (RootPathName, lpRootPathName, 3);
+  }
+  RootPathName[3] = 0;
+
+  hFile = InternalOpenDirW(RootPathName, FALSE);
+  if (hFile == INVALID_HANDLE_VALUE)
+    {
+      return FALSE;
+    }
 
-        FileFsVolume = (PFILE_FS_VOLUME_INFORMATION)Buffer;
-        FileFsAttribute = (PFILE_FS_ATTRIBUTE_INFORMATION)Buffer2;
+  DPRINT("hFile: %x\n", hFile);
+  errCode = NtQueryVolumeInformationFile(hFile,
+                                         &IoStatusBlock,
+                                         FileFsVolume,
+                                         FS_VOLUME_BUFFER_SIZE,
+                                         FileFsVolumeInformation);
+  if ( !NT_SUCCESS(errCode) )
+    {
+      DPRINT("Status: %x\n", errCode);
+      CloseHandle(hFile);
+      SetLastErrorByStatus (errCode);
+      return FALSE;
+    }
 
-        DPRINT("FileFsVolume %p\n", FileFsVolume);
-        DPRINT("FileFsAttribute %p\n", FileFsAttribute);
+  if (lpVolumeSerialNumber)
+    *lpVolumeSerialNumber = FileFsVolume->VolumeSerialNumber;
 
-       hFile = InternalOpenDirW(lpRootPathName, FALSE);
-       if (hFile == INVALID_HANDLE_VALUE)
-       {
-           return FALSE;
+  if (lpVolumeNameBuffer)
+    {
+      if (nVolumeNameSize * sizeof(WCHAR) >= FileFsVolume->VolumeLabelLength + sizeof(WCHAR))
+        {
+         memcpy(lpVolumeNameBuffer,
+                FileFsVolume->VolumeLabel,
+                FileFsVolume->VolumeLabelLength);
+         lpVolumeNameBuffer[FileFsVolume->VolumeLabelLength / sizeof(WCHAR)] = 0;
        }
-
-        DPRINT("hFile: %x\n", hFile);
-        errCode = NtQueryVolumeInformationFile(hFile,
-                                               &IoStatusBlock,
-                                               FileFsVolume,
-                                               FS_VOLUME_BUFFER_SIZE,
-                                               FileFsVolumeInformation);
-       if ( !NT_SUCCESS(errCode) ) {
-                DPRINT("Status: %x\n", errCode);
-                CloseHandle(hFile);
-               SetLastErrorByStatus (errCode);
-               return FALSE;
+      else
+        {
+         CloseHandle(hFile);
+         SetLastError(ERROR_MORE_DATA);
+         return FALSE;
        }
+    }
 
-        if (lpVolumeSerialNumber)
-                *lpVolumeSerialNumber = FileFsVolume->VolumeSerialNumber;
-
-       if (lpVolumeNameBuffer)
-               wcsncpy (lpVolumeNameBuffer,
-                        FileFsVolume->VolumeLabel,
-                        min(nVolumeNameSize,MAX_PATH));
+  errCode = NtQueryVolumeInformationFile (hFile,
+                                         &IoStatusBlock,
+                                         FileFsAttribute,
+                                         FS_ATTRIBUTE_BUFFER_SIZE,
+                                         FileFsAttributeInformation);
+  CloseHandle(hFile);
+  if (!NT_SUCCESS(errCode))
+    {
+      DPRINT("Status: %x\n", errCode);
+      SetLastErrorByStatus (errCode);
+      return FALSE;
+    }
 
-       errCode = NtQueryVolumeInformationFile (hFile,
-                                               &IoStatusBlock,
-                                               FileFsAttribute,
-                                               FS_ATTRIBUTE_BUFFER_SIZE,
-                                               FileFsAttributeInformation);
-       if (!NT_SUCCESS(errCode))
-       {
-               DPRINT("Status: %x\n", errCode);
-               CloseHandle(hFile);
-               SetLastErrorByStatus (errCode);
-               return FALSE;
+  if (lpFileSystemFlags)
+    *lpFileSystemFlags = FileFsAttribute->FileSystemAttributes;
+  if (lpMaximumComponentLength)
+    *lpMaximumComponentLength = FileFsAttribute->MaximumComponentNameLength;
+  if (lpFileSystemNameBuffer)
+    {
+      if (nFileSystemNameSize * sizeof(WCHAR) >= FileFsAttribute->FileSystemNameLength + sizeof(WCHAR))
+        {
+         memcpy(lpFileSystemNameBuffer,
+                FileFsAttribute->FileSystemName,
+                FileFsAttribute->FileSystemNameLength);
+         lpFileSystemNameBuffer[FileFsAttribute->FileSystemNameLength / sizeof(WCHAR)] = 0;
        }
-
-        if (lpFileSystemFlags)
-                *lpFileSystemFlags = FileFsAttribute->FileSystemAttributes;
-        if (lpMaximumComponentLength)
-                *lpMaximumComponentLength = FileFsAttribute->MaximumComponentNameLength;
-        if (lpFileSystemNameBuffer)
-                wcsncpy(lpFileSystemNameBuffer, FileFsAttribute->FileSystemName,min(nFileSystemNameSize,MAX_PATH));
-
-       CloseHandle(hFile);
-       return TRUE;
+      else
+        {
+         SetLastError(ERROR_MORE_DATA);
+         return FALSE;
+       }
+    }
+  return TRUE;
 }
 
 
-WINBOOL
+/*
+ * @implemented
+ */
+BOOL
 STDCALL
 SetVolumeLabelA (
        LPCSTR  lpRootPathName,
-       LPCSTR  lpVolumeName
+       LPCSTR  lpVolumeName /* NULL if deleting label */
        )
 {
-       UNICODE_STRING RootPathNameU;
-       ANSI_STRING RootPathName;
-       UNICODE_STRING VolumeNameU;
-       ANSI_STRING VolumeName;
-       WINBOOL Result;
-
-       RtlInitAnsiString (&RootPathName,
-                          (LPSTR)lpRootPathName);
-       RtlInitAnsiString (&VolumeName,
-                          (LPSTR)lpVolumeName);
-
-       /* convert ansi (or oem) strings to unicode */
-       if (bIsFileApiAnsi)
-       {
-               RtlAnsiStringToUnicodeString (&RootPathNameU,
-                                             &RootPathName,
-                                             TRUE);
-               RtlAnsiStringToUnicodeString (&VolumeNameU,
-                                             &VolumeName,
-                                             TRUE);
-       }
-       else
-       {
-               RtlOemStringToUnicodeString (&RootPathNameU,
-                                            &RootPathName,
-                                            TRUE);
-               RtlOemStringToUnicodeString (&VolumeNameU,
-                                            &VolumeName,
-                                            TRUE);
-       }
+       PWCHAR RootPathNameW;
+   PWCHAR VolumeNameW = NULL;
+       BOOL Result;
+
+   if (!(RootPathNameW = FilenameA2W(lpRootPathName, FALSE)))
+      return FALSE;
+
+   if (lpVolumeName)
+   {
+      if (!(VolumeNameW = FilenameA2W(lpVolumeName, TRUE)))
+         return FALSE;
+   }
 
-       Result = SetVolumeLabelW (RootPathNameU.Buffer,
-                                 VolumeNameU.Buffer);
+   Result = SetVolumeLabelW (RootPathNameW,
+                             VolumeNameW);
 
-       RtlFreeHeap (RtlGetProcessHeap (),
-                    0,
-                    RootPathNameU.Buffer);
-       RtlFreeHeap (RtlGetProcessHeap (),
-                    0,
-                    VolumeNameU.Buffer);
+   if (VolumeNameW)
+   {
+          RtlFreeHeap (RtlGetProcessHeap (),
+                       0,
+                   VolumeNameW );
+   }
 
        return Result;
 }
 
 
-WINBOOL STDCALL
-SetVolumeLabelW(LPCWSTR lpRootPathName,
-               LPCWSTR lpVolumeName)
+/*
+ * @implemented
+ */
+BOOL STDCALL
+SetVolumeLabelW(
+   LPCWSTR lpRootPathName,
+   LPCWSTR lpVolumeName /* NULL if deleting label */
+   )
 {
    PFILE_FS_LABEL_INFORMATION LabelInfo;
    IO_STATUS_BLOCK IoStatusBlock;
    ULONG LabelLength;
    HANDLE hFile;
    NTSTATUS Status;
-   
+
    LabelLength = wcslen(lpVolumeName) * sizeof(WCHAR);
    LabelInfo = RtlAllocateHeap(RtlGetProcessHeap(),
                               0,
                               sizeof(FILE_FS_LABEL_INFORMATION) +
                               LabelLength);
+   if (LabelInfo == NULL)
+   {
+       SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+       return FALSE;
+   }
    LabelInfo->VolumeLabelLength = LabelLength;
-   wcscpy(LabelInfo->VolumeLabel,
-         lpVolumeName);
-   
-   if (INVALID_HANDLE_VALUE == (hFile = InternalOpenDirW(lpRootPathName, TRUE)))
+   memcpy(LabelInfo->VolumeLabel,
+         lpVolumeName,
+         LabelLength);
+
+   hFile = InternalOpenDirW(lpRootPathName, TRUE);
+   if (INVALID_HANDLE_VALUE == hFile)
    {
+        RtlFreeHeap(RtlGetProcessHeap(),
+                   0,
+                   LabelInfo);
         return FALSE;
    }
-   
+
    Status = NtSetVolumeInformationFile(hFile,
                                       &IoStatusBlock,
                                       LabelInfo,
@@ -706,4 +782,223 @@ SetVolumeLabelW(LPCWSTR lpRootPathName,
    return TRUE;
 }
 
+/**
+ * @name GetVolumeNameForVolumeMountPointW
+ *
+ * Return an unique volume name for a drive root or mount point.
+ *
+ * @param VolumeMountPoint
+ *        Pointer to string that contains either root drive name or
+ *        mount point name.
+ * @param VolumeName
+ *        Pointer to buffer that is filled with resulting unique
+ *        volume name on success.
+ * @param VolumeNameLength
+ *        Size of VolumeName buffer in TCHARs.
+ *
+ * @return
+ *     TRUE when the function succeeds and the VolumeName buffer is filled,
+ *     FALSE otherwise.
+ */
+
+BOOL WINAPI
+GetVolumeNameForVolumeMountPointW(
+   IN LPCWSTR VolumeMountPoint,
+   OUT LPWSTR VolumeName,
+   IN DWORD VolumeNameLength)
+{
+   UNICODE_STRING NtFileName;
+   OBJECT_ATTRIBUTES ObjectAttributes;
+   HANDLE FileHandle;
+   IO_STATUS_BLOCK Iosb;
+   PVOID Buffer;
+   ULONG BufferLength;
+   PMOUNTDEV_NAME MountDevName;
+   PMOUNTMGR_MOUNT_POINT MountPoint;
+   ULONG MountPointSize;
+   PMOUNTMGR_MOUNT_POINTS MountPoints;
+   ULONG Index;
+   PUCHAR SymbolicLinkName;
+   NTSTATUS Status;
+
+   /*
+    * First step is to convert the passed volume mount point name to
+    * an NT acceptable name.
+    */
+
+   if (!RtlDosPathNameToNtPathName_U(VolumeName, &NtFileName, NULL, NULL))
+   {
+      SetLastError(ERROR_PATH_NOT_FOUND);
+      return FALSE;
+   }
+
+   if (NtFileName.Length > sizeof(WCHAR) &&
+       NtFileName.Buffer[(NtFileName.Length / sizeof(WCHAR)) - 1] == '\\')
+   {
+      NtFileName.Length -= sizeof(WCHAR);
+   }
+
+   /*
+    * Query mount point device name which we will later use for determining
+    * the volume name.
+    */
+
+   InitializeObjectAttributes(&ObjectAttributes, &NtFileName, 0, NULL, NULL);
+   Status = NtOpenFile(&FileHandle, FILE_READ_ATTRIBUTES | SYNCHRONIZE,
+                       &ObjectAttributes, &Iosb,
+                       FILE_SHARE_READ | FILE_SHARE_WRITE,
+                       FILE_SYNCHRONOUS_IO_NONALERT);
+   RtlFreeUnicodeString(&NtFileName);
+   if (!NT_SUCCESS(Status))
+   {
+      SetLastErrorByStatus(Status);
+      return FALSE;
+   }
+
+   BufferLength = sizeof(MOUNTDEV_NAME) + 50 * sizeof(WCHAR);
+   do
+   {
+      MountDevName = Buffer = RtlAllocateHeap(GetProcessHeap(), 0, BufferLength);
+      if (Buffer == NULL)
+      {
+         NtClose(FileHandle);
+         SetLastErrorByStatus(Status);
+         return FALSE;
+      }
+
+      Status = NtDeviceIoControlFile(FileHandle, NULL, NULL, NULL, &Iosb,
+                                     IOCTL_MOUNTDEV_QUERY_DEVICE_NAME,
+                                     NULL, 0, Buffer, BufferLength);
+      if (Status == STATUS_BUFFER_OVERFLOW)
+      {
+         BufferLength = sizeof(MOUNTDEV_NAME) + MountDevName->NameLength;
+         RtlFreeHeap(GetProcessHeap(), 0, Buffer);
+         continue;
+      }
+      else if (!NT_SUCCESS(Status))
+      {
+         RtlFreeHeap(GetProcessHeap(), 0, Buffer);
+         NtClose(FileHandle);
+         SetLastErrorByStatus(Status);
+         return FALSE;
+      }
+   }
+   while (!NT_SUCCESS(Status));
+
+   NtClose(FileHandle);
+
+   /*
+    * Get the mount point information from mount manager.
+    */
+
+   MountPointSize = MountDevName->NameLength + sizeof(MOUNTMGR_MOUNT_POINT);
+   MountPoint = RtlAllocateHeap(GetProcessHeap(), 0, MountPointSize);
+   if (MountPoint == NULL)
+   {
+      RtlFreeHeap(GetProcessHeap(), 0, MountDevName);
+      SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+      return FALSE;
+   }
+   RtlZeroMemory(MountPoint, sizeof(MOUNTMGR_MOUNT_POINT));
+   MountPoint->DeviceNameOffset = sizeof(MOUNTMGR_MOUNT_POINT);
+   MountPoint->DeviceNameLength = MountDevName->NameLength;
+   RtlCopyMemory(MountPoint + 1, MountDevName->Name, MountDevName->NameLength);
+   RtlFreeHeap(GetProcessHeap(), 0, MountDevName);
+
+   RtlInitUnicodeString(&NtFileName, L"\\??\\MountPointManager");
+   InitializeObjectAttributes(&ObjectAttributes, &NtFileName, 0, NULL, NULL);
+   Status = NtOpenFile(&FileHandle, FILE_GENERIC_READ, &ObjectAttributes,
+                       &Iosb, FILE_SHARE_READ | FILE_SHARE_WRITE,
+                       FILE_SYNCHRONOUS_IO_NONALERT);
+   if (!NT_SUCCESS(Status))
+   {
+      SetLastErrorByStatus(Status);
+      RtlFreeHeap(GetProcessHeap(), 0, MountPoint);
+      return FALSE;
+   }
+
+   BufferLength = sizeof(MOUNTMGR_MOUNT_POINTS);
+   do
+   {
+      MountPoints = Buffer = RtlAllocateHeap(GetProcessHeap(), 0, BufferLength);
+      if (Buffer == NULL)
+      {
+         RtlFreeHeap(GetProcessHeap(), 0, MountPoint);
+         NtClose(FileHandle);
+         SetLastErrorByStatus(Status);
+         return FALSE;
+      }
+
+      Status = NtDeviceIoControlFile(FileHandle, NULL, NULL, NULL, &Iosb,
+                                     IOCTL_MOUNTMGR_QUERY_POINTS,
+                                     MountPoint, MountPointSize,
+                                     Buffer, BufferLength);
+      if (Status == STATUS_BUFFER_OVERFLOW)
+      {
+         BufferLength = MountPoints->Size;
+         RtlFreeHeap(GetProcessHeap(), 0, Buffer);
+         continue;
+      }
+      else if (!NT_SUCCESS(Status))
+      {
+         RtlFreeHeap(GetProcessHeap(), 0, MountPoint);
+         RtlFreeHeap(GetProcessHeap(), 0, Buffer);
+         SetLastErrorByStatus(Status);
+         return FALSE;
+      }
+   }
+   while (!NT_SUCCESS(Status));
+
+   RtlFreeHeap(GetProcessHeap(), 0, MountPoint);
+   NtClose(FileHandle);
+
+   /*
+    * Now we've gathered info about all mount points mapped to our device, so
+    * select the correct one and copy it into the output buffer.
+    */
+
+   for (Index = 0; Index < MountPoints->NumberOfMountPoints; Index++)
+   {
+      MountPoint = MountPoints->MountPoints + Index;
+      SymbolicLinkName = (PUCHAR)MountPoints + MountPoint->SymbolicLinkNameOffset;
+      
+      /*
+       * Check for "\\?\Volume{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}\"
+       * (with the last slash being optional) style symbolic links.
+       */
+
+      if (MountPoint->SymbolicLinkNameLength == 48 * sizeof(WCHAR) ||
+          (MountPoint->SymbolicLinkNameLength == 49 * sizeof(WCHAR) &&
+           SymbolicLinkName[48] == L'\\'))
+      {
+         if (RtlCompareMemory(SymbolicLinkName, L"\\??\\Volume{",
+                              11 * sizeof(WCHAR)) == 11 * sizeof(WCHAR) &&
+             SymbolicLinkName[19] == L'-' && SymbolicLinkName[24] == L'-' &&
+             SymbolicLinkName[29] == L'-' && SymbolicLinkName[34] == L'-' &&
+             SymbolicLinkName[47] == L'}')
+         {
+            if (VolumeNameLength >= MountPoint->SymbolicLinkNameLength / sizeof(WCHAR))
+            {
+               RtlCopyMemory(VolumeName,
+                             (PUCHAR)MountPoints + MountPoint->SymbolicLinkNameOffset,
+                             MountPoint->SymbolicLinkNameLength);
+               VolumeName[1] = L'\\';
+               RtlFreeHeap(GetProcessHeap(), 0, MountPoints);
+               return TRUE;
+            }
+
+            RtlFreeHeap(GetProcessHeap(), 0, MountPoints);
+            SetLastError(ERROR_FILENAME_EXCED_RANGE);
+
+            return FALSE;
+         }
+      }
+   }
+
+   RtlFreeHeap(GetProcessHeap(), 0, MountPoints);
+   SetLastError(ERROR_INVALID_PARAMETER);
+
+   return FALSE;
+}
+
 /* EOF */