summaryrefslogtreecommitdiffstats
path: root/dir.c
diff options
context:
space:
mode:
Diffstat (limited to 'dir.c')
-rw-r--r--dir.c303
1 files changed, 0 insertions, 303 deletions
diff --git a/dir.c b/dir.c
deleted file mode 100644
index 024e767..0000000
--- a/dir.c
+++ /dev/null
@@ -1,303 +0,0 @@
-/****************************************************************************
- * bfs *
- * Copyright (C) 2021-2022 Tavian Barnes <tavianator@tavianator.com> *
- * *
- * Permission to use, copy, modify, and/or distribute this software for any *
- * purpose with or without fee is hereby granted. *
- * *
- * 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 "dir.h"
-#include "util.h"
-#include <dirent.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <unistd.h>
-
-#if __linux__
-# include <sys/syscall.h>
-#endif // __linux__
-
-enum bfs_type bfs_mode_to_type(mode_t mode) {
- switch (mode & S_IFMT) {
-#ifdef S_IFBLK
- case S_IFBLK:
- return BFS_BLK;
-#endif
-#ifdef S_IFCHR
- case S_IFCHR:
- return BFS_CHR;
-#endif
-#ifdef S_IFDIR
- case S_IFDIR:
- return BFS_DIR;
-#endif
-#ifdef S_IFDOOR
- case S_IFDOOR:
- return BFS_DOOR;
-#endif
-#ifdef S_IFIFO
- case S_IFIFO:
- return BFS_FIFO;
-#endif
-#ifdef S_IFLNK
- case S_IFLNK:
- return BFS_LNK;
-#endif
-#ifdef S_IFPORT
- case S_IFPORT:
- return BFS_PORT;
-#endif
-#ifdef S_IFREG
- case S_IFREG:
- return BFS_REG;
-#endif
-#ifdef S_IFSOCK
- case S_IFSOCK:
- return BFS_SOCK;
-#endif
-#ifdef S_IFWHT
- case S_IFWHT:
- return BFS_WHT;
-#endif
-
- default:
- return BFS_UNKNOWN;
- }
-}
-
-#if __linux__
-/**
- * This is not defined in the kernel headers for some reason, callers have to
- * define it themselves.
- */
-struct linux_dirent64 {
- ino64_t d_ino;
- off64_t d_off;
- unsigned short d_reclen;
- unsigned char d_type;
- char d_name[];
-};
-
-// Make the whole allocation 64k
-#define BUF_SIZE ((64 << 10) - 8)
-#endif
-
-struct bfs_dir {
-#if __linux__
- int fd;
- unsigned short pos;
- unsigned short size;
-#else
- DIR *dir;
- struct dirent *de;
-#endif
-};
-
-struct bfs_dir *bfs_opendir(int at_fd, const char *at_path) {
-#if __linux__
- struct bfs_dir *dir = malloc(sizeof(*dir) + BUF_SIZE);
-#else
- struct bfs_dir *dir = malloc(sizeof(*dir));
-#endif
- if (!dir) {
- return NULL;
- }
-
- int fd;
- if (at_path) {
- fd = openat(at_fd, at_path, O_RDONLY | O_CLOEXEC | O_DIRECTORY);
- } else if (at_fd >= 0) {
- fd = at_fd;
- } else {
- free(dir);
- errno = EBADF;
- return NULL;
- }
-
- if (fd < 0) {
- free(dir);
- return NULL;
- }
-
-#if __linux__
- dir->fd = fd;
- dir->pos = 0;
- dir->size = 0;
-#else
- dir->dir = fdopendir(fd);
- if (!dir->dir) {
- if (at_path) {
- close_quietly(fd);
- }
- free(dir);
- return NULL;
- }
-
- dir->de = NULL;
-#endif // __linux__
-
- return dir;
-}
-
-int bfs_dirfd(const struct bfs_dir *dir) {
-#if __linux__
- return dir->fd;
-#else
- return dirfd(dir->dir);
-#endif
-}
-
-/** Convert a dirent type to a bfs_type. */
-static enum bfs_type translate_type(int d_type) {
- switch (d_type) {
-#ifdef DT_BLK
- case DT_BLK:
- return BFS_BLK;
-#endif
-#ifdef DT_CHR
- case DT_CHR:
- return BFS_CHR;
-#endif
-#ifdef DT_DIR
- case DT_DIR:
- return BFS_DIR;
-#endif
-#ifdef DT_DOOR
- case DT_DOOR:
- return BFS_DOOR;
-#endif
-#ifdef DT_FIFO
- case DT_FIFO:
- return BFS_FIFO;
-#endif
-#ifdef DT_LNK
- case DT_LNK:
- return BFS_LNK;
-#endif
-#ifdef DT_PORT
- case DT_PORT:
- return BFS_PORT;
-#endif
-#ifdef DT_REG
- case DT_REG:
- return BFS_REG;
-#endif
-#ifdef DT_SOCK
- case DT_SOCK:
- return BFS_SOCK;
-#endif
-#ifdef DT_WHT
- case DT_WHT:
- return BFS_WHT;
-#endif
- }
-
- return BFS_UNKNOWN;
-}
-
-#if !__linux__
-/** Get the type from a struct dirent if it exists, and convert it. */
-static enum bfs_type dirent_type(const struct dirent *de) {
-#if defined(_DIRENT_HAVE_D_TYPE) || defined(DT_UNKNOWN)
- return translate_type(de->d_type);
-#else
- return BFS_UNKNOWN;
-#endif
-}
-#endif
-
-/** Check if a name is . or .. */
-static bool is_dot(const char *name) {
- return name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0'));
-}
-
-int bfs_readdir(struct bfs_dir *dir, struct bfs_dirent *de) {
- while (true) {
-#if __linux__
- char *buf = (char *)(dir + 1);
-
- if (dir->pos >= dir->size) {
-#if BFS_HAS_FEATURE(memory_sanitizer, false)
- // Make sure msan knows the buffer is initialized
- memset(buf, 0, BUF_SIZE);
-#endif
-
- ssize_t size = syscall(__NR_getdents64, dir->fd, buf, BUF_SIZE);
- if (size <= 0) {
- return size;
- }
- dir->pos = 0;
- dir->size = size;
- }
-
- const struct linux_dirent64 *lde = (void *)(buf + dir->pos);
- dir->pos += lde->d_reclen;
-
- if (is_dot(lde->d_name)) {
- continue;
- }
-
- if (de) {
- de->type = translate_type(lde->d_type);
- de->name = lde->d_name;
- }
-
- return 1;
-#else // !__linux__
- errno = 0;
- dir->de = readdir(dir->dir);
- if (dir->de) {
- if (is_dot(dir->de->d_name)) {
- continue;
- }
- if (de) {
- de->type = dirent_type(dir->de);
- de->name = dir->de->d_name;
- }
- return 1;
- } else if (errno != 0) {
- return -1;
- } else {
- return 0;
- }
-#endif // !__linux__
- }
-}
-
-int bfs_closedir(struct bfs_dir *dir) {
-#if __linux__
- int ret = xclose(dir->fd);
-#else
- int ret = closedir(dir->dir);
-#endif
- free(dir);
- return ret;
-}
-
-int bfs_freedir(struct bfs_dir *dir) {
-#if __linux__
- int ret = dir->fd;
- free(dir);
- return ret;
-#elif __FreeBSD__
- int ret = fdclosedir(dir->dir);
- free(dir);
- return ret;
-#else
- int ret = dup_cloexec(dirfd(dir->dir));
- bfs_closedir(dir);
- return ret;
-#endif
-}