[NTOSKRNL] In IoQueryFileDosDeviceName(), in case of an error, return appropriate...
[reactos.git] / ntoskrnl / io / iomgr / file.c
index 6133c9e..f8afc88 100644 (file)
@@ -1869,12 +1869,31 @@ IopGetSetSecurityObject(IN PVOID ObjectBody,
 
 NTSTATUS
 NTAPI
-IopQueryNameFile(IN PVOID ObjectBody,
-                 IN BOOLEAN HasName,
-                 OUT POBJECT_NAME_INFORMATION ObjectNameInfo,
-                 IN ULONG Length,
-                 OUT PULONG ReturnLength,
-                 IN KPROCESSOR_MODE PreviousMode)
+IopQueryName(IN PVOID ObjectBody,
+             IN BOOLEAN HasName,
+             OUT POBJECT_NAME_INFORMATION ObjectNameInfo,
+             IN ULONG Length,
+             OUT PULONG ReturnLength,
+             IN KPROCESSOR_MODE PreviousMode)
+{
+    return IopQueryNameInternal(ObjectBody,
+                                HasName,
+                                FALSE,
+                                ObjectNameInfo,
+                                Length,
+                                ReturnLength,
+                                PreviousMode);
+}
+
+NTSTATUS
+NTAPI
+IopQueryNameInternal(IN PVOID ObjectBody,
+                     IN BOOLEAN HasName,
+                     IN BOOLEAN QueryDosName,
+                     OUT POBJECT_NAME_INFORMATION ObjectNameInfo,
+                     IN ULONG Length,
+                     OUT PULONG ReturnLength,
+                     IN KPROCESSOR_MODE PreviousMode)
 {
     POBJECT_NAME_INFORMATION LocalInfo;
     PFILE_NAME_INFORMATION LocalFileInfo;
@@ -1883,6 +1902,9 @@ IopQueryNameFile(IN PVOID ObjectBody,
     BOOLEAN LengthMismatch = FALSE;
     NTSTATUS Status;
     PWCHAR p;
+    PDEVICE_OBJECT DeviceObject;
+    BOOLEAN NoObCall;
+
     IOTRACE(IO_FILE_DEBUG, "ObjectBody: %p\n", ObjectBody);
 
     /* Validate length */
@@ -1897,11 +1919,52 @@ IopQueryNameFile(IN PVOID ObjectBody,
     LocalInfo = ExAllocatePoolWithTag(PagedPool, Length, TAG_IO);
     if (!LocalInfo) return STATUS_INSUFFICIENT_RESOURCES;
 
-    /* Query the name */
-    Status = ObQueryNameString(FileObject->DeviceObject,
-                               LocalInfo,
-                               Length,
-                               &LocalReturnLength);
+    /* Query DOS name if the caller asked to */
+    NoObCall = FALSE;
+    if (QueryDosName)
+    {
+        DeviceObject = FileObject->DeviceObject;
+
+        /* In case of a network file system, don't call mountmgr */
+        if (DeviceObject->DeviceType == FILE_DEVICE_NETWORK_FILE_SYSTEM)
+        {
+            /* We'll store separator and terminator */
+            LocalReturnLength = sizeof(OBJECT_NAME_INFORMATION) + 2 * sizeof(WCHAR);
+            if (Length < LocalReturnLength)
+            {
+                Status = STATUS_BUFFER_OVERFLOW;
+            }
+            else
+            {
+                LocalInfo->Name.Length = sizeof(WCHAR);
+                LocalInfo->Name.MaximumLength = sizeof(WCHAR);
+                LocalInfo->Name.Buffer = (PVOID)((ULONG_PTR)LocalInfo + sizeof(OBJECT_NAME_INFORMATION));
+                LocalInfo->Name.Buffer[0] = OBJ_NAME_PATH_SEPARATOR;
+                Status = STATUS_SUCCESS;
+            }
+        }
+        /* Otherwise, call mountmgr to get DOS name */
+        else
+        {
+            Status = IoVolumeDeviceToDosName(DeviceObject, &LocalInfo->Name);
+            LocalReturnLength = LocalInfo->Name.Length + sizeof(OBJECT_NAME_INFORMATION) + sizeof(WCHAR);
+        }
+    }
+
+    /* Fall back if querying DOS name failed or if caller never wanted it ;-) */
+    if (!QueryDosName || !NT_SUCCESS(Status))
+    {
+        /* Query the name */
+        Status = ObQueryNameString(FileObject->DeviceObject,
+                                   LocalInfo,
+                                   Length,
+                                   &LocalReturnLength);
+    }
+    else
+    {
+        NoObCall = TRUE;
+    }
+
     if (!NT_SUCCESS(Status) && (Status != STATUS_INFO_LENGTH_MISMATCH))
     {
         /* Free the buffer and fail */
@@ -1909,14 +1972,36 @@ IopQueryNameFile(IN PVOID ObjectBody,
         return Status;
     }
 
+    /* Get buffer pointer */
+    p = (PWCHAR)(ObjectNameInfo + 1);
+
     /* Copy the information */
-    RtlCopyMemory(ObjectNameInfo,
-                  LocalInfo,
-                  (LocalReturnLength > Length) ?
-                  Length : LocalReturnLength);
+    if (QueryDosName && NoObCall)
+    {
+        ASSERT(PreviousMode == KernelMode);
+
+        /* Copy structure first */
+        RtlCopyMemory(ObjectNameInfo,
+                      LocalInfo,
+                      (Length >= LocalReturnLength ? sizeof(OBJECT_NAME_INFORMATION) : Length));
+        /* Name then */
+        RtlCopyMemory(p, LocalInfo->Name.Buffer,
+                      (Length >= LocalReturnLength ? LocalInfo->Name.Length : Length - sizeof(OBJECT_NAME_INFORMATION)));
+
+        if (FileObject->DeviceObject->DeviceType != FILE_DEVICE_NETWORK_FILE_SYSTEM)
+        {
+            ExFreePool(LocalInfo->Name.Buffer);
+        }
+    }
+    else
+    {
+        RtlCopyMemory(ObjectNameInfo,
+                      LocalInfo,
+                      (LocalReturnLength > Length) ?
+                      Length : LocalReturnLength);
+    }
 
     /* Set buffer pointer */
-    p = (PWCHAR)(ObjectNameInfo + 1);
     ObjectNameInfo->Name.Buffer = p;
 
     /* Advance in buffer */
@@ -1941,16 +2026,45 @@ IopQueryNameFile(IN PVOID ObjectBody,
                  FIELD_OFFSET(FILE_NAME_INFORMATION, FileName);
 
     /* Query the File name */
-    Status = IoQueryFileInformation(FileObject,
-                                    FileNameInformation,
-                                    LengthMismatch ? Length : FileLength,
-                                    LocalFileInfo,
-                                    &LocalReturnLength);
+    if (PreviousMode == KernelMode &&
+        BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO))
+    {
+        Status = IopGetFileInformation(FileObject,
+                                       LengthMismatch ? Length : FileLength,
+                                       FileNameInformation,
+                                       LocalFileInfo,
+                                       &LocalReturnLength);
+    }
+    else
+    {
+        Status = IoQueryFileInformation(FileObject,
+                                        FileNameInformation,
+                                        LengthMismatch ? Length : FileLength,
+                                        LocalFileInfo,
+                                        &LocalReturnLength);
+    }
     if (NT_ERROR(Status))
     {
-        /* Fail on errors only, allow warnings */
-        ExFreePoolWithTag(LocalInfo, TAG_IO);
-        return Status;
+        /* Allow status that would mean it's not implemented in the storage stack */
+        if (Status != STATUS_INVALID_PARAMETER && Status != STATUS_INVALID_DEVICE_REQUEST &&
+            Status != STATUS_NOT_IMPLEMENTED && Status != STATUS_INVALID_INFO_CLASS)
+        {
+            ExFreePoolWithTag(LocalInfo, TAG_IO);
+            return Status;
+        }
+
+        /* In such case, zero output */
+        LocalReturnLength = FIELD_OFFSET(FILE_NAME_INFORMATION, FileName);
+        LocalFileInfo->FileNameLength = 0;
+        LocalFileInfo->FileName[0] = OBJ_NAME_PATH_SEPARATOR;
+    }
+    else
+    {
+        /* We'll at least return the name length */
+        if (LocalReturnLength < FIELD_OFFSET(FILE_NAME_INFORMATION, FileName))
+        {
+            LocalReturnLength = FIELD_OFFSET(FILE_NAME_INFORMATION, FileName);
+        }
     }
 
     /* If the provided buffer is too small, return the required size */
@@ -1971,6 +2085,14 @@ IopQueryNameFile(IN PVOID ObjectBody,
                                 (ULONG_PTR)ObjectNameInfo +
                                 LocalFileInfo->FileNameLength);
 
+    /* Don't copy the name if it's not valid */
+    if (LocalFileInfo->FileName[0] != OBJ_NAME_PATH_SEPARATOR)
+    {
+        /* Free the allocated buffer and return failure */
+        ExFreePoolWithTag(LocalInfo, TAG_IO);
+        return STATUS_OBJECT_PATH_INVALID;
+    }
+
     /* Write the Name and null-terminate it */
     RtlCopyMemory(p, LocalFileInfo->FileName, FileLength);
     p += (FileLength / sizeof(WCHAR));
@@ -3447,15 +3569,63 @@ IoCancelFileOpen(IN PDEVICE_OBJECT DeviceObject,
 }
 
 /*
- * @unimplemented
+ * @implemented
  */
 NTSTATUS
 NTAPI
 IoQueryFileDosDeviceName(IN PFILE_OBJECT FileObject,
                          OUT POBJECT_NAME_INFORMATION *ObjectNameInformation)
 {
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
+    NTSTATUS Status;
+    ULONG Length, ReturnLength;
+    POBJECT_NAME_INFORMATION LocalInfo;
+
+    /* Start with a buffer length of 200 */
+    ReturnLength = 200;
+    /*
+     * We'll loop until query works.
+     * We will use returned length for next loop
+     * iteration, trying to have a big enough buffer.
+     */
+    for (Length = 200; ; Length = ReturnLength)
+    {
+        /* Allocate our work buffer */
+        LocalInfo = ExAllocatePoolWithTag(PagedPool, Length, 'nDoI');
+        if (LocalInfo == NULL)
+        {
+            return STATUS_INSUFFICIENT_RESOURCES;
+        }
+
+        /* Query the DOS name */
+        Status = IopQueryNameInternal(FileObject,
+                                      TRUE,
+                                      TRUE,
+                                      LocalInfo,
+                                      Length,
+                                      &ReturnLength,
+                                      KernelMode);
+        /* If it succeed, nothing more to do */
+        if (Status == STATUS_SUCCESS)
+        {
+            break;
+        }
+
+        /* Otherwise, prepare for re-allocation */
+        ExFreePoolWithTag(LocalInfo, 'nDoI');
+
+        /*
+         * If we failed because of something else
+         * than memory, simply stop and fail here
+         */
+        if (Status != STATUS_BUFFER_OVERFLOW)
+        {
+            return Status;
+        }
+    }
+
+    /* Success case here: return our buffer */
+    *ObjectNameInformation = LocalInfo;
+    return STATUS_SUCCESS;
 }
 
 /*