diff --git a/dlls/ntdll/om.c b/dlls/ntdll/om.c index c2567be3a9c..e9677d0c18f 100644 --- a/dlls/ntdll/om.c +++ b/dlls/ntdll/om.c @@ -85,6 +85,42 @@ NTSTATUS WINAPI NtQueryObject(IN HANDLE handle, SERVER_END_REQ; } break; + case ObjectNameInformation: + { + OBJECT_NAME_INFORMATION* p = ptr; + + SERVER_START_REQ( get_object_info ) + { + req->handle = wine_server_obj_handle( handle ); + if (len > sizeof(*p)) wine_server_set_reply( req, p + 1, len - sizeof(*p) ); + status = wine_server_call( req ); + if (status == STATUS_SUCCESS) + { + if (!reply->total) /* no name */ + { + if (sizeof(*p) > len) status = STATUS_INFO_LENGTH_MISMATCH; + else memset( p, 0, sizeof(*p) ); + if (used_len) *used_len = sizeof(*p); + } + else if (sizeof(*p) + reply->total + sizeof(WCHAR) > len) + { + if (used_len) *used_len = sizeof(*p) + reply->total + sizeof(WCHAR); + status = STATUS_INFO_LENGTH_MISMATCH; + } + else + { + ULONG res = wine_server_reply_size( reply ); + p->Name.Buffer = (WCHAR *)(p + 1); + p->Name.Length = res; + p->Name.MaximumLength = res + sizeof(WCHAR); + p->Name.Buffer[res / sizeof(WCHAR)] = 0; + if (used_len) *used_len = sizeof(*p) + p->Name.MaximumLength; + } + } + } + SERVER_END_REQ; + } + break; case ObjectDataInformation: { OBJECT_DATA_INFORMATION* p = ptr; diff --git a/dlls/ntdll/tests/om.c b/dlls/ntdll/tests/om.c index d5cf158a80b..cf9a1a54757 100644 --- a/dlls/ntdll/tests/om.c +++ b/dlls/ntdll/tests/om.c @@ -44,6 +44,7 @@ static NTSTATUS (WINAPI *pNtOpenDirectoryObject)(PHANDLE, ACCESS_MASK, POBJECT_A static NTSTATUS (WINAPI *pNtCreateDirectoryObject)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES); static NTSTATUS (WINAPI *pNtOpenSymbolicLinkObject)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES); static NTSTATUS (WINAPI *pNtCreateSymbolicLinkObject)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, PUNICODE_STRING); +static NTSTATUS (WINAPI *pNtQueryObject)(HANDLE,OBJECT_INFORMATION_CLASS,PVOID,ULONG,PULONG); static void test_case_sensitive (void) @@ -617,6 +618,57 @@ static void test_symboliclink(void) pNtClose(dir); } +static void test_query_object(void) +{ + static const WCHAR name[] = {'\\','B','a','s','e','N','a','m','e','d','O','b','j','e','c','t','s', + '\\','t','e','s','t','_','e','v','e','n','t'}; + HANDLE handle; + char buffer[1024]; + NTSTATUS status; + ULONG len; + UNICODE_STRING *str; + + handle = CreateEventA( NULL, FALSE, FALSE, "test_event" ); + + len = 0; + status = pNtQueryObject( handle, ObjectNameInformation, buffer, 0, &len ); + ok( status == STATUS_INFO_LENGTH_MISMATCH, "NtQueryObject failed %x\n", status ); + ok( len >= sizeof(UNICODE_STRING) + sizeof(name) + sizeof(WCHAR), "unexpected len %u\n", len ); + + len = 0; + status = pNtQueryObject( handle, ObjectNameInformation, buffer, sizeof(UNICODE_STRING), &len ); + ok( status == STATUS_INFO_LENGTH_MISMATCH, "NtQueryObject failed %x\n", status ); + ok( len >= sizeof(UNICODE_STRING) + sizeof(name) + sizeof(WCHAR), "unexpected len %u\n", len ); + + len = 0; + status = pNtQueryObject( handle, ObjectNameInformation, buffer, sizeof(buffer), &len ); + ok( status == STATUS_SUCCESS, "NtQueryObject failed %x\n", status ); + ok( len > sizeof(UNICODE_STRING), "unexpected len %u\n", len ); + str = (UNICODE_STRING *)buffer; + ok( sizeof(UNICODE_STRING) + str->Length + sizeof(WCHAR) == len, "unexpected len %u\n", len ); + ok( str->Length >= sizeof(name), "unexpected len %u\n", str->Length ); + /* there can be a \\Sessions prefix in the name */ + ok( !memcmp( str->Buffer + (str->Length - sizeof(name)) / sizeof(WCHAR), name, sizeof(name) ), + "wrong name %s\n", wine_dbgstr_w(str->Buffer) ); + + len -= sizeof(WCHAR); + status = pNtQueryObject( handle, ObjectNameInformation, buffer, len, &len ); + ok( status == STATUS_INFO_LENGTH_MISMATCH, "NtQueryObject failed %x\n", status ); + ok( len >= sizeof(UNICODE_STRING) + sizeof(name) + sizeof(WCHAR), "unexpected len %u\n", len ); + + pNtClose( handle ); + + handle = CreateEventA( NULL, FALSE, FALSE, NULL ); + len = 0; + status = pNtQueryObject( handle, ObjectNameInformation, buffer, sizeof(buffer), &len ); + ok( status == STATUS_SUCCESS, "NtQueryObject failed %x\n", status ); + ok( len == sizeof(UNICODE_STRING), "unexpected len %u\n", len ); + str = (UNICODE_STRING *)buffer; + ok( str->Length == 0, "unexpected len %u\n", len ); + ok( str->Buffer == NULL, "unexpected ptr %p\n", str->Buffer ); + pNtClose( handle ); +} + START_TEST(om) { HMODULE hntdll = GetModuleHandleA("ntdll.dll"); @@ -646,10 +698,12 @@ START_TEST(om) pNtCreateSemaphore = (void *)GetProcAddress(hntdll, "NtCreateSemaphore"); pNtCreateTimer = (void *)GetProcAddress(hntdll, "NtCreateTimer"); pNtCreateSection = (void *)GetProcAddress(hntdll, "NtCreateSection"); + pNtQueryObject = (void *)GetProcAddress(hntdll, "NtQueryObject"); test_case_sensitive(); test_namespace_pipe(); test_name_collisions(); test_directory(); test_symboliclink(); + test_query_object(); } diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index 6a860dfc53a..47c032e728e 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -4349,6 +4349,9 @@ struct get_object_info_reply struct reply_header __header; unsigned int access; unsigned int ref_count; + data_size_t total; + /* VARARG(name,unicode_str); */ + char __pad_20[4]; }; @@ -5394,6 +5397,6 @@ union generic_reply struct free_user_handle_reply free_user_handle_reply; }; -#define SERVER_PROTOCOL_VERSION 394 +#define SERVER_PROTOCOL_VERSION 395 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */ diff --git a/server/handle.c b/server/handle.c index 3baaa6d442e..4e52f0ed1cc 100644 --- a/server/handle.c +++ b/server/handle.c @@ -593,11 +593,14 @@ DECL_HANDLER(dup_handle) DECL_HANDLER(get_object_info) { struct object *obj; + WCHAR *name; if (!(obj = get_handle_obj( current->process, req->handle, 0, NULL ))) return; reply->access = get_handle_access( current->process, req->handle ); reply->ref_count = obj->refcount; + if ((name = get_object_full_name( obj, &reply->total ))) + set_reply_data_ptr( name, min( reply->total, get_reply_max_size() )); release_object( obj ); } diff --git a/server/object.c b/server/object.c index f08548c2127..d2a3930643d 100644 --- a/server/object.c +++ b/server/object.c @@ -171,6 +171,35 @@ const WCHAR *get_object_name( struct object *obj, data_size_t *len ) return ptr->name; } +/* get the full path name of an existing object */ +WCHAR *get_object_full_name( struct object *obj, data_size_t *ret_len ) +{ + static const WCHAR backslash = '\\'; + struct object *ptr = obj; + data_size_t len = 0; + char *ret; + + while (ptr && ptr->name) + { + struct object_name *name = ptr->name; + len += name->len + sizeof(WCHAR); + ptr = name->parent; + } + if (!len) return NULL; + if (!(ret = malloc( len ))) return NULL; + + *ret_len = len; + while (obj && obj->name) + { + struct object_name *name = obj->name; + memcpy( ret + len - name->len, name->name, name->len ); + len -= name->len + sizeof(WCHAR); + memcpy( ret + len, &backslash, sizeof(WCHAR) ); + obj = name->parent; + } + return (WCHAR *)ret; +} + /* allocate and initialize an object */ void *alloc_object( const struct object_ops *ops ) { diff --git a/server/object.h b/server/object.h index a5d0ffd304c..01dc00ea93a 100644 --- a/server/object.h +++ b/server/object.h @@ -115,6 +115,7 @@ extern void *mem_alloc( size_t size ); /* malloc wrapper */ extern void *memdup( const void *data, size_t len ); extern void *alloc_object( const struct object_ops *ops ); extern const WCHAR *get_object_name( struct object *obj, data_size_t *len ); +extern WCHAR *get_object_full_name( struct object *obj, data_size_t *ret_len ); extern void dump_object_name( struct object *obj ); extern void *create_object( struct namespace *namespace, const struct object_ops *ops, const struct unicode_str *name, struct object *parent ); diff --git a/server/protocol.def b/server/protocol.def index bba6788da3d..04f6e2ba891 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -3061,6 +3061,8 @@ enum message_type @REPLY unsigned int access; /* granted access mask */ unsigned int ref_count; /* object ref count */ + data_size_t total; /* total needed size for name */ + VARARG(name,unicode_str); /* object name */ @END diff --git a/server/request.h b/server/request.h index ca5fc88ed30..41c64091eb8 100644 --- a/server/request.h +++ b/server/request.h @@ -1817,7 +1817,8 @@ C_ASSERT( sizeof(struct query_symlink_reply) == 8 ); C_ASSERT( FIELD_OFFSET(struct get_object_info_request, handle) == 12 ); C_ASSERT( FIELD_OFFSET(struct get_object_info_reply, access) == 8 ); C_ASSERT( FIELD_OFFSET(struct get_object_info_reply, ref_count) == 12 ); -C_ASSERT( sizeof(struct get_object_info_reply) == 16 ); +C_ASSERT( FIELD_OFFSET(struct get_object_info_reply, total) == 16 ); +C_ASSERT( sizeof(struct get_object_info_reply) == 24 ); C_ASSERT( FIELD_OFFSET(struct unlink_object_request, handle) == 12 ); C_ASSERT( sizeof(struct unlink_object_request) == 16 ); C_ASSERT( FIELD_OFFSET(struct get_token_impersonation_level_request, handle) == 12 ); diff --git a/server/trace.c b/server/trace.c index df47e8f06e4..03e4c04437e 100644 --- a/server/trace.c +++ b/server/trace.c @@ -3600,6 +3600,8 @@ static void dump_get_object_info_reply( const struct get_object_info_reply *req { fprintf( stderr, " access=%08x", req->access ); fprintf( stderr, ", ref_count=%08x", req->ref_count ); + fprintf( stderr, ", total=%u", req->total ); + dump_varargs_unicode_str( ", name=", cur_size ); } static void dump_unlink_object_request( const struct unlink_object_request *req )