[libc-commits] [libc] 8b0e84a - [libc] Add implementation of the POSIX getcwd function.
Siva Chandra Reddy via libc-commits
libc-commits at lists.llvm.org
Fri Oct 14 09:21:10 PDT 2022
Author: Siva Chandra Reddy
Date: 2022-10-14T16:20:59Z
New Revision: 8b0e84a6f6be46b3b9002df161d398e403d184f6
URL: https://github.com/llvm/llvm-project/commit/8b0e84a6f6be46b3b9002df161d398e403d184f6
DIFF: https://github.com/llvm/llvm-project/commit/8b0e84a6f6be46b3b9002df161d398e403d184f6.diff
LOG: [libc] Add implementation of the POSIX getcwd function.
Reviewed By: michaelrj
Differential Revision: https://reviews.llvm.org/D135905
Added:
libc/src/unistd/getcwd.h
libc/src/unistd/linux/getcwd.cpp
libc/test/integration/src/unistd/getcwd_test.cpp
Modified:
libc/config/linux/x86_64/entrypoints.txt
libc/spec/posix.td
libc/src/string/CMakeLists.txt
libc/src/string/strdup.cpp
libc/src/string/string_utils.h
libc/src/unistd/CMakeLists.txt
libc/src/unistd/linux/CMakeLists.txt
libc/test/integration/src/unistd/CMakeLists.txt
Removed:
################################################################################
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 3a7b142a70f0..6198b353eaa4 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -152,6 +152,7 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.unistd.fchdir
libc.src.unistd.fsync
libc.src.unistd.ftruncate
+ libc.src.unistd.getcwd
libc.src.unistd.geteuid
libc.src.unistd.getpid
libc.src.unistd.getppid
diff --git a/libc/spec/posix.td b/libc/spec/posix.td
index 53906d0d060e..29f8ed9801db 100644
--- a/libc/spec/posix.td
+++ b/libc/spec/posix.td
@@ -359,6 +359,11 @@ def POSIX : StandardSpec<"POSIX"> {
RetValSpec<IntType>,
[ArgSpec<IntType>]
>,
+ FunctionSpec<
+ "getcwd",
+ RetValSpec<CharPtr>,
+ [ArgSpec<CharPtr>, ArgSpec<SizeTType>]
+ >,
FunctionSpec<
"close",
RetValSpec<IntType>,
diff --git a/libc/src/string/CMakeLists.txt b/libc/src/string/CMakeLists.txt
index 3525e8724049..ab579afa4cfd 100644
--- a/libc/src/string/CMakeLists.txt
+++ b/libc/src/string/CMakeLists.txt
@@ -5,6 +5,7 @@ add_header_library(
HDRS
string_utils.h
DEPENDS
+ libc.include.stdlib
libc.src.__support.CPP.bitset
.memory_utils.memcpy_implementation
.memory_utils.bzero_implementation
diff --git a/libc/src/string/strdup.cpp b/libc/src/string/strdup.cpp
index ee324b073663..d7adc85fc223 100644
--- a/libc/src/string/strdup.cpp
+++ b/libc/src/string/strdup.cpp
@@ -17,16 +17,7 @@
namespace __llvm_libc {
LLVM_LIBC_FUNCTION(char *, strdup, (const char *src)) {
- if (src == nullptr) {
- return nullptr;
- }
- size_t len = internal::string_length(src) + 1;
- char *dest = reinterpret_cast<char *>(::malloc(len));
- if (dest == nullptr) {
- return nullptr;
- }
- inline_memcpy(dest, src, len);
- return dest;
+ return internal::strdup(src);
}
} // namespace __llvm_libc
diff --git a/libc/src/string/string_utils.h b/libc/src/string/string_utils.h
index b1b434dbf172..da4ad8e4a270 100644
--- a/libc/src/string/string_utils.h
+++ b/libc/src/string/string_utils.h
@@ -11,9 +11,10 @@
#include "src/__support/CPP/bitset.h"
#include "src/__support/common.h"
-#include "src/string/memory_utils/memcpy_implementations.h"
#include "src/string/memory_utils/bzero_implementations.h"
-#include <stddef.h> // size_t
+#include "src/string/memory_utils/memcpy_implementations.h"
+#include <stddef.h> // For size_t
+#include <stdlib.h> // For malloc and free
namespace __llvm_libc {
namespace internal {
@@ -98,6 +99,17 @@ static inline size_t strlcpy(char *__restrict dst, const char *__restrict src,
return len;
}
+inline char *strdup(const char *src) {
+ if (src == nullptr)
+ return nullptr;
+ size_t len = string_length(src) + 1;
+ char *newstr = reinterpret_cast<char *>(::malloc(len));
+ if (newstr == nullptr)
+ return nullptr;
+ inline_memcpy(newstr, src, len);
+ return newstr;
+}
+
} // namespace internal
} // namespace __llvm_libc
diff --git a/libc/src/unistd/CMakeLists.txt b/libc/src/unistd/CMakeLists.txt
index 3d4fa3f13b38..cd4002e35d7a 100644
--- a/libc/src/unistd/CMakeLists.txt
+++ b/libc/src/unistd/CMakeLists.txt
@@ -86,6 +86,13 @@ add_entrypoint_object(
.${LIBC_TARGET_OS}.ftruncate
)
+add_entrypoint_object(
+ getcwd
+ ALIAS
+ DEPENDS
+ .${LIBC_TARGET_OS}.getcwd
+)
+
add_entrypoint_object(
getpid
ALIAS
diff --git a/libc/src/unistd/getcwd.h b/libc/src/unistd/getcwd.h
new file mode 100644
index 000000000000..8a6947f09a12
--- /dev/null
+++ b/libc/src/unistd/getcwd.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for getcwd ------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_UNISTD_GETCWD_H
+#define LLVM_LIBC_SRC_UNISTD_GETCWD_H
+
+#include <unistd.h>
+
+namespace __llvm_libc {
+
+char *getcwd(char *buf, size_t size);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_UNISTD_GETCWD_H
diff --git a/libc/src/unistd/linux/CMakeLists.txt b/libc/src/unistd/linux/CMakeLists.txt
index af4585457e09..47382d2490c1 100644
--- a/libc/src/unistd/linux/CMakeLists.txt
+++ b/libc/src/unistd/linux/CMakeLists.txt
@@ -159,6 +159,21 @@ add_entrypoint_object(
libc.src.errno.errno
)
+add_entrypoint_object(
+ getcwd
+ SRCS
+ getcwd.cpp
+ HDRS
+ ../getcwd.h
+ DEPENDS
+ libc.include.errno
+ libc.include.stdlib
+ libc.include.unistd
+ libc.include.sys_syscall
+ libc.src.__support.OSUtil.osutil
+ libc.src.errno.errno
+)
+
add_entrypoint_object(
geteuid
SRCS
diff --git a/libc/src/unistd/linux/getcwd.cpp b/libc/src/unistd/linux/getcwd.cpp
new file mode 100644
index 000000000000..7475f461d8b9
--- /dev/null
+++ b/libc/src/unistd/linux/getcwd.cpp
@@ -0,0 +1,66 @@
+//===-- Linux implementation of getcwd ------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/unistd/getcwd.h"
+
+#include "src/__support/OSUtil/syscall.h" // For internal syscall function.
+#include "src/__support/common.h"
+#include "src/string/string_utils.h" // For strdup.
+
+#include <errno.h>
+#include <linux/limits.h> // This is safe to include without any name pollution.
+#include <stdlib.h>
+#include <sys/syscall.h> // For syscall numbers.
+
+namespace __llvm_libc {
+
+namespace {
+
+bool getcwd_syscall(char *buf, size_t size) {
+ int ret = __llvm_libc::syscall_impl(SYS_getcwd, buf, size);
+ if (ret < 0) {
+ errno = -ret;
+ return false;
+ } else if (ret == 0 || buf[0] != '/') {
+ errno = ENOENT;
+ return false;
+ }
+ return true;
+}
+
+} // anonymous namespace
+
+LLVM_LIBC_FUNCTION(char *, getcwd, (char *buf, size_t size)) {
+ if (buf == nullptr) {
+ // We match glibc's behavior here and return the cwd in a malloc-ed buffer.
+ // We will allocate a static buffer of size PATH_MAX first and fetch the cwd
+ // into it. This way, if the syscall fails, we avoid unnecessary malloc
+ // and free.
+ char pathbuf[PATH_MAX];
+ if (!getcwd_syscall(pathbuf, PATH_MAX))
+ return nullptr;
+ char *cwd = internal::strdup(pathbuf);
+ if (cwd == nullptr) {
+ errno = ENOMEM;
+ return nullptr;
+ }
+ return cwd;
+ } else if (size == 0) {
+ errno = EINVAL;
+ return nullptr;
+ }
+
+ // TODO: When buf is not sufficient, evaluate the full cwd path using
+ // alternate approaches.
+
+ if (!getcwd_syscall(buf, size))
+ return nullptr;
+ return buf;
+}
+
+} // namespace __llvm_libc
diff --git a/libc/test/integration/src/unistd/CMakeLists.txt b/libc/test/integration/src/unistd/CMakeLists.txt
index 509666cdf0ee..7631f5bd4a3a 100644
--- a/libc/test/integration/src/unistd/CMakeLists.txt
+++ b/libc/test/integration/src/unistd/CMakeLists.txt
@@ -1,6 +1,21 @@
add_custom_target(unistd-integration-tests)
add_dependencies(libc-integration-tests unistd-integration-tests)
+add_integration_test(
+ getcwd_test
+ SUITE
+ unistd-integration-tests
+ SRCS
+ getcwd_test.cpp
+ LOADER
+ libc.loader.linux.crt1
+ DEPENDS
+ libc.include.errno
+ libc.src.__support.CPP.string_view
+ libc.src.stdlib.getenv
+ libc.src.unistd.getcwd
+)
+
add_integration_test(
fork_test
SUITE
diff --git a/libc/test/integration/src/unistd/getcwd_test.cpp b/libc/test/integration/src/unistd/getcwd_test.cpp
new file mode 100644
index 000000000000..80b45efb97fb
--- /dev/null
+++ b/libc/test/integration/src/unistd/getcwd_test.cpp
@@ -0,0 +1,42 @@
+//===-- Unittests for getcwd ----------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/__support/CPP/string_view.h"
+#include "src/stdlib/getenv.h"
+#include "src/unistd/getcwd.h"
+
+#include "utils/IntegrationTest/test.h"
+
+#include <errno.h>
+
+using __llvm_libc::cpp::string_view;
+
+TEST_MAIN(int argc, char **argv, char **envp) {
+ char buffer[1024];
+ ASSERT_TRUE(string_view(__llvm_libc::getenv("PWD")) ==
+ __llvm_libc::getcwd(buffer, 1024));
+
+ // nullptr buffer
+ char *cwd = __llvm_libc::getcwd(nullptr, 0);
+ ASSERT_TRUE(string_view(__llvm_libc::getenv("PWD")) == cwd);
+ free(cwd);
+
+ // Bad size
+ cwd = __llvm_libc::getcwd(buffer, 0);
+ ASSERT_TRUE(cwd == nullptr);
+ ASSERT_EQ(errno, EINVAL);
+ errno = 0;
+
+ // Insufficient size
+ cwd = __llvm_libc::getcwd(buffer, 2);
+ ASSERT_TRUE(cwd == nullptr);
+ int err = errno;
+ ASSERT_EQ(err, ERANGE);
+
+ return 0;
+}
More information about the libc-commits
mailing list