From f138e4a24919682cf477cf93ae47b9a89bb5a3f0 Mon Sep 17 00:00:00 2001 From: David Oberhollenzer Date: Thu, 10 Dec 2020 16:00:44 +0100 Subject: Move fstree dirscan code back to libfstree Signed-off-by: David Oberhollenzer --- bin/gensquashfs/Makemodule.am | 2 +- bin/gensquashfs/dirscan.c | 129 -------------------------------------- bin/gensquashfs/dirscan_xattr.c | 12 ++-- bin/gensquashfs/mkfs.c | 2 +- bin/gensquashfs/mkfs.h | 15 +---- bin/gensquashfs/options.c | 2 +- include/fstree.h | 13 ++++ lib/fstree/Makemodule.am | 2 +- lib/fstree/fstree_from_dir.c | 135 ++++++++++++++++++++++++++++++++++++++++ 9 files changed, 161 insertions(+), 151 deletions(-) delete mode 100644 bin/gensquashfs/dirscan.c create mode 100644 lib/fstree/fstree_from_dir.c diff --git a/bin/gensquashfs/Makemodule.am b/bin/gensquashfs/Makemodule.am index e030009..11a3535 100644 --- a/bin/gensquashfs/Makemodule.am +++ b/bin/gensquashfs/Makemodule.am @@ -1,6 +1,6 @@ gensquashfs_SOURCES = bin/gensquashfs/mkfs.c bin/gensquashfs/mkfs.h gensquashfs_SOURCES += bin/gensquashfs/options.c bin/gensquashfs/selinux.c -gensquashfs_SOURCES += bin/gensquashfs/dirscan.c bin/gensquashfs/dirscan_xattr.c +gensquashfs_SOURCES += bin/gensquashfs/dirscan_xattr.c gensquashfs_LDADD = libcommon.a libsquashfs.la libfstree.a libfstream.a gensquashfs_LDADD += libcompat.a $(LZO_LIBS) $(PTHREAD_LIBS) gensquashfs_CPPFLAGS = $(AM_CPPFLAGS) diff --git a/bin/gensquashfs/dirscan.c b/bin/gensquashfs/dirscan.c deleted file mode 100644 index bb6d2c3..0000000 --- a/bin/gensquashfs/dirscan.c +++ /dev/null @@ -1,129 +0,0 @@ -/* SPDX-License-Identifier: GPL-3.0-or-later */ -/* - * dirscan.c - * - * Copyright (C) 2019 David Oberhollenzer - */ -#include "mkfs.h" - -#ifdef _WIN32 -int fstree_from_dir(fstree_t *fs, const char *path, unsigned int flags) -{ - (void)fs; (void)path; (void)flags; - fputs("Packing a directory is not supported on Windows.\n", stderr); - return -1; -} -#else -static int populate_dir(int dir_fd, fstree_t *fs, tree_node_t *root, - dev_t devstart, unsigned int flags) -{ - char *extra = NULL; - struct dirent *ent; - struct stat sb; - tree_node_t *n; - int childfd; - 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; - } - - if ((flags & DIR_SCAN_ONE_FILESYSTEM) && sb.st_dev != devstart) - continue; - - if (S_ISLNK(sb.st_mode)) { - extra = calloc(1, sb.st_size + 1); - if (extra == NULL) - goto fail_rdlink; - - if (readlinkat(dir_fd, ent->d_name, - extra, 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; - - n = fstree_mknode(root, ent->d_name, strlen(ent->d_name), - extra, &sb); - if (n == NULL) { - perror("creating tree node"); - goto fail; - } - - free(extra); - extra = NULL; - - if (S_ISDIR(n->mode)) { - 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, flags)) - goto fail; - } - } - - closedir(dir); - return 0; -fail_rdlink: - perror("readlink"); -fail: - closedir(dir); - free(extra); - return -1; -} - -int fstree_from_dir(fstree_t *fs, const char *path, unsigned int flags) -{ - struct stat sb; - int fd; - - fd = open(path, O_DIRECTORY | O_RDONLY | O_CLOEXEC); - if (fd < 0) { - perror(path); - return -1; - } - - if (fstat(fd, &sb)) { - perror(path); - close(fd); - return -1; - } - - return populate_dir(fd, fs, fs->root, sb.st_dev, flags); -} -#endif diff --git a/bin/gensquashfs/dirscan_xattr.c b/bin/gensquashfs/dirscan_xattr.c index 5ed3c9c..65f7f5c 100644 --- a/bin/gensquashfs/dirscan_xattr.c +++ b/bin/gensquashfs/dirscan_xattr.c @@ -122,7 +122,7 @@ fail: #endif static int xattr_xcan_dfs(const char *path_prefix, void *selinux_handle, - sqfs_xattr_writer_t *xwr, unsigned int flags, + sqfs_xattr_writer_t *xwr, bool scan_xattr, tree_node_t *node) { char *path; @@ -136,7 +136,7 @@ static int xattr_xcan_dfs(const char *path_prefix, void *selinux_handle, } #ifdef HAVE_SYS_XATTR_H - if (flags & DIR_SCAN_READ_XATTR) { + if (scan_xattr) { path = get_full_path(path_prefix, node); if (path == NULL) return -1; @@ -176,7 +176,7 @@ static int xattr_xcan_dfs(const char *path_prefix, void *selinux_handle, while (node != NULL) { if (xattr_xcan_dfs(path_prefix, selinux_handle, xwr, - flags, node)) { + scan_xattr, node)) { return -1; } @@ -188,13 +188,13 @@ static int xattr_xcan_dfs(const char *path_prefix, void *selinux_handle, } int xattrs_from_dir(fstree_t *fs, const char *path, void *selinux_handle, - sqfs_xattr_writer_t *xwr, unsigned int flags) + sqfs_xattr_writer_t *xwr, bool scan_xattr) { if (xwr == NULL) return 0; - if (selinux_handle == NULL && !(flags & DIR_SCAN_READ_XATTR)) + if (selinux_handle == NULL && !scan_xattr) return 0; - return xattr_xcan_dfs(path, selinux_handle, xwr, flags, fs->root); + return xattr_xcan_dfs(path, selinux_handle, xwr, scan_xattr, fs->root); } diff --git a/bin/gensquashfs/mkfs.c b/bin/gensquashfs/mkfs.c index ce23e6f..6f26d56 100644 --- a/bin/gensquashfs/mkfs.c +++ b/bin/gensquashfs/mkfs.c @@ -206,7 +206,7 @@ int main(int argc, char **argv) if (opt.infile == NULL) { if (xattrs_from_dir(&sqfs.fs, opt.packdir, sehnd, - sqfs.xwr, opt.dirscan_flags)) { + sqfs.xwr, opt.scan_xattr)) { goto out; } } diff --git a/bin/gensquashfs/mkfs.h b/bin/gensquashfs/mkfs.h index 6aa0c87..e1e4e1b 100644 --- a/bin/gensquashfs/mkfs.h +++ b/bin/gensquashfs/mkfs.h @@ -34,7 +34,6 @@ #include #include #include -#include #include #include #include @@ -51,22 +50,14 @@ typedef struct { unsigned int force_gid_value; bool force_uid; bool force_gid; -} options_t; - -enum { - DIR_SCAN_KEEP_TIME = 0x01, - - DIR_SCAN_ONE_FILESYSTEM = 0x02, - DIR_SCAN_READ_XATTR = 0x04, -}; + bool scan_xattr; +} options_t; void process_command_line(options_t *opt, int argc, char **argv); -int fstree_from_dir(fstree_t *fs, const char *path, unsigned int flags); - int xattrs_from_dir(fstree_t *fs, const char *path, void *selinux_handle, - sqfs_xattr_writer_t *xwr, unsigned int flags); + sqfs_xattr_writer_t *xwr, bool scan_xattr); void *selinux_open_context_file(const char *filename); diff --git a/bin/gensquashfs/options.c b/bin/gensquashfs/options.c index b432a46..9153265 100644 --- a/bin/gensquashfs/options.c +++ b/bin/gensquashfs/options.c @@ -245,7 +245,7 @@ void process_command_line(options_t *opt, int argc, char **argv) break; #ifdef HAVE_SYS_XATTR_H case 'x': - opt->dirscan_flags |= DIR_SCAN_READ_XATTR; + opt->scan_xattr = true; break; #endif case 'o': diff --git a/include/fstree.h b/include/fstree.h index 884ff51..ac92daa 100644 --- a/include/fstree.h +++ b/include/fstree.h @@ -17,6 +17,12 @@ #include "sqfs/predef.h" #include "compat.h" +enum { + DIR_SCAN_KEEP_TIME = 0x01, + + DIR_SCAN_ONE_FILESYSTEM = 0x02, +}; + #define FSTREE_MODE_HARD_LINK (0) #define FSTREE_MODE_HARD_LINK_RESOLVED (1) @@ -230,4 +236,11 @@ tree_node_t *fstree_add_hard_link(fstree_t *fs, const char *path, */ int fstree_resolve_hard_link(fstree_t *fs, tree_node_t *node); +/* + Recursively scan a directory to build a file system tree. + + Returns 0 on success, prints to stderr on failure. + */ +int fstree_from_dir(fstree_t *fs, const char *path, unsigned int flags); + #endif /* FSTREE_H */ diff --git a/lib/fstree/Makemodule.am b/lib/fstree/Makemodule.am index 56394a6..97a2e6b 100644 --- a/lib/fstree/Makemodule.am +++ b/lib/fstree/Makemodule.am @@ -1,7 +1,7 @@ libfstree_a_SOURCES = lib/fstree/fstree.c lib/fstree/fstree_from_file.c libfstree_a_SOURCES += lib/fstree/fstree_sort.c lib/fstree/hardlink.c libfstree_a_SOURCES += lib/fstree/post_process.c lib/fstree/get_path.c -libfstree_a_SOURCES += lib/fstree/mknode.c +libfstree_a_SOURCES += lib/fstree/mknode.c lib/fstree/fstree_from_dir.c libfstree_a_SOURCES += lib/fstree/add_by_path.c lib/fstree/get_by_path.c libfstree_a_SOURCES += include/fstree.h lib/fstree/internal.h libfstree_a_SOURCES += lib/fstree/source_date_epoch.c diff --git a/lib/fstree/fstree_from_dir.c b/lib/fstree/fstree_from_dir.c new file mode 100644 index 0000000..e61b706 --- /dev/null +++ b/lib/fstree/fstree_from_dir.c @@ -0,0 +1,135 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later */ +/* + * fstree_from_dir.c + * + * Copyright (C) 2019 David Oberhollenzer + */ +#include "config.h" +#include "fstree.h" + +#include +#include +#include +#include + +#ifdef _WIN32 +int fstree_from_dir(fstree_t *fs, const char *path, unsigned int flags) +{ + (void)fs; (void)path; (void)flags; + fputs("Packing a directory is not supported on Windows.\n", stderr); + return -1; +} +#else +static int populate_dir(int dir_fd, fstree_t *fs, tree_node_t *root, + dev_t devstart, unsigned int flags) +{ + char *extra = NULL; + struct dirent *ent; + struct stat sb; + tree_node_t *n; + int childfd; + 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; + } + + if ((flags & DIR_SCAN_ONE_FILESYSTEM) && sb.st_dev != devstart) + continue; + + if (S_ISLNK(sb.st_mode)) { + extra = calloc(1, sb.st_size + 1); + if (extra == NULL) + goto fail_rdlink; + + if (readlinkat(dir_fd, ent->d_name, + extra, 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; + + n = fstree_mknode(root, ent->d_name, strlen(ent->d_name), + extra, &sb); + if (n == NULL) { + perror("creating tree node"); + goto fail; + } + + free(extra); + extra = NULL; + + if (S_ISDIR(n->mode)) { + 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, flags)) + goto fail; + } + } + + closedir(dir); + return 0; +fail_rdlink: + perror("readlink"); +fail: + closedir(dir); + free(extra); + return -1; +} + +int fstree_from_dir(fstree_t *fs, const char *path, unsigned int flags) +{ + struct stat sb; + int fd; + + fd = open(path, O_DIRECTORY | O_RDONLY | O_CLOEXEC); + if (fd < 0) { + perror(path); + return -1; + } + + if (fstat(fd, &sb)) { + perror(path); + close(fd); + return -1; + } + + return populate_dir(fd, fs, fs->root, sb.st_dev, flags); +} +#endif -- cgit v1.2.3