server: Add support for returning the object name in NtQueryObject.
diff --git a/dlls/ntdll/om.c b/dlls/ntdll/om.c
index c2567be..e9677d0 100644
--- a/dlls/ntdll/om.c
+++ b/dlls/ntdll/om.c
@@ -85,6 +85,42 @@
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 d5cf158..cf9a1a5 100644
--- a/dlls/ntdll/tests/om.c
+++ b/dlls/ntdll/tests/om.c
@@ -44,6 +44,7 @@
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 @@
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 @@
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 6a860df..47c032e 100644
--- a/include/wine/server_protocol.h
+++ b/include/wine/server_protocol.h
@@ -4349,6 +4349,9 @@
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 @@
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 3baaa6d..4e52f0e 100644
--- a/server/handle.c
+++ b/server/handle.c
@@ -593,11 +593,14 @@
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 f08548c..d2a3930 100644
--- a/server/object.c
+++ b/server/object.c
@@ -171,6 +171,35 @@
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 a5d0ffd..01dc00e 100644
--- a/server/object.h
+++ b/server/object.h
@@ -115,6 +115,7 @@
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 bba6788..04f6e2b 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -3061,6 +3061,8 @@
@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 ca5fc88..41c6409 100644
--- a/server/request.h
+++ b/server/request.h
@@ -1817,7 +1817,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 df47e8f..03e4c04 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -3600,6 +3600,8 @@
{
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 )