From 0a48bfe79a890ff6ea070b9c5328533fb772c64f Mon Sep 17 00:00:00 2001 From: Philip Withnall Date: Wed, 13 Nov 2024 13:21:44 +0000 Subject: [PATCH] tests: Factor out a function to convert FD to path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This could potentially eventually become a public GLib API, but there doesn’t seem to be a huge need for it right now (e.g. this file contains the only use of `/proc/self/fd/%d` in GLib), so let’s keep it private for now and avoid committing to API stability just yet. This gives time for other platforms to add their platform-specific implementations for it too, if they need. I’ve added a couple of pointers to what I *think* the right APIs might be, from my research, but I have not prototyped those implementations. Signed-off-by: Philip Withnall --- gio/tests/fake-desktop-portal.c | 54 ++++++++++++++++++++++++--------- 1 file changed, 40 insertions(+), 14 deletions(-) diff --git a/gio/tests/fake-desktop-portal.c b/gio/tests/fake-desktop-portal.c index 4cba067d3..cb38b9ddc 100644 --- a/gio/tests/fake-desktop-portal.c +++ b/gio/tests/fake-desktop-portal.c @@ -206,15 +206,52 @@ handle_request (GFakeDesktopPortalThread *self, return G_DBUS_METHOD_INVOCATION_HANDLED; } +/* This is currently private as there’s only one user of it, but it could become + * a public API in future. */ +static char * +_g_fd_query_path (int fd, + GError **error) +{ +#if defined(__FreeBSD__) + struct kinfo_file kf; + kf.kf_structsize = sizeof (kf); + if (fcntl (fd, F_KINFO, &kf) < 0) + { + int saved_errno = errno; + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Error querying file information for FD %d: %s", + fd, g_strerror (saved_errno)); + return NULL; + } + + return g_strdup (kf.kf_path); +#elif defined(G_OS_UNIX) + char *path = NULL; + char *proc_path = g_strdup_printf ("/proc/self/fd/%d", fd); + path = g_file_read_link (proc_path, error); + g_free (proc_path); + return g_steal_pointer (&path); +#else + /* - A NetBSD implementation would probably use `fcntl()` with `F_GETPATH`: + * https://man.netbsd.org/fcntl.2 + * - A Windows implementation would probably use `GetFinalPathNameByHandleW()`: + * https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfinalpathnamebyhandlea + * - A Hurd implementation could open("/dev/fd/%u"): + * https://gitlab.gnome.org/GNOME/glib/-/merge_requests/4396#note_2279923 + */ + #error "_g_fd_query_path() not supported on this platform" +#endif +} + static char * handle_to_uri (GVariant *handle, GUnixFDList *fd_list) { int fd = -1; int fd_id; - char *proc_path = NULL; char *path; char *uri; + GError *local_error = NULL; fd_id = g_variant_get_handle (handle); fd = g_unix_fd_list_get (fd_list, fd_id, NULL); @@ -222,21 +259,10 @@ handle_to_uri (GVariant *handle, if (fd == -1) return NULL; -#ifdef __FreeBSD__ - struct kinfo_file kf; - kf.kf_structsize = sizeof (kf); - if (fcntl (fd, F_KINFO, &kf) == -1) - return NULL; - path = g_strdup (kf.kf_path); - -#else - proc_path = g_strdup_printf ("/proc/self/fd/%d", fd); - path = g_file_read_link (proc_path, NULL); -#endif - g_assert_nonnull (path); + path = _g_fd_query_path (fd, &local_error); + g_assert_no_error (local_error); uri = g_filename_to_uri (path, NULL, NULL); - g_free (proc_path); g_free (path); close (fd);