diff options
author | David Oberhollenzer <david.oberhollenzer@sigma-star.at> | 2019-09-15 17:56:07 +0200 |
---|---|---|
committer | David Oberhollenzer <david.oberhollenzer@sigma-star.at> | 2019-09-15 17:59:00 +0200 |
commit | 8ee3ee9c71418dbdb73d4350c17056024fb7ec41 (patch) | |
tree | 28416eda2893ed28750c29b41b64d783a1aaa35d /lib/sqfs/io_file.c | |
parent | ab2d7fd8bfb1eafc61953e74757e84ed407b1f21 (diff) |
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 <david.oberhollenzer@sigma-star.at>
Diffstat (limited to 'lib/sqfs/io_file.c')
-rw-r--r-- | lib/sqfs/io_file.c | 151 |
1 files changed, 151 insertions, 0 deletions
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 <goliath@infraroot.at> + */ +#define SQFS_BUILDING_DLL +#include "config.h" + +#include "sqfs/io.h" +#include "sqfs/error.h" + +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> +#include <fcntl.h> + + +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; +} |