(linenum→info "unix/slp.c:2238")

coreutils/6.9/lib/cycle-check.c

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