Minor cleanup of GetVolumeNameForVolumeMountPointW and fix some incorrect return...
[reactos.git] / reactos / lib / kernel32 / file / volume.c
index 6427284..7ae9db1 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: volume.c,v 1.44 2004/11/21 10:39:11 weiden Exp $
+/* $Id$
  *
  * COPYRIGHT:       See COPYING in the top level directory
  * PROJECT:         ReactOS system libraries
@@ -13,7 +13,7 @@
  */
 //WINE copyright notice:
 /*
- * DOS drives handling functions 
+ * DOS drives handling functions
  *
  * Copyright 1993 Erik Bos
  * Copyright 1996 Alexandre Julliard
@@ -188,43 +188,19 @@ GetDiskFreeSpaceA (
        LPDWORD lpTotalNumberOfClusters
        )
 {
-       UNICODE_STRING RootPathNameU;
-       ANSI_STRING RootPathName;
-       BOOL Result;
-
-       RtlInitAnsiString (&RootPathName,
-                          (LPSTR)lpRootPathName);
-
-       RtlInitUnicodeString (&RootPathNameU,
-                             NULL);
+   PWCHAR RootPathNameW=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;
 }
 
 
@@ -290,48 +266,24 @@ GetDiskFreeSpaceW(
  */
 BOOL STDCALL
 GetDiskFreeSpaceExA (
-       LPCSTR          lpDirectoryName,
+       LPCSTR lpDirectoryName   OPTIONAL,
        PULARGE_INTEGER lpFreeBytesAvailableToCaller,
        PULARGE_INTEGER lpTotalNumberOfBytes,
        PULARGE_INTEGER lpTotalNumberOfFreeBytes
        )
 {
-       UNICODE_STRING DirectoryNameU;
-       ANSI_STRING DirectoryName;
-       BOOL 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;
 }
 
 
