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

@ -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"));
}