224 lines · cpp
1//===-- Unittest for fcntl ------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "hdr/fcntl_macros.h"10#include "hdr/stdio_macros.h"11#include "hdr/types/struct_flock.h"12#include "src/fcntl/fcntl.h"13#include "src/fcntl/open.h"14#include "src/unistd/close.h"15#include "src/unistd/getpid.h"16#include "test/UnitTest/ErrnoCheckingTest.h"17#include "test/UnitTest/ErrnoSetterMatcher.h"18#include "test/UnitTest/Test.h"19 20#include <sys/stat.h> // For S_IRWXU21 22using LlvmLibcFcntlTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest;23 24TEST_F(LlvmLibcFcntlTest, FcntlDupfd) {25 using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds;26 constexpr const char *TEST_FILE_NAME = "testdata/fcntl_dup.test";27 auto TEST_FILE = libc_make_test_file_path(TEST_FILE_NAME);28 int fd2, fd3;29 int fd = LIBC_NAMESPACE::open(TEST_FILE, O_CREAT | O_TRUNC, S_IRWXU);30 ASSERT_ERRNO_SUCCESS();31 ASSERT_GT(fd, 0);32 33 fd2 = LIBC_NAMESPACE::fcntl(fd, F_DUPFD, 0);34 ASSERT_ERRNO_SUCCESS();35 ASSERT_GT(fd2, 0);36 37 fd3 = LIBC_NAMESPACE::fcntl(fd, F_DUPFD, 10);38 ASSERT_ERRNO_SUCCESS();39 ASSERT_GT(fd3, 0);40 41 ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));42 ASSERT_THAT(LIBC_NAMESPACE::close(fd2), Succeeds(0));43 ASSERT_THAT(LIBC_NAMESPACE::close(fd3), Succeeds(0));44}45 46TEST_F(LlvmLibcFcntlTest, FcntlGetFl) {47 using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds;48 constexpr const char *TEST_FILE_NAME = "testdata/fcntl_getfl.test";49 auto TEST_FILE = libc_make_test_file_path(TEST_FILE_NAME);50 int retVal;51 int fd = LIBC_NAMESPACE::open(TEST_FILE, O_CREAT | O_TRUNC, S_IRWXU);52 ASSERT_ERRNO_SUCCESS();53 ASSERT_GT(fd, 0);54 55 retVal = LIBC_NAMESPACE::fcntl(fd, F_GETFL);56 ASSERT_ERRNO_SUCCESS();57 ASSERT_GT(retVal, -1);58 59 ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));60}61 62TEST_F(LlvmLibcFcntlTest, FcntlSetFl) {63 using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds;64 constexpr const char *TEST_FILE_NAME = "testdata/fcntl_setfl.test";65 auto TEST_FILE = libc_make_test_file_path(TEST_FILE_NAME);66 67 int retVal;68 int fd = LIBC_NAMESPACE::open(TEST_FILE, O_CREAT | O_TRUNC | O_RDWR, S_IRWXU);69 ASSERT_ERRNO_SUCCESS();70 ASSERT_GT(fd, 0);71 72 retVal = LIBC_NAMESPACE::fcntl(fd, F_GETFL);73 ASSERT_ERRNO_SUCCESS();74 ASSERT_GT(retVal, -1);75 76 int oldFlags = LIBC_NAMESPACE::fcntl(fd, F_GETFL, 0);77 ASSERT_ERRNO_SUCCESS();78 ASSERT_GT(oldFlags, 0);79 80 // Add the APPEND flag;81 oldFlags |= O_APPEND;82 83 retVal = LIBC_NAMESPACE::fcntl(fd, F_SETFL, oldFlags);84 ASSERT_ERRNO_SUCCESS();85 ASSERT_GT(retVal, -1);86 87 // Remove the APPEND flag;88 oldFlags = -oldFlags & O_APPEND;89 90 retVal = LIBC_NAMESPACE::fcntl(fd, F_SETFL, oldFlags);91 ASSERT_ERRNO_SUCCESS();92 ASSERT_GT(retVal, -1);93 94 ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));95}96 97/* Tests that are common between OFD and traditional variants of fcntl locks. */98template <int GETLK_CMD, int SETLK_CMD>99class LibcFcntlCommonLockTests : public LlvmLibcFcntlTest {100public:101 void GetLkRead() {102 using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds;103 constexpr const char *TEST_FILE_NAME = "testdata/fcntl_getlkread.test";104 const auto TEST_FILE = libc_make_test_file_path(TEST_FILE_NAME);105 106 struct flock flk = {};107 struct flock svflk = {};108 int retVal;109 int fd =110 LIBC_NAMESPACE::open(TEST_FILE, O_CREAT | O_TRUNC | O_RDONLY, S_IRWXU);111 ASSERT_ERRNO_SUCCESS();112 ASSERT_GT(fd, 0);113 114 flk.l_type = F_RDLCK;115 flk.l_start = 0;116 flk.l_whence = SEEK_SET;117 flk.l_len = 50;118 119 // copy flk into svflk120 svflk = flk;121 122 retVal = LIBC_NAMESPACE::fcntl(fd, GETLK_CMD, &svflk);123 ASSERT_ERRNO_SUCCESS();124 ASSERT_GT(retVal, -1);125 ASSERT_NE((int)svflk.l_type, F_WRLCK); // File should not be write locked.126 127 retVal = LIBC_NAMESPACE::fcntl(fd, SETLK_CMD, &svflk);128 ASSERT_ERRNO_SUCCESS();129 ASSERT_GT(retVal, -1);130 131 ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));132 }133 134 void GetLkWrite() {135 using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds;136 constexpr const char *TEST_FILE_NAME = "testdata/fcntl_getlkwrite.test";137 const auto TEST_FILE = libc_make_test_file_path(TEST_FILE_NAME);138 139 struct flock flk = {};140 struct flock svflk = {};141 int retVal;142 int fd =143 LIBC_NAMESPACE::open(TEST_FILE, O_CREAT | O_TRUNC | O_RDWR, S_IRWXU);144 ASSERT_ERRNO_SUCCESS();145 ASSERT_GT(fd, 0);146 147 flk.l_type = F_WRLCK;148 flk.l_start = 0;149 flk.l_whence = SEEK_SET;150 flk.l_len = 0;151 152 // copy flk into svflk153 svflk = flk;154 155 retVal = LIBC_NAMESPACE::fcntl(fd, GETLK_CMD, &svflk);156 ASSERT_ERRNO_SUCCESS();157 ASSERT_GT(retVal, -1);158 ASSERT_NE((int)svflk.l_type, F_RDLCK); // File should not be read locked.159 160 retVal = LIBC_NAMESPACE::fcntl(fd, SETLK_CMD, &svflk);161 ASSERT_ERRNO_SUCCESS();162 ASSERT_GT(retVal, -1);163 164 ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));165 }166 167 void UseAfterClose() {168 using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds;169 constexpr const char *TEST_FILE_NAME =170 "testdata/fcntl_use_after_close.test";171 const auto TEST_FILE = libc_make_test_file_path(TEST_FILE_NAME);172 int fd =173 LIBC_NAMESPACE::open(TEST_FILE, O_CREAT | O_TRUNC | O_RDWR, S_IRWXU);174 ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));175 176 flock flk = {};177 flk.l_type = F_RDLCK;178 flk.l_start = 0;179 flk.l_whence = SEEK_SET;180 flk.l_len = 50;181 ASSERT_EQ(-1, LIBC_NAMESPACE::fcntl(fd, GETLK_CMD, &flk));182 ASSERT_ERRNO_EQ(EBADF);183 }184};185 186#define COMMON_LOCK_TESTS(NAME, GETLK_CMD, SETLK_CMD) \187 using NAME = LibcFcntlCommonLockTests<GETLK_CMD, SETLK_CMD>; \188 TEST_F(NAME, GetLkRead) { GetLkRead(); } \189 TEST_F(NAME, GetLkWrite) { GetLkWrite(); } \190 TEST_F(NAME, UseAfterClose) { UseAfterClose(); } \191 static_assert(true, "Require semicolon.")192 193COMMON_LOCK_TESTS(LlvmLibcFcntlProcessAssociatedLockTest, F_GETLK, F_SETLK);194COMMON_LOCK_TESTS(LlvmLibcFcntlOpenFileDescriptionLockTest, F_OFD_GETLK,195 F_OFD_SETLK);196 197TEST_F(LlvmLibcFcntlTest, UseAfterClose) {198 using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds;199 constexpr const char *TEST_FILE_NAME = "testdata/fcntl_use_after_close.test";200 auto TEST_FILE = libc_make_test_file_path(TEST_FILE_NAME);201 int fd = LIBC_NAMESPACE::open(TEST_FILE, O_CREAT | O_TRUNC | O_RDWR, S_IRWXU);202 ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));203 ASSERT_EQ(-1, LIBC_NAMESPACE::fcntl(fd, F_GETFL));204 ASSERT_ERRNO_EQ(EBADF);205}206 207TEST_F(LlvmLibcFcntlTest, SetGetOwnerTest) {208 using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds;209 pid_t pid = LIBC_NAMESPACE::getpid();210 ASSERT_GT(pid, -1);211 constexpr const char *TEST_FILE_NAME = "testdata/fcntl_set_get_owner.test";212 auto TEST_FILE = libc_make_test_file_path(TEST_FILE_NAME);213 int fd = LIBC_NAMESPACE::open(TEST_FILE, O_CREAT | O_TRUNC | O_RDWR, S_IRWXU);214 ASSERT_ERRNO_SUCCESS();215 ASSERT_GT(fd, 0);216 int ret = LIBC_NAMESPACE::fcntl(fd, F_SETOWN, pid);217 ASSERT_ERRNO_SUCCESS();218 ASSERT_GT(ret, -1);219 int ret2 = LIBC_NAMESPACE::fcntl(fd, F_GETOWN);220 ASSERT_ERRNO_SUCCESS();221 ASSERT_EQ(ret2, pid);222 ASSERT_THAT(LIBC_NAMESPACE::close(fd), Succeeds(0));223}224