Signed-off-by: Zebediah Figura z.figura12@gmail.com --- This patch series doesn't handle ntoskrnl device files. It is written with the ntoskrnl tests previously written in mind, and therefore is structured to make implementation somewhat easier, but the implementation is rather nontrivial and so far not known to be necessary.
The equivalent Staging patch uses the object tree for device files. At least two problems immediately arise from this: firstly, there is no clean way to distinguish the root file name '\' from the directly opened device (a distinction particularly important for file systems, but in fact even visible with named pipes); secondly, this cannot accomodate an implementation that must plumb requests through ntoskrnl, since object names are set at creation time. In general it also smacks of hacking a name into the object tree, since that name is not actually looked up directly as other names are.
Another possible design would be to handle it all on the server side. This would mean changing the parameters of get_file_info to handle arbitrary buffers (or else adding a new callback specifically for ObjectNameInformation). It would also mean making get_object_info eventually asynchronous. After trying out that approach, this one seemed architecturally simpler.
The equivalent Staging patch was originally written for msys2's strace.exe. msys2 and cygwin have been broken in Wine for a long time, perhaps unfixably. I'm not aware of other applications that need pipes, or similar objects, to return accurate names from ObjectNameInformation. I'm submitting this patch partly to upstream a long-standing Staging patch and fix tests, and partly because I believe it will help implementation of object/file name information for regular files with some of my local/planned changes to volume infrastructure.
server/change.c | 1 + server/console.c | 3 +++ server/device.c | 1 + server/fd.c | 5 +++++ server/file.c | 1 + server/file.h | 3 +++ server/mailslot.c | 3 +++ server/mapping.c | 1 + server/named_pipe.c | 3 +++ server/serial.c | 1 + server/sock.c | 2 ++ 11 files changed, 24 insertions(+)
diff --git a/server/change.c b/server/change.c index a8f3329c722..1eba2e4dd88 100644 --- a/server/change.c +++ b/server/change.c @@ -138,6 +138,7 @@ static const struct fd_ops dir_fd_ops = dir_get_poll_events, /* get_poll_events */ default_poll_event, /* poll_event */ dir_get_fd_type, /* get_fd_type */ + no_fd_get_parent, /* get_parent */ no_fd_read, /* read */ no_fd_write, /* write */ no_fd_flush, /* flush */ diff --git a/server/console.c b/server/console.c index 53910b3f46e..bd8cb1995e7 100644 --- a/server/console.c +++ b/server/console.c @@ -111,6 +111,7 @@ static const struct fd_ops console_input_fd_ops = default_fd_get_poll_events, /* get_poll_events */ default_poll_event, /* poll_event */ console_get_fd_type, /* get_fd_type */ + no_fd_get_parent, /* get_parent */ no_fd_read, /* read */ no_fd_write, /* write */ no_fd_flush, /* flush */ @@ -168,6 +169,7 @@ static const struct fd_ops console_input_events_fd_ops = default_fd_get_poll_events, /* get_poll_events */ default_poll_event, /* poll_event */ console_get_fd_type, /* get_fd_type */ + no_fd_get_parent, /* get_parent */ no_fd_read, /* read */ no_fd_write, /* write */ no_fd_flush, /* flush */ @@ -248,6 +250,7 @@ static const struct fd_ops screen_buffer_fd_ops = default_fd_get_poll_events, /* get_poll_events */ default_poll_event, /* poll_event */ console_get_fd_type, /* get_fd_type */ + no_fd_get_parent, /* get_parent */ no_fd_read, /* read */ no_fd_write, /* write */ no_fd_flush, /* flush */ diff --git a/server/device.c b/server/device.c index 01e08f295f7..73c6edcb078 100644 --- a/server/device.c +++ b/server/device.c @@ -219,6 +219,7 @@ static const struct fd_ops device_file_fd_ops = default_fd_get_poll_events, /* get_poll_events */ default_poll_event, /* poll_event */ device_file_get_fd_type, /* get_fd_type */ + no_fd_get_parent, /* get_parent */ device_file_read, /* read */ device_file_write, /* write */ device_file_flush, /* flush */ diff --git a/server/fd.c b/server/fd.c index 7ea8ac273e5..064defc34e8 100644 --- a/server/fd.c +++ b/server/fd.c @@ -2246,6 +2246,11 @@ static void unmount_device( struct fd *device_fd ) release_object( device ); }
+struct object *no_fd_get_parent( struct fd *fd ) +{ + return NULL; +} + /* default read() routine */ int no_fd_read( struct fd *fd, struct async *async, file_pos_t pos ) { diff --git a/server/file.c b/server/file.c index 38260cfd2b3..0b92d6aae46 100644 --- a/server/file.c +++ b/server/file.c @@ -105,6 +105,7 @@ static const struct fd_ops file_fd_ops = file_get_poll_events, /* get_poll_events */ default_poll_event, /* poll_event */ file_get_fd_type, /* get_fd_type */ + no_fd_get_parent, /* get_parent */ no_fd_read, /* read */ no_fd_write, /* write */ no_fd_flush, /* flush */ diff --git a/server/file.h b/server/file.h index e8ace7f49e4..b407c725db2 100644 --- a/server/file.h +++ b/server/file.h @@ -56,6 +56,8 @@ struct fd_ops void (*poll_event)(struct fd *,int event); /* get file information */ enum server_fd_type (*get_fd_type)(struct fd *fd); + /* get the parent (device) object */ + struct object *(*get_parent)(struct fd *fd); /* perform a read on the file */ int (*read)(struct fd *, struct async *, file_pos_t ); /* perform a write on the file */ @@ -109,6 +111,7 @@ extern void default_poll_event( struct fd *fd, int event ); extern void fd_queue_async( struct fd *fd, struct async *async, int type ); extern void fd_async_wake_up( struct fd *fd, int type, unsigned int status ); extern void fd_reselect_async( struct fd *fd, struct async_queue *queue ); +extern struct object *no_fd_get_parent( struct fd *fd ); extern int no_fd_read( struct fd *fd, struct async *async, file_pos_t pos ); extern int no_fd_write( struct fd *fd, struct async *async, file_pos_t pos ); extern int no_fd_flush( struct fd *fd, struct async *async ); diff --git a/server/mailslot.c b/server/mailslot.c index 58d650cbb25..03f5308fcbf 100644 --- a/server/mailslot.c +++ b/server/mailslot.c @@ -101,6 +101,7 @@ static const struct fd_ops mailslot_fd_ops = default_fd_get_poll_events, /* get_poll_events */ default_poll_event, /* poll_event */ mailslot_get_fd_type, /* get_fd_type */ + no_fd_get_parent, /* get_parent */ no_fd_read, /* read */ no_fd_write, /* write */ no_fd_flush, /* flush */ @@ -157,6 +158,7 @@ static const struct fd_ops mail_writer_fd_ops = default_fd_get_poll_events, /* get_poll_events */ default_poll_event, /* poll_event */ mail_writer_get_fd_type, /* get_fd_type */ + no_fd_get_parent, /* get_parent */ no_fd_read, /* read */ no_fd_write, /* write */ no_fd_flush, /* flush */ @@ -245,6 +247,7 @@ static const struct fd_ops mailslot_device_fd_ops = default_fd_get_poll_events, /* get_poll_events */ default_poll_event, /* poll_event */ mailslot_device_file_get_fd_type, /* get_fd_type */ + no_fd_get_parent, /* get_parent */ no_fd_read, /* read */ no_fd_write, /* write */ no_fd_flush, /* flush */ diff --git a/server/mapping.c b/server/mapping.c index db0debe0af5..5d0a1c402b5 100644 --- a/server/mapping.c +++ b/server/mapping.c @@ -180,6 +180,7 @@ static const struct fd_ops mapping_fd_ops = default_fd_get_poll_events, /* get_poll_events */ default_poll_event, /* poll_event */ mapping_get_fd_type, /* get_fd_type */ + no_fd_get_parent, /* get_parent */ no_fd_read, /* read */ no_fd_write, /* write */ no_fd_flush, /* flush */ diff --git a/server/named_pipe.c b/server/named_pipe.c index b259abb8de4..7eb0905293e 100644 --- a/server/named_pipe.c +++ b/server/named_pipe.c @@ -180,6 +180,7 @@ static const struct fd_ops pipe_server_fd_ops = default_fd_get_poll_events, /* get_poll_events */ default_poll_event, /* poll_event */ pipe_end_get_fd_type, /* get_fd_type */ + no_fd_get_parent, /* get_parent */ pipe_end_read, /* read */ pipe_end_write, /* write */ pipe_end_flush, /* flush */ @@ -222,6 +223,7 @@ static const struct fd_ops pipe_client_fd_ops = default_fd_get_poll_events, /* get_poll_events */ default_poll_event, /* poll_event */ pipe_end_get_fd_type, /* get_fd_type */ + no_fd_get_parent, /* get_parent */ pipe_end_read, /* read */ pipe_end_write, /* write */ pipe_end_flush, /* flush */ @@ -297,6 +299,7 @@ static const struct fd_ops named_pipe_device_fd_ops = default_fd_get_poll_events, /* get_poll_events */ default_poll_event, /* poll_event */ named_pipe_device_file_get_fd_type, /* get_fd_type */ + no_fd_get_parent, /* get_parent */ no_fd_read, /* read */ no_fd_write, /* write */ no_fd_flush, /* flush */ diff --git a/server/serial.c b/server/serial.c index 4292472613a..4d112b8c6ff 100644 --- a/server/serial.c +++ b/server/serial.c @@ -112,6 +112,7 @@ static const struct fd_ops serial_fd_ops = default_fd_get_poll_events, /* get_poll_events */ default_poll_event, /* poll_event */ serial_get_fd_type, /* get_fd_type */ + no_fd_get_parent, /* get_parent */ no_fd_read, /* read */ no_fd_write, /* write */ no_fd_flush, /* flush */ diff --git a/server/sock.c b/server/sock.c index 1a53ce4b091..9f33bc0b95c 100644 --- a/server/sock.c +++ b/server/sock.c @@ -164,6 +164,7 @@ static const struct fd_ops sock_fd_ops = sock_get_poll_events, /* get_poll_events */ sock_poll_event, /* poll_event */ sock_get_fd_type, /* get_fd_type */ + no_fd_get_parent, /* get_parent */ no_fd_read, /* read */ no_fd_write, /* write */ no_fd_flush, /* flush */ @@ -979,6 +980,7 @@ static const struct fd_ops ifchange_fd_ops = ifchange_get_poll_events, /* get_poll_events */ ifchange_poll_event, /* poll_event */ NULL, /* get_fd_type */ + no_fd_get_parent, /* get_parent */ no_fd_read, /* read */ no_fd_write, /* write */ no_fd_flush, /* flush */
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/ntdll/unix/file.c | 45 ++++++++++++++++++++++++++++++++++++++++++ server/fd.c | 5 +++++ server/file.h | 1 + server/handle.c | 16 ++++++++++++--- server/protocol.def | 1 + 5 files changed, 65 insertions(+), 3 deletions(-)
diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c index 03e92a5c59e..26643dfdb3a 100644 --- a/dlls/ntdll/unix/file.c +++ b/dlls/ntdll/unix/file.c @@ -6496,6 +6496,7 @@ NTSTATUS WINAPI NtQueryObject( HANDLE handle, OBJECT_INFORMATION_CLASS info_clas OBJECT_NAME_INFORMATION *p = ptr; char *unix_name; WCHAR *nt_name; + BOOL is_file = FALSE;
/* first try as a file object */
@@ -6530,6 +6531,7 @@ NTSTATUS WINAPI NtQueryObject( HANDLE handle, OBJECT_INFORMATION_CLASS info_clas status = wine_server_call( req ); if (status == STATUS_SUCCESS) { + is_file = reply->is_file; if (!reply->total) /* no name */ { if (sizeof(*p) > len) status = STATUS_INFO_LENGTH_MISMATCH; @@ -6553,6 +6555,49 @@ NTSTATUS WINAPI NtQueryObject( HANDLE handle, OBJECT_INFORMATION_CLASS info_clas } } SERVER_END_REQ; + + if ((!status || status == STATUS_INFO_LENGTH_MISMATCH) && is_file) + { + FILE_NAME_INFORMATION *file_name; + IO_STATUS_BLOCK io; + NTSTATUS file_status; + + if (!(file_name = malloc( sizeof(*file_name) + len ))) return STATUS_NO_MEMORY; + + file_status = NtQueryInformationFile( handle, &io, file_name, + sizeof(*file_name) + len, FileNameInformation ); + switch (file_status) + { + case STATUS_SUCCESS: + case STATUS_BUFFER_OVERFLOW: + if (!status) + { + ULONG file_size = file_name->FileNameLength; + if (sizeof(*p) + p->Name.MaximumLength + file_name->FileNameLength > len) + { + file_size = len - (sizeof(*p) + p->Name.MaximumLength); + status = STATUS_BUFFER_OVERFLOW; + } + memcpy( p->Name.Buffer + p->Name.Length / sizeof(WCHAR), file_name->FileName, file_size ); + p->Name.Length += file_size; + p->Name.MaximumLength += file_size; + p->Name.Buffer[p->Name.Length / sizeof(WCHAR)] = 0; + } + if (used_len) *used_len += file_name->FileNameLength; + break; + + case STATUS_INVALID_DEVICE_REQUEST: + case STATUS_INVALID_PARAMETER: + case STATUS_NOT_IMPLEMENTED: + break; + + default: + status = file_status; + } + + free( file_name ); + } + break; }
diff --git a/server/fd.c b/server/fd.c index 064defc34e8..52881b34dd6 100644 --- a/server/fd.c +++ b/server/fd.c @@ -2592,6 +2592,11 @@ void fd_copy_completion( struct fd *src, struct fd *dst ) dst->comp_flags = src->comp_flags; }
+struct object *get_fd_parent( struct fd *fd ) +{ + return fd->fd_ops->get_parent( fd ); +} + /* flush a file buffers */ DECL_HANDLER(flush) { diff --git a/server/file.h b/server/file.h index b407c725db2..b24f0b943ec 100644 --- a/server/file.h +++ b/server/file.h @@ -103,6 +103,7 @@ extern void allow_fd_caching( struct fd *fd ); extern void set_fd_signaled( struct fd *fd, int signaled ); extern int is_fd_signaled( struct fd *fd ); extern char *dup_fd_name( struct fd *root, const char *name ); +extern struct object *get_fd_parent( struct fd *fd );
extern int default_fd_signaled( struct object *obj, struct wait_queue_entry *entry ); extern unsigned int default_fd_map_access( struct object *obj, unsigned int access ); diff --git a/server/handle.c b/server/handle.c index 9ae99cd0c63..8f371770bdf 100644 --- a/server/handle.c +++ b/server/handle.c @@ -38,6 +38,7 @@ #include "thread.h" #include "security.h" #include "request.h" +#include "file.h"
struct handle_entry { @@ -661,15 +662,24 @@ DECL_HANDLER(dup_handle)
DECL_HANDLER(get_object_info) { - struct object *obj; - WCHAR *name; + struct object *obj, *parent = NULL; + struct fd *fd; + WCHAR *name = NULL;
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; reply->handle_count = obj->handle_count; - if ((name = get_object_full_name( obj, &reply->total ))) + if ((fd = get_obj_fd( obj ))) + { + parent = get_fd_parent( fd ); + release_object( fd ); + } + else + clear_error(); + reply->is_file = !!parent; + if ((name = get_object_full_name( parent ? parent : obj, &reply->total ))) set_reply_data_ptr( name, min( reply->total, get_reply_max_size() )); release_object( obj ); } diff --git a/server/protocol.def b/server/protocol.def index 1bbc8c5008f..d9944a24873 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -3364,6 +3364,7 @@ struct handle_info unsigned int ref_count; /* object ref count */ unsigned int handle_count; /* object handle count */ data_size_t total; /* total needed size for name */ + int is_file; /* is this object a file? */ VARARG(name,unicode_str); /* object name */ @END
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/ntdll/tests/om.c | 4 ++-- server/directory.c | 2 +- server/file.h | 2 ++ server/named_pipe.c | 20 +++++++++++++++++--- 4 files changed, 22 insertions(+), 6 deletions(-)
diff --git a/dlls/ntdll/tests/om.c b/dlls/ntdll/tests/om.c index a9da114cb5c..20028cf5e9a 100644 --- a/dlls/ntdll/tests/om.c +++ b/dlls/ntdll/tests/om.c @@ -1455,7 +1455,7 @@ static void test_query_object(void) 1, 1000, 1000, 1000, NULL ); ok( handle != INVALID_HANDLE_VALUE, "CreateNamedPipe failed err %u\n", GetLastError() );
- test_object_name( handle, L"\Device\NamedPipe\test_pipe", TRUE ); + test_object_name( handle, L"\Device\NamedPipe\test_pipe", FALSE ); test_object_type( handle, L"File" ); test_file_info( handle );
@@ -1472,7 +1472,7 @@ static void test_query_object(void) handle = CreateFileA( "\\.\pipe", 0, 0, NULL, OPEN_EXISTING, 0, 0 ); ok( handle != INVALID_HANDLE_VALUE, "CreateFile failed (%d)\n", GetLastError() );
- test_object_name( handle, L"\Device\NamedPipe", TRUE ); + test_object_name( handle, L"\Device\NamedPipe", FALSE ); test_object_type_todo( handle, L"File" ); test_file_info( handle );
diff --git a/server/directory.c b/server/directory.c index 198fc48ece2..e988ab8bad5 100644 --- a/server/directory.c +++ b/server/directory.c @@ -404,7 +404,7 @@ void init_directories(void) struct directory *dir_driver, *dir_device, *dir_global, *dir_kernel; struct object *link_dosdev, *link_global, *link_nul, *link_pipe, *link_mailslot; struct object *link_conin, *link_conout, *link_con; - struct object *named_pipe_device, *mailslot_device, *null_device, *user_data_mapping, *console_device; + struct object *mailslot_device, *null_device, *user_data_mapping, *console_device; struct keyed_event *keyed_event; unsigned int i;
diff --git a/server/file.h b/server/file.h index b24f0b943ec..d869c53cdbc 100644 --- a/server/file.h +++ b/server/file.h @@ -181,6 +181,8 @@ extern struct object *create_user_data_mapping( struct object *root, const struc
/* device functions */
+extern struct object *named_pipe_device; + extern struct object *create_named_pipe_device( struct object *root, const struct unicode_str *name ); extern struct object *create_mailslot_device( struct object *root, const struct unicode_str *name ); extern struct object *create_console_device( struct object *root, const struct unicode_str *name ); diff --git a/server/named_pipe.c b/server/named_pipe.c index 7eb0905293e..2a6a341b24c 100644 --- a/server/named_pipe.c +++ b/server/named_pipe.c @@ -42,6 +42,8 @@ #include "security.h" #include "process.h"
+struct object *named_pipe_device; + struct named_pipe;
struct pipe_message @@ -136,6 +138,7 @@ static const struct object_ops named_pipe_ops = /* common server and client pipe end functions */ static void pipe_end_destroy( struct object *obj ); static enum server_fd_type pipe_end_get_fd_type( struct fd *fd ); +static struct object *pipe_end_get_parent( struct fd *fd ); static struct fd *pipe_end_get_fd( struct object *obj ); static struct security_descriptor *pipe_end_get_sd( struct object *obj ); static int pipe_end_set_sd( struct object *obj, const struct security_descriptor *sd, @@ -180,7 +183,7 @@ static const struct fd_ops pipe_server_fd_ops = default_fd_get_poll_events, /* get_poll_events */ default_poll_event, /* poll_event */ pipe_end_get_fd_type, /* get_fd_type */ - no_fd_get_parent, /* get_parent */ + pipe_end_get_parent, /* get_parent */ pipe_end_read, /* read */ pipe_end_write, /* write */ pipe_end_flush, /* flush */ @@ -223,7 +226,7 @@ static const struct fd_ops pipe_client_fd_ops = default_fd_get_poll_events, /* get_poll_events */ default_poll_event, /* poll_event */ pipe_end_get_fd_type, /* get_fd_type */ - no_fd_get_parent, /* get_parent */ + pipe_end_get_parent, /* get_parent */ pipe_end_read, /* read */ pipe_end_write, /* write */ pipe_end_flush, /* flush */ @@ -269,6 +272,7 @@ static void named_pipe_device_file_dump( struct object *obj, int verbose ); static struct fd *named_pipe_device_file_get_fd( struct object *obj ); static int named_pipe_device_ioctl( struct fd *fd, ioctl_code_t code, struct async *async ); static enum server_fd_type named_pipe_device_file_get_fd_type( struct fd *fd ); +static struct object *named_pipe_device_file_get_parent( struct fd *fd ); static void named_pipe_device_file_destroy( struct object *obj );
static const struct object_ops named_pipe_device_file_ops = @@ -299,7 +303,7 @@ static const struct fd_ops named_pipe_device_fd_ops = default_fd_get_poll_events, /* get_poll_events */ default_poll_event, /* poll_event */ named_pipe_device_file_get_fd_type, /* get_fd_type */ - no_fd_get_parent, /* get_parent */ + named_pipe_device_file_get_parent, /* get_parent */ no_fd_read, /* read */ no_fd_write, /* write */ no_fd_flush, /* flush */ @@ -538,6 +542,11 @@ static enum server_fd_type named_pipe_device_file_get_fd_type( struct fd *fd ) return FD_TYPE_DEVICE; }
+static struct object *named_pipe_device_file_get_parent( struct fd *fd ) +{ + return named_pipe_device; +} + static void named_pipe_device_file_destroy( struct object *obj ) { struct named_pipe_device_file *file = (struct named_pipe_device_file*)obj; @@ -936,6 +945,11 @@ static enum server_fd_type pipe_end_get_fd_type( struct fd *fd ) return FD_TYPE_PIPE; }
+static struct object *pipe_end_get_parent( struct fd *fd ) +{ + return named_pipe_device; +} + static int pipe_end_peek( struct pipe_end *pipe_end ) { unsigned reply_size = get_reply_max_size();