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

@ -33,48 +33,7 @@
#include "libc/nt/synchronization.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/at.h"
/**
* Performs synchronization on directory of pathname.
*
* This code is intended to help prevent subsequent i/o operations
* from failing for no reason at all. For example a unit test that
* repeatedly opens and unlinks the same filename.
*/
static textwindows int SyncDirectory(int df, char16_t path[PATH_MAX], int n) {
int rc;
int64_t fh;
char16_t *p;
if ((p = memrchr16(path, '\\', n))) {
if (p - path == 2 && path[1] == ':') return 0; // XXX: avoid syncing volume
*p = 0;
} else {
if (df != AT_FDCWD) {
if (FlushFileBuffers(df)) {
return 0;
} else {
return -1;
}
}
path[0] = '.';
path[1] = 0;
}
if ((fh = CreateFile(
path, kNtFileGenericWrite,
kNtFileShareRead | kNtFileShareWrite | kNtFileShareDelete, 0,
kNtOpenExisting, kNtFileAttributeNormal | kNtFileFlagBackupSemantics,
0)) != -1) {
if (FlushFileBuffers(fh)) {
rc = 0;
} else {
rc = -1;
}
CloseHandle(fh);
} else {
rc = -1;
}
return rc;
}
#include "libc/sysv/errfuns.h"
static textwindows bool IsDirectorySymlink(const char16_t *path) {
int e;
@ -102,13 +61,11 @@ static textwindows int sys_rmdir_nt(const char16_t *path) {
if (RemoveDirectory(path)) {
return 0;
}
/*
* Files can linger, for absolutely no reason.
* Possibly some Windows Defender bug on Win7.
* Sleep for up to one second w/ expo backoff.
* Alternative is use Microsoft internal APIs.
* Never could have imagined it'd be this bad.
*/
// Files can linger, for absolutely no reason.
// Possibly some Windows Defender bug on Win7.
// Sleep for up to one second w/ expo backoff.
// Alternative is use Microsoft internal APIs.
// Never could have imagined it'd be this bad.
if (GetLastError() == kNtErrorDirNotEmpty && ms <= 2048) {
errno = e;
Sleep(ms);
@ -130,19 +87,45 @@ static textwindows int sys_unlink_nt(const char16_t *path) {
}
}
textwindows int sys_unlinkat_nt(int dirfd, const char *path, int flags) {
int n, rc;
char16_t path16[PATH_MAX];
if ((n = __mkntpathat(dirfd, path, 0, path16)) == -1) {
rc = -1;
} else if (flags & AT_REMOVEDIR) {
rc = sys_rmdir_nt(path16);
textwindows int sys_unlinkat_nt_impl(const char16_t *path, int flags) {
if (flags & AT_REMOVEDIR) {
return sys_rmdir_nt(path);
} else {
rc = sys_unlink_nt(path16);
if (rc != -1) {
// TODO(jart): prove that it helps first
// rc = SyncDirectory(dirfd, path16, n);
return sys_unlink_nt(path);
}
}
textwindows int sys_unlinkat_nt(int dirfd, const char *path, int flags) {
char16_t path16[PATH_MAX];
// check validity of flags
if (flags & ~AT_REMOVEDIR) {
return einval();
}
// translate unix to windows path
int n;
if ((n = __mkntpathat(dirfd, path, 0, path16)) == -1) {
return -1;
}
// optimistic first attempt
int e = errno;
int rc = sys_unlinkat_nt_impl(path16, flags);
// reactively ensure unlink() deletes read-only files
if (rc == -1 && errno == kNtErrorAccessDenied) {
uint32_t attr;
if ((attr = GetFileAttributes(path16)) != -1u &&
(attr & kNtFileAttributeReadonly) &&
SetFileAttributes(path16, attr & ~kNtFileAttributeReadonly)) {
errno = e;
rc = sys_unlinkat_nt_impl(path16, flags);
} else {
errno = kNtErrorAccessDenied;
}
}
// return status
return __fix_enotdir(rc, path16);
}