From 8ee3ee9c71418dbdb73d4350c17056024fb7ec41 Mon Sep 17 00:00:00 2001 From: David Oberhollenzer Date: Sun, 15 Sep 2019 17:56:07 +0200 Subject: Replace file descriptor IO in data_writer with sqfs_file_t First, this commit moves the create-blocks-from-fd function over to libsquashfs and ports it to work on an sqfs_file_t instead. Second, the function in the data_writer that reads from a file descriptor is adjusted to use an sqfs_file_t instead. Finally, the tools that use it have to be adjusted accordingly. Signed-off-by: David Oberhollenzer --- include/data_writer.h | 4 +- include/sqfs/io.h | 22 +++++++ lib/sqfs/Makemodule.am | 4 +- lib/sqfs/io.c | 146 +++++------------------------------------ lib/sqfs/io_file.c | 151 +++++++++++++++++++++++++++++++++++++++++++ lib/sqfshelper/data_writer.c | 44 ++++--------- mkfs/mkfs.c | 13 ++-- tar/tar2sqfs.c | 10 ++- 8 files changed, 223 insertions(+), 171 deletions(-) create mode 100644 lib/sqfs/io_file.c diff --git a/include/data_writer.h b/include/data_writer.h index 5987cd6..c9e6f20 100644 --- a/include/data_writer.h +++ b/include/data_writer.h @@ -84,8 +84,8 @@ int data_writer_sync(data_writer_t *data); Returns 0 on success, prints errors to stderr. */ -int write_data_from_fd(data_writer_t *data, file_info_t *fi, int infd, - int flags); +int write_data_from_file(data_writer_t *data, file_info_t *fi, + sqfs_file_t *file, int flags); /* Does the same as write_data_from_fd but the input file is the condensed diff --git a/include/sqfs/io.h b/include/sqfs/io.h index a544875..9784113 100644 --- a/include/sqfs/io.h +++ b/include/sqfs/io.h @@ -150,9 +150,31 @@ SQFS_API sqfs_file_t *sqfs_open_file(const char *filename, int flags); * reading sequentially. * * @param size The alleged "size" of the file. + * + * @return A pointer to a file object on success, NULL on allocation failure. */ SQFS_API sqfs_file_t *sqfs_get_stdin_file(uint64_t size); + +/** + * @brief Read a chunk from a file and turn it into a block that can be + * fed to a block processor. + * + * @member sqfs_file_t + * + * @param file A pointer to a file implementation. + * @param offset A byte offset into the file. + * @param size The number of bytes to read, starting at the given offset. + * @param user A user pointer to set for the block. + * @param flags The flags to store in the newly created block. + * @param out Returns a pointer to a block on success. + * + * @return Zero on success, an @ref E_SQFS_ERROR identifier on failure. + */ +SQFS_API int sqfs_file_create_block(sqfs_file_t *file, uint64_t offset, + size_t size, void *user, uint32_t flags, + sqfs_block_t **out); + #ifdef __cplusplus } #endif diff --git a/lib/sqfs/Makemodule.am b/lib/sqfs/Makemodule.am index b58a28b..7d228a4 100644 --- a/lib/sqfs/Makemodule.am +++ b/lib/sqfs/Makemodule.am @@ -7,14 +7,14 @@ LIBSQFS_HEARDS = include/sqfs/data.h include/sqfs/meta_writer.h \ include/sqfs/error.h include/sqfs/io.h libsquashfs_la_SOURCES = $(LIBSQFS_HEARDS) lib/sqfs/id_table.c lib/sqfs/super.c -libsquashfs_la_SOURCES += lib/sqfs/readdir.c lib/sqfs/io.c lib/sqfs/xattr.c +libsquashfs_la_SOURCES += lib/sqfs/readdir.c lib/sqfs/io_file.c lib/sqfs/xattr.c libsquashfs_la_SOURCES += lib/sqfs/write_table.c lib/sqfs/meta_writer.c libsquashfs_la_SOURCES += lib/sqfs/read_super.c lib/sqfs/meta_reader.c libsquashfs_la_SOURCES += lib/sqfs/read_inode.c lib/sqfs/write_inode.c libsquashfs_la_SOURCES += lib/sqfs/dir_writer.c lib/sqfs/xattr_reader.c libsquashfs_la_SOURCES += lib/sqfs/read_table.c lib/sqfs/comp/compressor.c libsquashfs_la_SOURCES += lib/sqfs/io_stdin.c lib/sqfs/comp/internal.h -libsquashfs_la_SOURCES += lib/sqfs/blk_proc/process_block.c +libsquashfs_la_SOURCES += lib/sqfs/blk_proc/process_block.c lib/sqfs/io.c libsquashfs_la_SOURCES += lib/sqfs/blk_proc/internal.h libsquashfs_la_CPPFLAGS = $(AM_CPPFLAGS) libsquashfs_la_CFLAGS = $(AM_CFLAGS) $(PTHREAD_CFLAGS) $(ZLIB_CFLAGS) diff --git a/lib/sqfs/io.c b/lib/sqfs/io.c index f8773d0..4afb489 100644 --- a/lib/sqfs/io.c +++ b/lib/sqfs/io.c @@ -9,143 +9,31 @@ #include "sqfs/io.h" #include "sqfs/error.h" +#include "sqfs/block_processor.h" +#include "util.h" #include -#include -#include -#include - -typedef struct { - sqfs_file_t base; - - uint64_t size; - int fd; -} sqfs_file_stdio_t; - - -static void stdio_destroy(sqfs_file_t *base) -{ - sqfs_file_stdio_t *file = (sqfs_file_stdio_t *)base; - - close(file->fd); - free(file); -} - -static int stdio_read_at(sqfs_file_t *base, uint64_t offset, - void *buffer, size_t size) -{ - sqfs_file_stdio_t *file = (sqfs_file_stdio_t *)base; - ssize_t ret; - - while (size > 0) { - ret = pread(file->fd, buffer, size, offset); - - if (ret < 0) { - if (errno == EINTR) - continue; - return SQFS_ERROR_IO; - } - - if (ret == 0) - return SQFS_ERROR_OUT_OF_BOUNDS; - - buffer = (char *)buffer + ret; - size -= ret; - offset += ret; - } - - return 0; -} - -static int stdio_write_at(sqfs_file_t *base, uint64_t offset, - const void *buffer, size_t size) +int sqfs_file_create_block(sqfs_file_t *file, uint64_t offset, + size_t size, void *user, uint32_t flags, + sqfs_block_t **out) { - sqfs_file_stdio_t *file = (sqfs_file_stdio_t *)base; - ssize_t ret; - - while (size > 0) { - ret = pwrite(file->fd, buffer, size, offset); - - if (ret < 0) { - if (errno == EINTR) - continue; - return SQFS_ERROR_IO; - } + sqfs_block_t *blk = alloc_flex(sizeof(*blk), 1, size); + int err; - if (ret == 0) - return SQFS_ERROR_OUT_OF_BOUNDS; + if (blk == NULL) + return SQFS_ERROR_ALLOC; - buffer = (const char *)buffer + ret; - size -= ret; - offset += ret; + err = file->read_at(file, offset, blk->data, size); + if (err) { + free(blk); + return err; } - if (offset >= file->size) - file->size = offset; + blk->user = user; + blk->size = size; + blk->flags = flags; + *out = blk; return 0; } - -static uint64_t stdio_get_size(const sqfs_file_t *base) -{ - const sqfs_file_stdio_t *file = (const sqfs_file_stdio_t *)base; - - return file->size; -} - -static int stdio_truncate(sqfs_file_t *base, uint64_t size) -{ - sqfs_file_stdio_t *file = (sqfs_file_stdio_t *)base; - - if (ftruncate(file->fd, size)) - return SQFS_ERROR_IO; - - file->size = size; - return 0; -} - - -sqfs_file_t *sqfs_open_file(const char *filename, int flags) -{ - sqfs_file_stdio_t *file; - int open_mode, temp; - sqfs_file_t *base; - - if (flags & ~SQFS_FILE_OPEN_ALL_FLAGS) { - errno = EINVAL; - return NULL; - } - - file = calloc(1, sizeof(*file)); - base = (sqfs_file_t *)file; - if (file == NULL) - return NULL; - - if (flags & SQFS_FILE_OPEN_READ_ONLY) { - open_mode = O_RDONLY; - } else { - open_mode = O_CREAT | O_RDWR; - - if (flags & SQFS_FILE_OPEN_OVERWRITE) { - open_mode |= O_TRUNC; - } else { - open_mode |= O_EXCL; - } - } - - file->fd = open(filename, open_mode, 0600); - if (file->fd < 0) { - temp = errno; - free(file); - errno = temp; - return NULL; - } - - base->destroy = stdio_destroy; - base->read_at = stdio_read_at; - base->write_at = stdio_write_at; - base->get_size = stdio_get_size; - base->truncate = stdio_truncate; - return base; -} diff --git a/lib/sqfs/io_file.c b/lib/sqfs/io_file.c new file mode 100644 index 0000000..b57eddd --- /dev/null +++ b/lib/sqfs/io_file.c @@ -0,0 +1,151 @@ +/* SPDX-License-Identifier: LGPL-3.0-or-later */ +/* + * io_file.c + * + * Copyright (C) 2019 David Oberhollenzer + */ +#define SQFS_BUILDING_DLL +#include "config.h" + +#include "sqfs/io.h" +#include "sqfs/error.h" + +#include +#include +#include +#include + + +typedef struct { + sqfs_file_t base; + + uint64_t size; + int fd; +} sqfs_file_stdio_t; + + +static void stdio_destroy(sqfs_file_t *base) +{ + sqfs_file_stdio_t *file = (sqfs_file_stdio_t *)base; + + close(file->fd); + free(file); +} + +static int stdio_read_at(sqfs_file_t *base, uint64_t offset, + void *buffer, size_t size) +{ + sqfs_file_stdio_t *file = (sqfs_file_stdio_t *)base; + ssize_t ret; + + while (size > 0) { + ret = pread(file->fd, buffer, size, offset); + + if (ret < 0) { + if (errno == EINTR) + continue; + return SQFS_ERROR_IO; + } + + if (ret == 0) + return SQFS_ERROR_OUT_OF_BOUNDS; + + buffer = (char *)buffer + ret; + size -= ret; + offset += ret; + } + + return 0; +} + +static int stdio_write_at(sqfs_file_t *base, uint64_t offset, + const void *buffer, size_t size) +{ + sqfs_file_stdio_t *file = (sqfs_file_stdio_t *)base; + ssize_t ret; + + while (size > 0) { + ret = pwrite(file->fd, buffer, size, offset); + + if (ret < 0) { + if (errno == EINTR) + continue; + return SQFS_ERROR_IO; + } + + if (ret == 0) + return SQFS_ERROR_OUT_OF_BOUNDS; + + buffer = (const char *)buffer + ret; + size -= ret; + offset += ret; + } + + if (offset >= file->size) + file->size = offset; + + return 0; +} + +static uint64_t stdio_get_size(const sqfs_file_t *base) +{ + const sqfs_file_stdio_t *file = (const sqfs_file_stdio_t *)base; + + return file->size; +} + +static int stdio_truncate(sqfs_file_t *base, uint64_t size) +{ + sqfs_file_stdio_t *file = (sqfs_file_stdio_t *)base; + + if (ftruncate(file->fd, size)) + return SQFS_ERROR_IO; + + file->size = size; + return 0; +} + + +sqfs_file_t *sqfs_open_file(const char *filename, int flags) +{ + sqfs_file_stdio_t *file; + int open_mode, temp; + sqfs_file_t *base; + + if (flags & ~SQFS_FILE_OPEN_ALL_FLAGS) { + errno = EINVAL; + return NULL; + } + + file = calloc(1, sizeof(*file)); + base = (sqfs_file_t *)file; + if (file == NULL) + return NULL; + + if (flags & SQFS_FILE_OPEN_READ_ONLY) { + open_mode = O_RDONLY; + } else { + open_mode = O_CREAT | O_RDWR; + + if (flags & SQFS_FILE_OPEN_OVERWRITE) { + open_mode |= O_TRUNC; + } else { + open_mode |= O_EXCL; + } + } + + file->fd = open(filename, open_mode, 0600); + if (file->fd < 0) { + temp = errno; + free(file); + errno = temp; + return NULL; + } + + base->destroy = stdio_destroy; + base->read_at = stdio_read_at; + base->write_at = stdio_write_at; + base->get_size = stdio_get_size; + base->truncate = stdio_truncate; + return base; +} diff --git a/lib/sqfshelper/data_writer.c b/lib/sqfshelper/data_writer.c index 43d5851..edd1770 100644 --- a/lib/sqfshelper/data_writer.c +++ b/lib/sqfshelper/data_writer.c @@ -319,34 +319,11 @@ static int add_sentinel_block(data_writer_t *data, file_info_t *fi, return sqfs_block_processor_enqueue(data->proc, blk); } -static sqfs_block_t *create_block(file_info_t *fi, int fd, size_t size, - uint32_t flags) -{ - sqfs_block_t *blk = alloc_flex(sizeof(*blk), 1, size); - - if (blk == NULL) { - perror(fi->input_file); - return NULL; - } - - if (fd >= 0) { - if (read_data(fi->input_file, fd, blk->data, size)) { - free(blk); - return NULL; - } - } - - blk->size = size; - blk->user = fi; - blk->flags = flags; - return blk; -} - -int write_data_from_fd(data_writer_t *data, file_info_t *fi, - int infd, int flags) +int write_data_from_file(data_writer_t *data, file_info_t *fi, + sqfs_file_t *file, int flags) { uint32_t blk_flags = BLK_FIRST_BLOCK; - uint64_t file_size = fi->size; + uint64_t offset, file_size; size_t diff, i = 0; sqfs_block_t *blk; @@ -356,16 +333,19 @@ int write_data_from_fd(data_writer_t *data, file_info_t *fi, if (flags & DW_ALLIGN_DEVBLK) blk_flags |= BLK_ALLIGN; - for (; file_size > 0; file_size -= diff) { - if (file_size > data->super->block_size) { + file_size = file->get_size(file); + + for (offset = 0; offset < file_size; offset += diff) { + if (file_size - offset > data->super->block_size) { diff = data->super->block_size; } else { - diff = file_size; + diff = file_size - offset; } - blk = create_block(fi, infd, diff, blk_flags); - if (blk == NULL) + if (sqfs_file_create_block(file, offset, diff, fi, + blk_flags, &blk)) { return -1; + } blk->index = i++; @@ -405,7 +385,7 @@ int write_data_from_fd(data_writer_t *data, file_info_t *fi, return -1; } - data->stats.bytes_read += fi->size; + data->stats.bytes_read += file_size; data->stats.file_count += 1; return 0; } diff --git a/mkfs/mkfs.c b/mkfs/mkfs.c index a046cbd..cb65eda 100644 --- a/mkfs/mkfs.c +++ b/mkfs/mkfs.c @@ -30,8 +30,9 @@ static int restore_working_dir(options_t *opt) static int pack_files(data_writer_t *data, fstree_t *fs, options_t *opt) { + sqfs_file_t *file; file_info_t *fi; - int ret, infd; + int ret; if (set_working_dir(opt)) return -1; @@ -40,14 +41,16 @@ static int pack_files(data_writer_t *data, fstree_t *fs, options_t *opt) if (!opt->quiet) printf("packing %s\n", fi->input_file); - infd = open(fi->input_file, O_RDONLY); - if (infd < 0) { + file = sqfs_open_file(fi->input_file, + SQFS_FILE_OPEN_READ_ONLY); + if (file == NULL) { perror(fi->input_file); return -1; } - ret = write_data_from_fd(data, fi, infd, 0); - close(infd); + ret = write_data_from_file(data, fi, file, 0); + file->destroy(file); + if (ret) return -1; } diff --git a/tar/tar2sqfs.c b/tar/tar2sqfs.c index 13276b8..d693aa1 100644 --- a/tar/tar2sqfs.c +++ b/tar/tar2sqfs.c @@ -225,6 +225,7 @@ fail_arg: static int write_file(tar_header_decoded_t *hdr, file_info_t *fi, data_writer_t *data) { + sqfs_file_t *file; int ret; if (hdr->sparse != NULL) { @@ -236,9 +237,16 @@ static int write_file(tar_header_decoded_t *hdr, file_info_t *fi, return skip_padding(STDIN_FILENO, hdr->record_size); } - if (write_data_from_fd(data, fi, STDIN_FILENO, 0)) + file = sqfs_get_stdin_file(fi->size); + if (file == NULL) { + perror("packing files"); + return -1; + } + + if (write_data_from_file(data, fi, file, 0)) return -1; + file->destroy(file); return skip_padding(STDIN_FILENO, fi->size); } -- cgit v1.2.3