diff --git a/subprojects/libglnx/glnx-fdio.c b/subprojects/libglnx/glnx-fdio.c index 98732051aef02e5e7a697149c7ea19926a602191..3d9f9a759415ba1c15eb9807cf036d52f55dbd6d 100644 --- a/subprojects/libglnx/glnx-fdio.c +++ b/subprojects/libglnx/glnx-fdio.c @@ -321,6 +321,8 @@ glnx_open_anonymous_tmpfile (int flags, error); } +static const char proc_self_fd_slash[] = "/proc/self/fd/"; + /* Use this after calling glnx_open_tmpfile_linkable_at() to give * the file its final name (link into place). */ @@ -367,8 +369,8 @@ glnx_link_tmpfile_at (GLnxTmpfile *tmpf, else { /* This case we have O_TMPFILE, so our reference to it is via /proc/self/fd */ - char proc_fd_path[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(tmpf->fd) + 1]; - snprintf (proc_fd_path, sizeof (proc_fd_path), "/proc/self/fd/%i", tmpf->fd); + char proc_fd_path[sizeof (proc_self_fd_slash) + DECIMAL_STR_MAX(tmpf->fd)]; + snprintf (proc_fd_path, sizeof (proc_fd_path), "%s%i", proc_self_fd_slash, tmpf->fd); if (replace) { @@ -455,8 +457,8 @@ glnx_tmpfile_reopen_rdonly (GLnxTmpfile *tmpf, else { /* This case we have O_TMPFILE, so our reference to it is via /proc/self/fd */ - char proc_fd_path[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(tmpf->fd) + 1]; - snprintf (proc_fd_path, sizeof (proc_fd_path), "/proc/self/fd/%i", tmpf->fd); + char proc_fd_path[sizeof (proc_self_fd_slash) + DECIMAL_STR_MAX(tmpf->fd)]; + snprintf (proc_fd_path, sizeof (proc_fd_path), "%s%i", proc_self_fd_slash, tmpf->fd); if (!glnx_openat_rdonly (AT_FDCWD, proc_fd_path, TRUE, &rdonly_fd, error)) return FALSE; diff --git a/subprojects/libglnx/glnx-shutil.c b/subprojects/libglnx/glnx-shutil.c index 5ebe7f8886e02a95886a0814378c1fa15d51dd16..5a6fd7cecc81ae419eb0d98705fde9d032434978 100644 --- a/subprojects/libglnx/glnx-shutil.c +++ b/subprojects/libglnx/glnx-shutil.c @@ -149,12 +149,10 @@ mkdir_p_at_internal (int dfd, again: if (mkdirat (dfd, path, mode) == -1) { - if (errno == ENOENT) + if (errno == ENOENT && !did_recurse) { char *lastslash; - g_assert (!did_recurse); - lastslash = strrchr (path, '/'); if (lastslash == NULL) { diff --git a/subprojects/libglnx/meson_options.txt b/subprojects/libglnx/meson_options.txt index 1028017fb9ecfdfe36c9b109a5412ac55a5602d0..e90011144df53423d609aeff5a6ea860e27bb604 100644 --- a/subprojects/libglnx/meson_options.txt +++ b/subprojects/libglnx/meson_options.txt @@ -5,5 +5,5 @@ option( 'tests', type : 'boolean', description : 'build and run unit tests', - value : 'true', + value : true, ) diff --git a/subprojects/libglnx/tests/test-libglnx-shutil.c b/subprojects/libglnx/tests/test-libglnx-shutil.c index 28b34abe0f3bdd8ac19f3e469ed0598f8677889c..98e424aa0487ffaaa0a47b55c4efc44c316a7812 100644 --- a/subprojects/libglnx/tests/test-libglnx-shutil.c +++ b/subprojects/libglnx/tests/test-libglnx-shutil.c @@ -1,6 +1,7 @@ /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- * - * Copyright © 2017 Endless OS Foundation LLC + * Copyright © 2017-2019 Endless OS Foundation LLC + * Copyright © 2024 Collabora Ltd. * SPDX-License-Identifier: LGPL-2.0-or-later * * This library is free software; you can redistribute it and/or @@ -29,9 +30,47 @@ #include "libglnx-testlib.h" +static void +test_mkdir_p_parent_unsuitable (void) +{ + _GLNX_TEST_SCOPED_TEMP_DIR; + _GLNX_TEST_DECLARE_ERROR(local_error, error); + glnx_autofd int dfd = -1; + + if (!glnx_ensure_dir (AT_FDCWD, "test", 0755, error)) + return; + if (!glnx_opendirat (AT_FDCWD, "test", FALSE, &dfd, error)) + return; + + if (!glnx_file_replace_contents_at (dfd, "file", + (const guint8 *) "", 0, + GLNX_FILE_REPLACE_NODATASYNC, + NULL, error)) + return; + + if (symlinkat ("nosuchtarget", dfd, "link") < 0) + { + glnx_throw_errno_prefix (error, "symlinkat"); + return; + } + + glnx_shutil_mkdir_p_at (dfd, "file/baz", 0755, NULL, error); + g_test_message ("mkdir %s -> %s", "file/baz", + local_error ? local_error->message : "success"); + g_assert_error (local_error, G_IO_ERROR, G_IO_ERROR_NOT_DIRECTORY); + g_clear_error (&local_error); + + glnx_shutil_mkdir_p_at (dfd, "link/baz", 0755, NULL, error); + g_test_message ("mkdir %s -> %s", "link/baz", + local_error ? local_error->message : "success"); + g_assert_error (local_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND); + g_clear_error (&local_error); +} + static void test_mkdir_p_enoent (void) { + _GLNX_TEST_SCOPED_TEMP_DIR; _GLNX_TEST_DECLARE_ERROR(local_error, error); glnx_autofd int dfd = -1; @@ -57,6 +96,7 @@ main (int argc, g_test_init (&argc, &argv, NULL); g_test_add_func ("/mkdir-p/enoent", test_mkdir_p_enoent); + g_test_add_func ("/mkdir-p/parent-unsuitable", test_mkdir_p_parent_unsuitable); ret = g_test_run();