From 3afffc2a59cfc3888a84b2b2305b5312393ff4e8 Mon Sep 17 00:00:00 2001 From: David Oberhollenzer Date: Wed, 6 Nov 2019 10:44:26 +0100 Subject: Remove raw file descriptors from unpack write paths Instead, use stdio FILE pointers. On POSIX systems, use fileno to get the file descriptor and hopefully create sparase files. Signed-off-by: David Oberhollenzer --- difftool/extract.c | 13 +++++----- include/common.h | 2 +- include/tar.h | 7 +++--- lib/common/data_reader_dump.c | 57 +++++++++++++++++++++---------------------- lib/tar/padd_file.c | 4 +-- lib/tar/write_header.c | 30 +++++++++++------------ lib/tar/write_retry.c | 15 ++++++------ tar/sqfs2tar.c | 8 +++--- unpack/fill_files.c | 13 +++++----- unpack/rdsquashfs.c | 3 +-- 10 files changed, 76 insertions(+), 76 deletions(-) diff --git a/difftool/extract.c b/difftool/extract.c index df00977..979572a 100644 --- a/difftool/extract.c +++ b/difftool/extract.c @@ -10,7 +10,7 @@ static int extract(sqfs_data_reader_t *data, const sqfs_inode_generic_t *inode, const char *prefix, const char *path, size_t block_size) { char *ptr, *temp; - int fd; + FILE *fp; temp = alloca(strlen(prefix) + strlen(path) + 2); sprintf(temp, "%s/%s", prefix, path); @@ -21,18 +21,19 @@ static int extract(sqfs_data_reader_t *data, const sqfs_inode_generic_t *inode, return -1; *ptr = '/'; - fd = open(temp, O_CREAT | O_EXCL | O_WRONLY, 0600); - if (fd < 0) { + fp = fopen(temp, "wb"); + if (fp == NULL) { perror(temp); return -1; } - if (sqfs_data_reader_dump(path, data, inode, fd, block_size, true)) { - close(fd); + if (sqfs_data_reader_dump(path, data, inode, fp, block_size, true)) { + fclose(fp); return -1; } - close(fd); + fflush(fp); + fclose(fp); return 0; } diff --git a/include/common.h b/include/common.h index ba42054..da9093f 100644 --- a/include/common.h +++ b/include/common.h @@ -118,7 +118,7 @@ char *sqfs_tree_node_get_path(const sqfs_tree_node_t *node); int sqfs_data_reader_dump(const char *name, sqfs_data_reader_t *data, const sqfs_inode_generic_t *inode, - int outfd, size_t block_size, bool allow_sparse); + FILE *fp, size_t block_size, bool allow_sparse); sqfs_file_t *sqfs_get_stdin_file(const sparse_map_t *map, sqfs_u64 size); diff --git a/include/tar.h b/include/tar.h index c5d48ef..8f9f55c 100644 --- a/include/tar.h +++ b/include/tar.h @@ -12,6 +12,7 @@ #include #include +#include typedef struct sparse_map_t { struct sparse_map_t *next; @@ -118,7 +119,7 @@ typedef struct { The counter is an incremental record counter used if additional headers need to be generated. */ -int write_tar_header(int fd, const struct stat *sb, const char *name, +int write_tar_header(FILE *fp, const struct stat *sb, const char *name, const char *slink_target, const tar_xattr_t *xattr, unsigned int counter); @@ -136,7 +137,7 @@ void clear_header(tar_header_decoded_t *hdr); Write zero bytes to an output file to padd it to the tar record size. Returns 0 on success. On failure, prints error message to stderr. */ -int padd_file(int outfd, sqfs_u64 size); +int padd_file(FILE *fp, sqfs_u64 size); /* @@ -153,6 +154,6 @@ int read_retry(const char *errstr, int fd, void *buffer, size_t size); on success. Writes to stderr on failure using 'errstr' as a perror style error prefix. */ -int write_retry(const char *errstr, int fd, const void *data, size_t size); +int write_retry(const char *errstr, FILE *fp, const void *data, size_t size); #endif /* TAR_H */ diff --git a/lib/common/data_reader_dump.c b/lib/common/data_reader_dump.c index 4053f73..4065677 100644 --- a/lib/common/data_reader_dump.c +++ b/lib/common/data_reader_dump.c @@ -12,26 +12,23 @@ #include #include -static int append_block(int fd, const sqfs_block_t *blk) +static int append_block(FILE *fp, const sqfs_block_t *blk) { const unsigned char *ptr = blk->data; - size_t size = blk->size; - ssize_t ret; + size_t ret, size = blk->size; while (size > 0) { - ret = write(fd, ptr, size); - - if (ret < 0) { - if (errno == EINTR) - continue; - perror("writing data block"); + if (ferror(fp)) { + fputs("writing data block: error writing to file\n", + stderr); } - if (ret == 0) { + if (feof(fp)) { fputs("writing data block: unexpected end of file\n", stderr); } + ret = fwrite(ptr, 1, size, fp); ptr += ret; size -= ret; } @@ -41,7 +38,7 @@ static int append_block(int fd, const sqfs_block_t *blk) int sqfs_data_reader_dump(const char *name, sqfs_data_reader_t *data, const sqfs_inode_generic_t *inode, - int outfd, size_t block_size, bool allow_sparse) + FILE *fp, size_t block_size, bool allow_sparse) { sqfs_block_t *blk; sqfs_u64 filesz; @@ -50,21 +47,23 @@ int sqfs_data_reader_dump(const char *name, sqfs_data_reader_t *data, sqfs_inode_get_file_size(inode, &filesz); - if (allow_sparse && ftruncate(outfd, filesz)) - goto fail_sparse; +#if defined(_POSIX_VERSION) && (_POSIX_VERSION >= 200112L) + if (allow_sparse) { + int fd = fileno(fp); + + if (ftruncate(fd, filesz)) + goto fail_sparse; + } +#else + allow_sparse = false; +#endif for (i = 0; i < inode->num_file_blocks; ++i) { + diff = (filesz < block_size) ? filesz : block_size; + if (SQFS_IS_SPARSE_BLOCK(inode->block_sizes[i]) && allow_sparse) { - if (filesz < block_size) { - diff = filesz; - filesz = 0; - } else { - diff = block_size; - filesz -= block_size; - } - - if (lseek(outfd, diff, SEEK_CUR) == (off_t)-1) + if (fseek(fp, diff, SEEK_CUR) < 0) goto fail_sparse; } else { err = sqfs_data_reader_get_block(data, inode, i, &blk); @@ -73,14 +72,14 @@ int sqfs_data_reader_dump(const char *name, sqfs_data_reader_t *data, return -1; } - if (append_block(outfd, blk)) { - free(blk); - return -1; - } - - filesz -= blk->size; + err = append_block(fp, blk); free(blk); + + if (err) + return -1; } + + filesz -= diff; } if (filesz > 0) { @@ -90,7 +89,7 @@ int sqfs_data_reader_dump(const char *name, sqfs_data_reader_t *data, return -1; } - if (append_block(outfd, blk)) { + if (append_block(fp, blk)) { free(blk); return -1; } diff --git a/lib/tar/padd_file.c b/lib/tar/padd_file.c index f58cfbf..dd945a3 100644 --- a/lib/tar/padd_file.c +++ b/lib/tar/padd_file.c @@ -10,7 +10,7 @@ #include #include -int padd_file(int outfd, sqfs_u64 size) +int padd_file(FILE *fp, sqfs_u64 size) { size_t padd_sz = size % TAR_RECORD_SIZE; int status = -1; @@ -26,7 +26,7 @@ int padd_file(int outfd, sqfs_u64 size) goto fail_errno; if (write_retry("padding output file to block size", - outfd, buffer, padd_sz)) { + fp, buffer, padd_sz)) { goto out; } diff --git a/lib/tar/write_header.c b/lib/tar/write_header.c index 84aa2d3..6626d00 100644 --- a/lib/tar/write_header.c +++ b/lib/tar/write_header.c @@ -53,7 +53,7 @@ static void write_number_signed(char *dst, sqfs_s64 value, int digits) } } -static int write_header(int fd, const struct stat *sb, const char *name, +static int write_header(FILE *fp, const struct stat *sb, const char *name, const char *slink_target, int type) { int maj = 0, min = 0; @@ -88,10 +88,10 @@ static int write_header(int fd, const struct stat *sb, const char *name, update_checksum(&hdr); - return write_retry("writing tar header record", fd, &hdr, sizeof(hdr)); + return write_retry("writing tar header record", fp, &hdr, sizeof(hdr)); } -static int write_gnu_header(int fd, const struct stat *orig, +static int write_gnu_header(FILE *fp, const struct stat *orig, const char *payload, size_t payload_len, int type, const char *name) { @@ -101,15 +101,15 @@ static int write_gnu_header(int fd, const struct stat *orig, sb.st_mode = S_IFREG | 0644; sb.st_size = payload_len; - if (write_header(fd, &sb, name, NULL, type)) + if (write_header(fp, &sb, name, NULL, type)) return -1; if (write_retry("writing GNU extension header", - fd, payload, payload_len)) { + fp, payload, payload_len)) { return -1; } - return padd_file(fd, payload_len); + return padd_file(fp, payload_len); } static size_t num_digits(size_t num) @@ -124,7 +124,7 @@ static size_t num_digits(size_t num) return i; } -static int write_schily_xattr(int fd, const struct stat *orig, +static int write_schily_xattr(FILE *fp, const struct stat *orig, const char *name, const tar_xattr_t *xattr) { static const char *prefix = "SCHILY.xattr."; @@ -142,20 +142,20 @@ static int write_schily_xattr(int fd, const struct stat *orig, sb.st_mode = S_IFREG | 0644; sb.st_size = total_size; - if (write_header(fd, &sb, name, NULL, TAR_TYPE_PAX)) + if (write_header(fp, &sb, name, NULL, TAR_TYPE_PAX)) return -1; for (it = xattr; it != NULL; it = it->next) { len = strlen(prefix) + strlen(it->key) + strlen(it->value) + 2; len += num_digits(len) + 1; - dprintf(fd, "%zu %s%s=%s\n", len, prefix, it->key, it->value); + fprintf(fp, "%zu %s%s=%s\n", len, prefix, it->key, it->value); } - return padd_file(fd, total_size); + return padd_file(fp, total_size); } -int write_tar_header(int fd, const struct stat *sb, const char *name, +int write_tar_header(FILE *fp, const struct stat *sb, const char *name, const char *slink_target, const tar_xattr_t *xattr, unsigned int counter) { @@ -166,7 +166,7 @@ int write_tar_header(int fd, const struct stat *sb, const char *name, if (xattr != NULL) { sprintf(buffer, "pax/xattr%u", counter); - if (write_schily_xattr(fd, sb, buffer, xattr)) + if (write_schily_xattr(fp, sb, buffer, xattr)) return -1; } @@ -175,7 +175,7 @@ int write_tar_header(int fd, const struct stat *sb, const char *name, if (S_ISLNK(sb->st_mode) && sb->st_size >= 100) { sprintf(buffer, "gnu/target%u", counter); - if (write_gnu_header(fd, sb, slink_target, sb->st_size, + if (write_gnu_header(fp, sb, slink_target, sb->st_size, TAR_TYPE_GNU_SLINK, buffer)) return -1; slink_target = NULL; @@ -184,7 +184,7 @@ int write_tar_header(int fd, const struct stat *sb, const char *name, if (strlen(name) >= 100) { sprintf(buffer, "gnu/name%u", counter); - if (write_gnu_header(fd, sb, name, strlen(name), + if (write_gnu_header(fp, sb, name, strlen(name), TAR_TYPE_GNU_PATH, buffer)) { return -1; } @@ -208,7 +208,7 @@ int write_tar_header(int fd, const struct stat *sb, const char *name, goto out_skip; } - return write_header(fd, sb, name, slink_target, type); + return write_header(fp, sb, name, slink_target, type); out_skip: fprintf(stderr, "WARNING: %s: %s\n", name, reason); return 1; diff --git a/lib/tar/write_retry.c b/lib/tar/write_retry.c index 1ff1a7e..3977db1 100644 --- a/lib/tar/write_retry.c +++ b/lib/tar/write_retry.c @@ -12,23 +12,22 @@ #include "tar.h" -int write_retry(const char *errstr, int fd, const void *data, size_t size) +int write_retry(const char *errstr, FILE *fp, const void *data, size_t size) { - ssize_t ret; + size_t ret; while (size > 0) { - ret = write(fd, data, size); - if (ret == 0) { + if (feof(fp)) { fprintf(stderr, "%s: write truncated\n", errstr); return -1; } - if (ret < 0) { - if (errno == EINTR) - continue; - perror(errstr); + + if (ferror(fp)) { + fprintf(stderr, "%s: error writing to file\n", errstr); return -1; } + ret = fwrite(data, 1, size, fp); data = (const char *)data + ret; size -= ret; } diff --git a/tar/sqfs2tar.c b/tar/sqfs2tar.c index 1e05cd4..af116b8 100644 --- a/tar/sqfs2tar.c +++ b/tar/sqfs2tar.c @@ -174,7 +174,7 @@ static int terminate_archive(void) memset(buffer, '\0', sizeof(buffer)); - return write_retry("adding archive terminator", STDOUT_FILENO, + return write_retry("adding archive terminator", stdout, buffer, sizeof(buffer)); } @@ -295,7 +295,7 @@ static int write_tree_dfs(const sqfs_tree_node_t *n) } target = S_ISLNK(sb.st_mode) ? n->inode->slink_target : NULL; - ret = write_tar_header(STDOUT_FILENO, &sb, name, target, xattr, + ret = write_tar_header(stdout, &sb, name, target, xattr, record_counter++); while (xattr != NULL) { @@ -313,13 +313,13 @@ static int write_tree_dfs(const sqfs_tree_node_t *n) } if (S_ISREG(sb.st_mode)) { - if (sqfs_data_reader_dump(name, data, n->inode, STDOUT_FILENO, + if (sqfs_data_reader_dump(name, data, n->inode, stdout, super.block_size, false)) { free(name); return -1; } - if (padd_file(STDOUT_FILENO, sb.st_size)) { + if (padd_file(stdout, sb.st_size)) { free(name); return -1; } diff --git a/unpack/fill_files.c b/unpack/fill_files.c index e6444b2..d22e9d1 100644 --- a/unpack/fill_files.c +++ b/unpack/fill_files.c @@ -136,11 +136,11 @@ static int gen_file_list_dfs(const sqfs_tree_node_t *n) static int fill_files(sqfs_data_reader_t *data, int flags) { size_t i; - int fd; + FILE *fp; for (i = 0; i < num_files; ++i) { - fd = open(files[i].path, O_WRONLY); - if (fd < 0) { + fp = fopen(files[i].path, "wb"); + if (fp == NULL) { fprintf(stderr, "unpacking %s: %s\n", files[i].path, strerror(errno)); return -1; @@ -150,13 +150,14 @@ static int fill_files(sqfs_data_reader_t *data, int flags) printf("unpacking %s\n", files[i].path); if (sqfs_data_reader_dump(files[i].path, data, files[i].inode, - fd, block_size, + fp, block_size, (flags & UNPACK_NO_SPARSE) == 0)) { - close(fd); + fclose(fp); return -1; } - close(fd); + fflush(fp); + fclose(fp); } return 0; diff --git a/unpack/rdsquashfs.c b/unpack/rdsquashfs.c index 5ef367b..2f84264 100644 --- a/unpack/rdsquashfs.c +++ b/unpack/rdsquashfs.c @@ -128,8 +128,7 @@ int main(int argc, char **argv) } if (sqfs_data_reader_dump(opt.cmdpath, data, n->inode, - STDOUT_FILENO, - super.block_size, false)) { + stdout, super.block_size, false)) { goto out; } break; -- cgit v1.2.3