From d5e2c6a3146c20354ab11f1dae48ab755996fa96 Mon Sep 17 00:00:00 2001 From: David Oberhollenzer Date: Fri, 8 Sep 2023 18:49:54 +0200 Subject: libsqfs: bring sqfs_file_t in line with stream API Rename the open function to sqfs_file_open, use an argument for the return pointer and pass back and error number on failure. Also add an inermediate function to open an sqfs_file_t using a handle, similar to the stream API. The get_file_size function is moved to the native wrappers and some of the implementation is cleaned up a little. Signed-off-by: David Oberhollenzer --- bin/gensquashfs/src/mkfs.c | 6 +-- bin/rdsquashfs/src/rdsquashfs.c | 6 +-- bin/sqfs2tar/src/sqfs2tar.c | 6 +-- bin/sqfsdiff/src/sqfsdiff.c | 4 +- doc/mainpage.dox | 2 +- extras/browse.c | 5 +-- extras/extract_one.c | 6 +-- extras/list_files.c | 5 +-- extras/mk42sqfs.c | 3 +- extras/mknastyfs.c | 3 +- include/sqfs/io.h | 56 ++++++++++++++++++++------ lib/common/src/writer/init.c | 6 +-- lib/sqfs/src/io/file.c | 87 ++++++++++++++++++++++------------------- lib/sqfs/src/io/unix.c | 14 +++++++ lib/sqfs/src/io/win32.c | 13 ++++++ 15 files changed, 140 insertions(+), 82 deletions(-) diff --git a/bin/gensquashfs/src/mkfs.c b/bin/gensquashfs/src/mkfs.c index a178066..6d04040 100644 --- a/bin/gensquashfs/src/mkfs.c +++ b/bin/gensquashfs/src/mkfs.c @@ -40,9 +40,9 @@ static int pack_files(sqfs_block_processor_t *data, fstree_t *fs, if (!opt->cfg.quiet) printf("packing %s\n", path); - file = sqfs_open_file(path, SQFS_FILE_OPEN_READ_ONLY); - if (file == NULL) { - perror(path); + ret = sqfs_file_open(&file, path, SQFS_FILE_OPEN_READ_ONLY); + if (ret) { + sqfs_perror(path, "open", ret); free(node_path); return -1; } diff --git a/bin/rdsquashfs/src/rdsquashfs.c b/bin/rdsquashfs/src/rdsquashfs.c index 9d8f3ba..2f5c50d 100644 --- a/bin/rdsquashfs/src/rdsquashfs.c +++ b/bin/rdsquashfs/src/rdsquashfs.c @@ -114,9 +114,9 @@ int main(int argc, char **argv) process_command_line(&opt, argc, argv); - file = sqfs_open_file(opt.image_name, SQFS_FILE_OPEN_READ_ONLY); - if (file == NULL) { - perror(opt.image_name); + ret = sqfs_file_open(&file, opt.image_name, SQFS_FILE_OPEN_READ_ONLY); + if (ret) { + sqfs_perror(opt.image_name, "open", ret); goto out; } diff --git a/bin/sqfs2tar/src/sqfs2tar.c b/bin/sqfs2tar/src/sqfs2tar.c index 714f6db..e21cd7a 100644 --- a/bin/sqfs2tar/src/sqfs2tar.c +++ b/bin/sqfs2tar/src/sqfs2tar.c @@ -139,9 +139,9 @@ int main(int argc, char **argv) goto out; } - file = sqfs_open_file(filename, SQFS_FILE_OPEN_READ_ONLY); - if (file == NULL) { - perror(filename); + ret = sqfs_file_open(&file, filename, SQFS_FILE_OPEN_READ_ONLY); + if (ret) { + sqfs_perror(filename, "open", ret); goto out; } diff --git a/bin/sqfsdiff/src/sqfsdiff.c b/bin/sqfsdiff/src/sqfsdiff.c index d789fe1..1bbf62c 100644 --- a/bin/sqfsdiff/src/sqfsdiff.c +++ b/bin/sqfsdiff/src/sqfsdiff.c @@ -22,9 +22,9 @@ static int open_sfqs(sqfs_state_t *state, const char *path) memset(state, 0, sizeof(*state)); - state->file = sqfs_open_file(path, SQFS_FILE_OPEN_READ_ONLY); + ret = sqfs_file_open(&state->file, path, SQFS_FILE_OPEN_READ_ONLY); if (state->file == NULL) { - perror(path); + sqfs_perror(path, "open", ret); return -1; } diff --git a/doc/mainpage.dox b/doc/mainpage.dox index b9822ac..cd71ba0 100644 --- a/doc/mainpage.dox +++ b/doc/mainpage.dox @@ -10,7 +10,7 @@ * * All disk I/O is abstracted away through the \ref sqfs_file_t interface. A * reference implementation that uses native file I/O can be instatiated - * using @ref sqfs_open_file. Providing a custom implementation allows reading + * using @ref sqfs_file_open. Providing a custom implementation allows reading * or writing SquashFS images to something other than regular files, embedding * SquashFS in a custom container format or applying custom transformations on * the raw byte level. diff --git a/extras/browse.c b/extras/browse.c index c0c9995..a608021 100644 --- a/extras/browse.c +++ b/extras/browse.c @@ -506,9 +506,8 @@ int main(int argc, char **argv) return EXIT_FAILURE; } - file = sqfs_open_file(argv[1], SQFS_FILE_OPEN_READ_ONLY); - if (file == NULL) { - perror(argv[1]); + if (sqfs_file_open(&file, argv[1], SQFS_FILE_OPEN_READ_ONLY)) { + fprintf(stderr, "%s: error opening file.\n", argv[1]); return EXIT_FAILURE; } diff --git a/extras/extract_one.c b/extras/extract_one.c index 63c83f9..d0fe1b9 100644 --- a/extras/extract_one.c +++ b/extras/extract_one.c @@ -43,9 +43,9 @@ int main(int argc, char **argv) return EXIT_FAILURE; } - file = sqfs_open_file(argv[1], SQFS_FILE_OPEN_READ_ONLY); - if (file == NULL) { - perror(argv[1]); + ret = sqfs_file_open(&file, argv[1], SQFS_FILE_OPEN_READ_ONLY); + if (ret) { + fprintf(stderr, "%s: error opening file.\n", argv[1]); return EXIT_FAILURE; } diff --git a/extras/list_files.c b/extras/list_files.c index d1e0a64..89a1f30 100644 --- a/extras/list_files.c +++ b/extras/list_files.c @@ -70,9 +70,8 @@ int main(int argc, char **argv) return EXIT_FAILURE; } - file = sqfs_open_file(argv[1], SQFS_FILE_OPEN_READ_ONLY); - if (file == NULL) { - perror(argv[1]); + if (sqfs_file_open(&file, argv[1], SQFS_FILE_OPEN_READ_ONLY)) { + fprintf(stderr, "%s: error opening file.\n", argv[1]); return EXIT_FAILURE; } diff --git a/extras/mk42sqfs.c b/extras/mk42sqfs.c index 87e1523..abad4b4 100644 --- a/extras/mk42sqfs.c +++ b/extras/mk42sqfs.c @@ -71,8 +71,7 @@ int main(int argc, char **argv) (void)argc; (void)argv; /* get a file object referring to our destination file */ - file = sqfs_open_file("42.sqfs", SQFS_FILE_OPEN_OVERWRITE); - if (file == NULL) { + if (sqfs_file_open(&file, "42.sqfs", SQFS_FILE_OPEN_OVERWRITE)) { fputs("Error opening output file.\n", stderr); return EXIT_FAILURE; } diff --git a/extras/mknastyfs.c b/extras/mknastyfs.c index c72bd7d..5984828 100644 --- a/extras/mknastyfs.c +++ b/extras/mknastyfs.c @@ -66,8 +66,7 @@ int main(int argc, char **argv) (void)argc; (void)argv; /* get a file object referring to our destination file */ - file = sqfs_open_file("nasty.sqfs", 0); - if (file == NULL) { + if (sqfs_file_open(&file, "nasty.sqfs", 0)) { fputs("Error opening output file.\n", stderr); return EXIT_FAILURE; } diff --git a/include/sqfs/io.h b/include/sqfs/io.h index f148502..bf104f9 100644 --- a/include/sqfs/io.h +++ b/include/sqfs/io.h @@ -27,7 +27,7 @@ * * @brief Contains low-level interfaces for abstracting file I/O * - * The @ref sqfs_file_t interface abstracts I/O on a random-acces sread/write + * The @ref sqfs_file_t interface abstracts I/O on a random-acces read/write * file, @ref sqfs_ostream_t represents a buffered, sequential, append only * data stream, @ref sqfs_istream_t represents a buffered, sequential, read only * data stream. @@ -50,7 +50,7 @@ typedef int sqfs_file_handle_t; /** * @enum SQFS_FILE_OPEN_FLAGS * - * @brief Flags for @ref sqfs_open_file + * @brief Flags for file I/O related data structures and functions */ typedef enum { /** @@ -91,9 +91,8 @@ typedef enum { /** * @brief Do not use sparse file I/O APIs, always fill in zero bytes * - * This flag currently has no effect on @ref sqfs_open_file, it changes - * the behavior of @ref sqfs_ostream_open_file and - * @ref sqfs_ostream_open_handle. + * This flag currently has no effect on @ref sqfs_file_t, it changes + * the behavior of @ref sqfs_ostream_t when appending sparse data. */ SQFS_FILE_OPEN_NO_SPARSE = 0x08, @@ -438,24 +437,55 @@ SQFS_API int sqfs_native_file_duplicate(sqfs_file_handle_t in, SQFS_API int sqfs_native_file_seek(sqfs_file_handle_t hnd, sqfs_s64 offset, sqfs_u32 flags); +/** + * @brief Try to query the current on-disk size from a native file handle + * + * @param hnd A native OS file handle + * @param out Returns the file size on success + * + * @return Zero on success, a negative @ref SQFS_ERROR code on failure. + */ +SQFS_API int sqfs_native_file_get_size(sqfs_file_handle_t hnd, sqfs_u64 *out); + /** * @brief Open a file through the operating systems filesystem API * + * @memberof sqfs_file_t + * + * This function basically combines @ref sqfs_native_file_open + * and @ref sqfs_file_open_handle to conveniently open a file object in + * one operation + * + * @param out Returns a pointer to an @ref sqfs_file_t on success. + * @param filename The name of the file to open. + * @param flags A set of @ref SQFS_FILE_OPEN_FLAGS. + * + * @return Zero on success, a negative @ref SQFS_ERROR code on failure. + */ +SQFS_API int sqfs_file_open(sqfs_file_t **out, const char *filename, + sqfs_u32 flags); + +/** + * @brief Create an @ref sqfs_file_t implementation from a native file handle + * + * @memberof sqfs_file_t + * * This function internally creates an instance of a reference implementation * of the @ref sqfs_file_t interface that uses the operating systems native * API for file I/O. * - * On Unix-like systems, if the open call fails, this function makes sure to - * preserves the value in errno indicating the underlying problem. Similarly, - * on Windows, the implementation tries to preserve the GetLastError value. + * It takes up ownership of the file handle and takes care of cleaning it up. + * On failure, the handle remains usable, and ownership remains with the caller. * - * @param filename The name of the file to open. - * @param flags A set of @ref SQFS_FILE_OPEN_FLAGS. + * @param out Returns a pointer to a file object on success. + * @param filename The name to associate with the handle. + * @param fd A native file handle. + * @param flags A combination of @ref SQFS_FILE_OPEN_FLAGS flags. * - * @return A pointer to a file object on success, NULL on allocation failure, - * failure to open the file or if an unknown flag was set. + * @return Zero on success, a negative @ref SQFS_ERROR number on failure */ -SQFS_API sqfs_file_t *sqfs_open_file(const char *filename, sqfs_u32 flags); +SQFS_API int sqfs_file_open_handle(sqfs_file_t **out, const char *filename, + sqfs_file_handle_t fd, sqfs_u32 flags); /** * @brief Create an input stream for an OS native file handle. diff --git a/lib/common/src/writer/init.c b/lib/common/src/writer/init.c index 60d7a12..bf1d2ca 100644 --- a/lib/common/src/writer/init.c +++ b/lib/common/src/writer/init.c @@ -57,9 +57,9 @@ int sqfs_writer_init(sqfs_writer_t *sqfs, const sqfs_writer_cfg_t *wrcfg) return -1; } - sqfs->outfile = sqfs_open_file(wrcfg->filename, wrcfg->outmode); - if (sqfs->outfile == NULL) { - perror(wrcfg->filename); + ret = sqfs_file_open(&sqfs->outfile, wrcfg->filename, wrcfg->outmode); + if (ret) { + sqfs_perror(wrcfg->filename, "open", ret); return -1; } diff --git a/lib/sqfs/src/io/file.c b/lib/sqfs/src/io/file.c index 27ab5d6..e6b7ee3 100644 --- a/lib/sqfs/src/io/file.c +++ b/lib/sqfs/src/io/file.c @@ -13,29 +13,14 @@ #include #include +#include -#if defined(_WIN32) || defined(__WINDOWS__) -static int get_file_size(HANDLE fd, sqfs_u64 *out) -{ - LARGE_INTEGER size; - if (!GetFileSizeEx(fd, &size)) - return -1; - *out = size.QuadPart; - return 0; -} -#else -#include +#if !defined(_WIN32) && !defined(__WINDOWS__) #include -#include -static int get_file_size(int fd, sqfs_u64 *out) -{ - struct stat sb; - if (fstat(fd, &sb)) - return -1; - *out = sb.st_size; - return 0; -} +#define ERROR_NOT_ENOUGH_MEMORY ENOMEM +#define ERROR_NOT_SUPPORTED ENOTSUP +#define SetLastError(x) errno = (x) #endif typedef struct { @@ -64,11 +49,7 @@ static sqfs_object_t *stdio_copy(const sqfs_object_t *base) size_t size; if (!file->readonly) { -#if defined(_WIN32) || defined(__WINDOWS__) SetLastError(ERROR_NOT_SUPPORTED); -#else - errno = ENOTSUP; -#endif return NULL; } @@ -232,13 +213,16 @@ static const char *stdio_get_filename(sqfs_file_t *file) return ((sqfs_file_stdio_t *)file)->name; } -sqfs_file_t *sqfs_open_file(const char *filename, sqfs_u32 flags) +int sqfs_file_open_handle(sqfs_file_t **out, const char *filename, + sqfs_file_handle_t fd, sqfs_u32 flags) { - bool file_opened = false; sqfs_file_stdio_t *file; size_t size, namelen; sqfs_file_t *base; os_error_t err; + int ret; + + *out = NULL; namelen = strlen(filename); size = sizeof(*file) + 1; @@ -254,12 +238,15 @@ sqfs_file_t *sqfs_open_file(const char *filename, sqfs_u32 flags) sqfs_object_init(file, stdio_destroy, stdio_copy); memcpy(file->name, filename, namelen); - if (sqfs_native_file_open(&file->fd, filename, flags)) - goto fail; + ret = sqfs_native_file_get_size(fd, &file->size); + if (ret) + goto fail_free; + + ret = sqfs_native_file_duplicate(fd, &file->fd); + if (ret) + goto fail_free; - file_opened = true; - if (get_file_size(file->fd, &file->size)) - goto fail; + sqfs_native_file_close(fd); file->readonly = (flags & SQFS_FILE_OPEN_READ_ONLY) != 0; @@ -268,19 +255,37 @@ sqfs_file_t *sqfs_open_file(const char *filename, sqfs_u32 flags) base->get_size = stdio_get_size; base->truncate = stdio_truncate; base->get_filename = stdio_get_filename; - return base; -fail: + + *out = base; + return 0; +fail_free: err = get_os_error_state(); - if (file_opened) - sqfs_native_file_close(file->fd); free(file); set_os_error_state(err); - return NULL; + return ret; fail_no_mem: -#if defined(_WIN32) || defined(__WINDOWS__) SetLastError(ERROR_NOT_ENOUGH_MEMORY); -#else - errno = ENOMEM; -#endif - return NULL; + return SQFS_ERROR_ALLOC; +} + +int sqfs_file_open(sqfs_file_t **out, const char *filename, sqfs_u32 flags) +{ + sqfs_file_handle_t fd; + int ret; + + ret = sqfs_native_file_open(&fd, filename, flags); + if (ret) { + *out = NULL; + return ret; + } + + ret = sqfs_file_open_handle(out, filename, fd, flags); + if (ret) { + os_error_t err = get_os_error_state(); + sqfs_native_file_close(fd); + set_os_error_state(err); + return ret; + } + + return 0; } diff --git a/lib/sqfs/src/io/unix.c b/lib/sqfs/src/io/unix.c index 2e97394..cac8e55 100644 --- a/lib/sqfs/src/io/unix.c +++ b/lib/sqfs/src/io/unix.c @@ -10,6 +10,7 @@ #include "sqfs/io.h" #include "sqfs/error.h" +#include #include #include #include @@ -85,3 +86,16 @@ int sqfs_native_file_seek(sqfs_file_handle_t fd, return 0; } + +int sqfs_native_file_get_size(sqfs_file_handle_t hnd, sqfs_u64 *out) +{ + struct stat sb; + + if (fstat(hnd, &sb)) { + *out = 0; + return SQFS_ERROR_IO; + } + + *out = sb.st_size; + return 0; +} diff --git a/lib/sqfs/src/io/win32.c b/lib/sqfs/src/io/win32.c index bc625e4..fd10ab1 100644 --- a/lib/sqfs/src/io/win32.c +++ b/lib/sqfs/src/io/win32.c @@ -118,3 +118,16 @@ int sqfs_native_file_seek(sqfs_file_handle_t fd, return 0; } + +int sqfs_native_file_get_size(sqfs_file_handle_t hnd, sqfs_u64 *out) +{ + LARGE_INTEGER size; + + if (!GetFileSizeEx(hnd, &size)) { + *out = 0; + return SQFS_ERROR_IO; + } + + *out = size.QuadPart; + return 0; +} -- cgit v1.2.3