[libc-commits] [libc] 00e51f0 - [libc] Implement linux link, linkat, symlink, symlinkat, readlink, readlinkat.
Siva Chandra Reddy via libc-commits
libc-commits at lists.llvm.org
Thu Aug 25 11:50:59 PDT 2022
Author: Siva Chandra Reddy
Date: 2022-08-25T18:50:39Z
New Revision: 00e51f04e8c10d0ad3e6089c9ab490394cd69a83
URL: https://github.com/llvm/llvm-project/commit/00e51f04e8c10d0ad3e6089c9ab490394cd69a83
DIFF: https://github.com/llvm/llvm-project/commit/00e51f04e8c10d0ad3e6089c9ab490394cd69a83.diff
LOG: [libc] Implement linux link, linkat, symlink, symlinkat, readlink, readlinkat.
Reviewed By: michaelrj
Differential Revision: https://reviews.llvm.org/D132619
Added:
libc/src/unistd/link.h
libc/src/unistd/linkat.h
libc/src/unistd/linux/link.cpp
libc/src/unistd/linux/linkat.cpp
libc/src/unistd/linux/readlink.cpp
libc/src/unistd/linux/readlinkat.cpp
libc/src/unistd/linux/symlink.cpp
libc/src/unistd/linux/symlinkat.cpp
libc/src/unistd/readlink.h
libc/src/unistd/readlinkat.h
libc/src/unistd/symlink.h
libc/src/unistd/symlinkat.h
libc/test/src/unistd/link_test.cpp
libc/test/src/unistd/linkat_test.cpp
libc/test/src/unistd/readlink_test.cpp
libc/test/src/unistd/readlinkat_test.cpp
libc/test/src/unistd/symlink_test.cpp
libc/test/src/unistd/symlinkat_test.cpp
Modified:
libc/config/linux/aarch64/entrypoints.txt
libc/config/linux/x86_64/entrypoints.txt
libc/spec/posix.td
libc/src/unistd/CMakeLists.txt
libc/src/unistd/linux/CMakeLists.txt
libc/test/src/unistd/CMakeLists.txt
Removed:
################################################################################
diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index 95d6fcb2d986d..13ca094e5cee0 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -112,9 +112,15 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.unistd.close
libc.src.unistd.fchdir
libc.src.unistd.fsync
+ libc.src.unistd.link
+ libc.src.unistd.linkat
libc.src.unistd.lseek
libc.src.unistd.read
+ libc.src.unistd.readlink
+ libc.src.unistd.readlinkat
libc.src.unistd.rmdir
+ libc.src.unistd.symlink
+ libc.src.unistd.symlinkat
libc.src.unistd.unlink
libc.src.unistd.unlinkat
libc.src.unistd.write
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 787f22b12eeac..15bf3b13dc66e 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -112,9 +112,15 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.unistd.close
libc.src.unistd.fchdir
libc.src.unistd.fsync
+ libc.src.unistd.link
+ libc.src.unistd.linkat
libc.src.unistd.lseek
libc.src.unistd.read
+ libc.src.unistd.readlink
+ libc.src.unistd.readlinkat
libc.src.unistd.rmdir
+ libc.src.unistd.symlink
+ libc.src.unistd.symlinkat
libc.src.unistd.unlink
libc.src.unistd.unlinkat
libc.src.unistd.write
diff --git a/libc/spec/posix.td b/libc/spec/posix.td
index c4ab8efc4dda1..27fb7c23d45ce 100644
--- a/libc/spec/posix.td
+++ b/libc/spec/posix.td
@@ -283,6 +283,16 @@ def POSIX : StandardSpec<"POSIX"> {
RetValSpec<IntType>,
[ArgSpec<IntType>]
>,
+ FunctionSpec<
+ "link",
+ RetValSpec<IntType>,
+ [ArgSpec<ConstCharPtr>, ArgSpec<ConstCharPtr>]
+ >,
+ FunctionSpec<
+ "linkat",
+ RetValSpec<IntType>,
+ [ArgSpec<IntType>, ArgSpec<ConstCharPtr>, ArgSpec<IntType>, ArgSpec<ConstCharPtr>, ArgSpec<IntType>]
+ >,
FunctionSpec<
"lseek",
RetValSpec<OffTType>,
@@ -293,11 +303,31 @@ def POSIX : StandardSpec<"POSIX"> {
RetValSpec<SSizeTType>,
[ArgSpec<IntType>, ArgSpec<VoidPtr>, ArgSpec<SizeTType>]
>,
+ FunctionSpec<
+ "readlink",
+ RetValSpec<SSizeTType>,
+ [ArgSpec<ConstCharRestrictedPtr>, ArgSpec<CharRestrictedPtr>, ArgSpec<SizeTType>]
+ >,
+ FunctionSpec<
+ "readlinkat",
+ RetValSpec<SSizeTType>,
+ [ArgSpec<ConstCharRestrictedPtr>, ArgSpec<CharRestrictedPtr>, ArgSpec<SizeTType>]
+ >,
FunctionSpec<
"rmdir",
RetValSpec<IntType>,
[ArgSpec<ConstCharPtr>]
>,
+ FunctionSpec<
+ "symlink",
+ RetValSpec<IntType>,
+ [ArgSpec<ConstCharPtr>, ArgSpec<ConstCharPtr>]
+ >,
+ FunctionSpec<
+ "symlinkat",
+ RetValSpec<IntType>,
+ [ArgSpec<IntType>, ArgSpec<ConstCharPtr>, ArgSpec<IntType>, ArgSpec<ConstCharPtr>]
+ >,
FunctionSpec<
"unlink",
RetValSpec<IntType>,
diff --git a/libc/src/unistd/CMakeLists.txt b/libc/src/unistd/CMakeLists.txt
index 306fdd4a37dfc..849b83e6d23a6 100644
--- a/libc/src/unistd/CMakeLists.txt
+++ b/libc/src/unistd/CMakeLists.txt
@@ -30,6 +30,20 @@ add_entrypoint_object(
.${LIBC_TARGET_OS}.fsync
)
+add_entrypoint_object(
+ link
+ ALIAS
+ DEPENDS
+ .${LIBC_TARGET_OS}.link
+)
+
+add_entrypoint_object(
+ linkat
+ ALIAS
+ DEPENDS
+ .${LIBC_TARGET_OS}.linkat
+)
+
add_entrypoint_object(
lseek
ALIAS
@@ -44,6 +58,20 @@ add_entrypoint_object(
.${LIBC_TARGET_OS}.read
)
+add_entrypoint_object(
+ readlink
+ ALIAS
+ DEPENDS
+ .${LIBC_TARGET_OS}.readlink
+)
+
+add_entrypoint_object(
+ readlinkat
+ ALIAS
+ DEPENDS
+ .${LIBC_TARGET_OS}.readlinkat
+)
+
add_entrypoint_object(
rmdir
ALIAS
@@ -51,6 +79,20 @@ add_entrypoint_object(
.${LIBC_TARGET_OS}.rmdir
)
+add_entrypoint_object(
+ symlink
+ ALIAS
+ DEPENDS
+ .${LIBC_TARGET_OS}.symlink
+)
+
+add_entrypoint_object(
+ symlinkat
+ ALIAS
+ DEPENDS
+ .${LIBC_TARGET_OS}.symlinkat
+)
+
add_entrypoint_object(
unlink
ALIAS
diff --git a/libc/src/unistd/link.h b/libc/src/unistd/link.h
new file mode 100644
index 0000000000000..492274286e044
--- /dev/null
+++ b/libc/src/unistd/link.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for link --------------------------*- 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_LINK_H
+#define LLVM_LIBC_SRC_UNISTD_LINK_H
+
+#include <unistd.h>
+
+namespace __llvm_libc {
+
+int link(const char *, const char *);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_UNISTD_LINK_H
diff --git a/libc/src/unistd/linkat.h b/libc/src/unistd/linkat.h
new file mode 100644
index 0000000000000..7bc161952a866
--- /dev/null
+++ b/libc/src/unistd/linkat.h
@@ -0,0 +1,18 @@
+//===-- Implementation header for linkat ------------------------*- 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_LINKAT_H
+#define LLVM_LIBC_SRC_UNISTD_LINKAT_H
+
+namespace __llvm_libc {
+
+int linkat(int, const char *, int, const char *, int);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_UNISTD_LINKAT_H
diff --git a/libc/src/unistd/linux/CMakeLists.txt b/libc/src/unistd/linux/CMakeLists.txt
index 3889f6171c1c2..132fd7b78cb75 100644
--- a/libc/src/unistd/linux/CMakeLists.txt
+++ b/libc/src/unistd/linux/CMakeLists.txt
@@ -50,6 +50,34 @@ add_entrypoint_object(
libc.src.errno.errno
)
+add_entrypoint_object(
+ link
+ SRCS
+ link.cpp
+ HDRS
+ ../link.h
+ DEPENDS
+ libc.include.fcntl
+ libc.include.unistd
+ libc.include.sys_syscall
+ libc.src.__support.OSUtil.osutil
+ libc.src.errno.errno
+)
+
+add_entrypoint_object(
+ linkat
+ SRCS
+ linkat.cpp
+ HDRS
+ ../linkat.h
+ DEPENDS
+ libc.include.fcntl
+ libc.include.unistd
+ libc.include.sys_syscall
+ libc.src.__support.OSUtil.osutil
+ libc.src.errno.errno
+)
+
add_entrypoint_object(
lseek
SRCS
@@ -90,6 +118,62 @@ add_entrypoint_object(
libc.src.errno.errno
)
+add_entrypoint_object(
+ readlink
+ SRCS
+ readlink.cpp
+ HDRS
+ ../readlink.h
+ DEPENDS
+ libc.include.fcntl
+ libc.include.unistd
+ libc.include.sys_syscall
+ libc.src.__support.OSUtil.osutil
+ libc.src.errno.errno
+)
+
+add_entrypoint_object(
+ readlinkat
+ SRCS
+ readlinkat.cpp
+ HDRS
+ ../readlinkat.h
+ DEPENDS
+ libc.include.fcntl
+ libc.include.unistd
+ libc.include.sys_syscall
+ libc.src.__support.OSUtil.osutil
+ libc.src.errno.errno
+)
+
+add_entrypoint_object(
+ symlink
+ SRCS
+ symlink.cpp
+ HDRS
+ ../symlink.h
+ DEPENDS
+ libc.include.fcntl
+ libc.include.unistd
+ libc.include.sys_syscall
+ libc.src.__support.OSUtil.osutil
+ libc.src.errno.errno
+)
+
+add_entrypoint_object(
+ symlinkat
+ SRCS
+ symlinkat.cpp
+ HDRS
+ ../symlinkat.h
+ DEPENDS
+ libc.include.fcntl
+ libc.include.unistd
+ libc.include.sys_syscall
+ libc.src.__support.OSUtil.osutil
+ libc.src.errno.errno
+)
+
add_entrypoint_object(
unlink
SRCS
diff --git a/libc/src/unistd/linux/link.cpp b/libc/src/unistd/linux/link.cpp
new file mode 100644
index 0000000000000..9f6f915d16135
--- /dev/null
+++ b/libc/src/unistd/linux/link.cpp
@@ -0,0 +1,36 @@
+//===-- Linux implementation of link --------------------------------------===//
+//
+// 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/link.h"
+
+#include "src/__support/OSUtil/syscall.h" // For internal syscall function.
+#include "src/__support/common.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/syscall.h> // For syscall numbers.
+
+namespace __llvm_libc {
+
+LLVM_LIBC_FUNCTION(int, link, (const char *path1, const char *path2)) {
+#ifdef SYS_link
+ long ret = __llvm_libc::syscall(SYS_link, path1, path2);
+#elif defined(SYS_linkat)
+ long ret =
+ __llvm_libc::syscall(SYS_linkat, AT_FDCWD, path1, AT_FDCWD, path2, 0);
+#else
+#error "SYS_link or SYS_linkat not available."
+#endif
+ if (ret < 0) {
+ errno = -ret;
+ return -1;
+ }
+ return ret;
+}
+
+} // namespace __llvm_libc
diff --git a/libc/src/unistd/linux/linkat.cpp b/libc/src/unistd/linux/linkat.cpp
new file mode 100644
index 0000000000000..ef5761173dd0a
--- /dev/null
+++ b/libc/src/unistd/linux/linkat.cpp
@@ -0,0 +1,31 @@
+//===-- Linux implementation of linkat ------------------------------------===//
+//
+// 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/linkat.h"
+
+#include "src/__support/OSUtil/syscall.h" // For internal syscall function.
+#include "src/__support/common.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/syscall.h> // For syscall numbers.
+
+namespace __llvm_libc {
+
+LLVM_LIBC_FUNCTION(int, linkat,
+ (int fd1, const char *path1, int fd2, const char *path2,
+ int flags)) {
+ long ret = __llvm_libc::syscall(SYS_linkat, fd1, path1, fd2, path2, flags);
+ if (ret < 0) {
+ errno = -ret;
+ return -1;
+ }
+ return ret;
+}
+
+} // namespace __llvm_libc
diff --git a/libc/src/unistd/linux/readlink.cpp b/libc/src/unistd/linux/readlink.cpp
new file mode 100644
index 0000000000000..354cdb2dc4e70
--- /dev/null
+++ b/libc/src/unistd/linux/readlink.cpp
@@ -0,0 +1,38 @@
+//===-- Linux implementation of readlink ----------------------------------===//
+//
+// 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/readlink.h"
+
+#include "src/__support/OSUtil/syscall.h" // For internal syscall function.
+#include "src/__support/common.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/syscall.h> // For syscall numbers.
+
+namespace __llvm_libc {
+
+LLVM_LIBC_FUNCTION(ssize_t, readlink,
+ (const char *__restrict path, char *__restrict buf,
+ size_t bufsize)) {
+#ifdef SYS_readlink
+ ssize_t ret = __llvm_libc::syscall(SYS_readlink, path, buf, bufsize);
+#elif defined(SYS_readlinkat)
+ ssize_t ret =
+ __llvm_libc::syscall(SYS_readlinkat, AT_FDCWD, path, buf, bufsize);
+#else
+#error "SYS_readlink or SYS_readlinkat not available."
+#endif
+ if (ret < 0) {
+ errno = -ret;
+ return -1;
+ }
+ return ret;
+}
+
+} // namespace __llvm_libc
diff --git a/libc/src/unistd/linux/readlinkat.cpp b/libc/src/unistd/linux/readlinkat.cpp
new file mode 100644
index 0000000000000..ceb4061a84cd2
--- /dev/null
+++ b/libc/src/unistd/linux/readlinkat.cpp
@@ -0,0 +1,31 @@
+//===-- Linux implementation of readlinkat --------------------------------===//
+//
+// 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/readlinkat.h"
+
+#include "src/__support/OSUtil/syscall.h" // For internal syscall function.
+#include "src/__support/common.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/syscall.h> // For syscall numbers.
+
+namespace __llvm_libc {
+
+LLVM_LIBC_FUNCTION(ssize_t, readlinkat,
+ (int fd, const char *__restrict path, char *__restrict buf,
+ size_t bufsize)) {
+ ssize_t ret = __llvm_libc::syscall(SYS_readlinkat, fd, path, buf, bufsize);
+ if (ret < 0) {
+ errno = -ret;
+ return -1;
+ }
+ return ret;
+}
+
+} // namespace __llvm_libc
diff --git a/libc/src/unistd/linux/symlink.cpp b/libc/src/unistd/linux/symlink.cpp
new file mode 100644
index 0000000000000..add7b95f756dc
--- /dev/null
+++ b/libc/src/unistd/linux/symlink.cpp
@@ -0,0 +1,35 @@
+//===-- Linux implementation of symlink -----------------------------------===//
+//
+// 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/symlink.h"
+
+#include "src/__support/OSUtil/syscall.h" // For internal syscall function.
+#include "src/__support/common.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/syscall.h> // For syscall numbers.
+
+namespace __llvm_libc {
+
+LLVM_LIBC_FUNCTION(int, symlink, (const char *path1, const char *path2)) {
+#ifdef SYS_symlink
+ long ret = __llvm_libc::syscall(SYS_symlink, path1, path2);
+#elif defined(SYS_symlinkat)
+ long ret = __llvm_libc::syscall(SYS_symlinkat, path1, AT_FDCWD, path2);
+#else
+#error "SYS_symlink or SYS_symlinkat not available."
+#endif
+ if (ret < 0) {
+ errno = -ret;
+ return -1;
+ }
+ return ret;
+}
+
+} // namespace __llvm_libc
diff --git a/libc/src/unistd/linux/symlinkat.cpp b/libc/src/unistd/linux/symlinkat.cpp
new file mode 100644
index 0000000000000..e0edfc842dd68
--- /dev/null
+++ b/libc/src/unistd/linux/symlinkat.cpp
@@ -0,0 +1,30 @@
+//===-- Linux implementation of symlinkat ---------------------------------===//
+//
+// 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/symlinkat.h"
+
+#include "src/__support/OSUtil/syscall.h" // For internal syscall function.
+#include "src/__support/common.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/syscall.h> // For syscall numbers.
+
+namespace __llvm_libc {
+
+LLVM_LIBC_FUNCTION(int, symlinkat,
+ (const char *path1, int fd, const char *path2)) {
+ long ret = __llvm_libc::syscall(SYS_symlinkat, path1, fd, path2);
+ if (ret < 0) {
+ errno = -ret;
+ return -1;
+ }
+ return ret;
+}
+
+} // namespace __llvm_libc
diff --git a/libc/src/unistd/readlink.h b/libc/src/unistd/readlink.h
new file mode 100644
index 0000000000000..ba246bf91b8a8
--- /dev/null
+++ b/libc/src/unistd/readlink.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for readlink ----------------------*- 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_READLINK_H
+#define LLVM_LIBC_SRC_UNISTD_READLINK_H
+
+#include <unistd.h>
+
+namespace __llvm_libc {
+
+ssize_t readlink(const char *__restrict, char *__restrict, size_t);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_UNISTD_READLINK_H
diff --git a/libc/src/unistd/readlinkat.h b/libc/src/unistd/readlinkat.h
new file mode 100644
index 0000000000000..54346ee1132cb
--- /dev/null
+++ b/libc/src/unistd/readlinkat.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for readlinkat --------------------*- 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_READLINKAT_H
+#define LLVM_LIBC_SRC_UNISTD_READLINKAT_H
+
+#include <unistd.h>
+
+namespace __llvm_libc {
+
+ssize_t readlinkat(int, const char *__restrict, char *__restrict, size_t);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_UNISTD_READLINKAT_H
diff --git a/libc/src/unistd/symlink.h b/libc/src/unistd/symlink.h
new file mode 100644
index 0000000000000..a495db8238bc0
--- /dev/null
+++ b/libc/src/unistd/symlink.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for symlink -----------------------*- 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_SYMLINK_H
+#define LLVM_LIBC_SRC_UNISTD_SYMLINK_H
+
+#include <unistd.h>
+
+namespace __llvm_libc {
+
+int symlink(const char *, const char *);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_UNISTD_SYMLINK_H
diff --git a/libc/src/unistd/symlinkat.h b/libc/src/unistd/symlinkat.h
new file mode 100644
index 0000000000000..ff77f0a52f6d0
--- /dev/null
+++ b/libc/src/unistd/symlinkat.h
@@ -0,0 +1,20 @@
+//===-- Implementation header for symlinkat ---------------------*- 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_SYMLINKAT_H
+#define LLVM_LIBC_SRC_UNISTD_SYMLINKAT_H
+
+#include <unistd.h>
+
+namespace __llvm_libc {
+
+int symlinkat(const char *, int, const char *);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_UNISTD_SYMLINKAT_H
diff --git a/libc/test/src/unistd/CMakeLists.txt b/libc/test/src/unistd/CMakeLists.txt
index 30f7b370eb9ad..2c9369cbd51ed 100644
--- a/libc/test/src/unistd/CMakeLists.txt
+++ b/libc/test/src/unistd/CMakeLists.txt
@@ -49,6 +49,36 @@ add_libc_unittest(
libc.test.errno_setter_matcher
)
+add_libc_unittest(
+ link_test
+ SUITE
+ libc_unistd_unittests
+ SRCS
+ link_test.cpp
+ DEPENDS
+ libc.include.errno
+ libc.include.unistd
+ libc.src.fcntl.open
+ libc.src.unistd.close
+ libc.src.unistd.link
+ libc.src.unistd.unlink
+)
+
+add_libc_unittest(
+ linkat_test
+ SUITE
+ libc_unistd_unittests
+ SRCS
+ linkat_test.cpp
+ DEPENDS
+ libc.include.errno
+ libc.include.unistd
+ libc.src.fcntl.open
+ libc.src.unistd.close
+ libc.src.unistd.linkat
+ libc.src.unistd.unlink
+)
+
add_libc_unittest(
lseek_test
SUITE
@@ -78,6 +108,67 @@ add_libc_unittest(
libc.src.unistd.rmdir
)
+add_libc_unittest(
+ readlink_test
+ SUITE
+ libc_unistd_unittests
+ SRCS
+ readlink_test.cpp
+ DEPENDS
+ libc.include.errno
+ libc.include.unistd
+ libc.src.unistd.readlink
+ libc.src.unistd.symlink
+ libc.src.unistd.unlink
+ libc.src.__support.CPP.string_view
+)
+
+add_libc_unittest(
+ readlinkat_test
+ SUITE
+ libc_unistd_unittests
+ SRCS
+ readlinkat_test.cpp
+ DEPENDS
+ libc.include.errno
+ libc.include.fcntl
+ libc.include.unistd
+ libc.src.unistd.readlinkat
+ libc.src.unistd.symlink
+ libc.src.unistd.unlink
+ libc.src.__support.CPP.string_view
+)
+
+add_libc_unittest(
+ symlink_test
+ SUITE
+ libc_unistd_unittests
+ SRCS
+ symlink_test.cpp
+ DEPENDS
+ libc.include.errno
+ libc.include.unistd
+ libc.src.fcntl.open
+ libc.src.unistd.close
+ libc.src.unistd.symlink
+ libc.src.unistd.unlink
+)
+
+add_libc_unittest(
+ symlinkat_test
+ SUITE
+ libc_unistd_unittests
+ SRCS
+ symlinkat_test.cpp
+ DEPENDS
+ libc.include.errno
+ libc.include.unistd
+ libc.src.fcntl.open
+ libc.src.unistd.close
+ libc.src.unistd.symlinkat
+ libc.src.unistd.unlink
+)
+
add_libc_unittest(
unlink_test
SUITE
diff --git a/libc/test/src/unistd/link_test.cpp b/libc/test/src/unistd/link_test.cpp
new file mode 100644
index 0000000000000..e54005261d2d1
--- /dev/null
+++ b/libc/test/src/unistd/link_test.cpp
@@ -0,0 +1,49 @@
+//===-- Unittests for link ------------------------------------------------===//
+//
+// 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/fcntl/open.h"
+#include "src/unistd/close.h"
+#include "src/unistd/link.h"
+#include "src/unistd/unlink.h"
+#include "test/ErrnoSetterMatcher.h"
+#include "utils/UnitTest/Test.h"
+
+#include <errno.h>
+
+TEST(LlvmLibcLinkTest, CreateAndUnlink) {
+ using __llvm_libc::testing::ErrnoSetterMatcher::Succeeds;
+ constexpr const char *TEST_FILE = "testdata/link.test";
+ constexpr const char *TEST_FILE_LINK = "testdata/link.test.link";
+
+ // The test strategy is as follows:
+ // 1. Create a normal file
+ // 2. Create a link to that file.
+ // 3. Open the link to check that the link was created.
+ // 4. Cleanup the file and its link.
+ errno = 0;
+ int write_fd = __llvm_libc::open(TEST_FILE, O_WRONLY | O_CREAT, S_IRWXU);
+ ASSERT_EQ(errno, 0);
+ ASSERT_GT(write_fd, 0);
+ ASSERT_THAT(__llvm_libc::close(write_fd), Succeeds(0));
+ ASSERT_THAT(__llvm_libc::link(TEST_FILE, TEST_FILE_LINK), Succeeds(0));
+
+ int link_fd = __llvm_libc::open(TEST_FILE_LINK, O_PATH);
+ ASSERT_GT(link_fd, 0);
+ ASSERT_EQ(errno, 0);
+ ASSERT_THAT(__llvm_libc::close(link_fd), Succeeds(0));
+
+ ASSERT_THAT(__llvm_libc::unlink(TEST_FILE), Succeeds(0));
+ ASSERT_THAT(__llvm_libc::unlink(TEST_FILE_LINK), Succeeds(0));
+}
+
+TEST(LlvmLibcLinkTest, LinkToNonExistentFile) {
+ using __llvm_libc::testing::ErrnoSetterMatcher::Fails;
+ ASSERT_THAT(
+ __llvm_libc::link("testdata/non-existent-file", "testdata/bad-link"),
+ Fails(ENOENT));
+}
diff --git a/libc/test/src/unistd/linkat_test.cpp b/libc/test/src/unistd/linkat_test.cpp
new file mode 100644
index 0000000000000..8e3266ff26bd7
--- /dev/null
+++ b/libc/test/src/unistd/linkat_test.cpp
@@ -0,0 +1,56 @@
+//===-- Unittests for linkat ----------------------------------------------===//
+//
+// 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/fcntl/open.h"
+#include "src/unistd/close.h"
+#include "src/unistd/linkat.h"
+#include "src/unistd/unlink.h"
+#include "test/ErrnoSetterMatcher.h"
+#include "utils/UnitTest/Test.h"
+
+#include <errno.h>
+
+TEST(LlvmLibcLinkatTest, CreateAndUnlink) {
+ using __llvm_libc::testing::ErrnoSetterMatcher::Succeeds;
+ constexpr const char *TEST_DIR = "testdata";
+ constexpr const char *TEST_FILE = "linkat.test";
+ constexpr const char *TEST_FILE_PATH = "testdata/linkat.test";
+ constexpr const char *TEST_FILE_LINK = "linkat.test.link";
+ constexpr const char *TEST_FILE_LINK_PATH = "testdata/linkat.test.link";
+
+ // The test strategy is as follows:
+ // 1. Create a normal file
+ // 2. Create a link to that file.
+ // 3. Open the link to check that the link was created.
+ // 4. Cleanup the file and its link.
+ errno = 0;
+ int write_fd = __llvm_libc::open(TEST_FILE_PATH, O_WRONLY | O_CREAT, S_IRWXU);
+ ASSERT_EQ(errno, 0);
+ ASSERT_GT(write_fd, 0);
+ ASSERT_THAT(__llvm_libc::close(write_fd), Succeeds(0));
+
+ int dir_fd = __llvm_libc::open(TEST_DIR, O_DIRECTORY);
+ ASSERT_THAT(__llvm_libc::linkat(dir_fd, TEST_FILE, dir_fd, TEST_FILE_LINK, 0),
+ Succeeds(0));
+
+ int link_fd = __llvm_libc::open(TEST_FILE_LINK_PATH, O_PATH);
+ ASSERT_GT(link_fd, 0);
+ ASSERT_EQ(errno, 0);
+ ASSERT_THAT(__llvm_libc::close(link_fd), Succeeds(0));
+
+ ASSERT_THAT(__llvm_libc::unlink(TEST_FILE_PATH), Succeeds(0));
+ ASSERT_THAT(__llvm_libc::unlink(TEST_FILE_LINK_PATH), Succeeds(0));
+ ASSERT_THAT(__llvm_libc::close(dir_fd), Succeeds(0));
+}
+
+TEST(LlvmLibcLinkatTest, LinkToNonExistentFile) {
+ using __llvm_libc::testing::ErrnoSetterMatcher::Fails;
+ ASSERT_THAT(__llvm_libc::linkat(AT_FDCWD, "testdata/non-existent-file",
+ AT_FDCWD, "testdata/bad-link", 0),
+ Fails(ENOENT));
+}
diff --git a/libc/test/src/unistd/readlink_test.cpp b/libc/test/src/unistd/readlink_test.cpp
new file mode 100644
index 0000000000000..ea9e164144bd3
--- /dev/null
+++ b/libc/test/src/unistd/readlink_test.cpp
@@ -0,0 +1,45 @@
+//===-- Unittests for readlink --------------------------------------------===//
+//
+// 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/unistd/readlink.h"
+#include "src/unistd/symlink.h"
+#include "src/unistd/unlink.h"
+#include "test/ErrnoSetterMatcher.h"
+#include "utils/UnitTest/Test.h"
+
+#include <errno.h>
+
+namespace cpp = __llvm_libc::cpp;
+
+TEST(LlvmLibcReadlinkTest, CreateAndUnlink) {
+ using __llvm_libc::testing::ErrnoSetterMatcher::Succeeds;
+ constexpr const char LINK_VAL[] = "readlink_test_value";
+ constexpr const char LINK[] = "testdata/readlink.test.link";
+ errno = 0;
+
+ // The test strategy is as follows:
+ // 1. Create a symlink with value LINK_VAL.
+ // 2. Read the symlink with readlink. The link value read should be LINK_VAL
+ // 3. Cleanup the symlink created in step #1.
+ ASSERT_THAT(__llvm_libc::symlink(LINK_VAL, LINK), Succeeds(0));
+
+ char buf[sizeof(LINK_VAL)];
+ ssize_t len = __llvm_libc::readlink(LINK, buf, sizeof(buf));
+ ASSERT_EQ(errno, 0);
+ ASSERT_EQ(cpp::string_view(buf, len), cpp::string_view(LINK_VAL));
+
+ ASSERT_THAT(__llvm_libc::unlink(LINK), Succeeds(0));
+}
+
+TEST(LlvmLibcReadlinkTest, ReadlinkInNonExistentPath) {
+ using __llvm_libc::testing::ErrnoSetterMatcher::Fails;
+ char buf[8];
+ ASSERT_THAT(__llvm_libc::readlink("non-existent-link", buf, sizeof(buf)),
+ Fails(ENOENT));
+}
diff --git a/libc/test/src/unistd/readlinkat_test.cpp b/libc/test/src/unistd/readlinkat_test.cpp
new file mode 100644
index 0000000000000..942b6290288a1
--- /dev/null
+++ b/libc/test/src/unistd/readlinkat_test.cpp
@@ -0,0 +1,47 @@
+//===-- Unittests for readlinkat ------------------------------------------===//
+//
+// 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/unistd/readlinkat.h"
+#include "src/unistd/symlink.h"
+#include "src/unistd/unlink.h"
+#include "test/ErrnoSetterMatcher.h"
+#include "utils/UnitTest/Test.h"
+
+#include <errno.h>
+#include <fcntl.h>
+
+namespace cpp = __llvm_libc::cpp;
+
+TEST(LlvmLibcReadlinkatTest, CreateAndUnlink) {
+ using __llvm_libc::testing::ErrnoSetterMatcher::Succeeds;
+ constexpr const char LINK_VAL[] = "readlinkat_test_value";
+ constexpr const char LINK[] = "testdata/readlinkat.test.link";
+ errno = 0;
+
+ // The test strategy is as follows:
+ // 1. Create a symlink with value LINK_VAL.
+ // 2. Read the symlink with readlink. The link value read should be LINK_VAL
+ // 3. Cleanup the symlink created in step #1.
+ ASSERT_THAT(__llvm_libc::symlink(LINK_VAL, LINK), Succeeds(0));
+
+ char buf[sizeof(LINK_VAL)];
+ ssize_t len = __llvm_libc::readlinkat(AT_FDCWD, LINK, buf, sizeof(buf));
+ ASSERT_EQ(errno, 0);
+ ASSERT_EQ(cpp::string_view(buf, len), cpp::string_view(LINK_VAL));
+
+ ASSERT_THAT(__llvm_libc::unlink(LINK), Succeeds(0));
+}
+
+TEST(LlvmLibcReadlinkatTest, ReadlinkInNonExistentPath) {
+ using __llvm_libc::testing::ErrnoSetterMatcher::Fails;
+ char buf[8];
+ ASSERT_THAT(
+ __llvm_libc::readlinkat(AT_FDCWD, "non-existent-link", buf, sizeof(buf)),
+ Fails(ENOENT));
+}
diff --git a/libc/test/src/unistd/symlink_test.cpp b/libc/test/src/unistd/symlink_test.cpp
new file mode 100644
index 0000000000000..52d666262200a
--- /dev/null
+++ b/libc/test/src/unistd/symlink_test.cpp
@@ -0,0 +1,52 @@
+//===-- Unittests for symlink ---------------------------------------------===//
+//
+// 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/fcntl/open.h"
+#include "src/unistd/close.h"
+#include "src/unistd/symlink.h"
+#include "src/unistd/unlink.h"
+#include "test/ErrnoSetterMatcher.h"
+#include "utils/UnitTest/Test.h"
+
+#include <errno.h>
+
+TEST(LlvmLibcSymlinkTest, CreateAndUnlink) {
+ using __llvm_libc::testing::ErrnoSetterMatcher::Succeeds;
+ constexpr const char *TEST_FILE_BASE = "symlink.test";
+ constexpr const char *TEST_FILE = "testdata/symlink.test";
+ constexpr const char *TEST_FILE_LINK = "testdata/symlink.test.symlink";
+
+ // The test strategy is as follows:
+ // 1. Create a normal file
+ // 2. Create a symlink to that file.
+ // 3. Open the symlink to check that the symlink was created.
+ // 4. Cleanup the file and its symlink.
+ errno = 0;
+ int write_fd = __llvm_libc::open(TEST_FILE, O_WRONLY | O_CREAT, S_IRWXU);
+ ASSERT_EQ(errno, 0);
+ ASSERT_GT(write_fd, 0);
+ ASSERT_THAT(__llvm_libc::close(write_fd), Succeeds(0));
+
+ ASSERT_THAT(__llvm_libc::symlink(TEST_FILE_BASE, TEST_FILE_LINK),
+ Succeeds(0));
+
+ int symlink_fd = __llvm_libc::open(TEST_FILE_LINK, O_PATH);
+ ASSERT_GT(symlink_fd, 0);
+ ASSERT_EQ(errno, 0);
+ ASSERT_THAT(__llvm_libc::close(symlink_fd), Succeeds(0));
+
+ ASSERT_THAT(__llvm_libc::unlink(TEST_FILE), Succeeds(0));
+ ASSERT_THAT(__llvm_libc::unlink(TEST_FILE_LINK), Succeeds(0));
+}
+
+TEST(LlvmLibcSymlinkTest, SymlinkInNonExistentPath) {
+ using __llvm_libc::testing::ErrnoSetterMatcher::Fails;
+ ASSERT_THAT(__llvm_libc::symlink("non-existent-dir/non-existent-file",
+ "non-existent-dir/bad-symlink"),
+ Fails(ENOENT));
+}
diff --git a/libc/test/src/unistd/symlinkat_test.cpp b/libc/test/src/unistd/symlinkat_test.cpp
new file mode 100644
index 0000000000000..a1f416a403e61
--- /dev/null
+++ b/libc/test/src/unistd/symlinkat_test.cpp
@@ -0,0 +1,56 @@
+//===-- Unittests for symlinkat -------------------------------------------===//
+//
+// 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/fcntl/open.h"
+#include "src/unistd/close.h"
+#include "src/unistd/symlinkat.h"
+#include "src/unistd/unlink.h"
+#include "test/ErrnoSetterMatcher.h"
+#include "utils/UnitTest/Test.h"
+
+#include <errno.h>
+
+TEST(LlvmLibcSymlinkatTest, CreateAndUnlink) {
+ using __llvm_libc::testing::ErrnoSetterMatcher::Succeeds;
+ constexpr const char *TEST_DIR = "testdata";
+ constexpr const char *TEST_FILE = "symlinkat.test";
+ constexpr const char *TEST_FILE_PATH = "testdata/symlinkat.test";
+ constexpr const char *TEST_FILE_LINK = "symlinkat.test.link";
+ constexpr const char *TEST_FILE_LINK_PATH = "testdata/symlinkat.test.link";
+
+ // The test strategy is as follows:
+ // 1. Create a normal file
+ // 2. Create a link to that file.
+ // 3. Open the link to check that the link was created.
+ // 4. Cleanup the file and its link.
+ errno = 0;
+ int write_fd = __llvm_libc::open(TEST_FILE_PATH, O_WRONLY | O_CREAT, S_IRWXU);
+ ASSERT_EQ(errno, 0);
+ ASSERT_GT(write_fd, 0);
+ ASSERT_THAT(__llvm_libc::close(write_fd), Succeeds(0));
+
+ int dir_fd = __llvm_libc::open(TEST_DIR, O_DIRECTORY);
+ ASSERT_THAT(__llvm_libc::symlinkat(TEST_FILE, dir_fd, TEST_FILE_LINK),
+ Succeeds(0));
+
+ int link_fd = __llvm_libc::open(TEST_FILE_LINK_PATH, O_PATH);
+ ASSERT_GT(link_fd, 0);
+ ASSERT_EQ(errno, 0);
+ ASSERT_THAT(__llvm_libc::close(link_fd), Succeeds(0));
+
+ ASSERT_THAT(__llvm_libc::close(dir_fd), Succeeds(0));
+ ASSERT_THAT(__llvm_libc::unlink(TEST_FILE_LINK_PATH), Succeeds(0));
+ ASSERT_THAT(__llvm_libc::unlink(TEST_FILE_PATH), Succeeds(0));
+}
+
+TEST(LlvmLibcSymlinkatTest, SymlinkInNonExistentPath) {
+ using __llvm_libc::testing::ErrnoSetterMatcher::Fails;
+ ASSERT_THAT(__llvm_libc::symlinkat("non-existent-dir/non-existent-file",
+ AT_FDCWD, "non-existent-dir/bad-link"),
+ Fails(ENOENT));
+}
More information about the libc-commits
mailing list