Implement getcwd() for XNU

This commit is contained in:
Justine Tunney 2021-01-30 08:54:12 -08:00
parent 417797d218
commit 95173645a1
17 changed files with 239 additions and 77 deletions

View file

@ -11,12 +11,31 @@
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/errfuns.h"
#include "third_party/xed/x86.h"
/**
* @fileoverview x86 instruction length decoder by way of hex pipe.
*/
int fgethex(FILE *f) {
int o, t = -1;
while (!((o = fgetc(f)) & ~0xFF)) {
switch (t) {
case -1:
t = isxdigit(o) ? hextoint(o) : -1;
break;
default:
if (isxdigit(o)) {
return t * 16 + hextoint(o);
}
break;
}
}
if (t >= 0) return einval();
return -1;
}
int main(int argc, char *argv[argc]) {
unsigned c, i, j, l;
enum XedError err;
@ -42,9 +61,8 @@ int main(int argc, char *argv[argc]) {
l = xedd.length;
if (l <= 0 || l > i) abort();
for (j = 0; j < l; ++j) {
if (fputhex(buf[j], stdout) == -1) {
return errno;
}
fputc("0123456789ABCDEF"[(buf[j] & 0xf0) >> 4], stdout);
fputc("0123456789ABCDEF"[(buf[j] & 0x0f) >> 0], stdout);
}
putchar('\n');
memcpy(&buf[0], &buf[l], i -= l);

View file

@ -232,10 +232,6 @@ 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() \
: getcwd(BUF, SIZE))
/*───────────────────────────────────────────────────────────────────────────│─╗
cosmopolitan § system calls » formatting
*/
@ -248,6 +244,10 @@ int vdprintf(int, const char *, va_list) paramsnonnull();
*/
#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
#define getcwd(BUF, SIZE) \
(__builtin_constant_p(BUF) && !(BUF) ? get_current_dir_name() \
: getcwd(BUF, SIZE))
void _init_onntconsoleevent(void);
void _init_wincrash(void);

View file

@ -23,12 +23,12 @@
#include "libc/sysv/errfuns.h"
textwindows char *getcwd$nt(char *buf, size_t size) {
uint16_t name16[PATH_MAX + 1];
uint16_t name16[PATH_MAX];
if (GetCurrentDirectory(ARRAYLEN(name16), name16)) {
tprecode16to8(buf, size, name16);
return buf;
} else {
__winerr();
return NULL;
}
return NULL;
}

57
libc/calls/getcwd-xnu.c Normal file
View file

@ -0,0 +1,57 @@
/*-*- 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/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/struct/stat.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/at.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/errfuns.h"
#define XNU_F_GETPATH 50
#define XNU_MAXPATHLEN 1024
char *getcwd$xnu(char *res, size_t size) {
int fd;
struct stat st[2];
char buf[XNU_MAXPATHLEN], *ret = NULL;
if ((fd = openat$sysv(AT_FDCWD, ".", O_RDONLY | O_DIRECTORY)) != -1) {
if (fstat$sysv(fd, &st[0]) != -1) {
if (st[0].st_dev && st[0].st_ino) {
if (fcntl$sysv(fd, XNU_F_GETPATH, buf) != -1) {
if (fstatat$sysv(AT_FDCWD, buf, &st[1], 0) != -1) {
if (st[0].st_dev == st[1].st_dev && st[0].st_ino == st[1].st_ino) {
if (memccpy(res, buf, '\0', size)) {
ret = res;
} else {
erange();
}
} else {
einval();
}
}
}
} else {
einval();
}
}
close(fd);
}
return ret;
}

View file

@ -19,8 +19,6 @@
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/sysv/errfuns.h"
/**
* Returns current working directory.
@ -34,28 +32,16 @@
* @error ERANGE, EINVAL
*/
char *(getcwd)(char *buf, size_t size) {
if (buf) {
buf[0] = '\0';
if (!IsWindows()) {
int olderr = errno;
if (getcwd$sysv(buf, size) != NULL) {
return buf;
} else if (IsXnu() && errno == ENOSYS) {
if (size >= 2) {
buf[0] = '.'; /* XXX: could put forth more effort */
buf[1] = '\0';
errno = olderr;
return buf;
} else {
erange();
}
}
return NULL;
if (buf && size) buf[0] = '\0';
if (!IsWindows()) {
if (IsXnu()) {
return getcwd$xnu(buf, size);
} else if (getcwd$sysv(buf, size) != (void *)-1) {
return buf;
} else {
return getcwd$nt(buf, size);
return NULL;
}
} else {
efault();
return NULL;
return getcwd$nt(buf, size);
}
}

View file

@ -32,7 +32,6 @@
*/
nodiscard char *get_current_dir_name(void) {
char *buf, *res;
if ((res = getenv("PWD"))) return strdup(res);
if (!(buf = malloc(PATH_MAX))) return NULL;
if (!(res = (getcwd)(buf, PATH_MAX))) free(buf);
return res;

View file

@ -99,6 +99,7 @@ forceinline size_t clampio(size_t size) {
*/
char *getcwd$sysv(char *, u64) hidden;
char *getcwd$xnu(char *, u64) hidden;
i32 __dup3$sysv(i32, i32, i32) hidden;
i32 __execve$sysv(const char *, char *const[], char *const[]) hidden;
i32 __fstat$sysv(i32, struct stat *) hidden;
@ -120,7 +121,7 @@ i32 fchmod$sysv(i32, u32) hidden;
i32 fchmodat$sysv(i32, const char *, u32, u32) hidden;
i32 fchown$sysv(i64, u32, u32) hidden;
i32 fchownat$sysv(i32, const char *, u32, u32, u32) hidden;
i32 fcntl$sysv(i32, i32, i32) hidden;
i32 fcntl$sysv(i32, i32, ...) hidden;
i32 fdatasync$sysv(i32) hidden;
i32 flock$sysv(i32, i32) hidden;
i32 fork$sysv(void) hidden;
@ -151,7 +152,7 @@ i32 mprotect$sysv(void *, u64, i32) hidden;
i32 msync$sysv(void *, u64, i32) hidden;
i32 munmap$sysv(void *, u64) hidden;
i32 nanosleep$sysv(const struct timespec *, struct timespec *) hidden;
i32 openat$sysv(i32, const char *, i32, i32) hidden;
i32 openat$sysv(i32, const char *, i32, ...) hidden;
i32 pause$sysv(void) hidden;
i32 pipe$sysv(i32[hasatleast 2]) hidden;
i32 pipe2$sysv(i32[hasatleast 2], u32) hidden;

View file

@ -17,6 +17,7 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/bits/bits.h"
#include "libc/bits/safemacros.h"
#include "libc/calls/calls.h"
#include "libc/errno.h"
#include "libc/macros.h"
@ -31,19 +32,31 @@
* @return path to debug binary, or -1 w/ errno
*/
const char *FindDebugBinary(void) {
static char buf[PATH_MAX];
if (buf[0]) return &buf[0];
const char *const trybins[] = {program_invocation_name,
(const char *)getauxval(AT_EXECFN)};
for (unsigned i = 0; i < ARRAYLEN(trybins); ++i) {
const char *res = trybins[i];
unsigned len = strlen(res);
if (4 < len && len < sizeof(buf) - 5) {
if (strcmp(res + len - 4, ".dbg") == 0) return res;
/* try suffixing extension, e.g. .com → .com.dbg */
memcpy(mempcpy(buf, res, len), ".dbg", 5);
if (fileexists(buf)) return &buf[0];
buf[0] = '\0';
unsigned i, len;
char buf[2][PATH_MAX];
static char res[PATH_MAX];
const char *bins[4], *pwd;
bins[0] = program_invocation_name;
bins[1] = (const char *)getauxval(AT_EXECFN);
pwd = emptytonull(getenv("PWD"));
for (i = 0; i < 2; ++i) {
if (pwd && bins[i] && bins[i][0] != '/' && bins[i][0] != '\\' &&
strlen(pwd) + 1 + strlen(bins[i]) + 1 <= ARRAYLEN(buf[0])) {
strcpy(buf[i], pwd);
strcat(buf[i], "/");
strcat(buf[i], bins[i]);
bins[i + 2] = buf[i];
}
}
for (i = 0; i < 4; ++i) {
if (!bins[i]) continue;
len = strlen(bins[i]);
memcpy(res, bins[i], len + 1);
if (!endswith(res, ".dbg") && len + 3 + 1 <= ARRAYLEN(res)) {
strcat(res, ".dbg");
}
if (fileexists(res)) {
return res;
}
}
errno = ENOENT;

View file

@ -52,8 +52,6 @@ int putchar(int);
int puts(const char *) paramsnonnull();
ssize_t getline(char **, size_t *, FILE *) paramsnonnull();
ssize_t getdelim(char **, size_t *, int, FILE *) paramsnonnull();
int fputhex(int, FILE *) paramsnonnull();
int fgethex(FILE *) paramsnonnull();
FILE *fopen(const char *, const char *) paramsnonnull() nodiscard;
FILE *fdopen(int, const char *) paramsnonnull() nodiscard;
FILE *fmemopen(void *, size_t, const char *) paramsnonnull((3)) nodiscard;

View file

@ -24,7 +24,7 @@
* This API was thought to be nearly extinct until recent versions
* of Clang (c. 2019) started generating synthetic calls to it.
*
* @return unsigned char subtraction at stop index
* @return 0 if a and b have equal contents, otherwise non-zero
* @asyncsignalsafe
*/
int bcmp(const void *a, const void *b, size_t n) {

View file

@ -151,11 +151,13 @@ 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 *);
char16_t *strcat16(char16_t *, const char16_t *) memcpyesque;
wchar_t *wcscat(wchar_t *, const wchar_t *) memcpyesque;
size_t strlcpy(char *, const char *, size_t);
size_t strlcat(char *, const char *, size_t);
char *strcpy(char *, const char *) memcpyesque;
char16_t *strcpy16(char16_t *, const char16_t *) memcpyesque;
wchar_t *wcscpy(wchar_t *, const wchar_t *) memcpyesque;
char *strncat(char *, const char *, size_t) memcpyesque;
char *strncpy(char *, const char *, size_t) memcpyesque;
char *strtok(char *, const char *) paramsnonnull((2)) libcesque;

View file

@ -18,7 +18,6 @@
*/
#include "libc/intrin/pcmpeqb.h"
#include "libc/intrin/pmovmskb.h"
#include "libc/limits.h"
#include "libc/str/str.h"
/**

View file

@ -28,5 +28,5 @@
* @return original dest
*/
char16_t *strcpy16(char16_t *dest, const char16_t *src) {
return memcpy(dest, src, (strlen16(src) + 1) << 1);
return memcpy(dest, src, (strlen16(src) + 1) * sizeof(char16_t));
}

View file

@ -16,11 +16,16 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
int fputhex(int c, FILE *f) {
return (fputc("0123456789ABCDEF"[(c / 16) & 0xF], f) >= 0 &&
fputc("0123456789ABCDEF"[(c % 16) & 0xF], f) >= 0)
? c
: -1;
/**
* Appends 𝑠 to 𝑑.
*
* @param 𝑑 is a NUL-terminated 32-bit string
* @param 𝑠 is a NUL-terminated 32-bit string
* @return 𝑑
* @asyncsignalsafe
*/
wchar_t *wcscat(wchar_t *d, const wchar_t *s) {
return wcscpy(d + wcslen(d), s);
}

View file

@ -16,24 +16,18 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/errfuns.h"
int fgethex(FILE *f) {
int o, t = -1;
while (!((o = fgetc(f)) & ~0xFF)) {
switch (t) {
case -1:
t = isxdigit(o) ? hextoint(o) : -1;
break;
default:
if (isxdigit(o)) {
return t * 16 + hextoint(o);
}
break;
}
}
if (t >= 0) return einval();
return -1;
/**
* Copies NUL-terminated wide character string.
*
* 𝑑 and 𝑠 must not overlap unless 𝑑 𝑠.
*
* @param 𝑑 is destination memory
* @param 𝑠 is a NUL-terminated string
* @return original dest
* @asyncsignalsafe
*/
wchar_t *wcscpy(wchar_t *d, const wchar_t *s) {
return memcpy(d, s, (wcslen(s) + 1) * sizeof(wchar_t));
}

View file

@ -0,0 +1,55 @@
/*-*- 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/calls.h"
#include "libc/errno.h"
#include "libc/fmt/conv.h"
#include "libc/fmt/fmt.h"
#include "libc/log/check.h"
#include "libc/macros.h"
#include "libc/runtime/gc.h"
#include "libc/testlib/testlib.h"
#include "libc/x/x.h"
char basedir[PATH_MAX];
char testdir[PATH_MAX];
void SetUp(void) {
getcwd(basedir, ARRAYLEN(basedir));
sprintf(testdir, "o/tmp/%s.%d", program_invocation_short_name, getpid());
makedirs(testdir, 0755);
CHECK_NE(-1, chdir(testdir));
}
void TearDown(void) {
CHECK_NE(-1, chdir(basedir));
CHECK_NE(-1, rmrf(testdir));
}
TEST(getcwd, test) {
char buf[PATH_MAX];
EXPECT_NE(-1, mkdir("subdir", 0755));
EXPECT_NE(-1, chdir("subdir"));
EXPECT_STREQ("subdir", basename(getcwd(buf, ARRAYLEN(buf))));
}
TEST(getcwd, testNullBuf_allocatesResult) {
EXPECT_NE(-1, mkdir("subdir", 0755));
EXPECT_NE(-1, chdir("subdir"));
EXPECT_STREQ("subdir", basename(gc(getcwd(NULL, 0))));
}

View file

@ -0,0 +1,35 @@
/*-*- 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/str/str.h"
#include "libc/testlib/ezbench.h"
#include "libc/testlib/testlib.h"
TEST(strcasecmp, test) {
EXPECT_EQ(0, strcasecmp("HELLO", "hello"));
EXPECT_EQ(-17, strcasecmp("HELLO", "yello"));
EXPECT_EQ(-17, strcasecmp("HELLO", "YELLO"));
EXPECT_EQ(+17, strcasecmp("yello", "HELLO"));
EXPECT_EQ(+17, strcasecmp("YELLO", "HELLO"));
}
BENCH(strcasecmp, bench) {
EZBENCH2("strcasecmp 16 eq", donothing,
EXPROPRIATE(
strcasecmp(VEIL("r", "abcdefghijklmnop"), "ABCDEFGHIJKLMNOP")));
}