summary refs log tree commit diff
path: root/io/ftw.c
diff options
context:
space:
mode:
Diffstat (limited to 'io/ftw.c')
-rw-r--r--io/ftw.c216
1 files changed, 216 insertions, 0 deletions
diff --git a/io/ftw.c b/io/ftw.c
new file mode 100644
index 0000000000..7b264e032e
--- /dev/null
+++ b/io/ftw.c
@@ -0,0 +1,216 @@
+/* Copyright (C) 1992, 1995 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+Contributed by Ian Lance Taylor (ian@airs.com).
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#include <ansidecl.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dirent.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <ftw.h>
+
+
+#ifndef PATH_MAX
+#define PATH_MAX 1024		/* XXX */
+#endif
+
+
+/* Traverse one level of a directory tree.  */
+
+static int
+DEFUN (ftw_dir, (dirs, level, descriptors, dir, len, func),
+       DIR **dirs AND int level AND int descriptors AND
+       char *dir AND size_t len AND
+       int EXFUN((*func), (CONST char *file, struct stat *status,
+			   int flag)))
+{
+  int got;
+  struct dirent *entry;
+
+  got = 0;
+
+  errno = 0;
+
+  while ((entry = readdir (dirs[level])) != NULL)
+    {
+      struct stat s;
+      int flag, retval, newlev;
+
+      ++got;
+
+      if (entry->d_name[0] == '.'
+	  && (entry->d_namlen == 1 ||
+	      (entry->d_namlen == 2 && entry->d_name[1] == '.')))
+	{
+	  errno = 0;
+	  continue;
+	}
+
+      if (entry->d_namlen + len + 1 > PATH_MAX)
+	{
+#ifdef ENAMETOOLONG
+	  errno = ENAMETOOLONG;
+#else
+	  errno = ENOMEM;
+#endif
+	  return -1;
+	}
+
+      dir[len] = '/';
+      memcpy ((PTR) (dir + len + 1), (PTR) entry->d_name,
+	      entry->d_namlen + 1);
+
+      if (stat (dir, &s) < 0)
+	{
+	  if (errno != EACCES && errno != ENOENT)
+	    return -1;
+	  flag = FTW_NS;
+	}
+      else if (S_ISDIR (s.st_mode))
+	{
+	  newlev = (level + 1) % descriptors;
+
+	  if (dirs[newlev] != NULL)
+	    closedir (dirs[newlev]);
+
+	  dirs[newlev] = opendir (dir);
+	  if (dirs[newlev] != NULL)
+	    flag = FTW_D;
+	  else
+	    {
+	      if (errno != EACCES)
+		return -1;
+	      flag = FTW_DNR;
+	    }
+	}
+      else
+	flag = FTW_F;
+
+      retval = (*func) (dir, &s, flag);
+
+      if (flag == FTW_D)
+	{
+	  if (retval == 0)
+	    retval = ftw_dir (dirs, newlev, descriptors, dir,
+			      entry->d_namlen + len + 1, func);
+	  if (dirs[newlev] != NULL)
+	    {
+	      int save;
+
+	      save = errno;
+	      closedir (dirs[newlev]);
+	      errno = save;
+	      dirs[newlev] = NULL;
+	    }
+	}
+
+      if (retval != 0)
+	return retval;
+
+      if (dirs[level] == NULL)
+	{
+	  int skip;
+
+	  dir[len] = '\0';
+	  dirs[level] = opendir (dir);
+	  if (dirs[level] == NULL)
+	    return -1;
+	  skip = got;
+	  while (skip-- != 0)
+	    {
+	      errno = 0;
+	      if (readdir (dirs[level]) == NULL)
+		return errno == 0 ? 0 : -1;
+	    }
+	}
+
+      errno = 0;
+    }
+
+  return errno == 0 ? 0 : -1;
+}
+
+/* Call a function on every element in a directory tree.  */
+
+int
+DEFUN(ftw, (dir, func, descriptors),
+      CONST char *dir AND
+      int EXFUN((*func), (CONST char *file, struct stat *status,
+			  int flag)) AND
+      int descriptors)
+{
+  DIR **dirs;
+  size_t len;
+  char buf[PATH_MAX + 1];
+  struct stat s;
+  int flag, retval;
+  int i;
+
+  if (descriptors <= 0)
+    descriptors = 1;
+
+  dirs = (DIR **) __alloca (descriptors * sizeof (DIR *));
+  i = descriptors;
+  while (i-- > 0)
+    dirs[i] = NULL;
+
+  if (stat (dir, &s) < 0)
+    {
+      if (errno != EACCES && errno != ENOENT)
+	return -1;
+      flag = FTW_NS;
+    }
+  else if (S_ISDIR (s.st_mode))
+    {
+      dirs[0] = opendir (dir);
+      if (dirs[0] != NULL)
+	flag = FTW_D;
+      else
+	{
+	  if (errno != EACCES)
+	    return -1;
+	  flag = FTW_DNR;
+	}
+    }
+  else
+    flag = FTW_F;
+
+  len = strlen (dir);
+  memcpy ((PTR) buf, (PTR) dir, len + 1);
+
+  retval = (*func) (buf, &s, flag);
+
+  if (flag == FTW_D)
+    {
+      if (retval == 0)
+	retval = ftw_dir (dirs, 0, descriptors, buf, len, func);
+      if (dirs[0] != NULL)
+	{
+	  int save;
+
+	  save = errno;
+	  closedir (dirs[0]);
+	  errno = save;
+	}
+    }
+
+  return retval;
+}