]> git.ipfire.org Git - thirdparty/coreutils.git/commitdiff
.
authorJim Meyering <jim@meyering.net>
Fri, 3 Jan 2003 19:30:29 +0000 (19:30 +0000)
committerJim Meyering <jim@meyering.net>
Fri, 3 Jan 2003 19:30:29 +0000 (19:30 +0000)
lib/cycle-check.c [new file with mode: 0644]
lib/cycle-check.h [new file with mode: 0644]
lib/dev-ino.h [new file with mode: 0644]

diff --git a/lib/cycle-check.c b/lib/cycle-check.c
new file mode 100644 (file)
index 0000000..403dc16
--- /dev/null
@@ -0,0 +1,63 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <assert.h>
+#include <stdlib.h>
+
+#if HAVE_STDBOOL_H
+# include <stdbool.h>
+#else
+typedef enum {false = 0, true = 1} bool;
+#endif
+
+#include "cycle-check.h"
+#include "xalloc.h"
+
+#define SAME_INODE(Stat_buf_1, Stat_buf_2) \
+  ((Stat_buf_1).st_ino == (Stat_buf_2).st_ino \
+   && (Stat_buf_1).st_dev == (Stat_buf_2).st_dev)
+
+#define CC_MAGIC 9827862
+
+static inline bool
+is_power_of_two (unsigned int i)
+{
+  return (i & (i - 1)) == 0;
+}
+
+void
+cycle_check_init (struct cycle_check_state *state)
+{
+  state->chdir_counter = 0;
+  state->magic = CC_MAGIC;
+}
+
+/* In traversing a directory hierarchy, call this function once for each
+   descending chdir call, with SB corresponding to the chdir operand.
+   If SB corresponds to a directory that has already been seen,
+   return true to indicate that there is a directory cycle.
+   Note that this is done `lazily', which means that some of
+   the directories in the cycle may be processed twice before
+   the cycle is detected.  */
+
+bool
+cycle_check (struct cycle_check_state *state, struct stat const *sb)
+{
+  assert (state->magic == CC_MAGIC);
+
+  /* If the current directory ever happens to be the same
+     as the one we last recorded for the cycle detection,
+     then it's obviously part of a cycle.  */
+  if (state->chdir_counter && SAME_INODE (*sb, state->dev_ino))
+    return true;
+
+  /* If the number of `descending' chdir calls is a power of two,
+     record the dev/ino of the current directory.  */
+  if (is_power_of_two (++(state->chdir_counter)))
+    {
+      state->dev_ino.st_dev = sb->st_dev;
+      state->dev_ino.st_ino = sb->st_ino;
+    }
+
+  return false;
+}
diff --git a/lib/cycle-check.h b/lib/cycle-check.h
new file mode 100644 (file)
index 0000000..6f8c55d
--- /dev/null
@@ -0,0 +1,33 @@
+#ifndef CYCLE_CHECK_H
+# define CYCLE_CHECK_H 1
+
+/* Before including this file, you need something like the following:
+
+       #if HAVE_CONFIG_H
+       # include <config.h>
+       #endif
+
+       #include <sys/types.h>
+       #include <sys/stat.h>
+
+       #if HAVE_STDBOOL_H
+       # include <stdbool.h>
+       #else
+       typedef enum {false = 0, true = 1} bool;
+       #endif
+
+   so that the proper identifiers are all declared.  */
+
+# include "dev-ino.h"
+
+struct cycle_check_state
+{
+  struct dev_ino dev_ino;
+  size_t chdir_counter;
+  long unsigned int magic;
+};
+
+void cycle_check_init (struct cycle_check_state *state);
+bool cycle_check (struct cycle_check_state *state, struct stat const *sb);
+
+#endif
diff --git a/lib/dev-ino.h b/lib/dev-ino.h
new file mode 100644 (file)
index 0000000..79cc520
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef DEV_INO_H
+# define DEV_INO_H 1
+
+struct dev_ino
+{
+  ino_t st_ino;
+  dev_t st_dev;
+};
+
+#endif