Make improvements

- Introduce ualarm() function
- Make rename() report EISEMPTY on Windows
- Always raise EINVAL upon open(O_RDONLY|O_TRUNC)
- Add macro so ./configure will detect SOCK_CLOEXEC
- Fix O_TRUNC without O_CREAT not working on Windows
- Let fcntl(F_SETFL) change O_APPEND status on Windows
- Make sure pwrite() / pread() report ESPIPE on sockets
- Raise ESPIPE on Windows when pwrite() is used on pipe
- Properly compute O_APPEND CreateFile() flags on Windows
- Don't require O_DIRECTORY to open directories on Windows
- Fix more instances of Windows reporting EISDIR and ENOTDIR
- Normalize EFTYPE and EMLINK to ELOOP on NetBSD and FreeBSD
- Make unlink() / rmdir() work on read-only files on Windows
- Validate UTF-8 on Windows paths to fix bug with overlong NUL
- Always print signal name to stderr when crashing due to SIG_DFL
- Fix Windows bug where denormalized paths >260 chars didn't work
- Block signals on BSDs when thread exits before trashing its own stack
This commit is contained in:
Justine Tunney 2023-08-21 02:28:24 -07:00
parent ec957491ea
commit ebf784d4f5
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
76 changed files with 1019 additions and 568 deletions

View file

