annotate lib/fts-cycle.c @ 6163:bba2240c9260

* iconvme.h: Add prototype for iconv_alloc.
author Simon Josefsson <simon@josefsson.org>
date Tue, 30 Aug 2005 07:38:53 +0000
parents 14b1cca449ad
children 716071856296
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
5872
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
1 /* Detect cycles in file tree walks.
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
2
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
3 Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
4
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
5 Written by Jim Meyering.
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
6
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
7 This program is free software; you can redistribute it and/or modify
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
8 it under the terms of the GNU General Public License as published by
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
9 the Free Software Foundation; either version 2, or (at your option)
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
10 any later version.
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
11
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
12 This program is distributed in the hope that it will be useful,
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
15 GNU General Public License for more details.
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
16
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
17 You should have received a copy of the GNU General Public License
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
18 along with this program; if not, write to the Free Software Foundation,
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
19 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
20
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
21 #include "cycle-check.h"
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
22 #include "hash.h"
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
23
5907
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents: 5872
diff changeset
24 /* Use each of these to map a device/inode pair to an FTSENT. */
5872
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
25 struct Active_dir
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
26 {
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
27 dev_t dev;
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
28 ino_t ino;
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
29 FTSENT *fts_ent;
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
30 };
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
31
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
32 static bool
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
33 AD_compare (void const *x, void const *y)
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
34 {
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
35 struct Active_dir const *ax = x;
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
36 struct Active_dir const *ay = y;
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
37 return ax->ino == ay->ino
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
38 && ax->dev == ay->dev;
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
39 }
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
40
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
41 static size_t
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
42 AD_hash (void const *x, size_t table_size)
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
43 {
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
44 struct Active_dir const *ax = x;
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
45 return (uintmax_t) ax->ino % table_size;
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
46 }
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
47
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
48 /* Set up the cycle-detection machinery. */
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
49
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
50 static bool
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
51 setup_dir (FTS *fts)
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
52 {
6036
14b1cca449ad (setup_dir, enter_dir, leave_dir, free_dir):
Jim Meyering <jim@meyering.net>
parents: 5907
diff changeset
53 if (fts->fts_options & (FTS_TIGHT_CYCLE_CHECK | FTS_LOGICAL))
5872
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
54 {
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
55 enum { HT_INITIAL_SIZE = 31 };
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
56 fts->fts_cycle.ht = hash_initialize (HT_INITIAL_SIZE, NULL, AD_hash,
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
57 AD_compare, free);
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
58 if (! fts->fts_cycle.ht)
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
59 return false;
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
60 }
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
61 else
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
62 {
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
63 fts->fts_cycle.state = malloc (sizeof *fts->fts_cycle.state);
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
64 if (! fts->fts_cycle.state)
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
65 return false;
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
66 cycle_check_init (fts->fts_cycle.state);
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
67 }
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
68
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
69 return true;
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
70 }
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
71
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
72 /* Enter a directory during a file tree walk. */
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
73
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
74 static bool
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
75 enter_dir (FTS *fts, FTSENT *ent)
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
76 {
6036
14b1cca449ad (setup_dir, enter_dir, leave_dir, free_dir):
Jim Meyering <jim@meyering.net>
parents: 5907
diff changeset
77 if (fts->fts_options & (FTS_TIGHT_CYCLE_CHECK | FTS_LOGICAL))
5872
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
78 {
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
79 struct stat const *st = ent->fts_statp;
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
80 struct Active_dir *ad = malloc (sizeof *ad);
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
81 struct Active_dir *ad_from_table;
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
82
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
83 if (!ad)
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
84 return false;
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
85
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
86 ad->dev = st->st_dev;
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
87 ad->ino = st->st_ino;
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
88 ad->fts_ent = ent;
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
89
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
90 /* See if we've already encountered this directory.
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
91 This can happen when following symlinks as well as
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
92 with a corrupted directory hierarchy. */
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
93 ad_from_table = hash_insert (fts->fts_cycle.ht, ad);
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
94
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
95 if (ad_from_table != ad)
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
96 {
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
97 free (ad);
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
98 if (!ad_from_table)
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
99 return false;
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
100
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
101 /* There was an entry with matching dev/inode already in the table.
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
102 Record the fact that we've found a cycle. */
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
103 ent->fts_cycle = ad_from_table->fts_ent;
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
104 ent->fts_info = FTS_DC;
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
105 }
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
106 }
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
107 else
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
108 {
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
109 if (cycle_check (fts->fts_cycle.state, ent->fts_statp))
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
110 {
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
111 /* FIXME: setting fts_cycle like this isn't proper.
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
112 To do what the documentation requires, we'd have to
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
113 go around the cycle again and find the right entry.
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
114 But no callers in coreutils use the fts_cycle member. */
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
115 ent->fts_cycle = ent;
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
116 ent->fts_info = FTS_DC;
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
117 }
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
118 }
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
119
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
120 return true;
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
121 }
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
122
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
123 /* Leave a directory during a file tree walk. */
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
124
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
125 static void
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
126 leave_dir (FTS *fts, FTSENT *ent)
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
127 {
6036
14b1cca449ad (setup_dir, enter_dir, leave_dir, free_dir):
Jim Meyering <jim@meyering.net>
parents: 5907
diff changeset
128 if (fts->fts_options & (FTS_TIGHT_CYCLE_CHECK | FTS_LOGICAL))
5872
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
129 {
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
130 struct stat const *st = ent->fts_statp;
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
131 struct Active_dir obj;
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
132 void *found;
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
133 obj.dev = st->st_dev;
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
134 obj.ino = st->st_ino;
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
135 found = hash_delete (fts->fts_cycle.ht, &obj);
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
136 if (!found)
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
137 abort ();
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
138 free (found);
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
139 }
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
140 }
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
141
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
142 /* Free any memory used for cycle detection. */
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
143
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
144 static void
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
145 free_dir (FTS *sp)
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
146 {
6036
14b1cca449ad (setup_dir, enter_dir, leave_dir, free_dir):
Jim Meyering <jim@meyering.net>
parents: 5907
diff changeset
147 if (sp->fts_options & (FTS_TIGHT_CYCLE_CHECK | FTS_LOGICAL))
5872
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
148 {
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
149 if (sp->fts_cycle.ht)
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
150 hash_free (sp->fts_cycle.ht);
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
151 }
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
152 else
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
153 free (sp->fts_cycle.state);
fab6701e5cb2 New fts module.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
154 }