summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJim Meyering <jim@meyering.net>2003-01-03 19:30:29 +0000
committerJim Meyering <jim@meyering.net>2003-01-03 19:30:29 +0000
commitfab52f550d008951a2c8b78a9fe3f2dd4e30c3ea (patch)
treec2b3f0f7e8c7217318f0817d52d809b1bef43486
parent5ed7d34ed841aa0a04d5f5d721aab0c53b3ef5f8 (diff)
downloadcoreutils-fab52f550d008951a2c8b78a9fe3f2dd4e30c3ea.tar.xz
.
-rw-r--r--lib/cycle-check.c63
-rw-r--r--lib/cycle-check.h33
-rw-r--r--lib/dev-ino.h10
3 files changed, 106 insertions, 0 deletions
diff --git a/lib/cycle-check.c b/lib/cycle-check.c
new file mode 100644
index 000000000..403dc1615
--- /dev/null
+++ b/lib/cycle-check.c
@@ -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
index 000000000..6f8c55d5d
--- /dev/null
+++ b/lib/cycle-check.h
@@ -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
index 000000000..79cc5203f
--- /dev/null
+++ b/lib/dev-ino.h
@@ -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