util: Add file tree walk interface
authorAndreas Schneider <asn@samba.org>
Mon, 10 Sep 2018 13:20:03 +0000 (15:20 +0200)
committerBjoern Jacke <bjacke@samba.org>
Mon, 28 Jan 2019 14:44:18 +0000 (15:44 +0100)
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 <jstephen@redhat.com>
Reviewed-by: Andreas Schneider <asn@samba.org>
Reviewed-by: Bjoern Jacke <bjacke@samba.org>
lib/util/tftw.c [new file with mode: 0644]
lib/util/tftw.h [new file with mode: 0644]
lib/util/wscript_build

diff --git a/lib/util/tftw.c b/lib/util/tftw.c
new file mode 100644 (file)
index 0000000..c460e32
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2008-2018 by Andreas Schneider <asn@samba.org>
+ *
+ * Adopted from the csync source code
+ */
+
+#include <errno.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#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 (file)
index 0000000..0d3d007
--- /dev/null
@@ -0,0 +1,32 @@
+#include <talloc.h>
+
+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);
index 8fc402062fbdf8cefbd44d67dc050a2884b86b49..883c1dd5b29ea13b9954cccdcc2fee3ea815b37c 100644 (file)
@@ -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',