aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Oberhollenzer <david.oberhollenzer@sigma-star.at>2023-06-11 23:03:21 +0200
committerDavid Oberhollenzer <david.oberhollenzer@sigma-star.at>2023-06-12 13:34:55 +0200
commit2b10bb09beb03380c8b815a6f6be268f188ac78d (patch)
tree0d21f998d90aaa709e7ebb23c413a58232154439
parente57196f2f80432900523258af1038fb95a100b6b (diff)
libio: add open handle functions to istream/ostream
For the backends, this simplifies the code as both paths (open file and open stdio) use the same basic code. Even when merging them only in the backend, it would be done in a similar way. Making the functions public allows other uses as well. Signed-off-by: David Oberhollenzer <david.oberhollenzer@sigma-star.at>
-rw-r--r--include/io/file.h42
-rw-r--r--lib/io/src/unix/istream.c39
-rw-r--r--lib/io/src/unix/ostream.c49
-rw-r--r--lib/io/src/win32/istream.c76
-rw-r--r--lib/io/src/win32/ostream.c136
5 files changed, 173 insertions, 169 deletions
diff --git a/include/io/file.h b/include/io/file.h
index 8c6e851..f3723b2 100644
--- a/include/io/file.h
+++ b/include/io/file.h
@@ -10,11 +10,53 @@
#include "io/istream.h"
#include "io/ostream.h"
+#if defined(_WIN32) || defined(__WINDOWS__)
+#include <handleapi.h>
+
+typedef HANDLE os_file_t;
+#else
+typedef int os_file_t;
+#endif
+
#ifdef __cplusplus
extern "C" {
#endif
/**
+ * @brief Create an input stream for an OS native file handle.
+ *
+ * @memberof istream_t
+ *
+ * The functions 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 path The name to associate with the handle.
+ * @param fd A native file handle.
+ *
+ * @return A pointer to an output stream on success, NULL on failure.
+ */
+SQFS_INTERNAL istream_t *istream_open_handle(const char *path, os_file_t fd);
+
+/**
+ * @brief Create an output stream that writes to an OS native file handle.
+ *
+ * @memberof ostream_t
+ *
+ * If the flag OSTREAM_OPEN_SPARSE is set, the underlying implementation tries
+ * to use seek/truncate style API to create sparse output files. If the flag
+ * is not set, holes will always be filled with zero bytes.
+ *
+ * @param path The name to associate with the handle.
+ * @param fd A native file handle.
+ * @param flags A combination of flags.
+ *
+ * @return A pointer to an output stream on success, NULL on failure.
+ */
+SQFS_INTERNAL ostream_t *ostream_open_handle(const char *path, os_file_t hnd,
+ int flags);
+
+/**
* @brief Create an input stream that reads from a file.
*
* @memberof istream_t
diff --git a/lib/io/src/unix/istream.c b/lib/io/src/unix/istream.c
index 60abff1..e96bc6c 100644
--- a/lib/io/src/unix/istream.c
+++ b/lib/io/src/unix/istream.c
@@ -105,7 +105,7 @@ static void file_destroy(sqfs_object_t *obj)
free(file);
}
-istream_t *istream_open_file(const char *path)
+istream_t *istream_open_handle(const char *path, int fd)
{
file_istream_t *file = calloc(1, sizeof(*file));
istream_t *strm = (istream_t *)file;
@@ -123,11 +123,12 @@ istream_t *istream_open_file(const char *path)
goto fail_free;
}
- file->fd = open(path, O_RDONLY);
+ file->fd = dup(fd);
if (file->fd < 0) {
perror(path);
goto fail_path;
}
+ close(fd);
strm->get_buffered_data = file_get_buffered_data;
strm->advance_buffer = file_advance_buffer;
@@ -140,27 +141,25 @@ fail_free:
return NULL;
}
-istream_t *istream_open_stdin(void)
+istream_t *istream_open_file(const char *path)
{
- file_istream_t *file = calloc(1, sizeof(*file));
- istream_t *strm = (istream_t *)file;
+ istream_t *out;
+ int fd;
- if (file == NULL)
- goto fail;
+ fd = open(path, O_RDONLY);
+ if (fd < 0) {
+ perror(path);
+ return NULL;
+ }
- sqfs_object_init(file, file_destroy, NULL);
+ out = istream_open_handle(path, fd);
+ if (out == NULL)
+ close(fd);
- file->path = strdup("stdin");
- if (file->path == NULL)
- goto fail;
+ return out;
+}
- file->fd = STDIN_FILENO;
- strm->get_buffered_data = file_get_buffered_data;
- strm->advance_buffer = file_advance_buffer;
- strm->get_filename = file_get_filename;
- return strm;
-fail:
- perror("creating file wrapper for stdin");
- free(file);
- return NULL;
+istream_t *istream_open_stdin(void)
+{
+ return istream_open_handle("stdin", STDIN_FILENO);
}
diff --git a/lib/io/src/unix/ostream.c b/lib/io/src/unix/ostream.c
index 5ef2af2..294a15e 100644
--- a/lib/io/src/unix/ostream.c
+++ b/lib/io/src/unix/ostream.c
@@ -90,9 +90,7 @@ static void file_destroy(sqfs_object_t *obj)
{
file_ostream_t *file = (file_ostream_t *)obj;
- if (file->fd != STDOUT_FILENO)
- close(file->fd);
-
+ close(file->fd);
free(file->path);
free(file);
}
@@ -104,7 +102,7 @@ static const char *file_get_filename(ostream_t *strm)
return file->path;
}
-ostream_t *ostream_open_file(const char *path, int flags)
+ostream_t *ostream_open_handle(const char *path, int fd, int flags)
{
file_ostream_t *file = calloc(1, sizeof(*file));
ostream_t *strm = (ostream_t *)file;
@@ -122,17 +120,14 @@ ostream_t *ostream_open_file(const char *path, int flags)
goto fail_free;
}
- if (flags & OSTREAM_OPEN_OVERWRITE) {
- file->fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
- } else {
- file->fd = open(path, O_WRONLY | O_CREAT | O_EXCL, 0644);
- }
-
+ file->fd = dup(fd);
if (file->fd < 0) {
perror(path);
goto fail_path;
}
+ close(fd);
+
if (flags & OSTREAM_OPEN_SPARSE)
strm->append_sparse = file_append_sparse;
@@ -147,27 +142,25 @@ fail_free:
return NULL;
}
-ostream_t *ostream_open_stdout(void)
+ostream_t *ostream_open_file(const char *path, int flags)
{
- file_ostream_t *file = calloc(1, sizeof(*file));
- ostream_t *strm = (ostream_t *)file;
+ ostream_t *out;
+ int fd;
- if (file == NULL)
- goto fail;
+ if (flags & OSTREAM_OPEN_OVERWRITE) {
+ fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
+ } else {
+ fd = open(path, O_WRONLY | O_CREAT | O_EXCL, 0644);
+ }
- file->path = strdup("stdout");
- if (file->path == NULL)
- goto fail;
+ out = ostream_open_handle(path, fd, flags);
+ if (out == NULL)
+ close(fd);
- file->fd = STDOUT_FILENO;
- strm->append = file_append;
- strm->flush = file_flush;
- strm->get_filename = file_get_filename;
+ return out;
+}
- sqfs_object_init(file, file_destroy, NULL);
- return strm;
-fail:
- perror("creating file wrapper for stdout");
- free(file);
- return NULL;
+ostream_t *ostream_open_stdout(void)
+{
+ return ostream_open_handle("stdout", STDOUT_FILENO, 0);
}
diff --git a/lib/io/src/win32/istream.c b/lib/io/src/win32/istream.c
index 0d002cc..46bed30 100644
--- a/lib/io/src/win32/istream.c
+++ b/lib/io/src/win32/istream.c
@@ -24,7 +24,6 @@ static int precache(istream_t *strm)
{
file_istream_t *file = (file_istream_t *)strm;
DWORD diff, actual;
- HANDLE hnd;
if (file->eof)
return 0;
@@ -38,12 +37,10 @@ static int precache(istream_t *strm)
file->buffer_used -= file->buffer_offset;
file->buffer_offset = 0;
- hnd = file->path == NULL ? GetStdHandle(STD_INPUT_HANDLE) : file->hnd;
-
while (file->buffer_used < sizeof(file->buffer)) {
diff = sizeof(file->buffer) - file->buffer_used;
- if (!ReadFile(hnd, file->buffer + file->buffer_used,
+ if (!ReadFile(file->hnd, file->buffer + file->buffer_used,
diff, &actual, NULL)) {
DWORD error = GetLastError();
@@ -54,8 +51,7 @@ static int precache(istream_t *strm)
}
SetLastError(error);
-
- w32_perror(file->path == NULL ? "stdin" : file->path);
+ w32_perror(file->path);
return -1;
}
@@ -103,28 +99,23 @@ static void file_advance_buffer(istream_t *strm, size_t count)
static const char *file_get_filename(istream_t *strm)
{
- file_istream_t *file = (file_istream_t *)strm;
-
- return file->path == NULL ? "stdin" : file->path;
+ return ((file_istream_t *)strm)->path;
}
static void file_destroy(sqfs_object_t *obj)
{
file_istream_t *file = (file_istream_t *)obj;
- if (file->path != NULL) {
- CloseHandle(file->hnd);
- free(file->path);
- }
-
+ CloseHandle(file->hnd);
+ free(file->path);
free(file);
}
-istream_t *istream_open_file(const char *path)
+istream_t *istream_open_handle(const char *path, HANDLE hnd)
{
file_istream_t *file = calloc(1, sizeof(*file));
istream_t *strm = (istream_t *)file;
- WCHAR *wpath = NULL;
+ BOOL ret;
if (file == NULL) {
perror(path);
@@ -133,25 +124,21 @@ istream_t *istream_open_file(const char *path)
sqfs_object_init(file, file_destroy, NULL);
- wpath = path_to_windows(path);
- if (wpath == NULL)
- goto fail_free;
-
file->path = strdup(path);
if (file->path == NULL) {
perror(path);
goto fail_free;
}
- file->hnd = CreateFileW(wpath, GENERIC_READ, FILE_SHARE_READ, NULL,
- OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
-
- if (file->hnd == INVALID_HANDLE_VALUE) {
- perror(path);
+ ret = DuplicateHandle(GetCurrentProcess(), hnd,
+ GetCurrentProcess(), &file->hnd,
+ 0, FALSE, DUPLICATE_SAME_ACCESS);
+ if (!ret) {
+ w32_perror(path);
goto fail_path;
}
- free(wpath);
+ CloseHandle(hnd);
strm->get_buffered_data = file_get_buffered_data;
strm->advance_buffer = file_advance_buffer;
@@ -160,25 +147,40 @@ istream_t *istream_open_file(const char *path)
fail_path:
free(file->path);
fail_free:
- free(wpath);
free(file);
return NULL;
}
-istream_t *istream_open_stdin(void)
+istream_t *istream_open_file(const char *path)
{
- file_istream_t *file = calloc(1, sizeof(*file));
- istream_t *strm = (istream_t *)file;
+ WCHAR *wpath = path_to_windows(path);
+ istream_t *out;
+ HANDLE hnd;
- if (file == NULL) {
- perror("stdin");
+ if (wpath == NULL)
+ return NULL;
+
+ hnd = CreateFileW(wpath, GENERIC_READ, FILE_SHARE_READ, NULL,
+ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+
+ if (hnd == INVALID_HANDLE_VALUE) {
+ w32_perror(path);
+ free(wpath);
return NULL;
}
- sqfs_object_init(file, file_destroy, NULL);
+ free(wpath);
- strm->get_buffered_data = file_get_buffered_data;
- strm->advance_buffer = file_advance_buffer;
- strm->get_filename = file_get_filename;
- return strm;
+ out = istream_open_handle(path, hnd);
+ if (out == NULL)
+ CloseHandle(hnd);
+
+ return out;
+}
+
+istream_t *istream_open_stdin(void)
+{
+ HANDLE hnd = GetStdHandle(STD_INPUT_HANDLE);
+
+ return istream_open_handle("stdin", hnd);
}
diff --git a/lib/io/src/win32/ostream.c b/lib/io/src/win32/ostream.c
index 0fe04f3..d18130f 100644
--- a/lib/io/src/win32/ostream.c
+++ b/lib/io/src/win32/ostream.c
@@ -15,14 +15,14 @@ typedef struct {
HANDLE hnd;
} file_ostream_t;
-static int w32_append(HANDLE hnd, const char *filename,
- const void *data, size_t size)
+static int file_append(ostream_t *strm, const void *data, size_t size)
{
+ file_ostream_t *file = (file_ostream_t *)strm;
DWORD diff;
while (size > 0) {
- if (!WriteFile(hnd, data, size, &diff, NULL)) {
- w32_perror(filename);
+ if (!WriteFile(file->hnd, data, size, &diff, NULL)) {
+ w32_perror(file->path);
return -1;
}
@@ -33,25 +33,6 @@ static int w32_append(HANDLE hnd, const char *filename,
return 0;
}
-static int w32_flush(HANDLE hnd, const char *filename)
-{
- if (!FlushFileBuffers(hnd)) {
- w32_perror(filename);
- return -1;
- }
-
- return 0;
-}
-
-/*****************************************************************************/
-
-static int file_append(ostream_t *strm, const void *data, size_t size)
-{
- file_ostream_t *file = (file_ostream_t *)strm;
-
- return w32_append(file->hnd, file->path, data, size);
-}
-
static int file_append_sparse(ostream_t *strm, size_t size)
{
file_ostream_t *file = (file_ostream_t *)strm;
@@ -75,7 +56,12 @@ static int file_flush(ostream_t *strm)
{
file_ostream_t *file = (file_ostream_t *)strm;
- return w32_flush(file->hnd, file->path);
+ if (!FlushFileBuffers(file->hnd)) {
+ w32_perror(file->path);
+ return -1;
+ }
+
+ return 0;
}
static void file_destroy(sqfs_object_t *obj)
@@ -94,41 +80,11 @@ static const char *file_get_filename(ostream_t *strm)
return file->path;
}
-/*****************************************************************************/
-
-static int stdout_append(ostream_t *strm, const void *data, size_t size)
-{
- (void)strm;
- return w32_append(GetStdHandle(STD_OUTPUT_HANDLE), "stdout",
- data, size);
-}
-
-static int stdout_flush(ostream_t *strm)
-{
- (void)strm;
- return w32_flush(GetStdHandle(STD_OUTPUT_HANDLE), "stdout");
-}
-
-static void stdout_destroy(sqfs_object_t *obj)
-{
- free(obj);
-}
-
-static const char *stdout_get_filename(ostream_t *strm)
-{
- (void)strm;
- return "stdout";
-}
-
-/*****************************************************************************/
-
-ostream_t *ostream_open_file(const char *path, int flags)
+ostream_t *ostream_open_handle(const char *path, HANDLE hnd, int flags)
{
file_ostream_t *file = calloc(1, sizeof(*file));
- sqfs_object_t *obj = (sqfs_object_t *)file;
ostream_t *strm = (ostream_t *)file;
- int access_flags, creation_mode;
- WCHAR *wpath = NULL;
+ BOOL ret;
if (file == NULL) {
perror(path);
@@ -137,33 +93,21 @@ ostream_t *ostream_open_file(const char *path, int flags)
sqfs_object_init(file, file_destroy, NULL);
- wpath = path_to_windows(path);
- if (wpath == NULL)
- goto fail_free;
-
file->path = strdup(path);
if (file->path == NULL) {
perror(path);
goto fail_free;
}
- access_flags = GENERIC_WRITE;
-
- if (flags & OSTREAM_OPEN_OVERWRITE) {
- creation_mode = CREATE_ALWAYS;
- } else {
- creation_mode = CREATE_NEW;
- }
-
- file->hnd = CreateFileW(wpath, access_flags, 0, NULL, creation_mode,
- FILE_ATTRIBUTE_NORMAL, NULL);
-
- if (file->hnd == INVALID_HANDLE_VALUE) {
+ ret = DuplicateHandle(GetCurrentProcess(), hnd,
+ GetCurrentProcess(), &file->hnd,
+ 0, FALSE, DUPLICATE_SAME_ACCESS);
+ if (!ret) {
w32_perror(path);
goto fail_path;
}
- free(wpath);
+ CloseHandle(hnd);
if (flags & OSTREAM_OPEN_SPARSE)
strm->append_sparse = file_append_sparse;
@@ -176,24 +120,48 @@ fail_path:
free(file->path);
fail_free:
free(file);
- free(wpath);
return NULL;
}
-ostream_t *ostream_open_stdout(void)
+ostream_t *ostream_open_file(const char *path, int flags)
{
- ostream_t *strm = calloc(1, sizeof(*strm));
- sqfs_object_t *obj = (sqfs_object_t *)strm;
+ WCHAR *wpath = path_to_windows(path);
+ int access_flags, creation_mode;
+ ostream_t *out;
+ HANDLE hnd;
- if (strm == NULL) {
- perror("creating stdout file wrapper");
+ if (wpath == NULL)
return NULL;
+
+ access_flags = GENERIC_WRITE;
+
+ if (flags & OSTREAM_OPEN_OVERWRITE) {
+ creation_mode = CREATE_ALWAYS;
+ } else {
+ creation_mode = CREATE_NEW;
}
- sqfs_object_init(strm, stdout_destroy, NULL);
+ hnd = CreateFileW(wpath, access_flags, 0, NULL, creation_mode,
+ FILE_ATTRIBUTE_NORMAL, NULL);
- strm->append = stdout_append;
- strm->flush = stdout_flush;
- strm->get_filename = stdout_get_filename;
- return strm;
+ if (hnd == INVALID_HANDLE_VALUE) {
+ w32_perror(path);
+ free(wpath);
+ return NULL;
+ }
+
+ free(wpath);
+
+ out = ostream_open_handle(path, hnd, flags);
+ if (out == NULL)
+ CloseHandle(hnd);
+
+ return out;
+}
+
+ostream_t *ostream_open_stdout(void)
+{
+ HANDLE hnd = GetStdHandle(STD_OUTPUT_HANDLE);
+
+ return ostream_open_handle("stdout", hnd, 0);
}