cosmopolitan/libc/calls/open-nt.c

175 lines
7.3 KiB
C
Raw Normal View History

2020-06-15 14:18:57 +00:00
/*-*- 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
2020-12-28 01:18:44 +00:00
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.
2020-06-15 14:18:57 +00:00
2020-12-28 01:18:44 +00:00
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.
2020-06-15 14:18:57 +00:00
*/
#include "libc/assert.h"
2020-06-15 14:18:57 +00:00
#include "libc/calls/internal.h"
#include "libc/calls/ntmagicpaths.internal.h"
2022-05-23 22:06:11 +00:00
#include "libc/calls/state.internal.h"
#include "libc/calls/syscall-nt.internal.h"
#include "libc/calls/syscall_support-nt.internal.h"
#include "libc/errno.h"
#include "libc/intrin/kprintf.h"
2020-06-15 14:18:57 +00:00
#include "libc/nt/createfile.h"
#include "libc/nt/enum/creationdisposition.h"
#include "libc/nt/enum/fileflagandattributes.h"
2020-06-15 14:18:57 +00:00
#include "libc/nt/enum/filetype.h"
#include "libc/nt/files.h"
#include "libc/nt/process.h"
#include "libc/nt/runtime.h"
#include "libc/nt/thunk/msabi.h"
#include "libc/str/str.h"
2020-06-15 14:18:57 +00:00
#include "libc/sysv/consts/fileno.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/errfuns.h"
2020-06-15 14:18:57 +00:00
__msabi extern typeof(GetFileAttributes) *const __imp_GetFileAttributesW;
static textwindows int64_t sys_open_nt_impl(int dirfd, const char *path,
uint32_t flags, int32_t mode,
uint32_t extra_attr) {
// join(topath(dirfd), path) and translate from utf-8 to utf-16
char16_t path16[PATH_MAX];
if (__mkntpathat(dirfd, path, flags, path16) == -1) {
return kNtInvalidHandleValue;
}
// strip trailing slash
size_t n = strlen16(path16);
if (n > 1 && path16[n - 1] == '\\') {
// path denormalization only goes so far. when a trailing / or /.
// exists the kernel interprets that as having O_DIRECTORY intent
// furthermore, windows will throw an error on unc paths with it!
flags |= O_DIRECTORY;
path16[--n] = 0;
}
// implement no follow flag
// you can't open symlinks; use readlink
// this flag only applies to the final path component
// if O_NOFOLLOW_ANY is passed (-1 on NT) it'll be rejected later
uint32_t fattr = __imp_GetFileAttributesW(path16);
if (flags & O_NOFOLLOW) {
if (fattr != -1u && (fattr & kNtFileAttributeReparsePoint)) {
return eloop();
}
flags &= ~O_NOFOLLOW; // don't actually pass this to win32
}
// handle some obvious cases while we have the attributes
// we should ideally resolve symlinks ourself before doing this
if (fattr != -1u) {
if (fattr & kNtFileAttributeDirectory) {
if ((flags & O_ACCMODE) != O_RDONLY || (flags & O_CREAT)) {
// tried to open directory for writing. note that our
// undocumented O_TMPFILE support on windows requires that a
// filename be passed, rather than a directory like linux.
return eisdir();
}
// on posix, the o_directory flag is an advisory safeguard that
// isn't required. on windows, it's mandatory for opening a dir
flags |= O_DIRECTORY;
} else if (!(fattr & kNtFileAttributeReparsePoint)) {
// we know for certain file isn't a directory
if (flags & O_DIRECTORY) {
return enotdir();
}
}
}
// translate posix flags to win32 flags
uint32_t perm, share, disp, attr;
if (GetNtOpenFlags(flags, mode, &perm, &share, &disp, &attr) == -1) {
return kNtInvalidHandleValue;
}
// kNtTruncateExisting always returns kNtErrorInvalidParameter :'(
if (disp == kNtTruncateExisting) {
if (fattr != -1u) {
disp = kNtCreateAlways; // file exists (wish it could be more atomic)
} else {
return __fix_enotdir(enotdir(), path16);
}
}
// open the file, following symlinks
return __fix_enotdir(CreateFile(path16, perm, share, &kNtIsInheritable, disp,
attr | extra_attr, 0),
path16);
2020-06-15 14:18:57 +00:00
}
2022-05-23 22:06:11 +00:00
static textwindows int sys_open_nt_console(int dirfd,
const struct NtMagicPaths *mp,
uint32_t flags, int32_t mode,
size_t fd) {
2020-06-15 14:18:57 +00:00
if (GetFileType(g_fds.p[STDIN_FILENO].handle) == kNtFileTypeChar &&
GetFileType(g_fds.p[STDOUT_FILENO].handle) == kNtFileTypeChar) {
// this is an ugly hack that works for observed usage patterns
2020-06-15 14:18:57 +00:00
g_fds.p[fd].handle = g_fds.p[STDIN_FILENO].handle;
g_fds.p[fd].extra = g_fds.p[STDOUT_FILENO].handle;
g_fds.p[STDOUT_FILENO].dontclose = true;
g_fds.p[STDIN_FILENO].dontclose = true;
g_fds.p[fd].dontclose = true;
} else if ((g_fds.p[fd].handle = sys_open_nt_impl(
dirfd, mp->conin, (flags & ~O_ACCMODE) | O_RDONLY, mode,
kNtFileFlagOverlapped)) != -1) {
g_fds.p[fd].extra = sys_open_nt_impl(
dirfd, mp->conout, (flags & ~O_ACCMODE) | O_WRONLY, mode, 0);
npassert(g_fds.p[fd].extra != -1);
2020-06-15 14:18:57 +00:00
} else {
return -1;
2020-06-15 14:18:57 +00:00
}
g_fds.p[fd].kind = kFdConsole;
g_fds.p[fd].flags = flags;
g_fds.p[fd].mode = mode;
2020-06-15 14:18:57 +00:00
return fd;
}
2022-05-23 22:06:11 +00:00
static textwindows int sys_open_nt_file(int dirfd, const char *file,
uint32_t flags, int32_t mode,
size_t fd) {
if ((g_fds.p[fd].handle = sys_open_nt_impl(dirfd, file, flags, mode, 0)) !=
-1) {
2020-06-15 14:18:57 +00:00
g_fds.p[fd].kind = kFdFile;
g_fds.p[fd].flags = flags;
g_fds.p[fd].mode = mode;
2020-06-15 14:18:57 +00:00
return fd;
} else {
return -1;
2020-06-15 14:18:57 +00:00
}
}
2022-05-23 22:06:11 +00:00
textwindows int sys_open_nt(int dirfd, const char *file, uint32_t flags,
int32_t mode) {
int fd;
ssize_t rc;
__fds_lock();
2022-05-17 11:14:28 +00:00
if ((rc = fd = __reservefd_unlocked(-1)) != -1) {
if ((flags & O_ACCMODE) == O_RDWR && !strcmp(file, kNtMagicPaths.devtty)) {
rc = sys_open_nt_console(dirfd, &kNtMagicPaths, flags, mode, fd);
} else {
rc = sys_open_nt_file(dirfd, file, flags, mode, fd);
}
if (rc == -1) {
__releasefd(fd);
2022-05-17 11:14:28 +00:00
}
__fds_unlock();
}
return rc;
2020-06-15 14:18:57 +00:00
}