aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/io/src/unix/dir_iterator.c26
-rw-r--r--lib/io/src/win32/dir_iterator.c62
-rw-r--r--lib/io/test/dir_iterator.c47
-rw-r--r--lib/io/test/testdir/dirc/file_c01
-rw-r--r--lib/io/test/testdir/dirc/file_c21
5 files changed, 131 insertions, 6 deletions
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 <sys/stat.h>
#include <stdlib.h>
@@ -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 <windows.h>
#include <stdlib.h>
@@ -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)
diff --git a/lib/io/test/dir_iterator.c b/lib/io/test/dir_iterator.c
index 1f04b96..48a57ec 100644
--- a/lib/io/test/dir_iterator.c
+++ b/lib/io/test/dir_iterator.c
@@ -9,6 +9,7 @@
#include "io/dir_iterator.h"
#include "sqfs/error.h"
#include "util/test.h"
+#include "sqfs/io.h"
#include "compat.h"
static int compare_entries(const void *a, const void *b)
@@ -19,11 +20,22 @@ static int compare_entries(const void *a, const void *b)
return strcmp((*lhs)->name, (*rhs)->name);
}
+static int compare_files(const void *a, const void *b)
+{
+ const sqfs_istream_t *const *lhs = a;
+ const sqfs_istream_t *const *rhs = b;
+
+ return strcmp((*lhs)->get_filename(*lhs),
+ (*rhs)->get_filename(*rhs));
+}
+
int main(int argc, char **argv)
{
dir_iterator_t *dir, *suba, *subb, *subc, *sub;
sqfs_dir_entry_t *dent, *ent[6];
- size_t i;
+ sqfs_istream_t *files[3];
+ char buffer[128];
+ size_t i, j;
int ret;
(void)argc; (void)argv;
@@ -330,6 +342,8 @@ int main(int argc, char **argv)
free(ent[i]);
/* sub iterator c */
+ j = 0;
+
for (i = 0; i < 5; ++i) {
ret = subc->next(subc, &ent[i]);
TEST_NOT_NULL(ent[0]);
@@ -339,15 +353,22 @@ int main(int argc, char **argv)
ret = subc->open_subdir(subc, &sub);
TEST_NULL(sub);
TEST_EQUAL_I(ret, SQFS_ERROR_NOT_DIR);
+
+ TEST_ASSERT(j < 3);
+ ret = subc->open_file_ro(subc, &(files[j++]));
+ TEST_EQUAL_I(ret, 0);
}
}
+ TEST_EQUAL_UI(j, 3);
+
ret = subc->next(subc, &dent);
TEST_NULL(dent);
TEST_ASSERT(ret > 0);
subc = sqfs_drop(subc);
qsort(ent, 5, sizeof(ent[0]), compare_entries);
+ qsort(files, 3, sizeof(files[0]), compare_files);
TEST_STR_EQUAL(ent[0]->name, ".");
TEST_ASSERT(S_ISDIR(ent[0]->mode));
@@ -363,5 +384,29 @@ int main(int argc, char **argv)
for (i = 0; i < 5; ++i)
free(ent[i]);
+ TEST_STR_EQUAL(files[0]->get_filename(files[0]), "file_c0");
+ TEST_STR_EQUAL(files[1]->get_filename(files[1]), "file_c1");
+ TEST_STR_EQUAL(files[2]->get_filename(files[2]), "file_c2");
+
+ ret = sqfs_istream_read(files[0], buffer, sizeof(buffer));
+ TEST_EQUAL_I(ret, 12);
+ buffer[ret] = '\0';
+ TEST_STR_EQUAL(buffer, "test string\n");
+ ret = sqfs_istream_read(files[0], buffer, sizeof(buffer));
+ TEST_EQUAL_I(ret, 0);
+
+ ret = sqfs_istream_read(files[1], buffer, sizeof(buffer));
+ TEST_EQUAL_I(ret, 0);
+
+ ret = sqfs_istream_read(files[2], buffer, sizeof(buffer));
+ TEST_EQUAL_I(ret, 10);
+ buffer[ret] = '\0';
+ TEST_STR_EQUAL(buffer, "你好!\n");
+ ret = sqfs_istream_read(files[2], buffer, sizeof(buffer));
+ TEST_EQUAL_I(ret, 0);
+
+ for (i = 0; i < j; ++i)
+ sqfs_drop(files[i]);
+
return EXIT_SUCCESS;
}
diff --git a/lib/io/test/testdir/dirc/file_c0 b/lib/io/test/testdir/dirc/file_c0
index e69de29..71c1922 100644
--- a/lib/io/test/testdir/dirc/file_c0
+++ b/lib/io/test/testdir/dirc/file_c0
@@ -0,0 +1 @@
+test string
diff --git a/lib/io/test/testdir/dirc/file_c2 b/lib/io/test/testdir/dirc/file_c2
index e69de29..efde6ef 100644
--- a/lib/io/test/testdir/dirc/file_c2
+++ b/lib/io/test/testdir/dirc/file_c2
@@ -0,0 +1 @@
+你好!