aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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);
}