/* * Copyright (c) 2025 Jiri Svoboda * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** @addtogroup fmgt * @{ */ /** @file File system tree walker. */ #include #include #include #include #include #include #include #include #include #include "fmgt.h" #include "fmgt/walk.h" static errno_t fmgt_walk_subtree(fmgt_walk_params_t *, const char *); /** Initialize walk parameters. * * Every walk parameters structure must be initialized first using this * function. * * @param params Pointer to walk parameters structure. */ void fmgt_walk_params_init(fmgt_walk_params_t *params) { memset(params, 0, sizeof(fmgt_walk_params_t)); } /** Walk file (invoke file callback). * * @param params Walk parameters * @param fname File path * * @return EOK on success or an error code */ static errno_t fmgt_walk_file(fmgt_walk_params_t *params, const char *fname) { if (params->cb->file != NULL) return params->cb->file(params->arg, fname); else return EOK; } /** Enter directory (invoke directory entry callback). * * @param params Walk parameters * @param dname Directory path * @return EOK on success or an error code */ static errno_t fmgt_walk_dir_enter(fmgt_walk_params_t *params, const char *dname) { if (params->cb->dir_enter != NULL) return params->cb->dir_enter(params->arg, dname); else return EOK; } /** Leave directory (invoke directory exit callback). * * @param params Walk parameters * @param dname Directory path * @return EOK on success or an error code */ static errno_t fmgt_walk_dir_leave(fmgt_walk_params_t *params, const char *dname) { if (params->cb->dir_enter != NULL) return params->cb->dir_leave(params->arg, dname); else return EOK; } /** Walk directory. * * @param params Walk parameters * @param dname Directory name * @return EOK on success or an error code */ static errno_t fmgt_walk_dir(fmgt_walk_params_t *params, const char *dname) { DIR *dir = NULL; struct dirent *de; errno_t rc; char *pathname = NULL; int rv; rc = fmgt_walk_dir_enter(params, dname); if (rc != EOK) goto error; dir = opendir(dname); if (dir == NULL) { rc = EIO; goto error; } de = readdir(dir); while (de != NULL) { rv = asprintf(&pathname, "%s/%s", dname, de->d_name); if (rv < 0) { rc = ENOMEM; goto error; } rc = fmgt_walk_subtree(params, pathname); if (rc != EOK) { free(pathname); goto error; } free(pathname); de = readdir(dir); } rc = fmgt_walk_dir_leave(params, dname); if (rc != EOK) return rc; closedir(dir); return EOK; error: if (dir != NULL) closedir(dir); return rc; } /** Walk subtree. * * @params params Walk parameters. * @params fname Subtree path. * * @return EOK on success or an error code. */ static errno_t fmgt_walk_subtree(fmgt_walk_params_t *params, const char *fname) { vfs_stat_t stat; errno_t rc; rc = vfs_stat_path(fname, &stat); if (rc != EOK) return rc; if (stat.is_directory) { /* Directory */ rc = fmgt_walk_dir(params, fname); if (rc != EOK) return rc; } else { /* Not a directory */ rc = fmgt_walk_file(params, fname); if (rc != EOK) return rc; } return EOK; } /** Perform a file system walk. * * Walks the list of files/directories in @a params->flist. Directories * are walked recursively. Callbacks are involved for each file, directory, * if defined.in @a params->cb, the callback argument is @a params->arg. * * @param params Walk parameters * @return EOK on success or an error code. */ errno_t fmgt_walk(fmgt_walk_params_t *params) { fmgt_flist_entry_t *entry; errno_t rc; entry = fmgt_flist_first(params->flist); while (entry != NULL) { rc = fmgt_walk_subtree(params, entry->fname); if (rc != EOK) return rc; entry = fmgt_flist_next(entry); } return EOK; } /** @} */