@@ -340,7 +292,7 @@ GetDiskFreeSpaceExA (
  */
 BOOL STDCALL
 GetDiskFreeSpaceExW(
-    LPCWSTR lpDirectoryName,
+    LPCWSTR lpDirectoryName OPTIONAL,
     PULARGE_INTEGER lpFreeBytesAvailableToCaller,
     PULARGE_INTEGER lpTotalNumberOfBytes,
     PULARGE_INTEGER lpTotalNumberOfFreeBytes
@@ -353,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);
@@ -368,7 +324,7 @@ GetDiskFreeSpaceExW(
     {
         return FALSE;
     }
-   
+
     errCode = NtQueryVolumeInformationFile(hFile,
                                            &IoStatusBlock,
                                            &FileFsSize,
@@ -388,7 +344,7 @@ GetDiskFreeSpaceExW(
        if (lpFreeBytesAvailableToCaller)
         lpFreeBytesAvailableToCaller->QuadPart =
             BytesPerCluster.QuadPart * FileFsSize.AvailableAllocationUnits.QuadPart;
-       
+
        if (lpTotalNumberOfBytes)
         lpTotalNumberOfBytes->QuadPart =
             BytesPerCluster.QuadPart * FileFsSize.TotalAllocationUnits.QuadPart;
@@ -408,30 +364,12 @@ GetDiskFreeSpaceExW(
 UINT STDCALL
 GetDriveTypeA(LPCSTR lpRootPathName)
 {
-       UNICODE_STRING RootPathNameU;
-       ANSI_STRING RootPathName;
-       UINT Result;
-
-       RtlInitAnsiString (&RootPathName,
-                          (LPSTR)lpRootPathName);
+   PWCHAR RootPathNameW;
 
-       /* convert ansi (or oem) string to unicode */
-       if (bIsFileApiAnsi)
-               RtlAnsiStringToUnicodeString (&RootPathNameU,
-                                             &RootPathName,
-                                             TRUE);
-       else
-               RtlOemStringToUnicodeString (&RootPathNameU,
-                                            &RootPathName,
-                                            TRUE);
+   if (!(RootPathNameW = FilenameA2W(lpRootPathName, FALSE)))
+      return DRIVE_UNKNOWN;
 
-       Result = GetDriveTypeW (RootPathNameU.Buffer);
-
-       RtlFreeHeap (RtlGetProcessHeap (),
-                    0,
-                    RootPathNameU.Buffer);
-
-       return Result;
+   return GetDriveTypeW(RootPathNameW);
 }
 
 
@@ -462,7 +400,7 @@ GetDriveTypeW(LPCWSTR lpRootPathName)
        {
                CloseHandle(hFile);
                SetLastErrorByStatus (errCode);
-               return 0;       
+               return 0;
        }
        CloseHandle(hFile);
 
@@ -505,34 +443,26 @@ GetVolumeInformationA(
        DWORD   nFileSystemNameSize
        )
 {
-  UNICODE_STRING RootPathNameU;
   UNICODE_STRING FileSystemNameU;
-  UNICODE_STRING VolumeNameU;
-  ANSI_STRING RootPathName;
+  UNICODE_STRING VolumeNameU = {0};
   ANSI_STRING VolumeName;
   ANSI_STRING FileSystemName;
+  PWCHAR RootPathNameW;
   BOOL Result;
 
-  RtlInitAnsiString (&RootPathName,
-                    (LPSTR)lpRootPathName);
-
-  /* convert ansi (or oem) string to unicode */
-  if (bIsFileApiAnsi)
-    RtlAnsiStringToUnicodeString (&RootPathNameU,
-                                 &RootPathName,
-                                 TRUE);
-  else
-    RtlOemStringToUnicodeString (&RootPathNameU,
-                                &RootPathName,
-                                TRUE);
+  if (!(RootPathNameW = FilenameA2W(lpRootPathName, FALSE)))
+     return FALSE;
 
   if (lpVolumeNameBuffer)
     {
-      VolumeNameU.Length = 0;
       VolumeNameU.MaximumLength = nVolumeNameSize * sizeof(WCHAR);
       VolumeNameU.Buffer = RtlAllocateHeap (RtlGetProcessHeap (),
                                            0,
                                            VolumeNameU.MaximumLength);
+      if (VolumeNameU.Buffer == NULL)
+      {
+          goto FailNoMem;
+      }
     }
 
   if (lpFileSystemNameBuffer)
@@ -542,9 +472,22 @@ GetVolumeInformationA(
       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 (RootPathNameU.Buffer,
+  Result = GetVolumeInformationW (RootPathNameW,
                                  lpVolumeNameBuffer ? VolumeNameU.Buffer : NULL,
                                  nVolumeNameSize,
                                  lpVolumeSerialNumber,
@@ -604,9 +547,6 @@ GetVolumeInformationA(
        }
     }
 
-  RtlFreeHeap (RtlGetProcessHeap (),
-              0,
-              RootPathNameU.Buffer);
   if (lpVolumeNameBuffer)
     {
       RtlFreeHeap (RtlGetProcessHeap (),
@@ -679,7 +619,7 @@ GetVolumeInformationW(
                                          FileFsVolume,
                                          FS_VOLUME_BUFFER_SIZE,
                                          FileFsVolumeInformation);
-  if ( !NT_SUCCESS(errCode) ) 
+  if ( !NT_SUCCESS(errCode) )
     {
       DPRINT("Status: %x\n", errCode);
       CloseHandle(hFile);
@@ -694,8 +634,8 @@ GetVolumeInformationW(
     {
       if (nVolumeNameSize * sizeof(WCHAR) >= FileFsVolume->VolumeLabelLength + sizeof(WCHAR))
         {
-         memcpy(lpVolumeNameBuffer, 
-                FileFsVolume->VolumeLabel, 
+         memcpy(lpVolumeNameBuffer,
+                FileFsVolume->VolumeLabel,
                 FileFsVolume->VolumeLabelLength);
          lpVolumeNameBuffer[FileFsVolume->VolumeLabelLength / sizeof(WCHAR)] = 0;
        }
@@ -728,8 +668,8 @@ GetVolumeInformationW(
     {
       if (nFileSystemNameSize * sizeof(WCHAR) >= FileFsAttribute->FileSystemNameLength + sizeof(WCHAR))
         {
-         memcpy(lpFileSystemNameBuffer, 
-                FileFsAttribute->FileSystemName, 
+         memcpy(lpFileSystemNameBuffer,
+                FileFsAttribute->FileSystemName,
                 FileFsAttribute->FileSystemNameLength);
          lpFileSystemNameBuffer[FileFsAttribute->FileSystemNameLength / sizeof(WCHAR)] = 0;
        }
@@ -750,49 +690,31 @@ 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;
+       PWCHAR RootPathNameW;
+   PWCHAR VolumeNameW = NULL;
        BOOL Result;
 
-       RtlInitAnsiString (&RootPathName,
-                          (LPSTR)lpRootPathName);
-       RtlInitAnsiString (&VolumeName,
-                          (LPSTR)lpVolumeName);
+   if (!(RootPathNameW = FilenameA2W(lpRootPathName, FALSE)))
+      return FALSE;
 
-       /* 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);
-       }
+   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;
 }
@@ -802,20 +724,27 @@ SetVolumeLabelA (
  * @implemented
  */
 BOOL STDCALL
-SetVolumeLabelW(LPCWSTR lpRootPathName,
-               LPCWSTR lpVolumeName)
+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;
    memcpy(LabelInfo->VolumeLabel,
          lpVolumeName,
@@ -829,7 +758,7 @@ SetVolumeLabelW(LPCWSTR lpRootPathName,
                    LabelInfo);
         return FALSE;
    }
-   
+
    Status = NtSetVolumeInformationFile(hFile,
                                       &IoStatusBlock,
                                       LabelInfo,
@@ -853,4 +782,229 @@ 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;
+   ULONG BufferLength;
+   PMOUNTDEV_NAME MountDevName;
+   PMOUNTMGR_MOUNT_POINT MountPoint;
+   ULONG MountPointSize;
+   PMOUNTMGR_MOUNT_POINTS MountPoints;
+   ULONG Index;
+   PUCHAR SymbolicLinkName;
+   BOOL Result;
+   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 = RtlAllocateHeap(GetProcessHeap(), 0, BufferLength);
+      if (MountDevName == NULL)
+      {
+         NtClose(FileHandle);
+         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+         return FALSE;
+      }
+
+      Status = NtDeviceIoControlFile(FileHandle, NULL, NULL, NULL, &Iosb,
+                                     IOCTL_MOUNTDEV_QUERY_DEVICE_NAME,
+                                     NULL, 0, MountDevName, BufferLength);
+      if (!NT_SUCCESS(Status))
+      {
+         RtlFreeHeap(GetProcessHeap(), 0, MountDevName);
+         if (Status == STATUS_BUFFER_OVERFLOW)
+         {
+            BufferLength = sizeof(MOUNTDEV_NAME) + MountDevName->NameLength;
+            continue;
+         }
+         else 
+         {
+            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 = RtlAllocateHeap(GetProcessHeap(), 0, BufferLength);
+      if (MountPoints == NULL)
+      {
+         RtlFreeHeap(GetProcessHeap(), 0, MountPoint);
+         NtClose(FileHandle);
+         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+         return FALSE;
+      }
+
+      Status = NtDeviceIoControlFile(FileHandle, NULL, NULL, NULL, &Iosb,
+                                     IOCTL_MOUNTMGR_QUERY_POINTS,
+                                     MountPoint, MountPointSize,
+                                     MountPoints, BufferLength);
+      if (!NT_SUCCESS(Status))
+      {
+         RtlFreeHeap(GetProcessHeap(), 0, MountPoints);
+         if (Status == STATUS_BUFFER_OVERFLOW)
+         {
+            BufferLength = MountPoints->Size;
+            continue;
+         }
+         else if (!NT_SUCCESS(Status))
+         {
+            RtlFreeHeap(GetProcessHeap(), 0, MountPoint);
+            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'\\';
+               Result = TRUE;
+            }
+            else
+            {
+               RtlFreeHeap(GetProcessHeap(), 0, MountPoints);
+               SetLastError(ERROR_FILENAME_EXCED_RANGE);
+               Result = FALSE;
+            }
+
+            return Result;
+         }
+      }
+   }
+
+   RtlFreeHeap(GetProcessHeap(), 0, MountPoints);
+   SetLastError(ERROR_INVALID_PARAMETER);
+
+   return FALSE;
+}
+
 /* EOF */