[PATCH] kernel32: CreateDirectory shouldn't return ERROR_ACCESS_DENIED for the root of the drive.

Dmitry Timoshkov dmitry at baikal.ru
Tue Dec 11 04:03:32 CST 2018


According to the testbot results CreateDirectory("C:\\", NULL) fails
with ERROR_ACCESS_DENIED for not administrators. However with UAC enabled
and not and administrator account I get ERROR_ALREADY_EXISTS in that case
with Windows 7 64-bit running on real hardware. Moreover, Wine doesn't
really perform any access checks in that case and blindly assumes that
returning STATUS_ACCESS_DENIED is correct behaviour for the drive's root:
dlls/ntdll/directory.c,lookup_unix_name().

This patch fixes an application that can't find its data files because
after it receives ERROR_ACCESS_DENIED it stops further directory traversing.

Signed-off-by: Dmitry Timoshkov <dmitry at baikal.ru>
---
 dlls/kernel32/tests/directory.c | 43 +++++++++++++++++++++++++++++++++
 dlls/ntdll/directory.c          |  3 +--
 2 files changed, 44 insertions(+), 2 deletions(-)

diff --git a/dlls/kernel32/tests/directory.c b/dlls/kernel32/tests/directory.c
index 512dc6d22a..de78c61681 100644
--- a/dlls/kernel32/tests/directory.c
+++ b/dlls/kernel32/tests/directory.c
@@ -541,10 +541,53 @@ static void test_SetCurrentDirectoryA(void)
     ok( GetLastError() == ERROR_PATH_NOT_FOUND, "wrong error %d\n", GetLastError() );
 }
 
+static void test_CreateDirectory_root(void)
+{
+    static const WCHAR drive_c_root[] = { 'C',':','\\',0 };
+    static const WCHAR drive_c[] = { 'C',':',0 };
+    char curdir[MAX_PATH];
+    BOOL ret;
+
+    GetCurrentDirectoryA(sizeof(curdir), curdir);
+
+    ret = SetCurrentDirectoryA("C:\\");
+    ok(ret, "SetCurrentDirectory error %u\n", GetLastError());
+
+    SetLastError(0xdeadbeef);
+    ret = CreateDirectoryA("C:\\", NULL);
+    ok(!ret, "CreateDirectory should fail\n");
+    if (GetLastError() == ERROR_ACCESS_DENIED)
+    {
+        win_skip("not an administrator\n");
+        SetCurrentDirectoryA(curdir);
+        return;
+    }
+    ok(GetLastError() == ERROR_ALREADY_EXISTS, "got %u\n", GetLastError());
+
+    SetLastError(0xdeadbeef);
+    ret = CreateDirectoryA("C:", NULL);
+    ok(!ret, "CreateDirectory should fail\n");
+    ok(GetLastError() == ERROR_ALREADY_EXISTS, "got %u\n", GetLastError());
+
+    SetLastError(0xdeadbeef);
+    ret = CreateDirectoryW(drive_c_root, NULL);
+    ok(!ret, "CreateDirectory should fail\n");
+    ok(GetLastError() == ERROR_ALREADY_EXISTS, "got %u\n", GetLastError());
+
+    SetLastError(0xdeadbeef);
+    ret = CreateDirectoryW(drive_c, NULL);
+    ok(!ret, "CreateDirectory should fail\n");
+    ok(GetLastError() == ERROR_ALREADY_EXISTS, "got %u\n", GetLastError());
+
+    SetCurrentDirectoryA(curdir);
+}
+
 START_TEST(directory)
 {
     init();
 
+    test_CreateDirectory_root();
+
     test_GetWindowsDirectoryA();
     test_GetWindowsDirectoryW();
 
diff --git a/dlls/ntdll/directory.c b/dlls/ntdll/directory.c
index c48b9e97ea..2719958f67 100644
--- a/dlls/ntdll/directory.c
+++ b/dlls/ntdll/directory.c
@@ -2650,9 +2650,8 @@ static NTSTATUS lookup_unix_name( const WCHAR *name, int name_len, char **buffer
         {
             if (!stat( unix_name, &st ))
             {
-                /* creation fails with STATUS_ACCESS_DENIED for the root of the drive */
                 if (disposition == FILE_CREATE)
-                    return name_len ? STATUS_OBJECT_NAME_COLLISION : STATUS_ACCESS_DENIED;
+                    return STATUS_OBJECT_NAME_COLLISION;
                 return STATUS_SUCCESS;
             }
         }
-- 
2.19.2




More information about the wine-devel mailing list