server: Implement the \??\GLOBALROOT symbolic link.

\??\GLOBALROOT is a well-known NT symbolic link that allows applications
to access the NT object manager's root namespace via Win32 APIs.

Signed-off-by: Jinoh Kang <jinoh.kang.kr@gmail.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Jinoh Kang 2021-11-25 01:29:29 +09:00 committed by Alexandre Julliard
parent 9f0df41a6c
commit 3b37584316
4 changed files with 77 additions and 0 deletions

View File

@ -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();
}

View File

@ -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 ));

View File

@ -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 );

View File

@ -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 )