// Copyright © Tavian Barnes <tavianator@tavianator.com>
// SPDX-License-Identifier: 0BSD
#include "bfstd.h"
#include "bit.h"
#include "config.h"
#include "diag.h"
#include "sanity.h"
#include "thread.h"
#include "xregex.h"
#include <errno.h>
#include <fcntl.h>
#include <langinfo.h>
#include <limits.h>
#include <locale.h>
#include <nl_types.h>
#include <pthread.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/resource.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <wchar.h>
#if BFS_USE_SYS_SYSMACROS_H
# include <sys/sysmacros.h>
#elif BFS_USE_SYS_MKDEV_H
# include <sys/mkdev.h>
#endif
#if BFS_USE_UTIL_H
# include <util.h>
#endif
bool error_is_like(int error, int category) {
if (error == category) {
return true;
}
switch (category) {
case ENOENT:
return error == ENOTDIR;
case ENOSYS:
// https://github.com/opencontainers/runc/issues/2151
return errno == EPERM;
#if __DragonFly__
// https://twitter.com/tavianator/status/1742991411203485713
case ENAMETOOLONG:
return error == EFAULT;
#endif
}
return false;
}
bool errno_is_like(int category) {
return error_is_like(errno, category);
}
int try(int ret) {
if (ret >= 0) {
return ret;
} else {
bfs_assert(errno > 0, "errno should be positive, was %d\n", errno);
return -errno;
}
}
char *xdirname(const char *path) {
size_t i = xbaseoff(path);
// Skip trailing slashes
while (i > 0 && path[i - 1] == '/') {
--i;
}
if (i > 0) {
return strndup(path, i);
} else if (path[i] == '/') {
return strdup("/");
} else {
return strdup(".");
}
}
char *xbasename(const char *path) {
size_t i = xbaseoff(path);
size_t len = strcspn(path + i, "/");
if (len > 0) {
return strndup(path + i, len);
} else if (path[i] == '/') {
return strdup("/");
} else {
return strdup(".");
}
}
size_t xbaseoff(const char *path) {
size_t i = strlen(path);
// Skip trailing slashes
while (i > 0 && path[i - 1] == '/') {
--i;
}
// Find the beginning of the name
while (i > 0 && path[i - 1] != '/') {
--i;
}
// Skip leading slashes
while (path[i] == '/' && path[i + 1]) {
++i;
}
return i;
}
FILE *xfopen(const char *path, int flags) {
char mode[4];
switch (flags & O_ACCMODE) {
case O_RDONLY:
strcpy(mode, "rb");
break;
case O_WRONLY:
strcpy(mode, "wb");
break;
case O_RDWR:
strcpy(mode, "r+b");
break;
default:
bfs_bug("Invalid access mode");
errno = EINVAL;
return NULL;
}
if (flags & O_APPEND) {
mode[0] = 'a';
}
int fd;
if (flags & O_CREAT) {
fd = open(path, flags, 0666);
} else {
fd = open(path, flags);
}
if (fd < 0) {
return NULL;
}
FILE *ret = fdopen(fd, mode);
if (!ret) {
close_quietly(fd);
return N