diff options
author | David Oberhollenzer <david.oberhollenzer@sigma-star.at> | 2023-04-21 19:53:57 +0200 |
---|---|---|
committer | David Oberhollenzer <david.oberhollenzer@sigma-star.at> | 2023-04-21 20:16:46 +0200 |
commit | 73d342861a03c38528ca5f97cdd479b4fdb5b3fd (patch) | |
tree | 00cecdb98b09dfa4b61e4c055a4bf75a15edfa9d /lib/util/src | |
parent | f8270c05898313a8e75c367172958335dbec4a36 (diff) |
libutil: Add a method to the directory iterator to open a sub directory
This is also the reason we need to lug around the original directory
path on Windows.
Signed-off-by: David Oberhollenzer <david.oberhollenzer@sigma-star.at>
Diffstat (limited to 'lib/util/src')
-rw-r--r-- | lib/util/src/unix_dir_iterator.c | 49 | ||||
-rw-r--r-- | lib/util/src/w32_dir_iterator.c | 46 |
2 files changed, 95 insertions, 0 deletions
diff --git a/lib/util/src/unix_dir_iterator.c b/lib/util/src/unix_dir_iterator.c index 69a4251..ae878a2 100644 --- a/lib/util/src/unix_dir_iterator.c +++ b/lib/util/src/unix_dir_iterator.c @@ -136,6 +136,54 @@ static int dir_next(dir_iterator_t *base, dir_entry_t **out) return it->state; } +static int dir_open_subdir(dir_iterator_t *base, dir_iterator_t **out) +{ + const unix_dir_iterator_t *it = (const unix_dir_iterator_t *)base; + unix_dir_iterator_t *sub = NULL; + int fd; + + *out = NULL; + + 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 | O_DIRECTORY); + if (fd < 0) { + if (errno == ENOTDIR) + return SQFS_ERROR_NOT_DIR; + return SQFS_ERROR_IO; + } + + sub = calloc(1, sizeof(*sub)); + if (sub == NULL) + goto fail_alloc; + + sub->dir = fdopendir(fd); + if (sub->dir == NULL) + goto fail_alloc; + + if (fstat(dirfd(sub->dir), &sub->sb)) { + free(sub); + return SQFS_ERROR_IO; + } + + sqfs_object_init(sub, dir_destroy, NULL); + ((dir_iterator_t *)sub)->dev = sub->sb.st_dev; + ((dir_iterator_t *)sub)->next = dir_next; + ((dir_iterator_t *)sub)->read_link = dir_read_link; + ((dir_iterator_t *)sub)->open_subdir = dir_open_subdir; + + *out = (dir_iterator_t *)sub; + return 0; +fail_alloc: + free(sub); + close(fd); + return SQFS_ERROR_ALLOC; +} + dir_iterator_t *dir_iterator_create(const char *path) { unix_dir_iterator_t *it = calloc(1, sizeof(*it)); @@ -165,6 +213,7 @@ dir_iterator_t *dir_iterator_create(const char *path) ((dir_iterator_t *)it)->dev = it->sb.st_dev; ((dir_iterator_t *)it)->next = dir_next; ((dir_iterator_t *)it)->read_link = dir_read_link; + ((dir_iterator_t *)it)->open_subdir = dir_open_subdir; return (dir_iterator_t *)it; } diff --git a/lib/util/src/w32_dir_iterator.c b/lib/util/src/w32_dir_iterator.c index 5400975..f931a26 100644 --- a/lib/util/src/w32_dir_iterator.c +++ b/lib/util/src/w32_dir_iterator.c @@ -107,6 +107,51 @@ static void dir_iterator_destroy(sqfs_object_t *obj) free(dir); } +static int dir_iterator_open_subdir(dir_iterator_t *it, dir_iterator_t **out) +{ + const dir_iterator_win32_t *dir = (const dir_iterator_win32_t *)it; + dir_iterator_win32_t *sub = NULL; + size_t plen, slen, total; + + *out = NULL; + + if (dir->state != 0) + return (dir->state > 0) ? SQFS_ERROR_NO_ENTRY : dir->state; + + if (!(dir->ent.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) + return SQFS_ERROR_NOT_DIR; + + plen = wcslen(dir->path) - 1; + slen = wcslen(dir->ent.cFileName); + total = plen + slen + 3; + + sub = alloc_flex(sizeof(*sub), sizeof(WCHAR), total); + if (sub == NULL) + return SQFS_ERROR_ALLOC; + + memcpy(sub->path, dir->path, plen * sizeof(WCHAR)); + memcpy(sub->path + plen, dir->ent.cFileName, slen * sizeof(WCHAR)); + sub->path[plen + slen ] = '\\'; + sub->path[plen + slen + 1] = '*'; + sub->path[plen + slen + 2] = '\0'; + + sqfs_object_init(sub, dir_iterator_destroy, NULL); + ((dir_iterator_t *)sub)->next = dir_iterator_next; + ((dir_iterator_t *)sub)->read_link = dir_iterator_read_link; + ((dir_iterator_t *)sub)->open_subdir = dir_iterator_open_subdir; + sub->is_first = true; + sub->state = 0; + + sub->dirhnd = FindFirstFileW(sub->path, &sub->ent); + if (sub->dirhnd == INVALID_HANDLE_VALUE) { + free(sub); + return SQFS_ERROR_IO; + } + + *out = (dir_iterator_t *)sub; + return 0; +} + dir_iterator_t *dir_iterator_create(const char *path) { dir_iterator_win32_t *it; @@ -152,6 +197,7 @@ dir_iterator_t *dir_iterator_create(const char *path) ((dir_iterator_t *)it)->next = dir_iterator_next; ((dir_iterator_t *)it)->read_link = dir_iterator_read_link; + ((dir_iterator_t *)it)->open_subdir = dir_iterator_open_subdir; it->is_first = true; it->state = 0; |