From a7bf75ebdb991092dd9165db99acfa034166fb43 Mon Sep 17 00:00:00 2001 From: David Oberhollenzer Date: Sat, 15 Jul 2023 13:33:51 +0200 Subject: Implement pen_file_ro method in native dir iterators Signed-off-by: David Oberhollenzer --- lib/io/src/unix/dir_iterator.c | 26 +++++++++++++++-- lib/io/src/win32/dir_iterator.c | 62 +++++++++++++++++++++++++++++++++++++++-- 2 files changed, 83 insertions(+), 5 deletions(-) (limited to 'lib/io/src') diff --git a/lib/io/src/unix/dir_iterator.c b/lib/io/src/unix/dir_iterator.c index 12e2ac1..d2ae011 100644 --- a/lib/io/src/unix/dir_iterator.c +++ b/lib/io/src/unix/dir_iterator.c @@ -8,6 +8,7 @@ #include "io/dir_iterator.h" #include "util/util.h" #include "sqfs/error.h" +#include "sqfs/io.h" #include #include @@ -126,11 +127,30 @@ static void dir_ignore_subdir(dir_iterator_t *it) (void)it; } -static int dir_open_file_ro(dir_iterator_t *it, sqfs_istream_t **out) +static int dir_open_file_ro(dir_iterator_t *base, sqfs_istream_t **out) { - (void)it; + unix_dir_iterator_t *it = (unix_dir_iterator_t *)base; + int fd, ret; + *out = NULL; - return SQFS_ERROR_UNSUPPORTED; + if (it->state < 0) + return it->state; + + if (it->state > 0 || it->ent == NULL) + return SQFS_ERROR_NO_ENTRY; + + fd = openat(dirfd(it->dir), it->ent->d_name, O_RDONLY); + if (fd < 0) + return SQFS_ERROR_IO; + + ret = sqfs_istream_open_handle(out, it->ent->d_name, + fd, SQFS_FILE_OPEN_READ_ONLY); + if (ret != 0) { + int err = errno; + close(fd); + errno = err; + } + return ret; } static int dir_read_xattr(dir_iterator_t *it, sqfs_xattr_t **out) diff --git a/lib/io/src/win32/dir_iterator.c b/lib/io/src/win32/dir_iterator.c index d9e5b7c..f66e323 100644 --- a/lib/io/src/win32/dir_iterator.c +++ b/lib/io/src/win32/dir_iterator.c @@ -8,6 +8,7 @@ #include "io/dir_iterator.h" #include "util/util.h" #include "sqfs/error.h" +#include "sqfs/io.h" #include #include @@ -121,9 +122,66 @@ static void dir_iterator_ignore_subdir(dir_iterator_t *it) static int dir_iterator_open_file_ro(dir_iterator_t *it, sqfs_istream_t **out) { - (void)it; + dir_iterator_win32_t *dir = (dir_iterator_win32_t *)it; + size_t plen, slen; + os_error_t err; + WCHAR *str16; + DWORD length; + HANDLE hnd; + char *str8; + int ret; + *out = NULL; - return SQFS_ERROR_UNSUPPORTED; + + if (dir->state != 0) + return (dir->state > 0) ? SQFS_ERROR_NO_ENTRY : dir->state; + + plen = wcslen(dir->path) - 1; + slen = wcslen(dir->ent.cFileName); + + str16 = calloc(plen + slen + 1, sizeof(WCHAR)); + if (str16 == NULL) + return SQFS_ERROR_ALLOC; + + memcpy(str16, dir->path, plen * sizeof(WCHAR)); + memcpy(str16 + plen, dir->ent.cFileName, slen * sizeof(WCHAR)); + + hnd = CreateFileW(str16, GENERIC_READ, FILE_SHARE_READ, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, + NULL); + + err = get_os_error_state(); + free(str16); + set_os_error_state(err); + + if (hnd == INVALID_HANDLE_VALUE) + return SQFS_ERROR_IO; + + length = WideCharToMultiByte(CP_UTF8, 0, dir->ent.cFileName, + -1, NULL, 0, NULL, NULL); + if (length <= 0) { + CloseHandle(hnd); + return SQFS_ERROR_ALLOC; + } + + str8 = calloc(1, length + 1); + if (str8 == NULL) { + CloseHandle(hnd); + return SQFS_ERROR_ALLOC; + } + + WideCharToMultiByte(CP_UTF8, 0, dir->ent.cFileName, -1, str8, + length + 1, NULL, NULL); + + ret = sqfs_istream_open_handle(out, str8, hnd, + SQFS_FILE_OPEN_READ_ONLY); + err = get_os_error_state(); + free(str8); + if (ret != 0) + CloseHandle(hnd); + set_os_error_state(err); + + return ret; } static int dir_iterator_read_xattr(dir_iterator_t *it, sqfs_xattr_t **out) -- cgit v1.2.3