# unistd.h entrypoints
libc.src.unistd.close
libc.src.unistd.fsync
+ libc.src.unistd.lseek
libc.src.unistd.read
libc.src.unistd.rmdir
libc.src.unistd.unlink
}
def UniStdAPI : PublicAPI<"unistd.h"> {
- let Types = ["size_t", "ssize_t"];
+ let Types = ["off_t", "size_t", "ssize_t"];
}
def SysStatAPI : PublicAPI<"sys/stat.h"> {
# unistd.h entrypoints
libc.src.unistd.close
libc.src.unistd.fsync
+ libc.src.unistd.lseek
libc.src.unistd.read
libc.src.unistd.rmdir
libc.src.unistd.unlink
GEN_HDR stdio.h
DEPENDS
.llvm_libc_common_h
- .llvm-libc-macros.stdio_macros
+ .llvm-libc-macros.file_seek_macros
.llvm-libc-types.FILE
.llvm-libc-types.size_t
)
GEN_HDR unistd.h
DEPENDS
.llvm_libc_common_h
+ .llvm-libc-macros.file_seek_macros
.llvm-libc-types.size_t
.llvm-libc-types.ssize_t
)
)
add_header(
- stdio_macros
+ file_seek_macros
HDR
- stdio-macros.h
+ file-seek-macros.h
)
-//===-- Definition of macros from stdio.h ---------------------------------===//
+//===-- Definition of macros to be used with file seek functions ----------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
//
//===----------------------------------------------------------------------===//
-#ifndef __LLVM_LIBC_MACROS_STDIO_MACROS_H
-#define __LLVM_LIBC_MACROS_STDIO_MACROS_H
+#ifndef __LLVM_LIBC_MACROS_FILE_SEEK_MACROS_H
+#define __LLVM_LIBC_MACROS_FILE_SEEK_MACROS_H
#define SEEK_SET 0
#define SEEK_CUR 1
#define SEEK_END 2
-#endif // __LLVM_LIBC_MACROS_STDIO_MACROS_H
+#endif // __LLVM_LIBC_MACROS_FILE_SEEK_MACROS_H
#define LLVM_LIBC_STDIO_H
#include <__llvm-libc-common.h>
-#include <llvm-libc-macros/stdio-macros.h>
+#include <llvm-libc-macros/file-seek-macros.h>
%%public_api()
#define LLVM_LIBC_UNISTD_H
#include <__llvm-libc-common.h>
+#include <llvm-libc-macros/file-seek-macros.h>
%%public_api()
"unistd.h",
[], // Macros
[
+ OffTType,
SSizeTType,
SizeTType,
],
[ArgSpec<IntType>]
>,
FunctionSpec<
+ "lseek",
+ RetValSpec<OffTType>,
+ [ArgSpec<IntType>, ArgSpec<OffTType>, ArgSpec<IntType>]
+ >,
+ FunctionSpec<
"read",
RetValSpec<SSizeTType>,
[ArgSpec<IntType>, ArgSpec<VoidPtr>, ArgSpec<SizeTType>]
)
add_entrypoint_object(
+ lseek
+ ALIAS
+ DEPENDS
+ .${LIBC_TARGET_OS}.lseek
+)
+
+add_entrypoint_object(
read
ALIAS
DEPENDS
)
add_entrypoint_object(
+ lseek
+ SRCS
+ lseek.cpp
+ HDRS
+ ../lseek.h
+ DEPENDS
+ libc.include.unistd
+ libc.include.sys_syscall
+ libc.src.__support.OSUtil.osutil
+ libc.src.errno.errno
+)
+
+add_entrypoint_object(
read
SRCS
read.cpp
--- /dev/null
+//===-- Linux implementation of lseek -------------------------------------===//
+//
+// 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/lseek.h"
+
+#include "src/__support/OSUtil/syscall.h" // For internal syscall function.
+#include "src/__support/common.h"
+
+#include <errno.h>
+#include <sys/syscall.h> // For syscall numbers.
+#include <unistd.h>
+
+namespace __llvm_libc {
+
+LLVM_LIBC_FUNCTION(off_t, lseek, (int fd, off_t offset, int whence)) {
+ off_t result;
+#ifdef SYS_lseek
+ long ret = __llvm_libc::syscall(SYS_lseek, fd, offset, whence);
+ result = ret;
+#elif defined(SYS__llseek)
+ long ret = __llvm_libc::syscall(SYS__lseek, fd, offset >> 32, offset, &result,
+ whence);
+#else
+#error "lseek and _llseek syscalls not available."
+#endif
+
+ if (ret < 0) {
+ errno = -ret;
+ return -1;
+ }
+ return result;
+}
+
+} // namespace __llvm_libc
--- /dev/null
+//===-- Implementation header for lseek -------------------------*- 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_LSEEK_H
+#define LLVM_LIBC_SRC_UNISTD_LSEEK_H
+
+#include <unistd.h>
+
+namespace __llvm_libc {
+
+off_t lseek(int fd, off_t offset, int whence);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_UNISTD_LSEEK_H
)
add_libc_unittest(
+ lseek_test
+ SUITE
+ libc_unistd_unittests
+ SRCS
+ lseek_test.cpp
+ DEPENDS
+ libc.include.errno
+ libc.include.unistd
+ libc.src.fcntl.open
+ libc.src.unistd.close
+ libc.src.unistd.lseek
+ libc.src.unistd.read
+ libc.test.errno_setter_matcher
+)
+
+add_libc_unittest(
rmdir_test
SUITE
libc_unistd_unittests
--- /dev/null
+//===-- Unittests for lseek -----------------------------------------------===//
+//
+// 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/lseek.h"
+#include "src/unistd/read.h"
+#include "test/ErrnoSetterMatcher.h"
+#include "utils/UnitTest/Test.h"
+#include "utils/testutils/FDReader.h"
+
+#include <errno.h>
+#include <unistd.h>
+
+TEST(LlvmLibcUniStd, LseekTest) {
+ using __llvm_libc::testing::ErrnoSetterMatcher::Succeeds;
+ constexpr const char *TEST_FILE = "testdata/lseek.test";
+ int fd = __llvm_libc::open(TEST_FILE, O_RDONLY);
+ ASSERT_EQ(errno, 0);
+ ASSERT_GT(fd, 0);
+ constexpr const char LSEEK_TEST[] = "lseek test";
+ constexpr int LSEEK_TEST_SIZE = sizeof(LSEEK_TEST) - 1;
+
+ char read_buf[20];
+ ASSERT_THAT(__llvm_libc::read(fd, read_buf, LSEEK_TEST_SIZE),
+ Succeeds(LSEEK_TEST_SIZE));
+ read_buf[LSEEK_TEST_SIZE] = '\0';
+ EXPECT_STREQ(read_buf, LSEEK_TEST);
+
+ // Seek to the beginning of the file and re-read.
+ ASSERT_THAT(__llvm_libc::lseek(fd, 0, SEEK_SET), Succeeds(0));
+ ASSERT_THAT(__llvm_libc::read(fd, read_buf, LSEEK_TEST_SIZE),
+ Succeeds(LSEEK_TEST_SIZE));
+ read_buf[LSEEK_TEST_SIZE] = '\0';
+ EXPECT_STREQ(read_buf, LSEEK_TEST);
+
+ // Seek to the beginning of the file from the end and re-read.
+ ASSERT_THAT(__llvm_libc::lseek(fd, -LSEEK_TEST_SIZE, SEEK_END), Succeeds(0));
+ ASSERT_THAT(__llvm_libc::read(fd, read_buf, LSEEK_TEST_SIZE),
+ Succeeds(LSEEK_TEST_SIZE));
+ read_buf[LSEEK_TEST_SIZE] = '\0';
+ EXPECT_STREQ(read_buf, LSEEK_TEST);
+
+ ASSERT_THAT(__llvm_libc::close(fd), Succeeds(0));
+}
+
+TEST(LlvmLibcUniStd, LseekFailsTest) {
+ using __llvm_libc::testing::ErrnoSetterMatcher::Fails;
+ using __llvm_libc::testing::ErrnoSetterMatcher::Succeeds;
+ constexpr const char *TEST_FILE = "testdata/lseek.test";
+ int fd = __llvm_libc::open(TEST_FILE, O_RDONLY);
+ ASSERT_EQ(errno, 0);
+ ASSERT_GT(fd, 0);
+ EXPECT_THAT(__llvm_libc::lseek(fd, -1, SEEK_CUR), Fails(EINVAL));
+ ASSERT_THAT(__llvm_libc::close(fd), Succeeds(0));
+}
# This directory will be used to create test files and delete them
# from tests.
+
+file(GENERATE OUTPUT lseek.test CONTENT "lseek test")