1
0
mirror of git://git.sv.gnu.org/coreutils.git synced 2026-04-20 18:56:39 +02:00

Don't include <search.h>.

[HAVE_INTTYPES_H]: Include <inttypes.h>.
(tdestroy, tfind, tsearch): Remove definitions.
(struct Active_dir): Rename from `known_object'.
(AD_compare, AD_hash): New functions.
(enter_dir, leave_dir): Rewrite to manipulate a hash table
rather than a tree.
(fts_open): Initialize hash table or cycle_state buffer.
(free_node): Remove function.
(find_matching_ancestor): Renamed/rewritten from look_up_active_dir.
(fts_cross_check): Adapt to use new data structure.
This commit is contained in:
Jim Meyering
2003-12-19 12:50:33 +00:00
parent 7f49957342
commit 16972646cf

233
lib/fts.c
View File

@@ -46,10 +46,12 @@ static char sccsid[] = "@(#)fts.c 8.6 (Berkeley) 8/14/94";
#include <fcntl.h>
#include <errno.h>
#include "fts_.h"
#include <search.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#if HAVE_INTTYPES_H
# include <inttypes.h>
#endif
#if defined _LIBC
# include <dirent.h>
@@ -86,12 +88,6 @@ static char sccsid[] = "@(#)fts.c 8.6 (Berkeley) 8/14/94";
# define opendir __opendir
# undef readdir
# define readdir __readdir
# undef tdestroy
# define tdestroy __tdestroy
# undef tfind
# define tfind __tfind
# undef tsearch
# define tsearch __tsearch
#else
# undef internal_function
# define internal_function /* empty */
@@ -152,6 +148,8 @@ static int fts_safe_changedir __P((FTS *, FTSENT *, int, const char *))
#define BNAMES 2 /* fts_children, names only */
#define BREAD 3 /* fts_read */
#define HT_INITIAL_SIZE 31
#if FTS_DEBUG
int fts_debug = 0;
# include <stdio.h>
@@ -172,87 +170,101 @@ int fts_debug = 0;
leave_dir (sp, p); \
} while (0)
struct known_object
/* Use these each of these to map a device/inode pair to an FTSENT. */
struct Active_dir
{
dev_t dev;
ino_t ino;
FTSENT *fts_ent;
};
static int
object_compare (const void *p1, const void *p2)
static bool
AD_compare (void const *x, void const *y)
{
/* We don't need a sophisticated and useful comparison. We are only
interested in equality. However, we must be careful not to
accidentally compare `holes' in the structure. */
const struct known_object *kp1 = p1, *kp2 = p2;
int cmp1;
cmp1 = (kp1->ino > kp2->ino) - (kp1->ino < kp2->ino);
if (cmp1 != 0)
return cmp1;
return (kp1->dev > kp2->dev) - (kp1->dev < kp2->dev);
struct Active_dir const *ax = x;
struct Active_dir const *ay = y;
return ax->ino == ay->ino
&& ax->dev == ay->dev;
}
static inline FTSENT *
find_object (const FTS *fts, const struct stat *st)
static size_t
AD_hash (void const *x, size_t table_size)
{
struct known_object obj;
void const *tree_node;
struct known_object const *t;
obj.dev = st->st_dev;
obj.ino = st->st_ino;
tree_node = tfind (&obj, &fts->fts_dir_signatures, object_compare);
if ( ! tree_node)
return NULL;
t = *(void **)tree_node;
return t->fts_ent;
struct Active_dir const *ax = x;
return (uintmax_t) ax->ino % table_size;
}
static void
enter_dir (FTS *fts, FTSENT *ent)
{
struct known_object *newp;
struct stat const *st = ent->fts_statp;
/*
* See if we've already encountered this directory.
* This can happen when following symlinks as well as
* with a corrupted directory hierarchy.
*/
FTSENT *t = find_object (fts, st);
if (t)
if (fts->active_dir_ht)
{
ent->fts_cycle = t;
ent->fts_info = FTS_DC;
return;
}
struct stat const *st = ent->fts_statp;
struct Active_dir *ad = malloc (sizeof (struct Active_dir));
struct Active_dir *ad_from_table;
newp = malloc (sizeof (struct known_object));
if (newp == NULL)
return;
newp->dev = st->st_dev;
newp->ino = st->st_ino;
newp->fts_ent = ent;
tsearch (newp, &fts->fts_dir_signatures, object_compare);
if (ad == NULL)
goto give_up;
ad->dev = st->st_dev;
ad->ino = st->st_ino;
ad->fts_ent = ent;
/* See if we've already encountered this directory.
This can happen when following symlinks as well as
with a corrupted directory hierarchy. */
ad_from_table = hash_insert (fts->active_dir_ht, ad);
if (ad_from_table == NULL)
{
give_up:
/* Insertion failed due to lack of memory. Free the hash
table and turn off this sort of cycle detection. */
hash_free (fts->active_dir_ht);
fts->active_dir_ht = NULL;
return;
}
if (ad_from_table != ad)
{
/* There was an entry with matching dev/inode already in the table.
Record the fact that we've found a cycle. */
ent->fts_cycle = ad_from_table->fts_ent;
ent->fts_info = FTS_DC;
/* ad was not inserted, so free it. */
free (ad);
}
}
else if (fts->cycle_state)
{
if (cycle_check (fts->cycle_state, ent->fts_statp))
{
/* FIXME: setting fts_cycle like this isn't proper.
To do what the documentation requires, we'd have to
go around the cycle again and find the right entry.
But no callers in coreutils use the fts_cycle member. */
ent->fts_cycle = ent;
ent->fts_info = FTS_DC;
}
}
}
static inline void
static void
leave_dir (FTS *fts, FTSENT *ent)
{
struct stat const *st = ent->fts_statp;
struct known_object obj;
obj.dev = st->st_dev;
obj.ino = st->st_ino;
void *found = tdelete (&obj, &fts->fts_dir_signatures, object_compare);
if (!found)
abort ();
/* FIXME: there's a leak here. We want to
free the key data, but can't, because tdelete frees
the _tree_ data &!^!%#*, so we'd have to add a separate tfind.
Sheesh. Soon I'll rip out tsearch.c and use hash.c
functions here instead. */
if (fts->active_dir_ht)
{
struct stat const *st = ent->fts_statp;
struct Active_dir obj;
void *found;
obj.dev = st->st_dev;
obj.ino = st->st_ino;
found = hash_delete (fts->active_dir_ht, &obj);
if (!found)
abort ();
free (found);
}
}
FTS *
@@ -348,7 +360,23 @@ fts_open(argv, options, compar)
sp->fts_cur->fts_link = root;
sp->fts_cur->fts_info = FTS_INIT;
sp->fts_dir_signatures = NULL;
if (ISSET (FTS_TIGHT_CYCLE_CHECK))
{
sp->active_dir_ht = hash_initialize (HT_INITIAL_SIZE,
NULL, AD_hash,
AD_compare, free);
if (sp->active_dir_ht == NULL)
goto mem3;
sp->cycle_state = malloc (sizeof *sp->cycle_state);
}
else
{
sp->cycle_state = malloc (sizeof *sp->cycle_state);
if (sp->cycle_state == NULL)
goto mem3;
cycle_check_init (sp->cycle_state);
sp->active_dir_ht = NULL;
}
/*
* If using chdir(2), grab a file descriptor pointing to dot to ensure
@@ -397,13 +425,6 @@ fts_load(sp, p)
sp->fts_dev = p->fts_dev;
}
static void
free_node (void *nodep)
{
free (*(void **)nodep);
free (nodep);
}
int
fts_close(sp)
FTS *sp;
@@ -439,8 +460,11 @@ fts_close(sp)
(void)close(sp->fts_rfd);
}
/* Free all of the directory fingerprint info. */
tdestroy (sp->fts_dir_signatures, free_node);
/* Free any memory used for cycle detection. */
if (sp->active_dir_ht)
hash_free (sp->active_dir_ht);
if (sp->cycle_state)
free (sp->cycle_state);
/* Free up the stream pointer. */
free(sp);
@@ -1041,51 +1065,48 @@ mem1: saved_errno = errno;
#if FTS_DEBUG
static FTSENT const *G_current_ent;
/* Given dev/ino for a directory available through NODEP,
determine whether that directory is a parent directory
of G_current_ent. */
/* Walk ->fts_parent links starting at E_CURR, until the root of the
current hierarchy. There should be a directory with dev/inode
matching those of AD. If not, print a lot of diagnostics. */
static void
look_up_active_dir (const void *nodep, const VISIT which, const int depth)
find_matching_ancestor (FTSENT const *e_curr, struct Active_dir const *ad)
{
FTSENT const *ent;
if ( ! (which == preorder || which == leaf))
return;
struct known_object const *ko = *(void **)nodep;
for (ent = G_current_ent;
ent->fts_level >= FTS_ROOTLEVEL; ent = ent->fts_parent)
for (ent = e_curr; ent->fts_level >= FTS_ROOTLEVEL; ent = ent->fts_parent)
{
if (ko->ino == ent->fts_statp->st_ino
&& ko->dev == ent->fts_statp->st_dev)
if (ad->ino == ent->fts_statp->st_ino
&& ad->dev == ent->fts_statp->st_dev)
return;
}
printf ("ERROR: tree dir, %s, not active\n", ko->fts_ent->fts_accpath);
printf ("ERROR: tree dir, %s, not active\n", ad->fts_ent->fts_accpath);
printf ("active dirs:\n");
for (ent = G_current_ent;
for (ent = e_curr;
ent->fts_level >= FTS_ROOTLEVEL; ent = ent->fts_parent)
printf (" %s(%d/%d) to %s(%d/%d)...\n",
ko->fts_ent->fts_accpath,
(int)ko->dev,
(int)ko->ino,
ad->fts_ent->fts_accpath,
(int)ad->dev,
(int)ad->ino,
ent->fts_accpath,
(int)ent->fts_statp->st_dev,
(int)ent->fts_statp->st_ino);
}
void
fts_cross_check (FTS const *sp, FTSENT const *ent)
fts_cross_check (FTS const *sp)
{
FTSENT const *ent = sp->fts_cur;
FTSENT const *t;
Dprintf (("fts-cross-check %s\n", ent->fts_path));
if ( ! ISSET (FTS_TIGHT_CYCLE_CHECK))
return;
Dprintf (("fts-cross-check cur=%s\n", ent->fts_path));
/* Make sure every parent dir is in the tree. */
for (t = ent->fts_parent; t->fts_level >= FTS_ROOTLEVEL; t = t->fts_parent)
{
FTSENT *found = find_object (sp, t->fts_statp);
if (found == NULL)
struct Active_dir ad;
ad.ino = t->fts_statp->st_ino;
ad.dev = t->fts_statp->st_dev;
if ( ! hash_lookup (sp->active_dir_ht, &ad))
printf ("ERROR: active dir, %s, not in tree\n", t->fts_path);
}
@@ -1095,8 +1116,12 @@ fts_cross_check (FTS const *sp, FTSENT const *ent)
&& (ent->fts_info == FTS_DP
|| ent->fts_info == FTS_D))
{
G_current_ent = ent;
twalk (sp->fts_dir_signatures, look_up_active_dir);
struct Active_dir *ad;
for (ad = hash_get_first (sp->active_dir_ht); ad != NULL;
ad = hash_get_next (sp->active_dir_ht, ad))
{
find_matching_ancestor (ent, ad);
}
}
}
#endif