From: Andreas Schneider Date: Mon, 10 Sep 2018 13:20:03 +0000 (+0200) Subject: util: Add file tree walk interface X-Git-Tag: ldb-1.6.1~306 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=7abf1d03394fb7a97b2f8ca58c95ab1916c7583f;p=thirdparty%2Fsamba.git util: Add file tree walk interface Add tftw() utility to emulate nftw() behavior with a userdata pointer. This is repurposed from the csync project custom file tree walker. Signed-off-by: Justin Stephenson Reviewed-by: Andreas Schneider Reviewed-by: Bjoern Jacke --- diff --git a/lib/util/tftw.c b/lib/util/tftw.c new file mode 100644 index 00000000000..c460e32be04 --- /dev/null +++ b/lib/util/tftw.c @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2008-2018 by Andreas Schneider + * + * Adopted from the csync source code + */ + +#include +#include +#include +#include +#include +#include +#include +#include "memory.h" +#include "debug.h" +#include "replace.h" +#include "system/locale.h" +#include "lib/util/asn1.h" +#include "lib/util/debug.h" +#include "lib/util/samba_util.h" + +#include "tftw.h" + + +int tftw(TALLOC_CTX *mem_ctx, const char *fpath, tftw_walker_fn fn, size_t depth, void *userdata) +{ + char *filename = NULL; + char *d_name = NULL; + DIR *dh = NULL; + struct dirent *dirent = NULL; + struct stat sb = {0}; + int rc = 0; + + if (fpath[0] == '\0') { + errno = ENOENT; + goto error; + } + + if ((dh = opendir(fpath)) == NULL) { + /* permission denied */ + if (errno == EACCES) { + return 0; + } else { + DBG_ERR("opendir failed for: [%s]\n", strerror(errno)); + goto error; + } + } + + while ((dirent = readdir(dh))) { + int flag; + + d_name = dirent->d_name; + if (d_name == NULL) { + goto error; + } + + /* skip "." and ".." */ + if (d_name[0] == '.' && (d_name[1] == '\0' + || (d_name[1] == '.' && d_name[2] == '\0'))) { + dirent = NULL; + continue; + } + + filename = talloc_asprintf(mem_ctx, "%s/%s", fpath, d_name); + if (filename == NULL) { + goto error; + } + + rc = lstat(filename, &sb); + if (rc < 0) { + dirent = NULL; + goto error; + } + + switch (sb.st_mode & S_IFMT) { + case S_IFLNK: + flag = TFTW_FLAG_SLINK; + break; + case S_IFDIR: + flag = TFTW_FLAG_DIR; + break; + case S_IFBLK: + case S_IFCHR: + case S_IFSOCK: + case S_IFIFO: + flag = TFTW_FLAG_SPEC; + break; + default: + flag = TFTW_FLAG_FILE; + break; + } + + DBG_INFO("walk: [%s]\n", filename); + + /* Call walker function for each file */ + rc = fn(mem_ctx, filename, &sb, flag, userdata); + + if (rc < 0) { + DBG_ERR("provided callback fn() failed: [%s]\n", + strerror(errno)); + closedir(dh); + goto done; + } + + if (flag == TFTW_FLAG_DIR && depth) { + rc = tftw(mem_ctx, filename, fn, depth - 1, userdata); + if (rc < 0) { + closedir(dh); + goto done; + } + } + TALLOC_FREE(filename); + dirent = NULL; + } + closedir(dh); + +done: + TALLOC_FREE(filename); + return rc; +error: + if (dh != NULL) { + closedir(dh); + } + TALLOC_FREE(filename); + return -1; +} diff --git a/lib/util/tftw.h b/lib/util/tftw.h new file mode 100644 index 00000000000..0d3d007ad3b --- /dev/null +++ b/lib/util/tftw.h @@ -0,0 +1,32 @@ +#include + +enum tftw_flags_e { + /* Regular file. */ + TFTW_FLAG_FILE, + /* Directory. */ + TFTW_FLAG_DIR, + /* Unreadable directory. */ + TFTW_FLAG_DNR, + /* Unstatable file. */ + TFTW_FLAG_NSTAT, + /* Symbolic link. */ + TFTW_FLAG_SLINK, + /* Special file (fifo, ...). */ + TFTW_FLAG_SPEC, + + /* Directory, all subdirs have been visited. */ + TFTW_FLAG_DP, + /* Symbolic link naming non-existing file. */ + TFTW_FLAG_SLN +}; + +/* Maximum number of subdirectories to descend into */ +#define TFTW_MAX_DEPTH 50 + +typedef int (*tftw_walker_fn)(TALLOC_CTX *mem_ctx, + const char *fpath, + const struct stat *sb, + enum tftw_flags_e flag, + void *userdata); + +int tftw(TALLOC_CTX *mem_ctx, const char *fpath, tftw_walker_fn fn, size_t depth, void *userdata); diff --git a/lib/util/wscript_build b/lib/util/wscript_build index 8fc402062fb..883c1dd5b29 100644 --- a/lib/util/wscript_build +++ b/lib/util/wscript_build @@ -123,7 +123,8 @@ else: idtree_random.c base64.c util_str.c util_str_common.c ms_fnmatch.c server_id.c dprintf.c - tevent_debug.c memcache.c unix_match.c tfork.c''', + tevent_debug.c memcache.c unix_match.c tfork.c + tftw.c''', deps='samba-util-core DYNCONFIG close-low-fd tiniparser genrand util_str_hex', public_deps='talloc tevent execinfo pthread LIBCRYPTO charset util_setid', public_headers='debug.h attr.h byteorder.h data_blob.h memory.h safe_string.h time.h talloc_stack.h string_wrappers.h idtree.h idtree_random.h blocking.h signal.h substitute.h fault.h genrand.h tfork.h',