mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-03-02 23:18:44 +00:00
Support dirfd relative iops on Windows
We always favor calling functions like openat(), fstatat(), etc. because Linux, XNU, FreeBSD, and OpenBSD all elected to support them, while some systems like Android love them so much, that they stopped supporting the old interfaces. This change ensures that when dirfd is actually a dirfd and not AT_FDCWD we'll do the right thing on Windows NT. We use an API that's been around since Vista to accomplish that. This change also adds exponential backoff to chdir() on Windows since it seems almost as flaky on Windows 7 as the rmdir() function.
This commit is contained in:
parent
b8d26e2418
commit
417797d218
42 changed files with 361 additions and 241 deletions
|
@ -17,10 +17,7 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* Checks if effective user can access path in particular ways.
|
||||
|
@ -31,12 +28,5 @@
|
|||
* @asyncsignalsafe
|
||||
*/
|
||||
int access(const char *path, int mode) {
|
||||
char16_t path16[PATH_MAX];
|
||||
if (!path) return efault();
|
||||
if (!IsWindows()) {
|
||||
return faccessat$sysv(AT_FDCWD, path, mode, 0);
|
||||
} else {
|
||||
if (__mkntpath(path, path16) == -1) return -1;
|
||||
return ntaccesscheck(path16, mode);
|
||||
}
|
||||
return faccessat(AT_FDCWD, path, mode, 0);
|
||||
}
|
||||
|
|
|
@ -230,6 +230,7 @@ long ptrace(int, int, void *, void *);
|
|||
int chroot(const char *);
|
||||
int prctl();
|
||||
int sysctl(const int *, unsigned, void *, size_t *, void *, size_t);
|
||||
int fchdir(int);
|
||||
|
||||
#define getcwd(BUF, SIZE) \
|
||||
(__builtin_constant_p(BUF) && (&(BUF)[0] == NULL) ? get_current_dir_name() \
|
||||
|
|
|
@ -17,12 +17,14 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/nt/errors.h"
|
||||
#include "libc/nt/files.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/nt/synchronization.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
textwindows int chdir$nt(const char *path) {
|
||||
int len;
|
||||
int e, ms, len;
|
||||
char16_t path16[PATH_MAX];
|
||||
if ((len = __mkntpath(path, path16)) == -1) return -1;
|
||||
if (path16[len - 1] != u'\\') {
|
||||
|
@ -30,9 +32,24 @@ textwindows int chdir$nt(const char *path) {
|
|||
path16[len + 0] = u'\\';
|
||||
path16[len + 1] = u'\0';
|
||||
}
|
||||
if (SetCurrentDirectory(path16)) {
|
||||
return 0;
|
||||
} else {
|
||||
return __winerr();
|
||||
/*
|
||||
* chdir() seems flaky on windows 7
|
||||
* in a similar way to rmdir() sigh
|
||||
*/
|
||||
for (ms = 1;; ms *= 2) {
|
||||
if (SetCurrentDirectory(path16)) {
|
||||
return 0;
|
||||
} else {
|
||||
e = GetLastError();
|
||||
if (ms <= 512 &&
|
||||
(e == kNtErrorFileNotFound || e == kNtErrorAccessDenied)) {
|
||||
Sleep(ms);
|
||||
continue;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
|
|
|
@ -23,11 +23,11 @@
|
|||
|
||||
/**
|
||||
* Sets current directory.
|
||||
*
|
||||
* @asyncsignalsafe
|
||||
* @syscall
|
||||
* @see fchdir()
|
||||
*/
|
||||
int chdir(const char *path) {
|
||||
if (!path) return efault();
|
||||
if (!IsWindows()) {
|
||||
return chdir$sysv(path);
|
||||
} else {
|
||||
|
|
|
@ -32,9 +32,7 @@
|
|||
* @see /etc/passwd for user ids
|
||||
* @see /etc/group for group ids
|
||||
* @asyncsignalsafe
|
||||
* @syscall
|
||||
*/
|
||||
int chown(const char *pathname, uint32_t uid, uint32_t gid) {
|
||||
if (!pathname) return efault();
|
||||
return fchownat$sysv(AT_FDCWD, pathname, uid, gid, 0);
|
||||
}
|
||||
|
|
|
@ -22,7 +22,6 @@
|
|||
|
||||
int faccessat$nt(int dirfd, const char *path, int mode, uint32_t flags) {
|
||||
char16_t path16[PATH_MAX];
|
||||
if (dirfd != AT_FDCWD || flags) return einval();
|
||||
if (__mkntpath(path, path16) == -1) return -1;
|
||||
if (__mkntpathat(dirfd, path, 0, path16) == -1) return -1;
|
||||
return ntaccesscheck(path16, mode);
|
||||
}
|
||||
|
|
|
@ -25,12 +25,13 @@
|
|||
/**
|
||||
* Checks if effective user can access path in particular ways.
|
||||
*
|
||||
* @param dirfd is usually AT_FDCWD
|
||||
* @param dirfd is normally AT_FDCWD but if it's an open directory and
|
||||
* file is a relative path, then file is opened relative to dirfd
|
||||
* @param path is a filename or directory
|
||||
* @param flags can be R_OK, W_OK, X_OK, F_OK
|
||||
* @param mode can be R_OK, W_OK, X_OK, F_OK
|
||||
* @param flags should be 0
|
||||
* @return 0 if ok, or -1 and sets errno
|
||||
* @asyncsignalsafe
|
||||
* @syscall
|
||||
*/
|
||||
int faccessat(int dirfd, const char *path, int mode, uint32_t flags) {
|
||||
if (!path) return efault();
|
||||
|
|
41
libc/calls/fchdir-nt.c
Normal file
41
libc/calls/fchdir-nt.c
Normal file
|
@ -0,0 +1,41 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/nt/files.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
textwindows int fchdir$nt(int dirfd) {
|
||||
uint32_t len;
|
||||
char16_t dir[PATH_MAX];
|
||||
if (!__isfdkind(dirfd, kFdFile)) return ebadf();
|
||||
len = GetFinalPathNameByHandle(g_fds.p[dirfd].handle, dir, ARRAYLEN(dir),
|
||||
kNtFileNameNormalized | kNtVolumeNameDos);
|
||||
if (len + 1 + 1 > ARRAYLEN(dir)) return enametoolong();
|
||||
if (dir[len - 1] != u'\\') {
|
||||
dir[len + 0] = u'\\';
|
||||
dir[len + 1] = u'\0';
|
||||
}
|
||||
if (SetCurrentDirectory(dir)) {
|
||||
return 0;
|
||||
} else {
|
||||
return __winerr();
|
||||
}
|
||||
}
|
|
@ -18,7 +18,18 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/dce.h"
|
||||
|
||||
textwindows int lstat$nt(const char *pathname, struct stat *st) {
|
||||
return stat$nt(pathname, st); /* todo(jart) */
|
||||
/**
|
||||
* Sets current directory based on file descriptor.
|
||||
*
|
||||
* @see open(path, O_DIRECTORY)
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int fchdir(int dirfd) {
|
||||
if (!IsWindows()) {
|
||||
return fchdir$sysv(dirfd);
|
||||
} else {
|
||||
return fchdir$nt(dirfd);
|
||||
}
|
||||
}
|
|
@ -31,10 +31,8 @@
|
|||
* @see /etc/passwd for user ids
|
||||
* @see /etc/group for group ids
|
||||
* @asyncsignalsafe
|
||||
* @syscall
|
||||
*/
|
||||
int fchownat(int dirfd, const char *pathname, uint32_t uid, uint32_t gid,
|
||||
uint32_t flags) {
|
||||
/* TODO(jart): Windows? */
|
||||
return fchownat$sysv(dirfd, pathname, uid, gid, flags);
|
||||
}
|
||||
|
|
|
@ -26,11 +26,12 @@
|
|||
#include "libc/nt/runtime.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
|
||||
textwindows int stat$nt(const char *path, struct stat *st) {
|
||||
textwindows int fstatat$nt(int dirfd, const char *path, struct stat *st,
|
||||
uint32_t flags) {
|
||||
int rc;
|
||||
int64_t fh;
|
||||
uint16_t path16[PATH_MAX];
|
||||
if (__mkntpath(path, path16) == -1) return -1;
|
||||
if (__mkntpathat(dirfd, path, 0, path16) == -1) return -1;
|
||||
if ((fh = CreateFile(
|
||||
path16, kNtFileReadAttributes,
|
||||
kNtFileShareRead | kNtFileShareWrite | kNtFileShareDelete, NULL,
|
|
@ -16,33 +16,31 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/weaken.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
#include "libc/zipos/zipos.internal.h"
|
||||
|
||||
/**
|
||||
* Performs stat() w/ features for threaded apps.
|
||||
* Returns information about thing.
|
||||
*
|
||||
* @param dirfd can be AT_FDCWD or an open directory descriptor, and is
|
||||
* ignored if pathname is absolute
|
||||
* @param dirfd is normally AT_FDCWD but if it's an open directory and
|
||||
* file is a relative path, then file becomes relative to dirfd
|
||||
* @param st is where result is stored
|
||||
* @param flags can have AT_{EMPTY_PATH,NO_AUTOMOUNT,SYMLINK_NOFOLLOW}
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @see S_ISDIR(st.st_mode), S_ISREG()
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int fstatat(int dirfd, const char *pathname, struct stat *st, uint32_t flags) {
|
||||
int olderr = errno;
|
||||
int rc = fstatat$sysv(dirfd, pathname, st, flags);
|
||||
if (rc != -1) {
|
||||
stat2linux(st);
|
||||
} else if (errno == ENOSYS && dirfd == AT_FDCWD) {
|
||||
if (!flags) {
|
||||
errno = olderr;
|
||||
rc = stat(pathname, st);
|
||||
} else if (flags == AT_SYMLINK_NOFOLLOW) {
|
||||
errno = olderr;
|
||||
rc = lstat(pathname, st);
|
||||
}
|
||||
int fstatat(int dirfd, const char *path, struct stat *st, uint32_t flags) {
|
||||
struct ZiposUri zipname;
|
||||
if (weaken(__zipos_stat) && weaken(__zipos_parseuri)(path, &zipname) != -1) {
|
||||
return weaken(__zipos_stat)(&zipname, st);
|
||||
} else if (!IsWindows()) {
|
||||
return fstatat$sysv(dirfd, path, st, flags);
|
||||
} else {
|
||||
return fstatat$nt(dirfd, path, st, flags);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -115,6 +115,7 @@ i32 execve$sysv(const char *, char *const[], char *const[]) hidden;
|
|||
i32 faccessat$sysv(i32, const char *, i32, u32) hidden;
|
||||
i32 fadvise$sysv(i32, i64, i64, i32) hidden;
|
||||
i32 fallocate$sysv(i64, i32, i64, i64) hidden;
|
||||
i32 fchdir$sysv(i32) hidden;
|
||||
i32 fchmod$sysv(i32, u32) hidden;
|
||||
i32 fchmodat$sysv(i32, const char *, u32, u32) hidden;
|
||||
i32 fchown$sysv(i64, u32, u32) hidden;
|
||||
|
@ -230,11 +231,13 @@ int dup$nt(int, int, int) hidden;
|
|||
int execve$nt(const char *, char *const[], char *const[]) hidden;
|
||||
int faccessat$nt(int, const char *, int, uint32_t) hidden;
|
||||
int fadvise$nt(int, u64, u64, int) hidden;
|
||||
int fchdir$nt(int) hidden;
|
||||
int fcntl$nt(int, int, unsigned) hidden;
|
||||
int fdatasync$nt(int) hidden;
|
||||
int flock$nt(int, int) hidden;
|
||||
int fork$nt(void) hidden;
|
||||
int fstat$nt(i64, struct stat *) hidden;
|
||||
int fstatat$nt(int, const char *, struct stat *, uint32_t) hidden;
|
||||
int ftruncate$nt(int, u64) hidden;
|
||||
int getpriority$nt(int) hidden;
|
||||
int getrusage$nt(int, struct rusage *) hidden;
|
||||
|
@ -243,23 +246,21 @@ int kill$nt(int, int) hidden;
|
|||
int link$nt(const char *, const char *) hidden;
|
||||
int lstat$nt(const char *, struct stat *) hidden;
|
||||
int madvise$nt(void *, size_t, int) hidden;
|
||||
int mkdir$nt(const char *, uint32_t) hidden;
|
||||
int mkdirat$nt(int, const char *, uint32_t) hidden;
|
||||
int msync$nt(void *, size_t, int) hidden;
|
||||
int nanosleep$nt(const struct timespec *, struct timespec *) hidden;
|
||||
int pipe$nt(int[hasatleast 2], unsigned) hidden;
|
||||
int rename$nt(const char *, const char *) hidden;
|
||||
int rmdir$nt(const char *) hidden;
|
||||
int renameat$nt(int, const char *, int, const char *) hidden;
|
||||
int sched_yield$nt(void) hidden;
|
||||
int setitimer$nt(int, const struct itimerval *, struct itimerval *) hidden;
|
||||
int setpriority$nt(int) hidden;
|
||||
int stat$nt(const char *, struct stat *) hidden;
|
||||
int symlink$nt(const char *, const char *) hidden;
|
||||
int symlinkat$nt(const char *, int, const char *) hidden;
|
||||
int sync$nt(void) hidden;
|
||||
int sysinfo$nt(struct sysinfo *) hidden;
|
||||
int truncate$nt(const char *, u64) hidden;
|
||||
int unlink$nt(const char *) hidden;
|
||||
int unlinkat$nt(int, const char *, int) hidden;
|
||||
int utimensat$nt(int, const char *, const struct timespec *, int) hidden;
|
||||
ssize_t open$nt(const char *, u32, i32) nodiscard hidden;
|
||||
ssize_t open$nt(int, const char *, u32, i32) nodiscard hidden;
|
||||
ssize_t read$nt(struct Fd *, const struct iovec *, size_t, ssize_t) hidden;
|
||||
ssize_t write$nt(struct Fd *, const struct iovec *, size_t, ssize_t) hidden;
|
||||
|
||||
|
@ -279,6 +280,7 @@ int ntaccesscheck(const char16_t *, u32) paramsnonnull() hidden;
|
|||
int64_t __winerr(void) nocallback privileged;
|
||||
int __mkntpath(const char *, char16_t[hasatleast PATH_MAX - 16]) hidden;
|
||||
int __mkntpath2(const char *, char16_t[hasatleast PATH_MAX - 16], int) hidden;
|
||||
int __mkntpathat(int, const char *, int, char16_t[PATH_MAX]) hidden;
|
||||
unsigned __wincrash$nt(struct NtExceptionPointers *);
|
||||
|
||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||
|
|
|
@ -31,6 +31,5 @@
|
|||
* @see /etc/group for group ids
|
||||
*/
|
||||
int lchown(const char *pathname, uint32_t uid, uint32_t gid) {
|
||||
/* TODO(jart): Windows? */
|
||||
return fchownat$sysv(AT_FDCWD, pathname, uid, gid, AT_SYMLINK_NOFOLLOW);
|
||||
}
|
||||
|
|
|
@ -16,8 +16,6 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/dce.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
|
||||
|
@ -26,9 +24,5 @@
|
|||
* @asyncsignalsafe
|
||||
*/
|
||||
int lstat(const char *pathname, struct stat *st) {
|
||||
if (!IsWindows()) {
|
||||
return fstatat$sysv(AT_FDCWD, pathname, st, AT_SYMLINK_NOFOLLOW);
|
||||
} else {
|
||||
return lstat$nt(pathname, st);
|
||||
}
|
||||
return fstatat(AT_FDCWD, pathname, st, AT_SYMLINK_NOFOLLOW);
|
||||
}
|
||||
|
|
|
@ -41,10 +41,5 @@
|
|||
* @see makedirs()
|
||||
*/
|
||||
int mkdir(const char *path, unsigned mode) {
|
||||
if (!path) return efault();
|
||||
if (!IsWindows()) {
|
||||
return mkdirat$sysv(AT_FDCWD, path, mode);
|
||||
} else {
|
||||
return mkdir$nt(path, mode);
|
||||
}
|
||||
return mkdirat(AT_FDCWD, path, mode);
|
||||
}
|
||||
|
|
|
@ -36,10 +36,10 @@ static textwindows bool SubpathExistsThatsNotDirectory(char16_t *path) {
|
|||
return false;
|
||||
}
|
||||
|
||||
textwindows int mkdir$nt(const char *path, uint32_t mode) {
|
||||
textwindows int mkdirat$nt(int dirfd, const char *path, uint32_t mode) {
|
||||
int e;
|
||||
char16_t *p, path16[PATH_MAX];
|
||||
if (__mkntpath(path, path16) == -1) return -1;
|
||||
if (__mkntpathat(dirfd, path, 0, path16) == -1) return -1;
|
||||
if (CreateDirectory(path16, NULL)) return 0;
|
||||
e = GetLastError();
|
||||
/* WIN32 doesn't distinguish between ENOTDIR and ENOENT */
|
|
@ -24,7 +24,8 @@
|
|||
/**
|
||||
* Creates directory a.k.a. folder.
|
||||
*
|
||||
* @param dirfd is normally AT_FDCWD
|
||||
* @param dirfd is normally AT_FDCWD but if it's an open directory and
|
||||
* path is relative, then path becomes relative to dirfd
|
||||
* @param path is a UTF-8 string, preferably relative w/ forward slashes
|
||||
* @param mode can be, for example, 0755
|
||||
* @return 0 on success or -1 w/ errno
|
||||
|
@ -33,12 +34,9 @@
|
|||
* @see makedirs()
|
||||
*/
|
||||
int mkdirat(int dirfd, const char *path, unsigned mode) {
|
||||
if (!path) return efault();
|
||||
if (!IsWindows()) {
|
||||
return mkdirat$sysv(dirfd, path, mode);
|
||||
} else if (dirfd == AT_FDCWD) {
|
||||
return mkdir$nt(path, mode);
|
||||
} else {
|
||||
return einval();
|
||||
return mkdirat$nt(dirfd, path, mode);
|
||||
}
|
||||
}
|
||||
|
|
44
libc/calls/mkntpathat.c
Normal file
44
libc/calls/mkntpathat.c
Normal file
|
@ -0,0 +1,44 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2021 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/nt/files.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
int __mkntpathat(int dirfd, const char *path, int flags,
|
||||
char16_t file[PATH_MAX]) {
|
||||
char16_t dir[PATH_MAX];
|
||||
uint32_t dirlen, filelen;
|
||||
if ((filelen = __mkntpath2(path, file, flags)) == -1) return -1;
|
||||
if (file[0] != u'\\' && dirfd != AT_FDCWD) { /* ProTip: \\?\C:\foo */
|
||||
if (!__isfdkind(dirfd, kFdFile)) return ebadf();
|
||||
dirlen = GetFinalPathNameByHandle(g_fds.p[dirfd].handle, dir, ARRAYLEN(dir),
|
||||
kNtFileNameNormalized | kNtVolumeNameDos);
|
||||
if (!dirlen) return __winerr();
|
||||
if (dirlen + 1 + filelen + 1 > ARRAYLEN(dir)) return enametoolong();
|
||||
dir[dirlen] = u'\\';
|
||||
memcpy(dir + dirlen + 1, file, (filelen + 1) * sizeof(char16_t));
|
||||
memcpy(file, dir, (dirlen + 1 + filelen + 1) * sizeof(char16_t));
|
||||
return dirlen + 1 + filelen;
|
||||
} else {
|
||||
return filelen;
|
||||
}
|
||||
}
|
|
@ -30,18 +30,19 @@
|
|||
#include "libc/nt/files.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
#include "libc/sysv/consts/fileno.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
static textwindows int64_t open$nt$impl(const char *file, uint32_t flags,
|
||||
int32_t mode) {
|
||||
static textwindows int64_t open$nt$impl(int dirfd, const char *path,
|
||||
uint32_t flags, int32_t mode) {
|
||||
uint32_t br;
|
||||
int64_t handle;
|
||||
char16_t file16[PATH_MAX];
|
||||
if (__mkntpath2(file, file16, flags) == -1) return -1;
|
||||
char16_t path16[PATH_MAX];
|
||||
if (__mkntpathat(dirfd, path, flags, path16) == -1) return -1;
|
||||
if ((handle = CreateFile(
|
||||
file16,
|
||||
path16,
|
||||
(flags & 0xf000000f) |
|
||||
(/* this is needed if we mmap(rwx+cow)
|
||||
nt is choosy about open() access */
|
||||
|
@ -82,11 +83,18 @@ static textwindows int64_t open$nt$impl(const char *file, uint32_t flags,
|
|||
*/
|
||||
DeviceIoControl(handle, kNtFsctlSetSparse, NULL, 0, NULL, 0, &br, NULL);
|
||||
}
|
||||
return handle;
|
||||
} else if (GetLastError() == kNtErrorFileExists &&
|
||||
((flags & O_CREAT) &&
|
||||
(flags & O_TRUNC))) { /* TODO(jart): What was this? */
|
||||
return eisdir();
|
||||
} else {
|
||||
return __winerr();
|
||||
}
|
||||
return handle;
|
||||
}
|
||||
|
||||
static textwindows ssize_t open$nt$console(const struct NtMagicPaths *mp,
|
||||
static textwindows ssize_t open$nt$console(int dirfd,
|
||||
const struct NtMagicPaths *mp,
|
||||
uint32_t flags, int32_t mode,
|
||||
size_t fd) {
|
||||
if (GetFileType(g_fds.p[STDIN_FILENO].handle) == kNtFileTypeChar &&
|
||||
|
@ -94,39 +102,38 @@ static textwindows ssize_t open$nt$console(const struct NtMagicPaths *mp,
|
|||
g_fds.p[fd].handle = g_fds.p[STDIN_FILENO].handle;
|
||||
g_fds.p[fd].extra = g_fds.p[STDOUT_FILENO].handle;
|
||||
} else if ((g_fds.p[fd].handle = open$nt$impl(
|
||||
mp->conin, (flags & ~O_ACCMODE) | O_RDONLY, mode)) != -1) {
|
||||
dirfd, mp->conin, (flags & ~O_ACCMODE) | O_RDONLY, mode)) !=
|
||||
-1) {
|
||||
g_fds.p[fd].extra =
|
||||
open$nt$impl(mp->conout, (flags & ~O_ACCMODE) | O_WRONLY, mode);
|
||||
open$nt$impl(dirfd, mp->conout, (flags & ~O_ACCMODE) | O_WRONLY, mode);
|
||||
assert(g_fds.p[fd].extra != -1);
|
||||
} else {
|
||||
return __winerr();
|
||||
return -1;
|
||||
}
|
||||
g_fds.p[fd].kind = kFdConsole;
|
||||
g_fds.p[fd].flags = flags;
|
||||
return fd;
|
||||
}
|
||||
|
||||
static textwindows ssize_t open$nt$file(const char *file, uint32_t flags,
|
||||
int32_t mode, size_t fd) {
|
||||
if ((g_fds.p[fd].handle = open$nt$impl(file, flags, mode)) != -1) {
|
||||
static textwindows ssize_t open$nt$file(int dirfd, const char *file,
|
||||
uint32_t flags, int32_t mode,
|
||||
size_t fd) {
|
||||
if ((g_fds.p[fd].handle = open$nt$impl(dirfd, file, flags, mode)) != -1) {
|
||||
g_fds.p[fd].kind = kFdFile;
|
||||
g_fds.p[fd].flags = flags;
|
||||
return fd;
|
||||
} else if (GetLastError() == kNtErrorFileExists &&
|
||||
((flags & O_CREAT) && (flags & O_TRUNC))) {
|
||||
return eisdir();
|
||||
} else {
|
||||
return __winerr();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
textwindows ssize_t open$nt(const char *file, uint32_t flags, int32_t mode) {
|
||||
textwindows ssize_t open$nt(int dirfd, const char *file, uint32_t flags,
|
||||
int32_t mode) {
|
||||
size_t fd;
|
||||
if ((fd = __getemptyfd()) == -1) return -1;
|
||||
if ((flags & O_ACCMODE) == O_RDWR &&
|
||||
strcmp(file, kNtMagicPaths.devtty) == 0) {
|
||||
return open$nt$console(&kNtMagicPaths, flags, mode, fd);
|
||||
if ((flags & O_ACCMODE) == O_RDWR && !strcmp(file, kNtMagicPaths.devtty)) {
|
||||
return open$nt$console(dirfd, &kNtMagicPaths, flags, mode, fd);
|
||||
} else {
|
||||
return open$nt$file(file, flags, mode, fd);
|
||||
return open$nt$file(dirfd, file, flags, mode, fd);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,14 +16,8 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/weaken.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/zipos/zipos.internal.h"
|
||||
|
||||
/**
|
||||
* Opens file.
|
||||
|
@ -34,23 +28,14 @@
|
|||
* @param mode is an octal user/group/other permission signifier, that's
|
||||
* ignored if O_CREAT or O_TMPFILE weren't passed
|
||||
* @return number needing close(), or -1 w/ errno
|
||||
* @note don't call open() from signal handlers
|
||||
* @asyncsignalsafe
|
||||
* @vforksafe
|
||||
*/
|
||||
nodiscard int open(const char *file, int flags, ...) {
|
||||
va_list va;
|
||||
unsigned mode;
|
||||
struct ZiposUri zipname;
|
||||
va_start(va, flags);
|
||||
mode = va_arg(va, unsigned);
|
||||
va_end(va);
|
||||
if (!file) return efault();
|
||||
if (weaken(__zipos_open) && weaken(__zipos_parseuri)(file, &zipname) != -1) {
|
||||
return weaken(__zipos_open)(&zipname, flags, mode);
|
||||
} else if (!IsWindows()) {
|
||||
return openat$sysv(AT_FDCWD, file, flags, mode);
|
||||
} else {
|
||||
return open$nt(file, flags, mode);
|
||||
}
|
||||
return openat(AT_FDCWD, file, flags, mode);
|
||||
}
|
||||
|
|
|
@ -16,15 +16,20 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/weaken.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/zipos/zipos.internal.h"
|
||||
|
||||
/**
|
||||
* Opens file, the modern way.
|
||||
* Opens file.
|
||||
*
|
||||
* @param dirfd is normally AT_FDCWD or an open relative directory thing
|
||||
* @param dirfd is normally AT_FDCWD but if it's an open directory and
|
||||
* file is a relative path, then file is opened relative to dirfd
|
||||
* @param file is a UTF-8 string, preferably relative w/ forward slashes
|
||||
* @param flags should be O_RDONLY, O_WRONLY, or O_RDWR, and can be or'd
|
||||
* with O_CREAT, O_TRUNC, O_APPEND, O_EXCL, O_CLOEXEC, O_TMPFILE
|
||||
|
@ -33,16 +38,23 @@
|
|||
* @return number needing close(), or -1 w/ errno
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int openat(int dirfd, const char *pathname, int flags, ...) {
|
||||
nodiscard int openat(int dirfd, const char *file, int flags, ...) {
|
||||
va_list va;
|
||||
unsigned mode;
|
||||
struct ZiposUri zipname;
|
||||
va_start(va, flags);
|
||||
mode = va_arg(va, unsigned);
|
||||
va_end(va);
|
||||
if (!pathname) return efault();
|
||||
if (dirfd == AT_FDCWD) {
|
||||
return open(pathname, flags, mode);
|
||||
if (!file) return efault();
|
||||
if (weaken(__zipos_open) && weaken(__zipos_parseuri)(file, &zipname) != -1) {
|
||||
if (dirfd == AT_FDCWD) {
|
||||
return weaken(__zipos_open)(&zipname, flags, mode);
|
||||
} else {
|
||||
return eopnotsupp(); /* TODO */
|
||||
}
|
||||
} else if (!IsWindows()) {
|
||||
return openat$sysv(dirfd, file, flags, mode);
|
||||
} else {
|
||||
return openat$sysv(dirfd, pathname, flags, mode);
|
||||
return open$nt(dirfd, file, flags, mode);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,10 +17,7 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* Moves file the Unix way.
|
||||
|
@ -29,10 +26,5 @@
|
|||
* @asyncsignalsafe
|
||||
*/
|
||||
int rename(const char *oldpathname, const char *newpathname) {
|
||||
if (!oldpathname || !newpathname) return efault();
|
||||
if (!IsWindows()) {
|
||||
return renameat$sysv(AT_FDCWD, oldpathname, AT_FDCWD, newpathname);
|
||||
} else {
|
||||
return rename$nt(oldpathname, newpathname);
|
||||
}
|
||||
return renameat(AT_FDCWD, oldpathname, AT_FDCWD, newpathname);
|
||||
}
|
||||
|
|
|
@ -23,11 +23,12 @@
|
|||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
textwindows int rename$nt(const char *oldpath, const char *newpath) {
|
||||
textwindows int renameat$nt(int olddirfd, const char *oldpath, int newdirfd,
|
||||
const char *newpath) {
|
||||
char16_t oldpath16[PATH_MAX];
|
||||
char16_t newpath16[PATH_MAX];
|
||||
if (__mkntpath(oldpath, oldpath16) == -1 ||
|
||||
__mkntpath(newpath, newpath16) == -1) {
|
||||
if (__mkntpathat(olddirfd, oldpath, 0, oldpath16) == -1 ||
|
||||
__mkntpathat(newdirfd, newpath, 0, newpath16) == -1) {
|
||||
return -1;
|
||||
}
|
||||
if (MoveFileEx(oldpath16, newpath16, kNtMovefileReplaceExisting)) {
|
|
@ -19,16 +19,23 @@
|
|||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* Renames files relative to directories.
|
||||
*
|
||||
* @param olddirfd is normally AT_FDCWD but if it's an open directory
|
||||
* and oldpath is relative, then oldpath become relative to dirfd
|
||||
* @param newdirfd is normally AT_FDCWD but if it's an open directory
|
||||
* and newpath is relative, then newpath become relative to dirfd
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
*/
|
||||
int renameat(int olddirfd, const char *oldpath, int newdirfd,
|
||||
const char *newpath) {
|
||||
unsigned mode;
|
||||
if (olddirfd == AT_FDCWD && newdirfd == AT_FDCWD) {
|
||||
return rename(oldpath, newpath);
|
||||
} else {
|
||||
if (!oldpath || !newpath) return efault();
|
||||
if (!IsWindows()) {
|
||||
return renameat$sysv(olddirfd, oldpath, newdirfd, newpath);
|
||||
} else {
|
||||
return renameat$nt(olddirfd, oldpath, newdirfd, newpath);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,11 +16,7 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/dce.h"
|
||||
#include "libc/nt/files.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
|
||||
/**
|
||||
|
@ -29,10 +25,5 @@
|
|||
* @return 0 on success or -1 w/ errno on error
|
||||
*/
|
||||
int rmdir(const char *path) {
|
||||
if (!path) return efault();
|
||||
if (!IsWindows()) {
|
||||
return unlinkat$sysv(AT_FDCWD, path, AT_REMOVEDIR);
|
||||
} else {
|
||||
return rmdir$nt(path);
|
||||
}
|
||||
return unlinkat(AT_FDCWD, path, AT_REMOVEDIR);
|
||||
}
|
||||
|
|
|
@ -16,29 +16,16 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/weaken.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/zipos/zipos.internal.h"
|
||||
|
||||
/**
|
||||
* Returns information about thing.
|
||||
*
|
||||
* @param st is where result is stored
|
||||
* @see S_ISDIR(st.st_mode), S_ISREG(), etc.
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int stat(const char *pathname, struct stat *st) {
|
||||
struct ZiposUri zipname;
|
||||
if (weaken(__zipos_stat) &&
|
||||
weaken(__zipos_parseuri)(pathname, &zipname) != -1) {
|
||||
return weaken(__zipos_stat)(&zipname, st);
|
||||
} else if (!IsWindows()) {
|
||||
return fstatat$sysv(AT_FDCWD, pathname, st, 0);
|
||||
} else {
|
||||
return stat$nt(pathname, st);
|
||||
}
|
||||
int stat(const char *path, struct stat *st) {
|
||||
return fstatat(AT_FDCWD, path, st, 0);
|
||||
}
|
||||
|
|
|
@ -17,10 +17,7 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* Creates symbolic link.
|
||||
|
@ -36,10 +33,5 @@
|
|||
* @asyncsignalsafe
|
||||
*/
|
||||
int symlink(const char *target, const char *linkpath) {
|
||||
if (!target || !linkpath) return efault();
|
||||
if (!IsWindows()) {
|
||||
return symlinkat$sysv(target, AT_FDCWD, linkpath);
|
||||
} else {
|
||||
return symlink$nt(target, linkpath);
|
||||
}
|
||||
return symlinkat(target, AT_FDCWD, linkpath);
|
||||
}
|
||||
|
|
|
@ -20,10 +20,13 @@
|
|||
#include "libc/calls/internal.h"
|
||||
#include "libc/nt/files.h"
|
||||
|
||||
textwindows int symlink$nt(const char *target, const char *linkpath) {
|
||||
char16_t linkpath16[PATH_MAX], target16[PATH_MAX];
|
||||
uint32_t flags = isdirectory(target) ? kNtSymbolicLinkFlagDirectory : 0;
|
||||
if (__mkntpath(linkpath, linkpath16) == -1) return -1;
|
||||
textwindows int symlinkat$nt(const char *target, int newdirfd,
|
||||
const char *linkpath) {
|
||||
uint32_t flags;
|
||||
char16_t target16[PATH_MAX];
|
||||
char16_t linkpath16[PATH_MAX];
|
||||
flags = isdirectory(target) ? kNtSymbolicLinkFlagDirectory : 0;
|
||||
if (__mkntpathat(newdirfd, linkpath, 0, linkpath16) == -1) return -1;
|
||||
if (__mkntpath(target, target16) == -1) return -1;
|
||||
if (CreateSymbolicLink(linkpath16, target16, flags)) {
|
||||
return 0;
|
43
libc/calls/symlinkat.c
Normal file
43
libc/calls/symlinkat.c
Normal file
|
@ -0,0 +1,43 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
|
||||
/**
|
||||
* Creates symbolic link.
|
||||
*
|
||||
* This is like link() but adds a tiny indirection to make the fact that
|
||||
* the file is a link obvious. It also enables certain other features,
|
||||
* like the ability to be broken.
|
||||
*
|
||||
* @param target can be relative and needn't exist
|
||||
* @param linkpath is what gets created
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @note Windows NT only lets admins do this
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int symlinkat(const char *target, int newdirfd, const char *linkpath) {
|
||||
if (!IsWindows()) {
|
||||
return symlinkat$sysv(target, newdirfd, linkpath);
|
||||
} else {
|
||||
return symlinkat$nt(target, newdirfd, linkpath);
|
||||
}
|
||||
}
|
|
@ -16,12 +16,8 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/nt/files.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* Deletes file.
|
||||
|
@ -35,10 +31,5 @@
|
|||
* @asyncsignalsafe
|
||||
*/
|
||||
int unlink(const char *name) {
|
||||
if (!name) return efault();
|
||||
if (!IsWindows()) {
|
||||
return unlinkat$sysv(AT_FDCWD, name, 0);
|
||||
} else {
|
||||
return unlink$nt(name);
|
||||
}
|
||||
return unlinkat(AT_FDCWD, name, 0);
|
||||
}
|
||||
|
|
|
@ -17,20 +17,25 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/nt/errors.h"
|
||||
#include "libc/nt/files.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/nt/synchronization.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
|
||||
textwindows int rmdir$nt(const char *path) {
|
||||
int e, ms, len;
|
||||
char16_t path16[PATH_MAX];
|
||||
if ((len = __mkntpath(path, path16)) == -1) return -1;
|
||||
while (path16[len - 1] == u'\\') path16[--len] = u'\0';
|
||||
if (len + 2 + 1 > PATH_MAX) return enametoolong();
|
||||
static textwindows int unlink$nt(const char16_t *path) {
|
||||
if (DeleteFile(path)) {
|
||||
return 0;
|
||||
} else {
|
||||
return __winerr();
|
||||
}
|
||||
}
|
||||
|
||||
static textwindows int rmdir$nt(const char16_t *path) {
|
||||
int e, ms;
|
||||
for (ms = 1;; ms *= 2) {
|
||||
if (RemoveDirectory(path16)) return 0;
|
||||
if (RemoveDirectory(path)) return 0;
|
||||
/*
|
||||
* Files can linger, for absolutely no reason.
|
||||
* Possibly some Windows Defender bug on Win7.
|
||||
|
@ -48,3 +53,13 @@ textwindows int rmdir$nt(const char *path) {
|
|||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
|
||||
textwindows int unlinkat$nt(int dirfd, const char *path, int flags) {
|
||||
uint16_t path16[PATH_MAX];
|
||||
if (__mkntpathat(dirfd, path, 0, path16) == -1) return -1;
|
||||
if (flags & AT_REMOVEDIR) {
|
||||
return rmdir$nt(path16);
|
||||
} else {
|
||||
return unlink$nt(path16);
|
||||
}
|
||||
}
|
|
@ -18,12 +18,22 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
|
||||
int unlinkat(int dirfd, const char *pathname, int flags) {
|
||||
if (dirfd == AT_FDCWD) {
|
||||
return unlink(pathname);
|
||||
/**
|
||||
* Deletes inode and maybe the file too.
|
||||
*
|
||||
* @param dirfd is normally AT_FDCWD but if it's an open directory and
|
||||
* path is relative, then path becomes relative to dirfd
|
||||
* @param path is the thing to delete
|
||||
* @param flags can have AT_REMOVEDIR
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
*/
|
||||
int unlinkat(int dirfd, const char *path, int flags) {
|
||||
if (!IsWindows()) {
|
||||
return unlinkat$sysv(dirfd, path, flags);
|
||||
} else {
|
||||
return unlinkat$sysv(dirfd, pathname, flags);
|
||||
return unlinkat$nt(dirfd, path, flags);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,25 +35,12 @@ textwindows int utimensat$nt(int dirfd, const char *path,
|
|||
const struct timespec ts[2], int flags) {
|
||||
int i, rc;
|
||||
int64_t fh;
|
||||
bool closeme;
|
||||
uint16_t path16[PATH_MAX];
|
||||
struct NtFileTime ft[2], *ftp[2];
|
||||
if (flags) return einval();
|
||||
if (path) {
|
||||
if (dirfd == AT_FDCWD) {
|
||||
if (__mkntpath(path, path16) == -1) return -1;
|
||||
if ((fh = CreateFile(path16, kNtFileWriteAttributes, kNtFileShareRead,
|
||||
NULL, kNtOpenExisting, kNtFileAttributeNormal, 0)) !=
|
||||
-1) {
|
||||
closeme = true;
|
||||
} else {
|
||||
return __winerr();
|
||||
}
|
||||
} else {
|
||||
return einval();
|
||||
}
|
||||
} else {
|
||||
return ebadf();
|
||||
if (__mkntpathat(dirfd, path, 0, path16) == -1) return -1;
|
||||
if ((fh = CreateFile(path16, kNtFileWriteAttributes, kNtFileShareRead, NULL,
|
||||
kNtOpenExisting, kNtFileAttributeNormal, 0)) == -1) {
|
||||
return __winerr();
|
||||
}
|
||||
if (!ts || ts[0].tv_nsec == UTIME_NOW || ts[1].tv_nsec == UTIME_NOW) {
|
||||
GetSystemTimeAsFileTime(ft);
|
||||
|
@ -78,8 +65,6 @@ textwindows int utimensat$nt(int dirfd, const char *path,
|
|||
} else {
|
||||
rc = __winerr();
|
||||
}
|
||||
if (closeme) {
|
||||
CloseHandle(fh);
|
||||
}
|
||||
CloseHandle(fh);
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -200,13 +200,13 @@ bool32 WriteFileGather(int64_t hFileOpenedWithOverlappedAndNoBuffering,
|
|||
struct NtOverlapped inout_lpOverlapped) paramsnonnull();
|
||||
|
||||
#define kNtFileNameNormalized 0x0
|
||||
#define kNtVolumeNameDos 0x0
|
||||
#define kNtVolumeNameGuid 0x1
|
||||
#define kNtVolumeNameNt 0x2
|
||||
#define kNtVolumeNameNone 0x4
|
||||
#define kNtFileNameOpened 0x8
|
||||
#define kNtVolumeNameDos 0x0 /* e.g. \\?\C:\Users\jart */
|
||||
#define kNtVolumeNameGuid 0x1 /* e.g. \\?\Volume{ea38-etc.}\Users\jart */
|
||||
#define kNtVolumeNameNt 0x2 /* e.g. \Device\HarddiskVolume4\Users\jart */
|
||||
#define kNtVolumeNameNone 0x4 /* e.g. \Users\jart */
|
||||
uint32_t GetFinalPathNameByHandle(int64_t hFile, char16_t *out_path,
|
||||
uint32_t size, uint32_t flags);
|
||||
uint32_t arraylen, uint32_t flags);
|
||||
|
||||
#if ShouldUseMsabiAttribute()
|
||||
#include "libc/nt/thunk/files.inc"
|
||||
|
|
|
@ -151,6 +151,7 @@ int strcasecmpzbw(const uint16_t *, const char *) strlenesque;
|
|||
char *stpcpy(char *, const char *) memcpyesque;
|
||||
char *stpncpy(char *, const char *, size_t) memcpyesque;
|
||||
char *strcat(char *, const char *) memcpyesque;
|
||||
char16_t *strcat16(char16_t *, const char16_t *);
|
||||
size_t strlcpy(char *, const char *, size_t);
|
||||
size_t strlcat(char *, const char *, size_t);
|
||||
char *strcpy(char *, const char *) memcpyesque;
|
||||
|
|
|
@ -16,16 +16,16 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/nt/files.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
textwindows int unlink$nt(const char *name) {
|
||||
uint16_t name16[PATH_MAX];
|
||||
if (__mkntpath(name, name16) == -1) return -1;
|
||||
if (DeleteFile(name16)) {
|
||||
return 0;
|
||||
} else {
|
||||
return __winerr();
|
||||
}
|
||||
/**
|
||||
* Appends 𝑠 to 𝑑.
|
||||
*
|
||||
* @param 𝑑 is a NUL-terminated 16-bit string buffer
|
||||
* @param 𝑠 is a NUL-terminated 16-bit string
|
||||
* @return 𝑑
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
char16_t *strcat16(char16_t *d, const char16_t *s) {
|
||||
return strcpy16(d + strlen16(d), s);
|
||||
}
|
2
libc/sysv/calls/fchdir-sysv.s
Normal file
2
libc/sysv/calls/fchdir-sysv.s
Normal file
|
@ -0,0 +1,2 @@
|
|||
.include "o/libc/sysv/macros.internal.inc"
|
||||
.scall fchdir$sysv 0x000d000d200d0051 globl hidden
|
|
@ -1,2 +0,0 @@
|
|||
.include "o/libc/sysv/macros.internal.inc"
|
||||
.scall fchdir 0x000d000d200d0051 globl
|
|
@ -1,2 +1,2 @@
|
|||
.include "o/libc/sysv/macros.internal.inc"
|
||||
.scall mknodat 0x014022ffffff0103 globl
|
||||
.scall mknodat 0x0140022fffff0103 globl
|
||||
|
|
|
@ -118,7 +118,7 @@ scall '__truncate$sysv' 0x00c801df20c8004c globl hidden # openbsd:pad
|
|||
scall '__ftruncate$sysv' 0x00c901e020c9004d globl hidden # openbsd:pad
|
||||
scall 'getcwd$sysv' 0x01300146ffff004f globl hidden
|
||||
scall 'chdir$sysv' 0x000c000c200c0050 globl hidden
|
||||
scall fchdir 0x000d000d200d0051 globl
|
||||
scall 'fchdir$sysv' 0x000d000d200d0051 globl hidden
|
||||
scall 'rename$sysv' 0x0080008020800052 globl hidden
|
||||
scall 'mkdir$sysv' 0x0088008820880053 globl hidden
|
||||
scall 'rmdir$sysv' 0x0089008920890054 globl hidden
|
||||
|
@ -164,7 +164,7 @@ scall sigpending 0x003400342034007f globl
|
|||
scall 'sigsuspend$sysv' 0x006f0155206f0082 globl hidden
|
||||
scall sigaltstack 0x0120003520350083 globl
|
||||
scall 'mknod$sysv' 0x000e000e200e0085 globl hidden
|
||||
scall mknodat 0x014022ffffff0103 globl # FreeBSD 12+
|
||||
scall mknodat 0x0140022fffff0103 globl # FreeBSD 12+
|
||||
scall 'mkfifo$sysv' 0x008400842084ffff globl hidden
|
||||
scall mkfifoat 0x013f01f1ffffffff globl
|
||||
scall statfs 0x003f022b21590089 globl
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
#include "libc/x/x.h"
|
||||
|
||||
|
@ -68,3 +69,13 @@ TEST(makedirs, testEmptyString_ENOENT) {
|
|||
EXPECT_EQ(-1, makedirs("", 0755));
|
||||
EXPECT_EQ(ENOENT, errno);
|
||||
}
|
||||
|
||||
TEST(mkdirat, testRelativePath_opensRelativeToDirFd) {
|
||||
int dirfd;
|
||||
ASSERT_NE(-1, mkdir("foo", 0755));
|
||||
ASSERT_NE(-1, (dirfd = open("foo", O_RDONLY | O_DIRECTORY)));
|
||||
EXPECT_NE(-1, mkdirat(dirfd, "bar", 0755));
|
||||
EXPECT_TRUE(isdirectory("foo/bar"));
|
||||
EXPECT_EQ(-1, makedirs("", 0755));
|
||||
EXPECT_NE(-1, close(dirfd));
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue