summaryrefslogtreecommitdiff
path: root/mkfs
diff options
context:
space:
mode:
Diffstat (limited to 'mkfs')
-rw-r--r--mkfs/Makemodule.am1
-rw-r--r--mkfs/dirscan.c228
-rw-r--r--mkfs/mkfs.h15
3 files changed, 244 insertions, 0 deletions
diff --git a/mkfs/Makemodule.am b/mkfs/Makemodule.am
index 1955852..f1e0d0d 100644
--- a/mkfs/Makemodule.am
+++ b/mkfs/Makemodule.am
@@ -1,4 +1,5 @@
gensquashfs_SOURCES = mkfs/mkfs.c mkfs/mkfs.h mkfs/options.c
+gensquashfs_SOURCES += mkfs/dirscan.c
gensquashfs_LDADD = libsqfshelper.a libsquashfs.la libfstree.a libutil.la
gensquashfs_LDADD += $(LIBSELINUX_LIBS)
gensquashfs_CPPFLAGS = $(AM_CPPFLAGS)
diff --git a/mkfs/dirscan.c b/mkfs/dirscan.c
new file mode 100644
index 0000000..5cb955a
--- /dev/null
+++ b/mkfs/dirscan.c
@@ -0,0 +1,228 @@
+/* SPDX-License-Identifier: GPL-3.0-or-later */
+/*
+ * fstree_from_dir.c
+ *
+ * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at>
+ */
+#include "mkfs.h"
+
+static char *get_file_path(tree_node_t *n, const char *name)
+{
+ char *ptr, *new;
+ int ret;
+
+ if (n->parent == NULL) {
+ ptr = strdup(name);
+ if (ptr == NULL)
+ goto fail;
+ return ptr;
+ }
+
+ ptr = fstree_get_path(n);
+ if (ptr == NULL)
+ goto fail;
+
+ ret = canonicalize_name(ptr);
+ assert(ret == 0);
+
+ new = realloc(ptr, strlen(ptr) + strlen(name) + 2);
+ if (new == NULL)
+ goto fail;
+
+ ptr = new;
+ strcat(ptr, "/");
+ strcat(ptr, name);
+ return ptr;
+fail:
+ perror("getting absolute file path");
+ free(ptr);
+ return NULL;
+}
+
+#ifdef HAVE_SYS_XATTR_H
+static int populate_xattr(fstree_t *fs, tree_node_t *node)
+{
+ char *key, *value = NULL, *buffer = NULL;
+ ssize_t buflen, vallen, keylen;
+
+ buflen = listxattr(node->name, NULL, 0);
+
+ if (buflen < 0) {
+ perror("listxattr");
+ return -1;
+ }
+
+ if (buflen == 0)
+ return 0;
+
+ buffer = malloc(buflen);
+ if (buffer == NULL) {
+ perror("xattr name buffer");
+ return -1;
+ }
+
+ buflen = listxattr(node->name, buffer, buflen);
+ if (buflen == -1) {
+ perror("listxattr");
+ goto fail;
+ }
+
+ key = buffer;
+ while (buflen > 0) {
+ vallen = getxattr(node->name, key, NULL, 0);
+ if (vallen == -1)
+ goto fail;
+
+ if (vallen > 0) {
+ value = alloc_string(vallen);
+ if (value == NULL) {
+ perror("xattr value buffer");
+ goto fail;
+ }
+
+ vallen = getxattr(node->name, key, value, vallen);
+ if (vallen == -1) {
+ perror("getxattr");
+ goto fail;
+ }
+
+ value[vallen] = 0;
+ if (fstree_add_xattr(fs, node, key, value))
+ goto fail;
+
+ free(value);
+ value = NULL;
+ }
+
+ keylen = strlen(key) + 1;
+ buflen -= keylen;
+ key += keylen;
+ }
+
+ free(buffer);
+ return 0;
+fail:
+ free(value);
+ free(buffer);
+ return -1;
+}
+#endif
+
+static int populate_dir(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;
+ DIR *dir;
+
+ dir = opendir(".");
+ if (dir == NULL) {
+ perror("opendir");
+ return -1;
+ }
+
+ 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(AT_FDCWD, 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 = alloc_string(sb.st_size);
+ if (extra == NULL)
+ goto fail_rdlink;
+
+ if (readlink(ent->d_name, extra, sb.st_size) < 0)
+ goto fail_rdlink;
+
+ extra[sb.st_size] = '\0';
+ } else if (S_ISREG(sb.st_mode)) {
+ extra = get_file_path(root, ent->d_name);
+ if (extra == NULL)
+ goto fail;
+ }
+
+ if (!(flags & DIR_SCAN_KEEP_TIME))
+ sb.st_mtim = fs->defaults.st_mtim;
+
+ n = fstree_mknode(root, ent->d_name, strlen(ent->d_name),
+ extra, &sb);
+ if (n == NULL) {
+ perror("creating tree node");
+ goto fail;
+ }
+
+#ifdef HAVE_SYS_XATTR_H
+ if (flags & DIR_SCAN_READ_XATTR) {
+ if (populate_xattr(fs, n))
+ goto fail;
+ }
+#endif
+
+ free(extra);
+ extra = NULL;
+ }
+
+ closedir(dir);
+
+ for (n = root->data.dir.children; n != NULL; n = n->next) {
+ if (S_ISDIR(n->mode)) {
+ if (pushd(n->name))
+ return -1;
+
+ if (populate_dir(fs, n, devstart, flags))
+ return -1;
+
+ if (popd())
+ return -1;
+ }
+ }
+
+ 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 ret;
+
+ if (stat(path, &sb)) {
+ perror(path);
+ return -1;
+ }
+
+ if (pushd(path))
+ return -1;
+
+ ret = populate_dir(fs, fs->root, sb.st_dev, flags);
+
+ if (popd())
+ ret = -1;
+
+ return ret;
+}
diff --git a/mkfs/mkfs.h b/mkfs/mkfs.h
index 0e374dc..bce98d8 100644
--- a/mkfs/mkfs.h
+++ b/mkfs/mkfs.h
@@ -19,12 +19,17 @@
#include "fstree.h"
#include "util.h"
+#ifdef HAVE_SYS_XATTR_H
+#include <sys/xattr.h>
+#endif
+
#include <getopt.h>
#include <assert.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
+#include <dirent.h>
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
@@ -48,6 +53,16 @@ typedef struct {
char *comp_extra;
} options_t;
+enum {
+ DIR_SCAN_KEEP_TIME = 0x01,
+
+ DIR_SCAN_ONE_FILESYSTEM = 0x02,
+
+ DIR_SCAN_READ_XATTR = 0x04,
+};
+
void process_command_line(options_t *opt, int argc, char **argv);
+int fstree_from_dir(fstree_t *fs, const char *path, unsigned int flags);
+
#endif /* MKFS_H */