same-inode: make SAME_INODE tri-state, to port to mingw
[gnulib.git] / lib / cycle-check.c
1 /* help detect directory cycles efficiently
2
3    Copyright (C) 2003, 2004, 2005, 2006, 2009 Free Software
4    Foundation, Inc.
5
6    This program is free software: you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
18
19 /* Written by Jim Meyering */
20
21 #include <config.h>
22
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <stdio.h>
26 #include <assert.h>
27 #include <stdlib.h>
28
29 #include <stdbool.h>
30
31 #include "cycle-check.h"
32
33 #define CC_MAGIC 9827862
34
35 /* Return true if I is a power of 2, or is zero.  */
36
37 static inline bool
38 is_zero_or_power_of_two (uintmax_t i)
39 {
40   return (i & (i - 1)) == 0;
41 }
42
43 void
44 cycle_check_init (struct cycle_check_state *state)
45 {
46   state->chdir_counter = 0;
47   state->magic = CC_MAGIC;
48 }
49
50 /* In traversing a directory hierarchy, call this function once for each
51    descending chdir call, with SB corresponding to the chdir operand.
52    If SB corresponds to a directory that has already been seen,
53    return true to indicate that there is a directory cycle.
54    Note that this is done `lazily', which means that some of
55    the directories in the cycle may be processed twice before
56    the cycle is detected.  */
57
58 bool
59 cycle_check (struct cycle_check_state *state, struct stat const *sb)
60 {
61   assert (state->magic == CC_MAGIC);
62
63   /* If the current directory ever happens to be the same
64      as the one we last recorded for the cycle detection,
65      then it's obviously part of a cycle.  */
66   if (state->chdir_counter && SAME_INODE (*sb, state->dev_ino) == 1)
67     return true;
68
69   /* If the number of `descending' chdir calls is a power of two,
70      record the dev/ino of the current directory.  */
71   if (is_zero_or_power_of_two (++(state->chdir_counter)))
72     {
73       /* On all architectures that we know about, if the counter
74          overflows then there is a directory cycle here somewhere,
75          even if we haven't detected it yet.  Typically this happens
76          only after the counter is incremented 2**64 times, so it's a
77          fairly theoretical point.  */
78       if (state->chdir_counter == 0)
79         return true;
80
81       state->dev_ino.st_dev = sb->st_dev;
82       state->dev_ino.st_ino = sb->st_ino;
83     }
84
85   return false;
86 }