diff --git a/steam-runtime-tools/resolve-in-sysroot-internal.h b/steam-runtime-tools/resolve-in-sysroot-internal.h index 5eb4fcef64a3204e3d614964d0058d4c64e8af22..7d47024e76d347b474ebdea332486d4dbc93a10f 100644 --- a/steam-runtime-tools/resolve-in-sysroot-internal.h +++ b/steam-runtime-tools/resolve-in-sysroot-internal.h @@ -32,6 +32,8 @@ * the path is a symlink, fail with %G_IO_ERROR_TOO_MANY_LINKS. * @SRT_RESOLVE_FLAGS_READABLE: Open the last component of the path * for reading, instead of just as `O_PATH`. + * @SRT_RESOLVE_FLAGS_DIRECTORY: Open the last component of the path + * for reading, and it must be a directory. * @SRT_RESOLVE_FLAGS_NONE: No special behaviour. * * Flags affecting how _srt_resolve_in_sysroot() behaves. @@ -42,6 +44,7 @@ typedef enum SRT_RESOLVE_FLAGS_KEEP_FINAL_SYMLINK = (1 << 1), SRT_RESOLVE_FLAGS_REJECT_SYMLINKS = (1 << 2), SRT_RESOLVE_FLAGS_READABLE = (1 << 3), + SRT_RESOLVE_FLAGS_DIRECTORY = (1 << 4), SRT_RESOLVE_FLAGS_NONE = 0 } SrtResolveFlags; diff --git a/steam-runtime-tools/resolve-in-sysroot.c b/steam-runtime-tools/resolve-in-sysroot.c index 28eaffbfcddd34c428d4aea1e313775edcc39a91..21965157ee34bc16262527ab77dfc6487fe2496e 100644 --- a/steam-runtime-tools/resolve-in-sysroot.c +++ b/steam-runtime-tools/resolve-in-sysroot.c @@ -303,15 +303,23 @@ _srt_resolve_in_sysroot (int sysroot, } } - if (flags & SRT_RESOLVE_FLAGS_READABLE) + if (flags & (SRT_RESOLVE_FLAGS_READABLE|SRT_RESOLVE_FLAGS_DIRECTORY)) { g_autofree char *proc_fd_name = g_strdup_printf ("/proc/self/fd/%d", g_array_index (fds, int, fds->len - 1)); glnx_autofd int fd = -1; - if (!glnx_openat_rdonly (-1, proc_fd_name, TRUE, &fd, error)) - return -1; + if (flags & SRT_RESOLVE_FLAGS_DIRECTORY) + { + if (!glnx_opendirat (-1, proc_fd_name, TRUE, &fd, error)) + return -1; + } + else + { + if (!glnx_openat_rdonly (-1, proc_fd_name, TRUE, &fd, error)) + return -1; + } if (real_path_out != NULL) *real_path_out = g_string_free (g_steal_pointer (¤t_path), FALSE); diff --git a/tests/pressure-vessel/resolve-in-sysroot.c b/tests/pressure-vessel/resolve-in-sysroot.c index b7e1d850676b2b0fafee76ea1a76ea1873eacc44..bade3586d342b48abf63d1188f8a3992e5ada64d 100644 --- a/tests/pressure-vessel/resolve-in-sysroot.c +++ b/tests/pressure-vessel/resolve-in-sysroot.c @@ -110,6 +110,10 @@ test_resolve_in_sysroot (Fixture *f, "a/b/c/d/e", "a/b2/c2/d2/e2", }; + static const char * const prepare_files[] = + { + "a/b/c/file", + }; static const Symlink prepare_symlinks[] = { { "a/b/symlink_to_c", "c" }, @@ -137,6 +141,21 @@ test_resolve_in_sysroot (Fixture *f, { NULL, G_IO_ERROR_NOT_FOUND } }, { { "a/b/c/d", SRT_RESOLVE_FLAGS_MKDIR_P }, { "a/b/c/d" } }, + { { "a/b/c/d", SRT_RESOLVE_FLAGS_READABLE }, { "a/b/c/d" } }, + { { "a/b/c/d", SRT_RESOLVE_FLAGS_DIRECTORY }, { "a/b/c/d" } }, + { + { "a/b/c/d", SRT_RESOLVE_FLAGS_READABLE|SRT_RESOLVE_FLAGS_DIRECTORY }, + { "a/b/c/d" } + }, + { { "a/b/c/file", SRT_RESOLVE_FLAGS_READABLE }, { "a/b/c/file" } }, + { + { "a/b/c/file", SRT_RESOLVE_FLAGS_DIRECTORY }, + { NULL, G_IO_ERROR_NOT_DIRECTORY } + }, + { + { "a/b/c/file", SRT_RESOLVE_FLAGS_READABLE|SRT_RESOLVE_FLAGS_DIRECTORY }, + { NULL, G_IO_ERROR_NOT_DIRECTORY } + }, { { "a/b///////.////./././///././c/d" }, { "a/b/c/d" } }, { { "/a/b///////.////././../b2////././c2/d2" }, { "a/b2/c2/d2" } }, { { "a/b/c/d/e/f" }, { NULL, G_IO_ERROR_NOT_FOUND } }, @@ -193,6 +212,16 @@ test_resolve_in_sysroot (Fixture *f, g_assert_no_error (error); } + for (i = 0; i < G_N_ELEMENTS (prepare_files); i++) + { + const char *it = prepare_files[i]; + + glnx_file_replace_contents_at (tmpdir.fd, it, + (guint8 *) "hello", 5, + 0, NULL, &error); + g_assert_no_error (error); + } + for (i = 0; i < G_N_ELEMENTS (prepare_symlinks); i++) { const Symlink *it = &prepare_symlinks[i]; @@ -221,6 +250,12 @@ test_resolve_in_sysroot (Fixture *f, if (it->call.flags & SRT_RESOLVE_FLAGS_REJECT_SYMLINKS) g_string_append (description, " (not following any symlink)"); + if (it->call.flags & SRT_RESOLVE_FLAGS_DIRECTORY) + g_string_append (description, " (must be a directory)"); + + if (it->call.flags & SRT_RESOLVE_FLAGS_READABLE) + g_string_append (description, " (open for reading)"); + g_test_message ("%" G_GSIZE_FORMAT ": Resolving %s%s", i, it->call.path, description->str);