[libc-commits] [libc] [libc][realpath][test] Create test files/directories (PR #209369)

Jackson Stogel via libc-commits libc-commits at lists.llvm.org
Fri Jul 17 10:54:24 PDT 2026


================
@@ -12,23 +12,148 @@
 //===----------------------------------------------------------------------===//
 
 #include "hdr/errno_macros.h"
+#include "hdr/func/free.h"
 #include "hdr/limits_macros.h"
 #include "hdr/types/size_t.h"
 #include "src/__support/CPP/string.h"
+#include "src/__support/CPP/string_view.h"
+#include "src/__support/CPP/utility.h"
 #include "src/__support/OSUtil/path.h"
+#include "src/__support/fixedvector.h"
+#include "src/__support/libc_assert.h"
+#include "src/__support/libc_errno.h"
 #include "src/__support/macros/config.h"
+#include "src/fcntl/openat.h"
 #include "src/stdlib/realpath.h"
+#include "src/string/strdup.h"
+#include "src/sys/stat/mkdirat.h"
+#include "src/unistd/close.h"
+#include "src/unistd/getpid.h"
+#include "src/unistd/unlinkat.h"
 #include "test/UnitTest/ErrnoCheckingTest.h"
+#include "test/UnitTest/ErrnoSetterMatcher.h"
 
 namespace cpp = LIBC_NAMESPACE::cpp;
 namespace path = LIBC_NAMESPACE::path;
-using LIBC_NAMESPACE::testing::ErrnoCheckingTest;
+using LIBC_NAMESPACE::FixedVector;
+using LIBC_NAMESPACE::testing::tlog;
+using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds;
 
 // This test assumes the following values, so fail early if they mismatch.
 static_assert(path::SEPARATOR == '/');
 static_assert(path::CURRENT_DIR_COMPONENT == ".");
 static_assert(path::PARENT_DIR_COMPONENT == "..");
 
+// Size of a path separator.
+constexpr size_t PATH_SEP_SIZE = 1;
+
+// Creates the given directory if it does not exist. Returns zero on success.
+[[nodiscard]] int ensure_directory_exists(int dirfd, const char *path,
+                                          mode_t mode = 0755) {
+  if (LIBC_NAMESPACE::mkdirat(dirfd, path, mode) == 0)
+    return 0;
+  if (libc_errno == EEXIST)
+    libc_errno = 0;
+
+  if (libc_errno != 0) {
+    tlog << "Failed to create temp directory: " << path << "\n";
+    return -1;
+  }
+  return 0;
+}
+
+// A test directory that removes itself on destruction.
+class TestDir {
+  // The test directory's absolute path.
+  cpp::string path_;
+
+  // File descriptor of the test directory.
+  int fd_ = -1;
+
+  // Files created in this directory tree.
+  // Use a C string instead of cpp::string because FixedVector
+  // only supports trivially destructable types.
+  FixedVector<char *, 64> files_;
+
+  // Subdirectories created in this directory tree.
+  FixedVector<char *, 64> dirs_;
+
+public:
+  TestDir() = default;
+
+  // Initializes this TestDir container with the given path.
+  void initialize(cpp::string directory_path, int dirfd) {
+    LIBC_ASSERT(fd_ == -1);
+    path_ = directory_path;
+    fd_ = dirfd;
+  }
+
+  ~TestDir() {
+    if (path_.empty())
+      return;
+
+    for (size_t i = 0; i < files_.size(); i++) {
+      LIBC_NAMESPACE::unlinkat(fd_, files_[i], 0);
+      ::free(files_[i]);
+    }
+
+    // Remove directories in reverse order so they'll be empty.
+    for (size_t i = dirs_.size(); i > 0; i--) {
+      LIBC_NAMESPACE::unlinkat(fd_, dirs_[i - 1], AT_REMOVEDIR);
+      ::free(dirs_[i - 1]);
+    }
+
+    LIBC_NAMESPACE::close(fd_);
+    LIBC_NAMESPACE::unlinkat(AT_FDCWD, path_.c_str(), AT_REMOVEDIR);
+  }
+
+  TestDir(TestDir &other) = delete;
+  TestDir &operator=(TestDir &other) = delete;
+  TestDir(TestDir &&other) = delete;
+  TestDir &operator=(TestDir &&other) = delete;
+
+  // Returns the absolute path of `relpath` in this test directory.
+  cpp::string abspath(cpp::string_view relpath) const {
----------------
jtstogel wrote:

Done

https://github.com/llvm/llvm-project/pull/209369


More information about the libc-commits mailing list