@ -65,8 +65,25 @@ TEST(fcntl_getfl, testRemembersAccessMode) {
EXPECT_NE(-1, close(fd));
}
TEST(fcntl_setfl, testChangeAppendStatus) {
if (IsWindows()) return; // Can't ReOpenFile() w/ O_APPEND
TEST(fcntl_setfl, testChangeAppendStatus_proper) {
char buf[8] = {0};
ASSERT_SYS(0, 3, open("foo", O_CREAT | O_WRONLY, 0644));
// F_GETFL on XNU reports FWASWRITTEN (0x00010000) after write()
int old = fcntl(3, F_GETFL);
EXPECT_SYS(0, 3, write(3, "foo", 3));
EXPECT_SYS(0, 0, lseek(3, 0, SEEK_SET));
EXPECT_SYS(0, 0, fcntl(3, F_SETFL, old | O_APPEND));
EXPECT_SYS(0, 3, write(3, "bar", 3));
EXPECT_SYS(0, 0, lseek(3, 0, SEEK_SET));
EXPECT_SYS(0, 0, fcntl(3, F_SETFL, old));
EXPECT_SYS(0, 0, close(3));
ASSERT_SYS(0, 3, open("foo", 0));
EXPECT_SYS(0, 6, read(3, buf, 6));
EXPECT_STREQ("foobar", buf);
EXPECT_SYS(0, 0, close(3));
}
TEST(fcntl_setfl, testChangeAppendStatus_sloppy) {
char buf[8] = {0};
ASSERT_SYS(0, 3, open("foo", O_CREAT | O_WRONLY, 0644));
EXPECT_SYS(0, 3, write(3, "foo", 3));

View file

@ -29,6 +29,7 @@
#include "libc/sock/struct/ifreq.h"
#include "libc/stdio/stdio.h"
#include "libc/sysv/consts/af.h"
#include "libc/sysv/consts/fio.h"
#include "libc/sysv/consts/ipproto.h"
#include "libc/sysv/consts/sio.h"
#include "libc/sysv/consts/sock.h"
@ -82,3 +83,18 @@ TEST(siocgifconf, mkntenvblock_systemroot) {
EXITS(0);
}
#endif
TEST(fionread, pipe) {
int pfds[2];
int pending;
ASSERT_SYS(0, 0, pipe(pfds));
ASSERT_SYS(0, 2, write(pfds[1], "hi", 2));
// checking the reading end is agreed upon
ASSERT_SYS(0, 0, ioctl(pfds[0], FIONREAD, &pending));
ASSERT_EQ(2, pending);
// checking the writing end is real hairy
// ASSERT_SYS(0, 0, ioctl(pfds[1], FIONREAD, &pending));
// ASSERT_EQ(2, pending);
ASSERT_SYS(0, 0, close(pfds[1]));
ASSERT_SYS(0, 0, close(pfds[0]));
}

View file

@ -23,7 +23,11 @@
#include "libc/limits.h"
#include "libc/log/check.h"
#include "libc/runtime/runtime.h"
#include "libc/sock/sock.h"
#include "libc/sysv/consts/af.h"
#include "libc/sysv/consts/ipproto.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/sock.h"
#include "libc/testlib/subprocess.h"
#include "libc/testlib/testlib.h"
#include "libc/x/x.h"
@ -31,7 +35,7 @@
char testlib_enable_tmp_setup_teardown;
void SetUpOnce(void) {
ASSERT_SYS(0, 0, pledge("stdio rpath wpath cpath fattr proc", 0));
ASSERT_SYS(0, 0, pledge("stdio rpath wpath cpath fattr proc inet", 0));
}
TEST(lseek, ebadf) {
@ -59,14 +63,26 @@ TEST(lseek, 64bit) {
EXPECT_SYS(0, 0, close(3));
}
TEST(lseek, nonSeekableFd_espipe) {
TEST(lseek, isPipe_ESPIPE) {
int fds[2];
char buf[2];
ASSERT_SYS(0, 0, pipe(fds));
ASSERT_SYS(ESPIPE, -1, lseek(3, 0, SEEK_SET));
ASSERT_SYS(ESPIPE, -1, pwrite(4, "hi", 2, 0));
ASSERT_SYS(ESPIPE, -1, pread(3, buf, 2, 0));
EXPECT_SYS(0, 0, close(4));
EXPECT_SYS(0, 0, close(3));
}
TEST(lseek, isSocket_ESPIPE) {
char buf[2];
ASSERT_SYS(0, 3, socket(AF_INET, SOCK_STREAM, IPPROTO_TCP));
ASSERT_SYS(ESPIPE, -1, lseek(3, 0, SEEK_SET));
ASSERT_SYS(ESPIPE, -1, pwrite(3, "hi", 2, 0));
ASSERT_SYS(ESPIPE, -1, pread(3, buf, 2, 0));
EXPECT_SYS(0, 0, close(3));
}
TEST(lseek, filePositionChanges_areObservableAcrossDup) {
ASSERT_SYS(0, 3, creat("wut", 0644));
ASSERT_SYS(0, 4, dup(3));

View file

@ -18,14 +18,20 @@
*/
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/struct/stat.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/macros.internal.h"
#include "libc/mem/gc.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/o.h"
#include "libc/testlib/testlib.h"
#include "libc/x/x.h"
#include "libc/x/xasprintf.h"
#define abs(rel) gc(xasprintf("%s/%s", gc(getcwd(0, 0)), rel))
char testlib_enable_tmp_setup_teardown;
@ -113,6 +119,7 @@ TEST(open, testOpenExistingForAppendWriteOnly_seeksToEnd) {
char buf[16] = {0};
ASSERT_SYS(0, 0, xbarf("hello.txt", "hell", -1));
ASSERT_SYS(0, 3, open("hello.txt", O_WRONLY | O_APPEND));
EXPECT_SYS(EBADF, -1, pread(3, buf, 4, 0)); // in O_WRONLY mode
EXPECT_SYS(0, 1, write(3, "o", 1));
EXPECT_SYS(0, 0, lseek(3, 0, SEEK_SET));
EXPECT_SYS(0, 1, write(3, "!", 1));
@ -123,6 +130,50 @@ TEST(open, testOpenExistingForAppendWriteOnly_seeksToEnd) {
EXPECT_SYS(0, 0, close(3));
}
TEST(open, appendRwMode_readsStartZero_writesAlwaysEof) {
char buf[8] = {0};
ASSERT_SYS(0, 0, xbarf("hello.txt", "hell", -1));
ASSERT_SYS(0, 3, open("hello.txt", O_RDWR | O_APPEND));
ASSERT_SYS(0, 2, read(3, buf, 2));
ASSERT_SYS(0, 2, read(3, buf + 2, 2));
EXPECT_STREQ("hell", buf);
EXPECT_SYS(0, 2, write(3, "o!", 2));
ASSERT_SYS(0, 6, pread(3, buf, 8, 0));
EXPECT_STREQ("hello!", buf);
EXPECT_SYS(0, 0, close(3));
}
TEST(open, appendReadOnlyMode_appendIsIgnored) {
char buf[8] = {0};
ASSERT_SYS(0, 0, xbarf("hello.txt", "hell", -1));
ASSERT_SYS(0, 3, open("hello.txt", O_RDONLY | O_APPEND));
EXPECT_SYS(EBADF, -1, write(3, "o!", 2)); // due to O_RDONLY
ASSERT_EQ(0, errno);
ASSERT_SYS(0, 2, read(3, buf, 2));
ASSERT_SYS(0, 2, read(3, buf + 2, 2));
EXPECT_STREQ("hell", buf);
ASSERT_SYS(0, 4, pread(3, buf, 4, 0));
EXPECT_SYS(0, 0, close(3));
}
TEST(open, truncReadWriteMode_getsTruncated) {
char buf[8] = {0};
ASSERT_FALSE(fileexists("hello.txt"));
ASSERT_SYS(ENOENT, -1, open("hello.txt", O_RDWR | O_TRUNC));
ASSERT_SYS(ENOENT, -1, open("hello.txt/there", O_RDWR | O_TRUNC));
ASSERT_SYS(0, 0, xbarf("hello.txt", "hell", -1));
ASSERT_SYS(ENOTDIR, -1, open("hello.txt/there", O_RDWR | O_TRUNC));
ASSERT_SYS(0, 3, open("hello.txt", O_RDWR | O_TRUNC));
ASSERT_SYS(0, 0, read(3, buf, 8));
EXPECT_STREQ("", buf);
ASSERT_SYS(0, 8, write(3, buf, 8));
EXPECT_SYS(0, 0, close(3));
}
TEST(open, truncReadOnlyMode_wontTruncate) {
ASSERT_SYS(EINVAL, -1, open("hello.txt", O_RDONLY | O_TRUNC));
}
TEST(open, testRelativePath_opensRelativeToDirFd) {
ASSERT_SYS(0, 0, mkdir("foo", 0755));
ASSERT_SYS(0, 3, open("foo", O_RDONLY | O_DIRECTORY));
@ -132,6 +183,104 @@ TEST(open, testRelativePath_opensRelativeToDirFd) {
EXPECT_SYS(0, 0, close(3));
}
TEST(open, eloop) {
ASSERT_SYS(0, 0, symlink("froot", "link"));
ASSERT_TRUE(issymlink("link"));
ASSERT_SYS(ELOOP, -1, open("link", O_RDONLY | O_NOFOLLOW));
}
TEST(open, norm) {
ASSERT_SYS(0, 0, mkdir("fun", 0755));
ASSERT_SYS(0, 0, mkdir("fun/house", 0755));
ASSERT_SYS(0, 0, touch("fun/house/norm", 0644));
ASSERT_SYS(0, 3, open("fun//house//norm", O_RDONLY));
ASSERT_SYS(0, 0, close(3));
ASSERT_SYS(0, 3, open(abs("fun//house//norm"), O_RDONLY));
ASSERT_SYS(0, 0, close(3));
ASSERT_SYS(0, 3, open("fun//house/./norm", O_RDONLY));
ASSERT_SYS(0, 0, close(3));
ASSERT_SYS(0, 3, open(abs("fun//house/./norm"), O_RDONLY));
ASSERT_SYS(0, 0, close(3));
ASSERT_SYS(0, 3, open("fun//house/../house/norm", O_RDONLY));
ASSERT_SYS(0, 0, close(3));
ASSERT_SYS(0, 3, open(abs("fun//house/../house/norm"), O_RDONLY));
ASSERT_SYS(0, 0, close(3));
ASSERT_SYS(ENOTDIR, -1, open("fun//house//norm/", O_RDONLY));
ASSERT_SYS(ENOTDIR, -1, open("fun//house//norm/.", O_RDONLY));
ASSERT_SYS(ENOTDIR, -1, open("fun//house//norm/./", O_RDONLY));
ASSERT_SYS(0, 3, open("fun//house//", O_RDONLY | O_DIRECTORY));
ASSERT_SYS(0, 0, close(3));
}
TEST(open, longNormDot) {
#define NAME \
"funfunfunfunfunfunfunfunfunfunfunfunfunfunfunfunfunfunfunfunfunfunfunfunfu" \
"nfunfunfunfunfunfunnfunfunfunfunfunfunnfunfunfunfunfunfununfunfunfunfunfun"
ASSERT_SYS(0, 0, mkdir(NAME, 0755));
ASSERT_SYS(0, 0, mkdir(abs(NAME "/" NAME), 0755));
ASSERT_SYS(0, 3, creat(abs(NAME "//" NAME "/./norm"), 0644));
ASSERT_TRUE(fileexists(abs(NAME "//" NAME "/norm")));
ASSERT_SYS(0, 0, close(3));
}
TEST(open, longNormDotDot) {
#define NAME \
"funfunfunfunfunfunfunfunfunfunfunfunfunfunfunfunfunfunfunfunfunfunfunfunfu" \
"nfunfunfunfunfunfunnfunfunfunfunfunfunnfunfunfunfunfunfununfunfunfunfunfun"
ASSERT_SYS(0, 0, mkdir(NAME, 0755));
ASSERT_SYS(0, 0, mkdir(abs(NAME "/" NAME), 0755));
ASSERT_SYS(0, 0, mkdir(abs(NAME "/" NAME "/" NAME), 0755));
ASSERT_SYS(0, 3, creat(abs(NAME "//" NAME "//" NAME "/../norm"), 0644));
ASSERT_TRUE(fileexists(abs(NAME "//" NAME "/norm")));
ASSERT_SYS(0, 0, close(3));
}
TEST(open, creat_directory) {
ASSERT_SYS(ENOENT, -1, open("fun", O_WRONLY | O_DIRECTORY));
ASSERT_FALSE(fileexists("fun"));
if (1) return; // linux 5.15.122-0-lts creates file and returns error D:
ASSERT_SYS(ENOTDIR, -1, open("fun", O_CREAT | O_WRONLY | O_DIRECTORY, 0644));
ASSERT_TRUE(fileexists("fun"));
}
TEST(open, O_DIRECTORY_preventsOpeningRegularFiles) {
ASSERT_SYS(0, 0, touch("file", 0644));
ASSERT_SYS(ENOTDIR, -1, open("file", O_WRONLY | O_DIRECTORY));
}
TEST(open, O_DIRECTORY_isNotARequirementToOpenDirectory) {
ASSERT_SYS(0, 0, mkdir("dir", 0755));
ASSERT_SYS(0, 3, open("dir", O_RDONLY));
ASSERT_SYS(0, 0, close(3));
}
TEST(open, openExistingDirectoryForWriting_raisesError) {
ASSERT_SYS(0, 0, mkdir("dir", 0755));
ASSERT_SYS(EISDIR, -1, open("dir", O_WRONLY));
}
TEST(open, nameWithControlCode) {
if (IsWindows()) {
ASSERT_SYS(EINVAL, -1, touch("hi\1there", 0755));
} else {
ASSERT_SYS(0, 0, touch("hi\1there", 0755));
}
}
TEST(open, nameWithOverlongNul_doesntCreateTruncatedName) {
if (IsXnu() || IsWindows()) {
// XNU is the only one that thought to restrict this. XNU chose
// EILSEQ which makes the most sense. Linux says it'll raise EINVAL
// if invalid characters are detected. Not sure yet which characters
// those are. POSIX says nothing about invalid charaters in open.
ASSERT_SYS(EILSEQ, -1, touch("hi\300\200there", 0755));
} else {
ASSERT_SYS(0, 0, touch("hi\300\200there", 0755));
ASSERT_TRUE(fileexists("hi\300\200there"));
ASSERT_FALSE(fileexists("hi"));
}
}
int CountFds(void) {
int i, count;
for (count = i = 0; i < g_fds.n; ++i) {
@ -154,3 +303,18 @@ TEST(open, lotsOfFds) {
EXPECT_SYS(0, 0, close(i));
}
}
static int64_t GetInode(const char *path) {
struct stat st;
ASSERT_SYS(0, 0, stat(path, &st));
return st.st_ino;
}
TEST(open, drive) {
if (!IsWindows()) return;
ASSERT_NE(GetInode("/"), GetInode("."));
ASSERT_EQ(GetInode("/"), GetInode("/c")); // sorry you have to run on c:/
ASSERT_EQ(GetInode("/"), GetInode("/c/"));
ASSERT_SYS(0, 3, open("/", O_RDONLY));
ASSERT_SYS(0, 0, close(3));
}

View file

@ -447,7 +447,7 @@ TEST(pledge, open_rpath) {
if (!pid) {
ASSERT_SYS(0, 0, pledge("stdio rpath", 0));
ASSERT_SYS(0, 3, open("foo", O_RDONLY));
ASSERT_SYS(EPERM, -1, open("foo", O_RDONLY | O_TRUNC));
ASSERT_SYS(EINVAL, -1, open("foo", O_RDONLY | O_TRUNC));
ASSERT_SYS(EPERM, -1, open("foo", O_RDONLY | O_TMPFILE));
ASSERT_SYS(EPERM, -1, open("foo", O_RDWR | O_TRUNC | O_CREAT, 0644));
ASSERT_SYS(EPERM, -1, open("foo", O_WRONLY | O_TRUNC | O_CREAT, 0644));

View file

@ -62,9 +62,6 @@ TEST(readlinkat, test) {
EXPECT_EQ(255, buf[8] & 255);
buf[8] = 0;
EXPECT_STREQ("hello→", buf);
p = gc(xjoinpaths(g_testlib_tmpdir, "hello→"));
q = gc(realpath("there→", 0));
EXPECT_EQ(0, strcmp(p, q), "%`'s\n\t%`'s", p, q);
}
TEST(readlinkat, efault) {
@ -89,10 +86,7 @@ TEST(readlinkat, frootloop) {
ASSERT_SYS(0, 0, symlink("froot", "froot"));
ASSERT_SYS(ELOOP, -1, readlink("froot/loop", buf, sizeof(buf)));
if (O_NOFOLLOW) {
ASSERT_SYS(IsFreebsd() ? EMLINK
: IsNetbsd() ? EFTYPE
: ELOOP,
-1, open("froot", O_RDONLY | O_NOFOLLOW));
ASSERT_SYS(ELOOP, -1, open("froot", O_RDONLY | O_NOFOLLOW));
if (0 && O_PATH) { /* need rhel5 test */
ASSERT_NE(-1, (fd = open("froot", O_RDONLY | O_NOFOLLOW | O_PATH)));
ASSERT_NE(-1, close(fd));

View file

@ -17,7 +17,9 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/runtime/runtime.h"
#include "libc/sysv/consts/at.h"
#include "libc/testlib/testlib.h"
#include "libc/x/x.h"
@ -42,18 +44,76 @@ TEST(renameat, enotdir) {
// EXPECT_SYS(ENOTDIR, -1, rename("zoo", "yo/there"));
}
TEST(rename, eisdir) {
// new is a directory but old is not a directory
ASSERT_SYS(0, 0, mkdir("foo", 0755));
ASSERT_SYS(0, 0, touch("foo/bar", 0644));
ASSERT_SYS(0, 0, touch("lol", 0644));
ASSERT_SYS(EISDIR, -1, rename("lol", "foo"));
}
TEST(rename, enotdir) {
// old is a directory but new is not a directory
ASSERT_SYS(0, 0, mkdir("lol", 0755));
ASSERT_SYS(0, 0, touch("foo", 0644));
ASSERT_SYS(ENOTDIR, -1, rename("lol", "foo"));
}
TEST(rename, eisdir_again) {
// old is a directory but new is not a directory
ASSERT_SYS(0, 0, touch("foo", 0644));
ASSERT_SYS(0, 0, touch("bar", 0644));
ASSERT_SYS(ENOTDIR, -1, rename("foo/", "bar"));
ASSERT_SYS(ENOTDIR, -1, rename("foo", "bar/"));
}
TEST(rename, moveDirectoryOverDirectory_replacesOldDirectory) {
ASSERT_SYS(0, 0, mkdir("foo//", 0755));
ASSERT_SYS(0, 0, mkdir("lol", 0755));
ASSERT_SYS(0, 0, rename("lol", "foo"));
ASSERT_TRUE(fileexists("foo"));
ASSERT_FALSE(fileexists("lol"));
}
TEST(rename, enotempty) {
// POSIX specifies EEXIST or ENOTEMPTY when new path is non-empty dir.
// Old version of Linux (e.g. RHEL7) return EEXIST.
// Everything else returns ENOTEMPTY.
int rc;
ASSERT_SYS(0, 0, mkdir("foo", 0755));
ASSERT_SYS(0, 0, touch("foo/bar", 0644));
ASSERT_SYS(0, 0, mkdir("lol", 0755));
ASSERT_EQ(-1, (rc = rename("lol", "foo")));
ASSERT_TRUE(errno == ENOTEMPTY || errno == EEXIST);
errno = 0;
}
TEST(rename, moveIntoNonWritableDirectory_raisesEacces) {
// old versions of linux allow this
// new versions of linux report exdev?!
if (IsLinux()) return;
// netbsd and openbsd allow this
if (IsNetbsd() || IsOpenbsd()) return;
// windows doesn't really have permissions
if (IsWindows()) return;
// posix specifies this behavior
ASSERT_SYS(0, 0, mkdir("foo", 0111));
ASSERT_SYS(0, 0, touch("lol", 0644));
ASSERT_SYS(EACCES, -1, rename("lol", "foo/bar"));
}
TEST(renameat, testNull_returnsEfault) {
ASSERT_SYS(0, 0, close(creat("hello", 0644)));
EXPECT_SYS(EFAULT, -1, renameat(AT_FDCWD, 0, AT_FDCWD, 0));
EXPECT_SYS(EFAULT, -1, renameat(AT_FDCWD, 0, AT_FDCWD, "hello"));
EXPECT_SYS(EFAULT, -1, renameat(AT_FDCWD, "hello", AT_FDCWD, 0));
ASSERT_SYS(EFAULT, -1, renameat(AT_FDCWD, 0, AT_FDCWD, 0));
ASSERT_SYS(EFAULT, -1, renameat(AT_FDCWD, 0, AT_FDCWD, "hello"));
ASSERT_SYS(EFAULT, -1, renameat(AT_FDCWD, "hello", AT_FDCWD, 0));
}
TEST(renameat, test) {
ASSERT_SYS(0, 0, close(creat("first", 0644)));
EXPECT_TRUE(fileexists("first"));
EXPECT_TRUE(!fileexists("second"));
EXPECT_SYS(0, 0, renameat(AT_FDCWD, "first", AT_FDCWD, "second"));
EXPECT_TRUE(!fileexists("first"));
EXPECT_TRUE(fileexists("second"));
ASSERT_TRUE(fileexists("first"));
ASSERT_TRUE(!fileexists("second"));
ASSERT_SYS(0, 0, renameat(AT_FDCWD, "first", AT_FDCWD, "second"));
ASSERT_TRUE(!fileexists("first"));
ASSERT_TRUE(fileexists("second"));
}

View file

@ -25,6 +25,7 @@
#include "libc/errno.h"
#include "libc/macros.internal.h"
#include "libc/runtime/internal.h"
#include "libc/runtime/runtime.h"
#include "libc/runtime/stack.h"
#include "libc/stdio/rand.h"
#include "libc/str/str.h"
@ -66,13 +67,17 @@ TEST(reservefd, testGrowthOfFdsDataStructure) {
int i, n;
struct rlimit rlim;
n = 1700; // pe '2**16/40' → 1638 (likely value of g_fds.n)
if (!getrlimit(RLIMIT_NOFILE, &rlim)) n = MIN(n, rlim.rlim_cur - 3);
if (!getrlimit(RLIMIT_NOFILE, &rlim)) {
n = MIN(n, rlim.rlim_cur - 3);
} else {
errno = 0;
}
for (i = 0; i < n; ++i) {
EXPECT_SYS(0, i + 3, open("/zip/usr/share/zoneinfo/UTC", O_RDONLY));
ASSERT_SYS(0, i + 3, open("/zip/usr/share/zoneinfo/UTC", O_RDONLY));
}
ASSERT_GT(g_fds.n, OPEN_MAX);
for (i = 0; i < n; ++i) {
EXPECT_SYS(0, 0, close(i + 3));
ASSERT_SYS(0, 0, close(i + 3));
}
}

View file

@ -150,6 +150,7 @@ o/$(MODE)/test/libc/calls/zipread.com.zip.o: private \
o/$(MODE)/test/libc/calls/ioctl_test.com.runs: \
private .PLEDGE =
o/$(MODE)/test/libc/calls/lseek_test.com.runs \
o/$(MODE)/test/libc/calls/poll_test.com.runs: \
private .PLEDGE = stdio rpath wpath cpath fattr proc inet

View file

@ -20,6 +20,7 @@
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/sysv/consts/at.h"
#include "libc/sysv/consts/o.h"
#include "libc/testlib/testlib.h"
char testlib_enable_tmp_setup_teardown;
@ -45,6 +46,16 @@ TEST(unlink, enotdir) {
ASSERT_SYS(ENOTDIR, -1, unlink("o/doesnotexist"));
}
TEST(rmdir, willDeleteRegardlessOfAccessBits) {
ASSERT_SYS(0, 0, mkdir("foo", 0));
ASSERT_SYS(0, 0, rmdir("foo/"));
}
TEST(unlink, willDeleteRegardlessOfAccessBits) {
ASSERT_SYS(0, 0, touch("foo", 0));
ASSERT_SYS(0, 0, unlink("foo"));
}
TEST(unlinkat, test) {
int i, fd;
EXPECT_EQ(0, touch("mytmp", 0644));

View file

@ -94,6 +94,7 @@ TEST(__zipos_normpath, vectors) {
{"./", ""},
{"..", ""},
{"../", ""},
{"./foo/", "foo/"},
{"foo/", "foo/"},
{"../abc/def", "abc/def"},
{"../abc/def/..", "abc/"},

View file

@ -28,25 +28,24 @@
void SetUpOnce(void) {
GetSymbolTable();
ASSERT_SYS(0, 0, pledge("stdio rpath", 0));
}
TEST(isutf8, good) {
ASSERT_TRUE(_isutf8("\0\1\2\3", 4));
EXPECT_TRUE(_isutf8(kHyperion, kHyperionSize));
EXPECT_TRUE(_isutf8("𐌰𐌱𐌲𐌳𐌴𐌵𐌶𐌷▒▒▒▒▒▒▒▒▒▒▒▒", -1));
EXPECT_TRUE(_isutf8("天地玄黄 宇宙洪荒 日月盈昃 辰宿列张 寒来暑往 秋收冬藏"
"闰馀成岁 律吕调阳 云腾致雨 露结为霜 金生丽水 玉出昆冈"
"剑号巨阙 珠称夜光 果珍李柰 菜重芥姜 海咸河淡 鳞潜羽翔"
"龙师火帝 鸟官人皇 始制文字 乃服衣裳 推位让国 有虞陶唐",
-1));
ASSERT_TRUE(isutf8("\0\1\2\3", 4));
EXPECT_TRUE(isutf8(kHyperion, kHyperionSize));
EXPECT_TRUE(isutf8("𐌰𐌱𐌲𐌳𐌴𐌵𐌶𐌷▒▒▒▒▒▒▒▒▒▒▒▒", -1));
EXPECT_TRUE(isutf8("天地玄黄 宇宙洪荒 日月盈昃 辰宿列张 寒来暑往 秋收冬藏"
"闰馀成岁 律吕调阳 云腾致雨 露结为霜 金生丽水 玉出昆冈"
"剑号巨阙 珠称夜光 果珍李柰 菜重芥姜 海咸河淡 鳞潜羽翔"
"龙师火帝 鸟官人皇 始制文字 乃服衣裳 推位让国 有虞陶唐",
-1));
}
TEST(isutf8, bad) {
ASSERT_FALSE(_isutf8("\300\200", -1)); // overlong nul
ASSERT_FALSE(_isutf8("\200\300", -1)); // latin1 c1 control code
ASSERT_FALSE(_isutf8("\300\300", -1)); // missing continuation
ASSERT_FALSE(_isutf8("\377\200\200\200\200", -1)); // thompson-pike varint
ASSERT_FALSE(isutf8("\300\200", -1)); // overlong nul
ASSERT_FALSE(isutf8("\200\300", -1)); // latin1 c1 control code
ASSERT_FALSE(isutf8("\300\300", -1)); // missing continuation
ASSERT_FALSE(isutf8("\377\200\200\200\200", -1)); // thompson-pike varint
}
TEST(isutf8, oob) {
@ -54,15 +53,15 @@ TEST(isutf8, oob) {
char *p;
for (n = 0; n < 32; ++n) {
p = memset(malloc(n), 'a', n);
ASSERT_TRUE(_isutf8(p, n));
ASSERT_TRUE(isutf8(p, n));
free(p);
}
}
BENCH(isutf8, bench) {
EZBENCH_N("_isutf8", 0, _isutf8(0, 0));
EZBENCH_N("_isutf8", 5, _isutf8("hello", 5));
EZBENCH_N("_isutf8 ascii", kHyperionSize, _isutf8(kHyperion, kHyperionSize));
EZBENCH_N("_isutf8 unicode", kBlocktronicsSize,
_isutf8(kBlocktronics, kBlocktronicsSize));
EZBENCH_N("isutf8", 0, isutf8(0, 0));
EZBENCH_N("isutf8", 5, isutf8("hello", 5));
EZBENCH_N("isutf8 ascii", kHyperionSize, isutf8(kHyperion, kHyperionSize));
EZBENCH_N("isutf8 unicode", kBlocktronicsSize,
isutf8(kBlocktronics, kBlocktronicsSize));
}