mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-05-28 08:12:28 +00:00
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:
parent
ec957491ea
commit
ebf784d4f5
76 changed files with 1019 additions and 568 deletions
|
@ -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));
|
||||
|
|
|
@ -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]));
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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"));
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -94,6 +94,7 @@ TEST(__zipos_normpath, vectors) {
|
|||
{"./", ""},
|
||||
{"..", ""},
|
||||
{"../", ""},
|
||||
{"./foo/", "foo/"},
|
||||
{"foo/", "foo/"},
|
||||
{"../abc/def", "abc/def"},
|
||||
{"../abc/def/..", "abc/"},
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue