| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| //===-- Linux implementation of fstat -------------------------------------===// | ||
| // | ||
| // 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/sys/stat/fstat.h" | ||
| #include "kernel_statx.h" | ||
|
|
||
| #include "src/__support/common.h" | ||
|
|
||
| #include <fcntl.h> | ||
| #include <sys/stat.h> | ||
|
|
||
| namespace __llvm_libc { | ||
|
|
||
| LLVM_LIBC_FUNCTION(int, fstat, (int fd, struct stat *statbuf)) { | ||
| return statx(fd, "", AT_EMPTY_PATH, statbuf); | ||
| } | ||
|
|
||
| } // namespace __llvm_libc |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,105 @@ | ||
| //===-- Wrapper over SYS_statx syscall ------------------------------------===// | ||
| // | ||
| // 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_SYS_STAT_LINUX_STATX_H | ||
| #define LLVM_LIBC_SRC_SYS_STAT_LINUX_STATX_H | ||
|
|
||
| #include "src/__support/OSUtil/syscall.h" // For internal syscall function. | ||
|
|
||
| #include <errno.h> | ||
| #include <stdint.h> | ||
| #include <sys/stat.h> | ||
| #include <sys/syscall.h> // For syscall numbers. | ||
|
|
||
| // It is safe to include this kernel header as it is designed to be | ||
| // included from user programs without causing any name pollution. | ||
| #include <linux/kdev_t.h> | ||
|
|
||
| namespace { | ||
|
|
||
| // The type definitions in the internal namespace match kernel's definition of | ||
| // the statx_timestamp and statx types in linux/stat.h. We define equivalent | ||
| // types here instead of including that header file to avoid name mixup between | ||
| // linux/stat.h and the libc's stat.h. | ||
| struct statx_timestamp { | ||
| int64_t tv_sec; | ||
| uint32_t tv_nsec; | ||
| int32_t __reserved; | ||
| }; | ||
|
|
||
| struct statx_buf { | ||
| uint32_t stx_mask; // What results were written | ||
| uint32_t stx_blksize; // Preferred general I/O size | ||
| uint64_t stx_attributes; // Flags conveying information about the file | ||
| uint32_t stx_nlink; // Number of hard links | ||
| uint32_t stx_uid; // User ID of owner | ||
| uint32_t stx_gid; // Group ID of owner | ||
| uint16_t stx_mode; // File mode | ||
| uint16_t __spare0[1]; | ||
| uint64_t stx_ino; // Inode number | ||
| uint64_t stx_size; // File size | ||
| uint64_t stx_blocks; // Number of 512-byte blocks allocated | ||
| uint64_t stx_attributes_mask; // Mask to show what's supported in | ||
| // stx_attributes | ||
| struct statx_timestamp stx_atime; // Last access time | ||
| struct statx_timestamp stx_btime; // File creation time | ||
| struct statx_timestamp stx_ctime; // Last attribute change time | ||
| struct statx_timestamp stx_mtime; // Last data modification time | ||
| uint32_t stx_rdev_major; // Device ID of special file | ||
| uint32_t stx_rdev_minor; | ||
| uint32_t stx_dev_major; // ID of device containing file | ||
| uint32_t stx_dev_minor; | ||
| uint64_t stx_mnt_id; | ||
| uint64_t __spare2; | ||
| uint64_t __spare3[12]; // Spare space for future expansion | ||
| }; | ||
|
|
||
| // The below mask value is based on the definition of a similarly | ||
| // named macro in linux/stat.h. When this flag is passed for the | ||
| // mask argument to the statx syscall, all fields except the | ||
| // stx_btime field will be filled in. | ||
| constexpr unsigned int STATX_BASIC_STATS_MASK = 0x7FF; | ||
|
|
||
| } // Anonymous namespace | ||
|
|
||
| namespace __llvm_libc { | ||
|
|
||
| inline int statx(int dirfd, const char *__restrict path, int flags, | ||
| struct stat *__restrict statbuf) { | ||
| // We make a statx syscall and copy out the result into the |statbuf|. | ||
| ::statx_buf xbuf; | ||
| long ret = | ||
| syscall(SYS_statx, dirfd, path, flags, ::STATX_BASIC_STATS_MASK, &xbuf); | ||
| if (ret < 0) { | ||
| errno = -ret; | ||
| return -1; | ||
| } | ||
|
|
||
| statbuf->st_dev = MKDEV(xbuf.stx_dev_major, xbuf.stx_dev_minor); | ||
| statbuf->st_ino = xbuf.stx_ino; | ||
| statbuf->st_mode = xbuf.stx_mode; | ||
| statbuf->st_nlink = xbuf.stx_nlink; | ||
| statbuf->st_uid = xbuf.stx_uid; | ||
| statbuf->st_gid = xbuf.stx_gid; | ||
| statbuf->st_rdev = MKDEV(xbuf.stx_rdev_major, xbuf.stx_rdev_minor); | ||
| statbuf->st_size = xbuf.stx_size; | ||
| statbuf->st_atim.tv_sec = xbuf.stx_atime.tv_sec; | ||
| statbuf->st_atim.tv_nsec = xbuf.stx_atime.tv_nsec; | ||
| statbuf->st_mtim.tv_sec = xbuf.stx_mtime.tv_sec; | ||
| statbuf->st_mtim.tv_nsec = xbuf.stx_mtime.tv_nsec; | ||
| statbuf->st_ctim.tv_sec = xbuf.stx_ctime.tv_sec; | ||
| statbuf->st_ctim.tv_nsec = xbuf.stx_ctime.tv_nsec; | ||
| statbuf->st_blksize = xbuf.stx_blksize; | ||
| statbuf->st_blocks = xbuf.stx_blocks; | ||
|
|
||
| return 0; | ||
| } | ||
|
|
||
| } // namespace __llvm_libc | ||
|
|
||
| #endif // LLVM_LIBC_SRC_SYS_STAT_LINUX_STATX_H |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| //===-- Linux implementation of lstat -------------------------------------===// | ||
| // | ||
| // 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/sys/stat/lstat.h" | ||
| #include "kernel_statx.h" | ||
|
|
||
| #include "src/__support/OSUtil/syscall.h" // For internal syscall function. | ||
| #include "src/__support/common.h" | ||
|
|
||
| #include <fcntl.h> | ||
| #include <sys/stat.h> | ||
|
|
||
| namespace __llvm_libc { | ||
|
|
||
| LLVM_LIBC_FUNCTION(int, lstat, | ||
| (const char *__restrict path, | ||
| struct stat *__restrict statbuf)) { | ||
| return statx(AT_FDCWD, path, AT_SYMLINK_NOFOLLOW, statbuf); | ||
| } | ||
|
|
||
| } // namespace __llvm_libc |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| //===-- Linux implementation of stat --------------------------------------===// | ||
| // | ||
| // 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/sys/stat/stat.h" | ||
| #include "kernel_statx.h" | ||
|
|
||
| #include "src/__support/common.h" | ||
|
|
||
| #include <fcntl.h> | ||
| #include <sys/stat.h> | ||
|
|
||
| namespace __llvm_libc { | ||
|
|
||
| LLVM_LIBC_FUNCTION(int, stat, | ||
| (const char *__restrict path, | ||
| struct stat *__restrict statbuf)) { | ||
| return statx(AT_FDCWD, path, 0, statbuf); | ||
| } | ||
|
|
||
| } // namespace __llvm_libc |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| //===-- Implementation header for lstat -------------------------*- 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_SYS_STAT_LSTAT_H | ||
| #define LLVM_LIBC_SRC_SYS_STAT_LSTAT_H | ||
|
|
||
| #include <sys/stat.h> | ||
|
|
||
| namespace __llvm_libc { | ||
|
|
||
| int lstat(const char *__restrict path, struct stat *__restrict statbuf); | ||
|
|
||
| } // namespace __llvm_libc | ||
|
|
||
| #endif // LLVM_LIBC_SRC_SYS_STAT_LSTAT_H |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| //===-- Implementation header for stat --------------------------*- 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_SYS_STAT_STAT_H | ||
| #define LLVM_LIBC_SRC_SYS_STAT_STAT_H | ||
|
|
||
| #include <sys/stat.h> | ||
|
|
||
| namespace __llvm_libc { | ||
|
|
||
| int stat(const char *__restrict path, struct stat *__restrict statbuf); | ||
|
|
||
| } // namespace __llvm_libc | ||
|
|
||
| #endif // LLVM_LIBC_SRC_SYS_STAT_STAT_H |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| //===-- Unittests for fstat -----------------------------------------------===// | ||
| // | ||
| // 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/sys/stat/fstat.h" | ||
| #include "src/unistd/close.h" | ||
| #include "src/unistd/unlink.h" | ||
| #include "test/ErrnoSetterMatcher.h" | ||
| #include "utils/UnitTest/Test.h" | ||
| #include "utils/testutils/FDReader.h" | ||
|
|
||
| #include <errno.h> | ||
| #include <fcntl.h> | ||
| #include <sys/stat.h> | ||
|
|
||
| TEST(LlvmLibcFStatTest, CreatAndReadMode) { | ||
| using __llvm_libc::testing::ErrnoSetterMatcher::Fails; | ||
| using __llvm_libc::testing::ErrnoSetterMatcher::Succeeds; | ||
|
|
||
| // The test file is initially writable. We open it for writing and ensure | ||
| // that it indeed can be opened for writing. Next, we close the file and | ||
| // make it readonly using chmod. We test that chmod actually succeeded by | ||
| // trying to open the file for writing and failing. | ||
| constexpr const char *TEST_FILE = "testdata/fstat.test"; | ||
| errno = 0; | ||
|
|
||
| int fd = __llvm_libc::open(TEST_FILE, O_CREAT | O_WRONLY, S_IRWXU); | ||
| ASSERT_GT(fd, 0); | ||
| ASSERT_EQ(errno, 0); | ||
|
|
||
| struct stat statbuf; | ||
| ASSERT_THAT(__llvm_libc::fstat(fd, &statbuf), Succeeds(0)); | ||
|
|
||
| ASSERT_EQ(int(statbuf.st_mode), int(S_IRWXU | S_IFREG)); | ||
|
|
||
| ASSERT_THAT(__llvm_libc::close(fd), Succeeds(0)); | ||
| ASSERT_THAT(__llvm_libc::unlink(TEST_FILE), Succeeds(0)); | ||
| } | ||
|
|
||
| TEST(LlvmLibcFStatTest, NonExistentFile) { | ||
| errno = 0; | ||
| using __llvm_libc::testing::ErrnoSetterMatcher::Fails; | ||
| struct stat statbuf; | ||
| ASSERT_THAT(__llvm_libc::fstat(-1, &statbuf), Fails(EBADF)); | ||
| errno = 0; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| //===-- Unittests for lstat -----------------------------------------------===// | ||
| // | ||
| // 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/sys/stat/lstat.h" | ||
| #include "src/unistd/close.h" | ||
| #include "src/unistd/unlink.h" | ||
| #include "test/ErrnoSetterMatcher.h" | ||
| #include "utils/UnitTest/Test.h" | ||
| #include "utils/testutils/FDReader.h" | ||
|
|
||
| #include <errno.h> | ||
| #include <fcntl.h> | ||
| #include <sys/stat.h> | ||
|
|
||
| TEST(LlvmLibcLStatTest, CreatAndReadMode) { | ||
| using __llvm_libc::testing::ErrnoSetterMatcher::Fails; | ||
| using __llvm_libc::testing::ErrnoSetterMatcher::Succeeds; | ||
|
|
||
| // The test file is initially writable. We open it for writing and ensure | ||
| // that it indeed can be opened for writing. Next, we close the file and | ||
| // make it readonly using chmod. We test that chmod actually succeeded by | ||
| // trying to open the file for writing and failing. | ||
| constexpr const char *TEST_FILE = "testdata/lstat.test"; | ||
| errno = 0; | ||
|
|
||
| int fd = __llvm_libc::open(TEST_FILE, O_CREAT | O_WRONLY, S_IRWXU); | ||
| ASSERT_GT(fd, 0); | ||
| ASSERT_EQ(errno, 0); | ||
| ASSERT_THAT(__llvm_libc::close(fd), Succeeds(0)); | ||
|
|
||
| struct stat statbuf; | ||
| ASSERT_THAT(__llvm_libc::lstat(TEST_FILE, &statbuf), Succeeds(0)); | ||
|
|
||
| ASSERT_EQ(int(statbuf.st_mode), int(S_IRWXU | S_IFREG)); | ||
|
|
||
| ASSERT_THAT(__llvm_libc::unlink(TEST_FILE), Succeeds(0)); | ||
| } | ||
|
|
||
| TEST(LlvmLibcLStatTest, NonExistentFile) { | ||
| errno = 0; | ||
| using __llvm_libc::testing::ErrnoSetterMatcher::Fails; | ||
| struct stat statbuf; | ||
| ASSERT_THAT(__llvm_libc::lstat("non-existent-file", &statbuf), Fails(ENOENT)); | ||
| errno = 0; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| //===-- Unittests for stat ------------------------------------------------===// | ||
| // | ||
| // 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/sys/stat/stat.h" | ||
| #include "src/unistd/close.h" | ||
| #include "src/unistd/unlink.h" | ||
| #include "test/ErrnoSetterMatcher.h" | ||
| #include "utils/UnitTest/Test.h" | ||
| #include "utils/testutils/FDReader.h" | ||
|
|
||
| #include <errno.h> | ||
| #include <fcntl.h> | ||
| #include <sys/stat.h> | ||
|
|
||
| TEST(LlvmLibcStatTest, CreatAndReadMode) { | ||
| using __llvm_libc::testing::ErrnoSetterMatcher::Fails; | ||
| using __llvm_libc::testing::ErrnoSetterMatcher::Succeeds; | ||
|
|
||
| // The test file is initially writable. We open it for writing and ensure | ||
| // that it indeed can be opened for writing. Next, we close the file and | ||
| // make it readonly using chmod. We test that chmod actually succeeded by | ||
| // trying to open the file for writing and failing. | ||
| constexpr const char *TEST_FILE = "testdata/stat.test"; | ||
| errno = 0; | ||
|
|
||
| int fd = __llvm_libc::open(TEST_FILE, O_CREAT | O_WRONLY, S_IRWXU); | ||
| ASSERT_GT(fd, 0); | ||
| ASSERT_EQ(errno, 0); | ||
| ASSERT_THAT(__llvm_libc::close(fd), Succeeds(0)); | ||
|
|
||
| struct stat statbuf; | ||
| ASSERT_THAT(__llvm_libc::stat(TEST_FILE, &statbuf), Succeeds(0)); | ||
|
|
||
| ASSERT_EQ(int(statbuf.st_mode), int(S_IRWXU | S_IFREG)); | ||
|
|
||
| ASSERT_THAT(__llvm_libc::unlink(TEST_FILE), Succeeds(0)); | ||
| } | ||
|
|
||
| TEST(LlvmLibcStatTest, NonExistentFile) { | ||
| errno = 0; | ||
| using __llvm_libc::testing::ErrnoSetterMatcher::Fails; | ||
| struct stat statbuf; | ||
| ASSERT_THAT(__llvm_libc::stat("non-existent-file", &statbuf), Fails(ENOENT)); | ||
| errno = 0; | ||
| } |