From 35fabedb49be3904a18af694a676efde813e3adc Mon Sep 17 00:00:00 2001 From: David Oberhollenzer Date: Wed, 30 Jan 2019 12:59:20 +0100 Subject: [PATCH] Move package unpacking functionality to generic pkg_unpack function Signed-off-by: David Oberhollenzer --- Makefile.am | 2 +- main/cmd/unpack/create_hierarchy.c | 27 ---- main/cmd/unpack/pkg_unpack.c | 190 +++++++++++++++++++++++++++++ main/cmd/unpack/unpack.c | 157 +----------------------- main/cmd/unpack/unpack.h | 4 +- 5 files changed, 195 insertions(+), 185 deletions(-) delete mode 100644 main/cmd/unpack/create_hierarchy.c create mode 100644 main/cmd/unpack/pkg_unpack.c diff --git a/Makefile.am b/Makefile.am index 8797601..46046f6 100644 --- a/Makefile.am +++ b/Makefile.am @@ -35,7 +35,7 @@ pkg_SOURCES += main/cmd/dump/dump_header.c # unpack command pkg_SOURCES += main/cmd/unpack/unpack.c main/cmd/unpack/unpack.h -pkg_SOURCES += main/cmd/unpack/create_hierarchy.c +pkg_SOURCES += main/cmd/unpack/pkg_unpack.c # help command pkg_SOURCES += main/cmd/help.c diff --git a/main/cmd/unpack/create_hierarchy.c b/main/cmd/unpack/create_hierarchy.c deleted file mode 100644 index 3649da2..0000000 --- a/main/cmd/unpack/create_hierarchy.c +++ /dev/null @@ -1,27 +0,0 @@ -#include "unpack.h" - -int create_hierarchy(int dirfd, image_entry_t *list) -{ - image_entry_t *ent; - - for (ent = list; ent != NULL; ent = ent->next) { - if (S_ISDIR(ent->mode)) { - if (mkdirat(dirfd, ent->name, 0755)) { - perror(ent->name); - return -1; - } - } - } - - for (ent = list; ent != NULL; ent = ent->next) { - if (S_ISLNK(ent->mode)) { - if (symlinkat(ent->data.symlink.target, - dirfd, ent->name)) { - perror(ent->name); - return -1; - } - } - } - - return 0; -} diff --git a/main/cmd/unpack/pkg_unpack.c b/main/cmd/unpack/pkg_unpack.c new file mode 100644 index 0000000..d72a0d5 --- /dev/null +++ b/main/cmd/unpack/pkg_unpack.c @@ -0,0 +1,190 @@ +#include "unpack.h" + +static int create_hierarchy(int dirfd, image_entry_t *list) +{ + image_entry_t *ent; + + for (ent = list; ent != NULL; ent = ent->next) { + if (S_ISDIR(ent->mode)) { + if (mkdirat(dirfd, ent->name, 0755)) { + perror(ent->name); + return -1; + } + } + } + + for (ent = list; ent != NULL; ent = ent->next) { + if (S_ISLNK(ent->mode)) { + if (symlinkat(ent->data.symlink.target, + dirfd, ent->name)) { + perror(ent->name); + return -1; + } + } + } + + return 0; +} + +static image_entry_t *get_file_entry(image_entry_t *list, uint32_t id) +{ + while (list != NULL) { + if (S_ISREG(list->mode) && list->data.file.id == id) + return list; + + list = list->next; + } + + return NULL; +} + +static int unpack_files(int dirfd, image_entry_t *list, pkg_reader_t *rd) +{ + uint8_t buffer[2048]; + image_entry_t *meta; + file_data_t frec; + ssize_t ret; + size_t diff; + uint64_t i; + int fd; + + for (;;) { + ret = pkg_reader_read_payload(rd, &frec, sizeof(frec)); + if (ret == 0) + break; + if (ret < 0) + return -1; + if ((size_t)ret < sizeof(frec)) + goto fail_trunc; + + frec.id = le32toh(frec.id); + + meta = get_file_entry(list, frec.id); + if (meta == NULL) { + fprintf(stderr, "%s: missing meta information for " + "file %u\n", pkg_reader_get_filename(rd), + (unsigned int)frec.id); + return -1; + } + + fd = openat(dirfd, meta->name, O_WRONLY | O_CREAT | O_EXCL, + 0644); + if (fd < 0) { + perror(meta->name); + return -1; + } + + for (i = 0; i < meta->data.file.size; i += ret) { + if ((meta->data.file.size - i) < + (uint64_t)sizeof(buffer)) { + diff = meta->data.file.size - i; + } else { + diff = sizeof(buffer); + } + + ret = pkg_reader_read_payload(rd, buffer, diff); + if (ret < 0) + goto fail_fd; + if ((size_t)ret < diff) + goto fail_trunc; + + ret = write_retry(fd, buffer, diff); + if (ret < 0) { + perror(meta->name); + goto fail_fd; + } + + if ((size_t)ret < diff) { + fprintf(stderr, "%s: truncated write\n", + pkg_reader_get_filename(rd)); + goto fail_fd; + } + } + + close(fd); + } + + return 0; +fail_fd: + close(fd); + return -1; +fail_trunc: + fprintf(stderr, "%s: truncated file data record\n", + pkg_reader_get_filename(rd)); + return -1; +} + +static int change_permissions(int dirfd, image_entry_t *list, int flags) +{ + while (list != NULL) { + if (S_ISLNK(list->mode)) { + list = list->next; + continue; + } + + if (!(flags & FLAG_NO_CHMOD) && !S_ISLNK(list->mode)) { + if (fchmodat(dirfd, list->name, + list->mode & 07777, 0)) { + fprintf(stderr, "%s: chmod: %s\n", list->name, + strerror(errno)); + return -1; + } + } + + if (!(flags & FLAG_NO_CHOWN)) { + if (fchownat(dirfd, list->name, list->uid, list->gid, + AT_SYMLINK_NOFOLLOW)) { + fprintf(stderr, "%s: chown: %s\n", list->name, + strerror(errno)); + return -1; + } + } + + list = list->next; + } + + return 0; +} + +int pkg_unpack(int rootfd, int flags, pkg_reader_t *rd) +{ + image_entry_t *list = NULL; + record_t *hdr; + int ret; + + list = image_entry_list_from_package(rd); + if (list == NULL) + return -1; + + list = image_entry_sort(list); + + if (pkg_reader_rewind(rd)) + goto fail; + + if (create_hierarchy(rootfd, list)) + goto fail; + + for (;;) { + ret = pkg_reader_get_next_record(rd); + if (ret == 0) + break; + if (ret < 0) + goto fail; + + hdr = pkg_reader_current_record_header(rd); + + if (hdr->magic == PKG_MAGIC_DATA) { + if (unpack_files(rootfd, list, rd)) + goto fail; + } + } + + if (change_permissions(rootfd, list, flags)) + goto fail; + + image_entry_free_list(list); + return 0; +fail: + image_entry_free_list(list); + return -1; +} diff --git a/main/cmd/unpack/unpack.c b/main/cmd/unpack/unpack.c index 539931c..bdcb087 100644 --- a/main/cmd/unpack/unpack.c +++ b/main/cmd/unpack/unpack.c @@ -10,133 +10,11 @@ static const struct option long_opts[] = { static const char *short_opts = "r:om"; -static image_entry_t *get_file_entry(image_entry_t *list, uint32_t id) -{ - while (list != NULL) { - if (S_ISREG(list->mode) && list->data.file.id == id) - return list; - - list = list->next; - } - - return NULL; -} - -static int unpack_files(int dirfd, image_entry_t *list, pkg_reader_t *rd) -{ - uint8_t buffer[2048]; - image_entry_t *meta; - file_data_t frec; - ssize_t ret; - size_t diff; - uint64_t i; - int fd; - - for (;;) { - ret = pkg_reader_read_payload(rd, &frec, sizeof(frec)); - if (ret == 0) - break; - if (ret < 0) - return -1; - if ((size_t)ret < sizeof(frec)) - goto fail_trunc; - - frec.id = le32toh(frec.id); - - meta = get_file_entry(list, frec.id); - if (meta == NULL) { - fprintf(stderr, "%s: missing meta information for " - "file %u\n", pkg_reader_get_filename(rd), - (unsigned int)frec.id); - return -1; - } - - fd = openat(dirfd, meta->name, O_WRONLY | O_CREAT | O_EXCL, - 0644); - if (fd < 0) { - perror(meta->name); - return -1; - } - - for (i = 0; i < meta->data.file.size; i += ret) { - if ((meta->data.file.size - i) < - (uint64_t)sizeof(buffer)) { - diff = meta->data.file.size - i; - } else { - diff = sizeof(buffer); - } - - ret = pkg_reader_read_payload(rd, buffer, diff); - if (ret < 0) - goto fail_fd; - if ((size_t)ret < diff) - goto fail_trunc; - - ret = write_retry(fd, buffer, diff); - if (ret < 0) { - perror(meta->name); - goto fail_fd; - } - - if ((size_t)ret < diff) { - fprintf(stderr, "%s: truncated write\n", - pkg_reader_get_filename(rd)); - goto fail_fd; - } - } - - close(fd); - } - - return 0; -fail_fd: - close(fd); - return -1; -fail_trunc: - fprintf(stderr, "%s: truncated file data record\n", - pkg_reader_get_filename(rd)); - return -1; -} - -static int change_permissions(int dirfd, image_entry_t *list, int flags) -{ - while (list != NULL) { - if (S_ISLNK(list->mode)) { - list = list->next; - continue; - } - - if (!(flags & FLAG_NO_CHMOD) && !S_ISLNK(list->mode)) { - if (fchmodat(dirfd, list->name, - list->mode & 07777, 0)) { - fprintf(stderr, "%s: chmod: %s\n", list->name, - strerror(errno)); - return -1; - } - } - - if (!(flags & FLAG_NO_CHOWN)) { - if (fchownat(dirfd, list->name, list->uid, list->gid, - AT_SYMLINK_NOFOLLOW)) { - fprintf(stderr, "%s: chown: %s\n", list->name, - strerror(errno)); - return -1; - } - } - - list = list->next; - } - - return 0; -} - static int cmd_unpack(int argc, char **argv) { const char *root = NULL, *filename; - int i, rootfd, ret, flags = 0; - image_entry_t *list = NULL; + int i, rootfd, flags = 0; pkg_reader_t *rd; - record_t *hdr; for (;;) { i = getopt_long(argc, argv, short_opts, long_opts, NULL); @@ -186,45 +64,14 @@ static int cmd_unpack(int argc, char **argv) if (rd == NULL) goto fail_rootfd; - list = image_entry_list_from_package(rd); - if (list == NULL) { - pkg_reader_close(rd); - goto fail_rootfd; - } - - list = image_entry_sort(list); - - if (pkg_reader_rewind(rd)) + if (pkg_unpack(rootfd, flags, rd)) goto fail; - if (create_hierarchy(rootfd, list)) - goto fail; - - for (;;) { - ret = pkg_reader_get_next_record(rd); - if (ret == 0) - break; - if (ret < 0) - goto fail; - - hdr = pkg_reader_current_record_header(rd); - - if (hdr->magic == PKG_MAGIC_DATA) { - if (unpack_files(rootfd, list, rd)) - goto fail; - } - } - - if (change_permissions(rootfd, list, flags)) - goto fail; - - image_entry_free_list(list); pkg_reader_close(rd); if (rootfd != AT_FDCWD) close(rootfd); return EXIT_SUCCESS; fail: - image_entry_free_list(list); pkg_reader_close(rd); fail_rootfd: if (rootfd != AT_FDCWD) diff --git a/main/cmd/unpack/unpack.h b/main/cmd/unpack/unpack.h index 586a6a8..74b5bbe 100644 --- a/main/cmd/unpack/unpack.h +++ b/main/cmd/unpack/unpack.h @@ -22,8 +22,8 @@ enum { FLAG_NO_CHMOD = 0x02, }; -int create_hierarchy(int dirfd, image_entry_t *list); - int mkdir_p(const char *path); +int pkg_unpack(int rootfd, int flags, pkg_reader_t *rd); + #endif /* UNPACK_H */