llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-libc Author: Jackson Stogel (jtstogel) <details> <summary>Changes</summary> Updates realpath to call the `getcwd` linux syscall wrapper to resolve cwd-relative queries. This is a stacked PR on top of https://github.com/llvm/llvm-project/pull/209369. --- Full diff: https://github.com/llvm/llvm-project/pull/209374.diff 4 Files Affected: - (modified) libc/src/stdlib/linux/CMakeLists.txt (+1) - (modified) libc/src/stdlib/linux/realpath.cpp (+16-1) - (modified) libc/test/src/stdlib/CMakeLists.txt (+2) - (modified) libc/test/src/stdlib/realpath_test.cpp (+84-3) ``````````diff diff --git a/libc/src/stdlib/linux/CMakeLists.txt b/libc/src/stdlib/linux/CMakeLists.txt index 357073f61962b..e71e3bf3e4ddf 100644 --- a/libc/src/stdlib/linux/CMakeLists.txt +++ b/libc/src/stdlib/linux/CMakeLists.txt @@ -30,6 +30,7 @@ add_entrypoint_object( libc.src.__support.libc_errno libc.src.__support.macros.config libc.src.__support.OSUtil.linux.stat.kernel_statx_types + libc.src.__support.OSUtil.linux.syscall_wrappers.getcwd libc.src.__support.OSUtil.linux.syscall_wrappers.statx libc.src.__support.OSUtil.path libc.src.string.memory_utils.inline_memcpy diff --git a/libc/src/stdlib/linux/realpath.cpp b/libc/src/stdlib/linux/realpath.cpp index bebfc14f3d256..4c6a1e14e8e47 100644 --- a/libc/src/stdlib/linux/realpath.cpp +++ b/libc/src/stdlib/linux/realpath.cpp @@ -22,6 +22,7 @@ #include "src/__support/CPP/string.h" #include "src/__support/CPP/string_view.h" #include "src/__support/OSUtil/linux/stat/kernel_statx_types.h" +#include "src/__support/OSUtil/linux/syscall_wrappers/getcwd.h" #include "src/__support/OSUtil/linux/syscall_wrappers/statx.h" #include "src/__support/OSUtil/path.h" #include "src/__support/common.h" @@ -46,7 +47,21 @@ class ResolvedPath { void set_to_root() { path_ = path::SEPARATOR; } - cpp::optional<Error> set_to_cwd() { return Error(ENOSYS); } + cpp::optional<Error> set_to_cwd() { + char buf[PATH_MAX]; + ErrorOr<ssize_t> ret = linux_syscalls::getcwd(buf, PATH_MAX); + if (!ret) { + if (ret.error() == ERANGE) + return Error(ENAMETOOLONG); + return Error(ret.error()); + } + + if (*ret <= 0) + return Error(EIO); + + path_ = cpp::string_view(buf, *ret - 1); + return cpp::nullopt; + } // Removes the trailing path component. void set_to_parent() { diff --git a/libc/test/src/stdlib/CMakeLists.txt b/libc/test/src/stdlib/CMakeLists.txt index 31b710229ce95..2d03a3d2e4702 100644 --- a/libc/test/src/stdlib/CMakeLists.txt +++ b/libc/test/src/stdlib/CMakeLists.txt @@ -398,7 +398,9 @@ add_libc_test( libc.src.fcntl.openat libc.src.stdlib.realpath libc.src.sys.stat.mkdirat + libc.src.unistd.chdir libc.src.unistd.close + libc.src.unistd.getcwd libc.src.unistd.unlinkat libc.test.UnitTest.ErrnoCheckingTest libc.test.UnitTest.ErrnoSetterMatcher diff --git a/libc/test/src/stdlib/realpath_test.cpp b/libc/test/src/stdlib/realpath_test.cpp index 0a7f0032d292c..20a12cd3358d8 100644 --- a/libc/test/src/stdlib/realpath_test.cpp +++ b/libc/test/src/stdlib/realpath_test.cpp @@ -25,7 +25,9 @@ #include "src/fcntl/openat.h" #include "src/stdlib/realpath.h" #include "src/sys/stat/mkdirat.h" +#include "src/unistd/chdir.h" #include "src/unistd/close.h" +#include "src/unistd/getcwd.h" #include "src/unistd/unlinkat.h" #include "test/UnitTest/ErrnoCheckingTest.h" #include "test/UnitTest/ErrnoSetterMatcher.h" @@ -33,6 +35,7 @@ namespace cpp = LIBC_NAMESPACE::cpp; namespace path = LIBC_NAMESPACE::path; using LIBC_NAMESPACE::FixedVector; +using LIBC_NAMESPACE::testing::ErrnoCheckingTest; using LIBC_NAMESPACE::testing::tlog; using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds; @@ -153,10 +156,23 @@ class TestDir { } }; -class LlvmLibcRealpathTest : public LIBC_NAMESPACE::testing::ErrnoCheckingTest { +class LlvmLibcRealpathTest : public ErrnoCheckingTest { public: + void SetUp() override { + ErrnoCheckingTest::SetUp(); + + (void)LIBC_NAMESPACE::getcwd(start_dir_, sizeof(start_dir_)); + ASSERT_ERRNO_SUCCESS(); + } + + void TearDown() override { + ASSERT_THAT(LIBC_NAMESPACE::chdir(start_dir_), Succeeds()); + + ErrnoCheckingTest::TearDown(); + } + char *realpath_buffered(const char *path) { - return LIBC_NAMESPACE::realpath(path, buf_); + return LIBC_NAMESPACE::realpath(path, realpath_buf_); } char *realpath_buffered(const cpp::string &path) { @@ -184,7 +200,11 @@ class LlvmLibcRealpathTest : public LIBC_NAMESPACE::testing::ErrnoCheckingTest { } private: - char buf_[PATH_MAX]; + // Buffer for storing realpath output. + char realpath_buf_[PATH_MAX]; + + // Current working dir at test SetUp. + char start_dir_[PATH_MAX]; }; TEST_F(LlvmLibcRealpathTest, ErrorsWithInvalidArgIfNullPath) { @@ -378,3 +398,64 @@ TEST_F(LlvmLibcRealpathTest, ErrorsWithNoAccesWhenDirectoryNotSearchable) { ASSERT_STREQ(realpath_buffered(test_dir.abspath("a/b")), nullptr); ASSERT_ERRNO_EQ(EACCES); } + +TEST_F(LlvmLibcRealpathTest, RelativePathResolvesToCurrentWorkingDir) { + TestDir test_dir; + ASSERT_TRUE( + create_test_dir("RelativePathResolvesToCurrentWorkingDir", test_dir)); + + ASSERT_THAT(LIBC_NAMESPACE::chdir(test_dir.c_str()), Succeeds()); + ASSERT_STREQ(realpath_buffered("."), test_dir.c_str()); + + ASSERT_THAT(test_dir.mkdir("a"), Succeeds()); + ASSERT_STREQ(realpath_buffered("a"), test_dir.abspath("a").c_str()); +} + +// Creates a directory with the desired_size and then chdir's into it. +// Returns true on success. +[[nodiscard]] bool chdir_to_abspath_with_size(TestDir &test_dir, + size_t desired_size, + cpp::string &out) { + if (!create_abspath_with_size(test_dir, desired_size, out)) + return false; + + // Convert the directory to be relative to test_dir. + const char *test_dir_relative_path = + out.c_str() + test_dir.view().size() + PATH_SEP_SIZE; + + // Change directories into the path iteratively. + // This allows us to chdir into paths longer than PATH_MAX, as long + // as each of test_dir and relpath are shorter than PATH_MAX. + if (LIBC_NAMESPACE::chdir(test_dir.c_str())) + return false; + if (LIBC_NAMESPACE::chdir(test_dir_relative_path)) + return false; + return true; +} + +TEST_F(LlvmLibcRealpathTest, RelativeRealpathAcceptsPathExactlyMaxSize) { + TestDir test_dir; + ASSERT_TRUE( + create_test_dir("RelativeRealpathAcceptsPathExactlyMaxSize", test_dir)); + + cpp::string path; + ASSERT_TRUE(chdir_to_abspath_with_size(test_dir, PATH_MAX - 1, path)); + + ASSERT_STREQ(realpath_buffered("."), path.c_str()); +} + +TEST_F(LlvmLibcRealpathTest, RelativeRealpathRejectsPathExceedingMaxSize) { + TestDir test_dir; + ASSERT_TRUE( + create_test_dir("RelativeRealpathRejectsPathExceedingMaxSize", test_dir)); + + cpp::string path; + if (!chdir_to_abspath_with_size(test_dir, PATH_MAX, path)) { + // Skip the test if the system didn't allow creating the path. + ASSERT_ERRNO_EQ(ENAMETOOLONG); + return; + } + + ASSERT_EQ(realpath_buffered("."), nullptr); + ASSERT_ERRNO_EQ(ENAMETOOLONG); +} `````````` </details> https://github.com/llvm/llvm-project/pull/209374 _______________________________________________ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
