diff options
Diffstat (limited to 'lib/fstree/fstree_from_dir.c')
-rw-r--r-- | lib/fstree/fstree_from_dir.c | 493 |
1 files changed, 0 insertions, 493 deletions
diff --git a/lib/fstree/fstree_from_dir.c b/lib/fstree/fstree_from_dir.c deleted file mode 100644 index 01f331d..0000000 --- a/lib/fstree/fstree_from_dir.c +++ /dev/null @@ -1,493 +0,0 @@ -/* SPDX-License-Identifier: GPL-3.0-or-later */ -/* - * fstree_from_dir.c - * - * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at> - */ -#include "config.h" -#include "fstree.h" - -#include <dirent.h> -#include <stdlib.h> -#include <string.h> -#include <errno.h> - -#if defined(_WIN32) || defined(__WINDOWS__) -#define UNIX_EPOCH_ON_W32 11644473600UL -#define W32_TICS_PER_SEC 10000000UL - -static sqfs_u32 w32time_to_sqfs_time(const FILETIME *ft) -{ - sqfs_u64 w32ts; - - w32ts = ft->dwHighDateTime; - w32ts <<= 32UL; - w32ts |= ft->dwLowDateTime; - - w32ts /= W32_TICS_PER_SEC; - - if (w32ts <= UNIX_EPOCH_ON_W32) - return 0; - - w32ts -= UNIX_EPOCH_ON_W32; - - return (w32ts < 0x0FFFFFFFFUL) ? w32ts : 0xFFFFFFFF; -} - -static int add_node(fstree_t *fs, tree_node_t *root, - scan_node_callback cb, void *user, - unsigned int flags, - const LPWIN32_FIND_DATAW entry) -{ - tree_node_t *n; - DWORD length; - - if (entry->cFileName[0] == '.') { - if (entry->cFileName[1] == '\0') - return 0; - - if (entry->cFileName[1] == '.' && entry->cFileName[2] == '\0') - return 0; - } - - length = WideCharToMultiByte(CP_UTF8, 0, entry->cFileName, - -1, NULL, 0, NULL, NULL); - if (length <= 0) { - w32_perror("converting path to UTF-8"); - return -1; - } - - n = calloc(1, sizeof(*n) + length + 1); - if (n == NULL) { - fprintf(stderr, "creating tree node: out-of-memory\n"); - return -1; - } - - n->name = (char *)n->payload; - WideCharToMultiByte(CP_UTF8, 0, entry->cFileName, -1, - n->name, length + 1, NULL, NULL); - - if (entry->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { - if (flags & DIR_SCAN_NO_DIR) { - free(n); - return 0; - } - - n->mode = S_IFDIR | 0755; - } else { - if (flags & DIR_SCAN_NO_FILE) { - free(n); - return 0; - } - - n->mode = S_IFREG | 0644; - } - - if (cb != NULL) { - int ret = cb(user, fs, n); - - if (ret != 0) { - free(n); - return ret < 0 ? ret : 0; - } - } - - if (flags & DIR_SCAN_KEEP_TIME) { - n->mod_time = w32time_to_sqfs_time(&(entry->ftLastWriteTime)); - } else { - n->mod_time = fs->defaults.st_mtime; - } - - fstree_insert_sorted(root, n); - return 0; -} - -static int scan_dir(fstree_t *fs, tree_node_t *root, - const char *path, const WCHAR *wpath, - scan_node_callback cb, void *user, - unsigned int flags) -{ - WIN32_FIND_DATAW entry; - HANDLE dirhnd; - - dirhnd = FindFirstFileW(wpath, &entry); - - if (dirhnd == INVALID_HANDLE_VALUE) - goto fail_perror; - - do { - if (add_node(fs, root, cb, user, flags, &entry)) - goto fail; - } while (FindNextFileW(dirhnd, &entry)); - - if (GetLastError() != ERROR_NO_MORE_FILES) - goto fail_perror; - - FindClose(dirhnd); - return 0; -fail_perror: - w32_perror(path); -fail: - if (dirhnd != INVALID_HANDLE_VALUE) - FindClose(dirhnd); - return -1; -} - -int fstree_from_dir(fstree_t *fs, tree_node_t *root, - const char *path, scan_node_callback cb, - void *user, unsigned int flags) -{ - WCHAR *wpath = NULL, *new = NULL; - size_t len, newlen; - tree_node_t *n; - - /* path -> to_wchar(path) + L"\*" */ - wpath = path_to_windows(path); - if (wpath == NULL) { - fprintf(stderr, "%s: allocation failure.\n", path); - return -1; - } - - for (len = 0; wpath[len] != '\0'; ++len) - ; - - newlen = len + 1; - - if (len > 0 && wpath[len - 1] != '\\') - newlen += 1; - - new = realloc(wpath, sizeof(wpath[0]) * (newlen + 1)); - if (new == NULL) { - fprintf(stderr, "%s: allocation failure.\n", path); - goto fail; - } - - wpath = new; - - if (len > 0 && wpath[len - 1] != '\\') - wpath[len++] = '\\'; - - wpath[len++] = '*'; - wpath[len++] = '\0'; - - /* scan directory contents */ - if (scan_dir(fs, root, path, wpath, cb, user, flags)) - goto fail; - - free(wpath); - wpath = NULL; - - /* recursion step */ - if (flags & DIR_SCAN_NO_RECURSION) - return 0; - - for (n = root->data.dir.children; n != NULL; n = n->next) { - if (!S_ISDIR(n->mode)) - continue; - - if (fstree_from_subdir(fs, n, path, n->name, cb, user, flags)) - return -1; - } - - return 0; -fail: - free(wpath); - return -1; -} - -int fstree_from_subdir(fstree_t *fs, tree_node_t *root, - const char *path, const char *subdir, - scan_node_callback cb, void *user, - unsigned int flags) -{ - size_t len, plen, slen; - WCHAR *wpath = NULL; - char *temp = NULL; - tree_node_t *n; - - plen = strlen(path); - slen = subdir == NULL ? 0 : strlen(subdir); - - if (slen == 0) - return fstree_from_dir(fs, root, path, cb, user, flags); - - len = plen + 1 + slen + 2; - - temp = calloc(1, len + 1); - if (temp == NULL) { - fprintf(stderr, "%s/%s: allocation failure.\n", path, subdir); - return -1; - } - - memcpy(temp, path, plen); - temp[plen] = '/'; - memcpy(temp + plen + 1, subdir, slen); - temp[plen + 1 + slen ] = '/'; - temp[plen + 1 + slen + 1] = '*'; - temp[plen + 1 + slen + 2] = '\0'; - - wpath = path_to_windows(temp); - if (wpath == NULL) { - fprintf(stderr, "%s: allocation failure.\n", temp); - goto fail; - } - - if (scan_dir(fs, root, temp, wpath, cb, user, flags)) - goto fail; - - free(wpath); - wpath = NULL; - - if (flags & DIR_SCAN_NO_RECURSION) { - free(temp); - return 0; - } - - temp[plen + 1 + slen] = '\0'; - - for (n = root->data.dir.children; n != NULL; n = n->next) { - if (!S_ISDIR(n->mode)) - continue; - - if (fstree_from_subdir(fs, n, temp, n->name, cb, user, flags)) - goto fail; - } - - free(temp); - return 0; -fail: - free(temp); - free(wpath); - return -1; - -} -#else -static void discard_node(tree_node_t *root, tree_node_t *n) -{ - tree_node_t *it; - - if (n == root->data.dir.children) { - root->data.dir.children = n->next; - } else { - it = root->data.dir.children; - - while (it != NULL && it->next != n) - it = it->next; - - if (it != NULL) - it->next = n->next; - } - - free(n); -} - -static int populate_dir(int dir_fd, fstree_t *fs, tree_node_t *root, - dev_t devstart, scan_node_callback cb, - void *user, unsigned int flags) -{ - char *extra = NULL; - struct dirent *ent; - int ret, childfd; - struct stat sb; - tree_node_t *n; - DIR *dir; - - dir = fdopendir(dir_fd); - if (dir == NULL) { - perror("fdopendir"); - close(dir_fd); - return -1; - } - - /* XXX: fdopendir can dup and close dir_fd internally - and still be compliant with the spec. */ - dir_fd = dirfd(dir); - - for (;;) { - errno = 0; - ent = readdir(dir); - - if (ent == NULL) { - if (errno) { - perror("readdir"); - goto fail; - } - break; - } - - if (!strcmp(ent->d_name, "..") || !strcmp(ent->d_name, ".")) - continue; - - if (fstatat(dir_fd, ent->d_name, &sb, AT_SYMLINK_NOFOLLOW)) { - perror(ent->d_name); - goto fail; - } - - switch (sb.st_mode & S_IFMT) { - case S_IFSOCK: - if (flags & DIR_SCAN_NO_SOCK) - continue; - break; - case S_IFLNK: - if (flags & DIR_SCAN_NO_SLINK) - continue; - break; - case S_IFREG: - if (flags & DIR_SCAN_NO_FILE) - continue; - break; - case S_IFBLK: - if (flags & DIR_SCAN_NO_BLK) - continue; - break; - case S_IFCHR: - if (flags & DIR_SCAN_NO_CHR) - continue; - break; - case S_IFIFO: - if (flags & DIR_SCAN_NO_FIFO) - continue; - break; - default: - break; - } - - if ((flags & DIR_SCAN_ONE_FILESYSTEM) && sb.st_dev != devstart) - continue; - - if (S_ISLNK(sb.st_mode)) { - size_t size; - - if ((sizeof(sb.st_size) > sizeof(size_t)) && - sb.st_size > SIZE_MAX) { - errno = EOVERFLOW; - goto fail_rdlink; - } - - if (SZ_ADD_OV((size_t)sb.st_size, 1, &size)) { - errno = EOVERFLOW; - goto fail_rdlink; - } - - extra = calloc(1, size); - if (extra == NULL) - goto fail_rdlink; - - if (readlinkat(dir_fd, ent->d_name, - extra, (size_t)sb.st_size) < 0) { - goto fail_rdlink; - } - - extra[sb.st_size] = '\0'; - } - - if (!(flags & DIR_SCAN_KEEP_TIME)) - sb.st_mtime = fs->defaults.st_mtime; - - if (S_ISDIR(sb.st_mode) && (flags & DIR_SCAN_NO_DIR)) { - n = fstree_get_node_by_path(fs, root, ent->d_name, - false, false); - if (n == NULL) - continue; - - ret = 0; - } else { - n = fstree_mknode(root, ent->d_name, - strlen(ent->d_name), extra, &sb); - if (n == NULL) { - perror("creating tree node"); - goto fail; - } - - ret = (cb == NULL) ? 0 : cb(user, fs, n); - } - - free(extra); - extra = NULL; - - if (ret < 0) - goto fail; - - if (ret > 0) { - discard_node(root, n); - continue; - } - - if (S_ISDIR(n->mode) && !(flags & DIR_SCAN_NO_RECURSION)) { - childfd = openat(dir_fd, n->name, O_DIRECTORY | - O_RDONLY | O_CLOEXEC); - if (childfd < 0) { - perror(n->name); - goto fail; - } - - if (populate_dir(childfd, fs, n, devstart, - cb, user, flags)) { - goto fail; - } - } - } - - closedir(dir); - return 0; -fail_rdlink: - perror("readlink"); -fail: - closedir(dir); - free(extra); - return -1; -} - -int fstree_from_subdir(fstree_t *fs, tree_node_t *root, - const char *path, const char *subdir, - scan_node_callback cb, void *user, - unsigned int flags) -{ - struct stat sb; - int fd, subfd; - - if (!S_ISDIR(root->mode)) { - fprintf(stderr, - "scanning %s/%s into %s: target is not a directory\n", - path, subdir == NULL ? "" : subdir, root->name); - return -1; - } - - fd = open(path, O_DIRECTORY | O_RDONLY | O_CLOEXEC); - if (fd < 0) { - perror(path); - return -1; - } - - if (subdir != NULL) { - subfd = openat(fd, subdir, O_DIRECTORY | O_RDONLY | O_CLOEXEC); - - if (subfd < 0) { - fprintf(stderr, "%s/%s: %s\n", path, subdir, - strerror(errno)); - close(fd); - return -1; - } - - close(fd); - fd = subfd; - } - - if (fstat(fd, &sb)) { - fprintf(stderr, "%s/%s: %s\n", path, - subdir == NULL ? "" : subdir, - strerror(errno)); - close(fd); - return -1; - } - - return populate_dir(fd, fs, root, sb.st_dev, cb, user, flags); -} - -int fstree_from_dir(fstree_t *fs, tree_node_t *root, - const char *path, scan_node_callback cb, - void *user, unsigned int flags) -{ - return fstree_from_subdir(fs, root, path, NULL, cb, user, flags); -} -#endif |