diff --git a/dlls/ntdll/tests/om.c b/dlls/ntdll/tests/om.c index 77eb58a23b5..250984ebdda 100644 --- a/dlls/ntdll/tests/om.c +++ b/dlls/ntdll/tests/om.c @@ -2388,6 +2388,64 @@ static void test_get_next_thread(void) CloseHandle(thread); } +static void test_globalroot(void) +{ + NTSTATUS status; + IO_STATUS_BLOCK iosb; + UNICODE_STRING str; + OBJECT_ATTRIBUTES attr; + HANDLE h; + WCHAR buffer[256]; + ULONG len, full_len, i; + static const struct { const WCHAR *name, *target; } symlinks[] = { + { L"\\??\\GLOBALROOT", L"" }, + { L"\\??\\GLOBALROOT\\??\\GLOBALROOT", L"" }, + { L"\\??\\GLOBALROOT\\??\\GLOBALROOT\\??\\GLOBALROOT", L"" }, + { L"\\??\\GLOBALROOT\\DosDevices", L"\\??" }, + { L"\\??\\GLOBALROOT\\BaseNamedObjects\\Global", NULL }, + }; + + for (i = 0; i < ARRAY_SIZE(symlinks); i++) + { + pRtlInitUnicodeString(&str, symlinks[i].name); + InitializeObjectAttributes(&attr, &str, 0, 0, NULL); + status = pNtOpenSymbolicLinkObject( &h, SYMBOLIC_LINK_QUERY, &attr ); + ok(status == STATUS_SUCCESS, "NtOpenSymbolicLinkObject failed %08x\n", status); + + str.Buffer = buffer; + str.MaximumLength = sizeof(buffer); + len = 0xdeadbeef; + memset( buffer, 0xaa, sizeof(buffer) ); + status = pNtQuerySymbolicLinkObject( h, &str, &len); + ok( status == STATUS_SUCCESS, "NtQuerySymbolicLinkObject failed %08x\n", status ); + full_len = str.Length + sizeof(WCHAR); + ok( len == full_len, "bad length %u (expected %u)\n", len, full_len ); + ok( buffer[len / sizeof(WCHAR) - 1] == 0, "no terminating null\n" ); + + if (symlinks[i].target) + { + ok( compare_unicode_string( &str, symlinks[i].target ), + "symlink %s: target expected %s, got %s\n", + debugstr_w( symlinks[i].name ), + debugstr_w( symlinks[i].target ), + debugstr_w( str.Buffer ) ); + } + + pNtClose(h); + } + + pRtlInitUnicodeString(&str, L"\\??\\GLOBALROOT\\Device\\Null"); + InitializeObjectAttributes(&attr, &str, OBJ_CASE_INSENSITIVE, 0, NULL); + status = pNtOpenFile(&h, GENERIC_READ | GENERIC_WRITE, &attr, &iosb, + FILE_SHARE_READ | FILE_SHARE_WRITE, 0); + ok(status == STATUS_SUCCESS, + "expected STATUS_SUCCESS, got %08x\n", status); + + test_object_type(h, L"File"); + + pNtClose(h); +} + START_TEST(om) { HMODULE hntdll = GetModuleHandleA("ntdll.dll"); @@ -2446,4 +2504,5 @@ START_TEST(om) test_duplicate_object(); test_object_types(); test_get_next_thread(); + test_globalroot(); } diff --git a/server/directory.c b/server/directory.c index 70a34d3f1bb..2cd61be0838 100644 --- a/server/directory.c +++ b/server/directory.c @@ -378,6 +378,7 @@ void init_directories( struct fd *intl_fd ) /* symlinks */ static const WCHAR link_dosdevW[] = {'D','o','s','D','e','v','i','c','e','s'}; + static const WCHAR link_globalrootW[] = {'G','L','O','B','A','L','R','O','O','T'}; static const WCHAR link_globalW[] = {'G','l','o','b','a','l'}; static const WCHAR link_nulW[] = {'N','U','L'}; static const WCHAR link_pipeW[] = {'P','I','P','E'}; @@ -392,6 +393,7 @@ void init_directories( struct fd *intl_fd ) static const WCHAR link_consoleW[] = {'\\','D','e','v','i','c','e','\\','C','o','n','D','r','v', '\\','C','o','n','s','o','l','e'}; static const struct unicode_str link_dosdev_str = {link_dosdevW, sizeof(link_dosdevW)}; + static const struct unicode_str link_globalroot_str = {link_globalrootW, sizeof(link_globalrootW)}; static const struct unicode_str link_global_str = {link_globalW, sizeof(link_globalW)}; static const struct unicode_str link_nul_str = {link_nulW, sizeof(link_nulW)}; static const struct unicode_str link_pipe_str = {link_pipeW, sizeof(link_pipeW)}; @@ -470,6 +472,7 @@ void init_directories( struct fd *intl_fd ) /* symlinks */ release_object( create_obj_symlink( &root_directory->obj, &link_dosdev_str, OBJ_PERMANENT, &dir_global->obj, NULL )); + release_object( create_root_symlink( &dir_global->obj, &link_globalroot_str, OBJ_PERMANENT, NULL )); release_object( create_obj_symlink( &dir_global->obj, &link_global_str, OBJ_PERMANENT, &dir_global->obj, NULL )); release_object( create_obj_symlink( &dir_global->obj, &link_nul_str, OBJ_PERMANENT, null_device, NULL )); release_object( create_obj_symlink( &dir_global->obj, &link_pipe_str, OBJ_PERMANENT, named_pipe_device, NULL )); diff --git a/server/object.h b/server/object.h index 97d6c0e91f8..f156f1d2f13 100644 --- a/server/object.h +++ b/server/object.h @@ -279,6 +279,8 @@ extern void init_directories( struct fd *intl_fd ); /* symbolic link functions */ +extern struct object *create_root_symlink( struct object *root, const struct unicode_str *name, + unsigned int attr, const struct security_descriptor *sd ); extern struct object *create_obj_symlink( struct object *root, const struct unicode_str *name, unsigned int attr, struct object *target, const struct security_descriptor *sd ); diff --git a/server/symlink.c b/server/symlink.c index fa97d9155fa..27d48e2f994 100644 --- a/server/symlink.c +++ b/server/symlink.c @@ -110,6 +110,8 @@ static struct object *symlink_lookup_name( struct object *obj, struct unicode_st if (!name->len && (attr & OBJ_OPENLINK)) return NULL; if (obj == root) return NULL; + if (!symlink->len) return get_root_directory(); + target_str.str = symlink->target; target_str.len = symlink->len; if ((target = lookup_named_object( NULL, &target_str, attr, &name_left ))) @@ -131,6 +133,17 @@ static void symlink_destroy( struct object *obj ) free( symlink->target ); } +struct object *create_root_symlink( struct object *root, const struct unicode_str *name, + unsigned int attr, const struct security_descriptor *sd ) +{ + struct symlink *symlink; + + if (!(symlink = create_named_object( root, &symlink_ops, name, attr, sd ))) return NULL; + symlink->target = NULL; + symlink->len = 0; + return &symlink->obj; +} + struct object *create_symlink( struct object *root, const struct unicode_str *name, unsigned int attr, const struct unicode_str *target, const struct security_descriptor *sd )