diff options
Diffstat (limited to 'unpack/restore_fstree.c')
-rw-r--r-- | unpack/restore_fstree.c | 171 |
1 files changed, 89 insertions, 82 deletions
diff --git a/unpack/restore_fstree.c b/unpack/restore_fstree.c index 5a20c5f..270b25a 100644 --- a/unpack/restore_fstree.c +++ b/unpack/restore_fstree.c @@ -1,103 +1,99 @@ /* SPDX-License-Identifier: GPL-3.0-or-later */ #include "rdsquashfs.h" -static int restore_directory(int dirfd, tree_node_t *n, compressor_t *cmp, - size_t block_size, frag_reader_t *frag, - int sqfsfd, int flags) +static int create_node(int dirfd, tree_node_t *n, compressor_t *cmp, + size_t block_size, frag_reader_t *frag, + int sqfsfd, int flags) { int fd; - for (n = n->data.dir->children; n != NULL; n = n->next) { - switch (n->mode & S_IFMT) { - case S_IFDIR: - if (mkdirat(dirfd, n->name, 0755) && - errno != EEXIST) { - fprintf(stderr, "mkdir %s: %s\n", - n->name, strerror(errno)); - return -1; - } + switch (n->mode & S_IFMT) { + case S_IFDIR: + if (mkdirat(dirfd, n->name, 0755) && errno != EEXIST) { + fprintf(stderr, "mkdir %s: %s\n", + n->name, strerror(errno)); + return -1; + } - fd = openat(dirfd, n->name, O_RDONLY | O_DIRECTORY); - if (fd < 0) { - fprintf(stderr, "open dir %s: %s\n", - n->name, strerror(errno)); - return -1; - } + fd = openat(dirfd, n->name, O_RDONLY | O_DIRECTORY); + if (fd < 0) { + fprintf(stderr, "open dir %s: %s\n", + n->name, strerror(errno)); + return -1; + } - if (restore_directory(fd, n, cmp, block_size, - frag, sqfsfd, flags)) { + for (n = n->data.dir->children; n != NULL; n = n->next) { + if (create_node(fd, n, cmp, block_size, frag, sqfsfd, + flags)) { close(fd); return -1; } + } - close(fd); - break; - case S_IFLNK: - if (symlinkat(n->data.slink_target, dirfd, n->name)) { - fprintf(stderr, "ln -s %s %s: %s\n", - n->data.slink_target, n->name, - strerror(errno)); - return -1; - } - break; - case S_IFSOCK: - case S_IFIFO: - if (mknodat(dirfd, n->name, - (n->mode & S_IFMT) | 0700, 0)) { - fprintf(stderr, "creating %s: %s\n", - n->name, strerror(errno)); - return -1; - } - break; - case S_IFBLK: - case S_IFCHR: - if (mknodat(dirfd, n->name, (n->mode & S_IFMT), - n->data.devno)) { - fprintf(stderr, "creating device %s: %s\n", - n->name, strerror(errno)); - return -1; - } - break; - case S_IFREG: - fd = openat(dirfd, n->name, - O_WRONLY | O_CREAT | O_EXCL, 0600); - if (fd < 0) { - fprintf(stderr, "creating %s: %s\n", - n->name, strerror(errno)); - return -1; - } - - if (extract_file(n->data.file, cmp, block_size, - frag, sqfsfd, fd)) { - close(fd); - return -1; - } + close(fd); + break; + case S_IFLNK: + if (symlinkat(n->data.slink_target, dirfd, n->name)) { + fprintf(stderr, "ln -s %s %s: %s\n", + n->data.slink_target, n->name, + strerror(errno)); + return -1; + } + break; + case S_IFSOCK: + case S_IFIFO: + if (mknodat(dirfd, n->name, (n->mode & S_IFMT) | 0700, 0)) { + fprintf(stderr, "creating %s: %s\n", + n->name, strerror(errno)); + return -1; + } + break; + case S_IFBLK: + case S_IFCHR: + if (mknodat(dirfd, n->name, (n->mode & S_IFMT), + n->data.devno)) { + fprintf(stderr, "creating device %s: %s\n", + n->name, strerror(errno)); + return -1; + } + break; + case S_IFREG: + fd = openat(dirfd, n->name, O_WRONLY | O_CREAT | O_EXCL, 0600); + if (fd < 0) { + fprintf(stderr, "creating %s: %s\n", + n->name, strerror(errno)); + return -1; + } + if (extract_file(n->data.file, cmp, block_size, + frag, sqfsfd, fd)) { close(fd); - break; - default: - break; + return -1; } - if (flags & UNPACK_CHOWN) { - if (fchownat(dirfd, n->name, n->uid, n->gid, - AT_SYMLINK_NOFOLLOW)) { - fprintf(stderr, "chown %s: %s\n", - n->name, strerror(errno)); - return -1; - } - } + close(fd); + break; + default: + break; + } - if (flags & UNPACK_CHMOD) { - if (fchmodat(dirfd, n->name, n->mode, - AT_SYMLINK_NOFOLLOW)) { - fprintf(stderr, "chmod %s: %s\n", - n->name, strerror(errno)); - return -1; - } + if (flags & UNPACK_CHOWN) { + if (fchownat(dirfd, n->name, n->uid, n->gid, + AT_SYMLINK_NOFOLLOW)) { + fprintf(stderr, "chown %s: %s\n", + n->name, strerror(errno)); + return -1; } } + if (flags & UNPACK_CHMOD) { + if (fchmodat(dirfd, n->name, n->mode, + AT_SYMLINK_NOFOLLOW)) { + fprintf(stderr, "chmod %s: %s\n", + n->name, strerror(errno)); + return -1; + } + } return 0; } @@ -105,6 +101,7 @@ int restore_fstree(const char *rootdir, tree_node_t *root, compressor_t *cmp, size_t block_size, frag_reader_t *frag, int sqfsfd, int flags) { + tree_node_t *n; int dirfd; if (mkdir_p(rootdir)) @@ -116,8 +113,18 @@ int restore_fstree(const char *rootdir, tree_node_t *root, compressor_t *cmp, return -1; } - if (restore_directory(dirfd, root, cmp, block_size, frag, - sqfsfd, flags)) { + if (S_ISDIR(root->mode)) { + for (n = root->data.dir->children; n != NULL; n = n->next) { + if (create_node(dirfd, n, cmp, block_size, frag, + sqfsfd, flags)) { + close(dirfd); + return -1; + } + } + return 0; + } + + if (create_node(dirfd, root, cmp, block_size, frag, sqfsfd, flags)) { close(dirfd); return -1; } |