39 changes: 39 additions & 0 deletions libc/src/unistd/linux/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,42 @@
add_entrypoint_object(
close
SRCS
close.cpp
HDRS
../close.h
DEPENDS
libc.include.unistd
libc.include.sys_syscall
libc.src.__support.OSUtil.osutil
libc.src.errno.__errno_location
)

add_entrypoint_object(
fsync
SRCS
fsync.cpp
HDRS
../fsync.h
DEPENDS
libc.include.unistd
libc.include.sys_syscall
libc.src.__support.OSUtil.osutil
libc.src.errno.__errno_location
)

add_entrypoint_object(
read
SRCS
read.cpp
HDRS
../read.h
DEPENDS
libc.include.unistd
libc.include.sys_syscall
libc.src.__support.OSUtil.osutil
libc.src.errno.__errno_location
)

add_entrypoint_object(
write
SRCS
Expand Down
28 changes: 28 additions & 0 deletions libc/src/unistd/linux/close.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//===-- Linux implementation of close -------------------------------------===//
//
// 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/close.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.

namespace __llvm_libc {

LLVM_LIBC_FUNCTION(int, close, (int fd)) {
long ret = __llvm_libc::syscall(SYS_close, fd);
if (ret < 0) {
errno = -ret;
return -1;
}
return ret;
}

} // namespace __llvm_libc
28 changes: 28 additions & 0 deletions libc/src/unistd/linux/fsync.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//===-- Linux implementation of fsync -------------------------------------===//
//
// 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/fsync.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.

namespace __llvm_libc {

LLVM_LIBC_FUNCTION(int, fsync, (int fd)) {
long ret = __llvm_libc::syscall(SYS_fsync, fd);
if (ret < 0) {
errno = -ret;
return -1;
}
return ret;
}

} // namespace __llvm_libc
28 changes: 28 additions & 0 deletions libc/src/unistd/linux/read.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//===-- Linux implementation of read --------------------------------------===//
//
// 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/read.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.

namespace __llvm_libc {

LLVM_LIBC_FUNCTION(ssize_t, read, (int fd, void *buf, size_t count)) {
long ret = __llvm_libc::syscall(SYS_read, fd, buf, count);
if (ret < 0) {
errno = -ret;
return -1;
}
return ret;
}

} // namespace __llvm_libc
2 changes: 1 addition & 1 deletion libc/src/unistd/linux/write.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
#include "src/__support/common.h"

#include <errno.h>
#include <sys/syscall.h> // For syscall numbers.
#include <sys/syscall.h> // For syscall numbers.

namespace __llvm_libc {

Expand Down
20 changes: 20 additions & 0 deletions libc/src/unistd/read.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//===-- Implementation header for read --------------------------*- 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_READ_H
#define LLVM_LIBC_SRC_UNISTD_READ_H

#include <unistd.h>

namespace __llvm_libc {

ssize_t read(int fd, void *buf, size_t count);

} // namespace __llvm_libc

#endif // LLVM_LIBC_SRC_UNISTD_READ_H
8 changes: 6 additions & 2 deletions libc/test/src/unistd/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
add_libc_testsuite(libc_unistd_unittests)

add_libc_unittest(
write_test
read_write_test
SUITE
libc_unistd_unittests
SRCS
write_test.cpp
read_write_test.cpp
DEPENDS
libc.include.errno
libc.include.unistd
libc.src.fcntl.open
libc.src.unistd.close
libc.src.unistd.fsync
libc.src.unistd.read
libc.src.unistd.write
libc.test.errno_setter_matcher
)
59 changes: 59 additions & 0 deletions libc/test/src/unistd/read_write_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
//===-- Unittests for read and write --------------------------------------===//
//
// 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/fsync.h"
#include "src/unistd/read.h"
#include "src/unistd/write.h"
#include "test/ErrnoSetterMatcher.h"
#include "utils/UnitTest/Test.h"
#include "utils/testutils/FDReader.h"

#include <errno.h>

TEST(LlvmLibcUniStd, WriteAndReadBackTest) {
using __llvm_libc::testing::ErrnoSetterMatcher::Succeeds;
constexpr const char *TEST_FILE = "__unistd_read_write.test";
int write_fd = __llvm_libc::open(TEST_FILE, O_WRONLY | O_CREAT);
ASSERT_EQ(errno, 0);
ASSERT_GT(write_fd, 0);
constexpr const char HELLO[] = "hello";
constexpr int HELLO_SIZE = sizeof(HELLO);
ASSERT_THAT(__llvm_libc::write(write_fd, HELLO, HELLO_SIZE),
Succeeds(HELLO_SIZE));
ASSERT_THAT(__llvm_libc::fsync(write_fd), Succeeds(0));
ASSERT_THAT(__llvm_libc::close(write_fd), Succeeds(0));

int read_fd = __llvm_libc::open(TEST_FILE, O_RDONLY);
ASSERT_EQ(errno, 0);
ASSERT_GT(read_fd, 0);
char read_buf[10];
ASSERT_THAT(__llvm_libc::read(read_fd, read_buf, HELLO_SIZE),
Succeeds(HELLO_SIZE));
EXPECT_STREQ(read_buf, HELLO);
ASSERT_THAT(__llvm_libc::close(read_fd), Succeeds(0));

// TODO: 'remove' the test file after the test.
}

TEST(LlvmLibcUniStd, WriteFails) {
using __llvm_libc::testing::ErrnoSetterMatcher::Fails;

EXPECT_THAT(__llvm_libc::write(-1, "", 1), Fails(EBADF));
EXPECT_THAT(__llvm_libc::write(1, reinterpret_cast<const void *>(-1), 1),
Fails(EFAULT));
}

TEST(LlvmLibcUniStd, ReadFails) {
using __llvm_libc::testing::ErrnoSetterMatcher::Fails;

EXPECT_THAT(__llvm_libc::read(-1, nullptr, 1), Fails(EBADF));
EXPECT_THAT(__llvm_libc::read(0, reinterpret_cast<void *>(-1), 1),
Fails(EFAULT));
}
30 changes: 0 additions & 30 deletions libc/test/src/unistd/write_test.cpp

This file was deleted.