diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt index dbf81c284e7845d..6abb35ab0ead705 100644 --- a/libc/config/linux/aarch64/entrypoints.txt +++ b/libc/config/linux/aarch64/entrypoints.txt @@ -195,6 +195,7 @@ set(TARGET_LIBC_ENTRYPOINTS # stdio.h entrypoints libc.src.stdio.remove + libc.src.stdio.rename libc.src.stdio.sprintf libc.src.stdio.snprintf libc.src.stdio.vsprintf diff --git a/libc/config/linux/riscv/entrypoints.txt b/libc/config/linux/riscv/entrypoints.txt index b42a55a4d712e18..e34c87ec6b5d342 100644 --- a/libc/config/linux/riscv/entrypoints.txt +++ b/libc/config/linux/riscv/entrypoints.txt @@ -196,6 +196,7 @@ set(TARGET_LIBC_ENTRYPOINTS # stdio.h entrypoints libc.src.stdio.remove + libc.src.stdio.rename libc.src.stdio.sprintf libc.src.stdio.snprintf libc.src.stdio.fprintf diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt index c216f43496270b4..8e1ab5cd65f005f 100644 --- a/libc/config/linux/x86_64/entrypoints.txt +++ b/libc/config/linux/x86_64/entrypoints.txt @@ -198,6 +198,7 @@ set(TARGET_LIBC_ENTRYPOINTS # stdio.h entrypoints libc.src.stdio.remove + libc.src.stdio.rename libc.src.stdio.sprintf libc.src.stdio.snprintf libc.src.stdio.fprintf diff --git a/libc/docs/stdio.rst b/libc/docs/stdio.rst index 4fd6b71a09171ba..d17821562c25567 100644 --- a/libc/docs/stdio.rst +++ b/libc/docs/stdio.rst @@ -68,7 +68,7 @@ These functions operate on files on the host's system, without using the Function_Name Available ============= ========= remove |check| -rename +rename |check| tmpnam ============= ========= diff --git a/libc/spec/stdc.td b/libc/spec/stdc.td index 920036adfed5c13..76010a4b4533a7d 100644 --- a/libc/spec/stdc.td +++ b/libc/spec/stdc.td @@ -706,6 +706,11 @@ def StdC : StandardSpec<"stdc"> { RetValSpec, [ArgSpec] >, + FunctionSpec< + "rename", + RetValSpec, + [ArgSpec, ArgSpec] + >, FunctionSpec< "setbuf", RetValSpec, diff --git a/libc/src/stdio/CMakeLists.txt b/libc/src/stdio/CMakeLists.txt index ece93fd56ef0c52..11e15c91735188d 100644 --- a/libc/src/stdio/CMakeLists.txt +++ b/libc/src/stdio/CMakeLists.txt @@ -256,6 +256,13 @@ add_entrypoint_object( .${LIBC_TARGET_OS}.remove ) +add_entrypoint_object( + rename + ALIAS + DEPENDS + .${LIBC_TARGET_OS}.rename +) + # These entrypoints have multiple potential implementations. add_stdio_entrypoint_object(feof) add_stdio_entrypoint_object(feof_unlocked) diff --git a/libc/src/stdio/linux/CMakeLists.txt b/libc/src/stdio/linux/CMakeLists.txt index 774f24b2db0bdcb..a08ff0ba4832ffe 100644 --- a/libc/src/stdio/linux/CMakeLists.txt +++ b/libc/src/stdio/linux/CMakeLists.txt @@ -12,3 +12,15 @@ add_entrypoint_object( libc.src.__support.OSUtil.osutil libc.src.errno.errno ) + +add_entrypoint_object( + rename + SRCS + rename.cpp + HDRS + ../rename.h + DEPENDS + libc.include.sys_syscall + libc.src.__support.OSUtil.osutil + libc.src.errno.errno +) diff --git a/libc/src/stdio/linux/rename.cpp b/libc/src/stdio/linux/rename.cpp new file mode 100644 index 000000000000000..f3d684249ad28ee --- /dev/null +++ b/libc/src/stdio/linux/rename.cpp @@ -0,0 +1,26 @@ +//===-- Linux implementation of rename ------------------------------------===// +// +// 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/stdio/rename.h" +#include "src/__support/OSUtil/syscall.h" // For internal syscall function. +#include "src/__support/common.h" +#include "src/errno/libc_errno.h" +#include // For syscall numbers. + +namespace LIBC_NAMESPACE { + +LLVM_LIBC_FUNCTION(int, rename, (const char *oldpath, const char *newpath)) { + int ret = LIBC_NAMESPACE::syscall_impl(SYS_rename, oldpath, newpath); + + if (ret >= 0) + return 0; + libc_errno = -ret; + return -1; +} + +} // namespace LIBC_NAMESPACE diff --git a/libc/src/stdio/rename.h b/libc/src/stdio/rename.h new file mode 100644 index 000000000000000..eadda7c3eac9b63 --- /dev/null +++ b/libc/src/stdio/rename.h @@ -0,0 +1,18 @@ +//===-- Implementation header of rename -------------------------*- 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_STDIO_RENAME_H +#define LLVM_LIBC_SRC_STDIO_RENAME_H + +namespace LIBC_NAMESPACE { + +int rename(const char *oldpath, const char *newpath); + +} // namespace LIBC_NAMESPACE + +#endif // LLVM_LIBC_SRC_STDIO_RENAME_H diff --git a/libc/test/src/stdio/CMakeLists.txt b/libc/test/src/stdio/CMakeLists.txt index 3ccce16a76a2d5a..a11a232c27e1a72 100644 --- a/libc/test/src/stdio/CMakeLists.txt +++ b/libc/test/src/stdio/CMakeLists.txt @@ -354,6 +354,21 @@ if(${LIBC_TARGET_OS} STREQUAL "linux") libc.src.unistd.access libc.src.unistd.close ) + + add_libc_test( + rename_test + SUITE + libc_stdio_unittests + SRCS + rename_test.cpp + DEPENDS + libc.src.errno.errno + libc.src.fcntl.open + libc.src.stdio.rename + libc.src.unistd.access + libc.src.unistd.close + libc.test.UnitTest.ErrnoSetterMatcher + ) endif() add_libc_test( diff --git a/libc/test/src/stdio/rename_test.cpp b/libc/test/src/stdio/rename_test.cpp new file mode 100644 index 000000000000000..a9fbe24ded9cf7c --- /dev/null +++ b/libc/test/src/stdio/rename_test.cpp @@ -0,0 +1,49 @@ +//===-- Unittests for rename ----------------------------------------------===// +// +// 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/errno/libc_errno.h" +#include "src/fcntl/open.h" +#include "src/stdio/rename.h" +#include "src/unistd/access.h" +#include "src/unistd/close.h" +#include "test/UnitTest/ErrnoSetterMatcher.h" +#include "test/UnitTest/Test.h" + +TEST(LlvmLibcRenameTest, CreateAndRenameFile) { + // The test strategy is to create a file and rename it, and also verify that + // it was renamed. + LIBC_NAMESPACE::libc_errno = 0; + using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Fails; + using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds; + + constexpr const char *FILENAME0 = "rename.test.file0"; + auto TEST_FILEPATH0 = libc_make_test_file_path(FILENAME0); + + int fd = LIBC_NAMESPACE::open(TEST_FILEPATH0, O_WRONLY | O_CREAT, S_IRWXU); + ASSERT_ERRNO_SUCCESS(); + ASSERT_GT(fd, 0); + ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0)); + ASSERT_THAT(LIBC_NAMESPACE::access(TEST_FILEPATH0, F_OK), Succeeds(0)); + + constexpr const char *FILENAME1 = "rename.test.file1"; + auto TEST_FILEPATH1 = libc_make_test_file_path(FILENAME1); + ASSERT_THAT(LIBC_NAMESPACE::rename(TEST_FILEPATH0, TEST_FILEPATH1), + Succeeds(0)); + ASSERT_THAT(LIBC_NAMESPACE::access(TEST_FILEPATH1, F_OK), Succeeds(0)); + ASSERT_THAT(LIBC_NAMESPACE::access(TEST_FILEPATH0, F_OK), Fails(ENOENT)); +} + +TEST(LlvmLibcRenameTest, RenameNonExistent) { + using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Fails; + + constexpr const char *FILENAME1 = "rename.test.file1"; + auto TEST_FILEPATH1 = libc_make_test_file_path(FILENAME1); + + ASSERT_THAT(LIBC_NAMESPACE::rename("non-existent", TEST_FILEPATH1), + Fails(ENOENT)); +} diff --git a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel index 40cfb1f470dbec2..fe4b8e2de14e663 100644 --- a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel +++ b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel @@ -3262,6 +3262,17 @@ libc_function( ], ) +libc_function( + name = "rename", + srcs = ["src/stdio/linux/rename.cpp"], + hdrs = ["src/stdio/rename.h"], + deps = [ + ":__support_common", + ":__support_osutil_syscall", + ":errno", + ], +) + ############################### sys/stat targets ############################### libc_function(