summaryrefslogtreecommitdiffstats
path: root/lib/idwalk.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/idwalk.c')
-rw-r--r--lib/idwalk.c1189
1 files changed, 0 insertions, 1189 deletions
diff --git a/lib/idwalk.c b/lib/idwalk.c
deleted file mode 100644
index 77aacf2..0000000
--- a/lib/idwalk.c
+++ /dev/null
@@ -1,1189 +0,0 @@
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/param.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <stddef.h>
-#include <dirent.h>
-#include <unistd.h>
-#include <string.h>
-#include <fcntl.h>
-#include <fnmatch.h>
-#ifndef FNM_FILE_NAME
-#define FNM_FILE_NAME FNM_PATHNAME
-#endif
-
-#define DEBUG(args) /* printf args */
-
-#include <config.h>
-#include "system.h"
-#include "idfile.h"
-#include "error.h"
-#include "alloc.h"
-#include "dynvec.h"
-#include "strxtra.h"
-#include "scanners.h"
-#include "pathmax.h"
-
-int walk_dir __P((struct file_link *dir_link));
-void walk_flink __P((struct file_link *flink, struct dynvec *sub_dirs_vec));
-struct member_file *get_member_file __P((struct file_link *flink));
-struct lang_args *get_lang_args __P((struct file_link const *flink));
-int walk_sub_dirs __P((struct dynvec *sub_dirs_vec));
-int classify_link __P((struct file_link *flink, struct stat *st));
-struct file_link *get_link_from_dirent __P((struct dirent *dirent, struct file_link *parent));
-struct file_link *make_link_from_dirent __P((struct dirent *dirent, struct file_link *parent));
-struct file_link *get_link_from_string __P((char const *name, struct file_link *parent));
-struct file_link *make_link_from_string __P((char const *name, struct file_link *parent));
-static int same_as_dot __P((char const *cwd));
-int chdir_to_link __P((struct file_link* dir_link));
-struct file_link const **fill_link_vector __P((struct file_link const **vec_buf, struct file_link const *flink));
-struct file_link const **fill_link_vector_1 __P((struct file_link const **vec_buf, struct file_link const *flink));
-char const *maybe_relative_path __P((char *buffer, struct file_link const *to_link, struct file_link const *from_link));
-char *fill_dot_dots __P((char *buf, int levels));
-char *absolute_path __P((char *buffer, struct file_link const *flink));
-static char *absolute_path_1 __P((char *buffer, struct file_link const *flink));
-unsigned long member_file_hash_1 __P((void const *key));
-unsigned long member_file_hash_2 __P((void const *key));
-int member_file_hash_compare __P((void const *x, void const *y));
-unsigned long file_link_hash_1 __P((void const *key));
-unsigned long file_link_hash_2 __P((void const *key));
-int file_link_hash_compare __P((void const *x, void const *y));
-int file_link_qsort_compare __P((void const *x, void const *y));
-int links_depth __P((struct file_link const *flink));
-unsigned long dev_ino_hash_1 __P((void const *key));
-unsigned long dev_ino_hash_2 __P((void const *key));
-int dev_ino_hash_compare __P((void const *x, void const *y));
-int symlink_ancestry __P((struct file_link *flink));
-
-/* Interpret `HAVE_LINK' as meaning `UN*X style' directory structure
- (e.g., A single root called `/', with `/' separating links), and
- !HAVE_LINK as `DOS|OS/2|Windows style' (e.g., Multiple root volues
- named `x:', with `\' separating links). */
-
-#if HAVE_LINK
-struct file_link *find_alias_link __P((struct file_link *flink, struct stat *st));
-struct member_file *maybe_get_member_file __P((struct file_link *flink, struct stat *st));
-struct member_file *find_member_file __P((struct file_link const *flink));
-# define IS_ABSOLUTE(_dir_) ((_dir_)[0] == '/')
-# define SLASH_STRING "/"
-# define SLASH_CHAR '/'
-# define DOT_DOT_SLASH "../"
-# define MAYBE_FNM_CASEFOLD 0
-#else
-/* NEEDSWORK: prefer forward-slashes as a user-configurable option. */
-# define IS_ABSOLUTE(_dir_) ((_dir_)[1] == ':')
-# define SLASH_STRING "\\/"
-# define SLASH_CHAR '\\'
-# define DOT_DOT_SLASH "..\\"
-# define MAYBE_FNM_CASEFOLD FNM_CASEFOLD
-#endif
-
-#define IS_DOT(s) ((s)[0] == '.' && (s)[1] == '\0')
-#define IS_DOT_DOT(s) ((s)[0] == '.' && (s)[1] == '.' && (s)[2] == '\0')
-#define IS_DOT_or_DOT_DOT(s) \
- (((s)[0] == '.') && (((s)[1] == '\0') || ((s)[1] == '.' && (s)[2] == '\0')))
-
-static struct file_link *current_dir_link = 0;
-
-char* xgetcwd __P((void));
-
-/****************************************************************************/
-/* Walk the file-system tree rooted at `dir_link', looking for files
- that are eligible for scanning. */
-
-int
-walk_dir (struct file_link *dir_link)
-{
- char buf[PATH_MAX];
- int scannable_files;
- struct dynvec *sub_dirs_vec;
- DIR *dirp;
-
- if (!chdir_to_link (dir_link))
- return 0;
- dirp = opendir (".");
- if (dirp == 0)
- {
- error (0, errno, _("can't read directory `%s' (`.' from `%s')"),
- absolute_path (buf, dir_link), xgetcwd ());
- return 0;
- }
- sub_dirs_vec = make_dynvec (32);
- scannable_files = 0;
- for (;;)
- {
- struct file_link *flink;
- struct dirent *dirent = readdir (dirp);
-
- if (dirent == 0)
- break;
- if (IS_DOT_or_DOT_DOT (dirent->d_name))
- continue;
-
- flink = get_link_from_dirent (dirent, dir_link);
- walk_flink (flink, sub_dirs_vec);
- }
- closedir (dirp);
-
- scannable_files += walk_sub_dirs (sub_dirs_vec);
- dynvec_free (sub_dirs_vec);
- return scannable_files;
-}
-
-/* Walk the directories found by walk_dir, calling walk_dir
- recursively for each directory. */
-
-int
-walk_sub_dirs (struct dynvec *sub_dirs_vec)
-{
- struct file_link **sub_dirs;
- struct file_link **sub_dirs_end;
- int total_scannable_files = 0;
-
- dynvec_freeze (sub_dirs_vec);
- sub_dirs_end = (struct file_link **)
- &sub_dirs_vec->dv_vec[sub_dirs_vec->dv_fill];
- sub_dirs = (struct file_link **) sub_dirs_vec->dv_vec;
- for ( ; sub_dirs < sub_dirs_end; sub_dirs++)
- {
- struct file_link *sub_dir_link = *sub_dirs;
- int scannable_files = walk_dir (sub_dir_link);
- if (scannable_files)
- total_scannable_files += scannable_files;
- }
- return total_scannable_files;
-}
-
-void
-walk_flink (struct file_link *flink, struct dynvec *sub_dirs_vec)
-{
- char buf[PATH_MAX];
- struct stat st;
- unsigned int old_flags;
- unsigned int new_flags;
-
- new_flags = classify_link (flink, &st);
- if (new_flags == 0)
- return;
-
- old_flags = flink->fl_flags;
- if ((old_flags & FL_TYPE_MASK)
- && (old_flags & FL_TYPE_MASK) != (new_flags & FL_TYPE_MASK))
- error (0, 0, _("notice: `%s' was a %s, but is now a %s!"),
- absolute_path (buf, flink),
- (FL_IS_FILE (old_flags) ? _("file") : _("directory")),
- (FL_IS_FILE (new_flags) ? _("file") : _("directory")));
-
- flink->fl_flags = (old_flags & ~(FL_TYPE_MASK|FL_SYM_LINK)) | new_flags;
- if (FL_IS_DIR (new_flags))
- {
- if (sub_dirs_vec == 0)
- walk_dir (flink);
- else if (!(new_flags & FL_SYM_LINK)) /* NEEDSWORK: optinally ignore? */
- dynvec_append (sub_dirs_vec, flink);
- }
- else
- {
- struct member_file *member;
-#if HAVE_LINK
- member = maybe_get_member_file (flink, &st);
-#else
- member = get_member_file (flink);
-#endif
- if (member == 0)
- return;
-#if 0
- member->mf_modify_time = st.st_mtime;
- member->mf_access_time = st.st_atime;
- if (member->mf_old_index < 0 || st.st_mtime > idh.idh_mod_time)
- member->mf_scan_index = 0;
-#endif
- }
-}
-
-/****************************************************************************/
-/* Serialize and write a file_link hierarchy. */
-
-void
-serialize_file_links (struct idhead *idhp)
-{
- struct file_link **flinks_0;
- struct file_link **flinks;
- struct file_link **end;
- struct file_link **parents_0;
- struct file_link **parents;
- unsigned long parent_index = 0;
-
- flinks_0 = (struct file_link **) hash_dump (&idhp->idh_file_link_table,
- 0, file_link_qsort_compare);
- end = &flinks_0[idhp->idh_file_link_table.ht_fill];
- parents = parents_0 = MALLOC (struct file_link *, idhp->idh_file_link_table.ht_fill);
- for (flinks = flinks_0; flinks < end; flinks++)
- {
- struct file_link *flink = *flinks;
- if (!(flink->fl_flags & FL_USED))
- break;
- io_write (idhp->idh_FILE, flink->fl_name, 0, IO_TYPE_STR);
- io_write (idhp->idh_FILE, &flink->fl_flags, sizeof (flink->fl_flags), IO_TYPE_INT);
- io_write (idhp->idh_FILE, (IS_ROOT_FILE_LINK (flink)
- ? &parent_index : &flink->fl_parent->fl_index),
- FL_PARENT_INDEX_BYTES, IO_TYPE_INT);
- *parents++ = flink->fl_parent; /* save parent link before clobbering */
- flink->fl_index = parent_index++;
- }
- /* restore parent links */
- for ((flinks = flinks_0), (parents = parents_0); flinks < end; flinks++)
- {
- struct file_link *flink = *flinks;
- if (!(flink->fl_flags & FL_USED))
- break;
- flink->fl_parent = *parents++;
- }
- free (parents_0);
- free (flinks_0);
- idhp->idh_file_links = parent_index;
- idhp->idh_files = idhp->idh_member_file_table.ht_fill;
-}
-
-/* Separate the wheat from the chaff. Mark those file_links that are
- components in member files. */
-
-void
-mark_member_file_links (struct idhead *idhp)
-{
- struct member_file **members_0
- = (struct member_file **) hash_dump (&idhp->idh_member_file_table,
- 0, member_file_qsort_compare);
- struct member_file **end = &members_0[idhp->idh_member_file_table.ht_fill];
- struct member_file **members;
- int new_index = 0;
-
- for (members = members_0; members < end; members++)
- {
- struct member_file *member = *members;
- struct file_link *flink;
- member->mf_index = new_index++;
- for (flink = member->mf_link;
- !(flink->fl_flags & FL_USED); flink = flink->fl_parent)
- flink->fl_flags |= FL_USED;
- }
- free (members_0);
-}
-
-/* Read and reconstruct a serialized file_link hierarchy. */
-
-struct file_link **
-deserialize_file_links (struct idhead *idhp)
-{
- struct file_link **flinks_0 = MALLOC (struct file_link *, idhp->idh_file_links);
- struct file_link **flinks = flinks_0;
- struct file_link **members_0 = MALLOC (struct file_link *, idhp->idh_files + 1);
- struct file_link **members = members_0;
- struct file_link *flink;
- struct file_link **slot;
- int i;
-
- for (i = 0; i < idhp->idh_file_links; i++)
- {
- unsigned long parent_index;
- int c;
-
- obstack_blank (&idhp->idh_file_link_obstack, offsetof (struct file_link, fl_name));
- if (obstack_room (&idhp->idh_file_link_obstack) >= idhp->idh_max_link)
- do
- {
- c = getc (idhp->idh_FILE);
- obstack_1grow_fast (&idhp->idh_file_link_obstack, c);
- }
- while (c);
- else
- do
- {
- c = getc (idhp->idh_FILE);
- obstack_1grow (&idhp->idh_file_link_obstack, c);
- }
- while (c);
- flink = (struct file_link *) obstack_finish (&idhp->idh_file_link_obstack);
- *flinks = flink;
- io_read (idhp->idh_FILE, &flink->fl_flags, sizeof (flink->fl_flags), IO_TYPE_INT);
- io_read (idhp->idh_FILE, &parent_index, FL_PARENT_INDEX_BYTES, IO_TYPE_INT);
- flink->fl_parent = flinks_0[parent_index];
- slot = (struct file_link **) hash_find_slot (&idhp->idh_file_link_table, flink);
- if (HASH_VACANT (*slot))
- hash_insert_at (&idhp->idh_file_link_table, flink, slot);
- else
- {
- obstack_free (&idhp->idh_file_link_obstack, flink);
- (*slot)->fl_flags = flink->fl_flags;
- flink = *flinks = *slot;
- }
- flinks++;
- if (flink->fl_flags & FL_MEMBER)
- *members++ = flink;
- }
- free (flinks_0);
- *members = 0;
- return members_0;
-}
-
-
-#if HAVE_LINK
-
-/****************************************************************************/
-/* Return a `member_file' for this `flink' *if* the filename matches
- some scan pattern, and no alias for the file takes precedence ([1]
- hard-links dominate symbolic-links; [2] for two hard-links: first
- come, first served). */
-
-struct member_file *
-maybe_get_member_file (struct file_link *flink, struct stat *st)
-{
- char buf[PATH_MAX];
- struct file_link *alias_link;
- struct member_file *member;
- struct member_file *alias_member = 0;
-
- member = get_member_file (flink);
- alias_link = find_alias_link (flink, st);
- if (alias_link)
- alias_member = find_member_file (alias_link);
-
- if (member && alias_member)
- {
- char alias_buf[PATH_MAX];
- int ancestry = symlink_ancestry (flink);
- int alias_ancestry = symlink_ancestry (alias_link);
- if (member->mf_lang_args != alias_member->mf_lang_args)
- error (0, 0, _("warning: `%s' and `%s' are the same file, but yield different scans!"),
- absolute_path (buf, flink), absolute_path (alias_buf, alias_link));
- else if (alias_ancestry > ancestry)
- {
- hash_delete (&idh.idh_member_file_table, member);
- member->mf_link->fl_flags &= ~FL_MEMBER;
- return 0;
- }
- else
- {
- hash_delete (&idh.idh_member_file_table, alias_member);
- alias_member->mf_link->fl_flags &= ~FL_MEMBER;
- }
- }
- return member;
-}
-
-/* Return a previously registered alias for `flink', if any. */
-
-struct file_link *
-find_alias_link (struct file_link *flink, struct stat *st)
-{
- struct dev_ino *dev_ino;
- struct dev_ino **slot;
-
- dev_ino = (struct dev_ino *) obstack_alloc (&idh.idh_dev_ino_obstack, sizeof (struct dev_ino));
- dev_ino->di_dev = st->st_dev;
- dev_ino->di_ino = st->st_ino;
- slot = (struct dev_ino **) hash_find_slot (&idh.idh_dev_ino_table, dev_ino);
- if (HASH_VACANT (*slot))
- {
- dev_ino->di_link = flink;
- hash_insert_at (&idh.idh_dev_ino_table, dev_ino, slot);
- return 0;
- }
- else
- {
- obstack_free (&idh.idh_dev_ino_obstack, dev_ino);
- return (*slot)->di_link;
- }
-}
-
-/* Return the distance from `flink' to a symbolic-link ancestor
- directory. PATH_MAX is considered an infinite distance (e.g.,
- there are no symlinks between `flink' and the root). */
-
-int
-symlink_ancestry (struct file_link *flink)
-{
- int ancestry = 0;
- while (!IS_ROOT_FILE_LINK (flink))
- {
- if (flink->fl_flags & FL_SYM_LINK)
- return ancestry;
- ancestry++;
- flink = flink->fl_parent;
- }
- return PATH_MAX;
-}
-
-#endif /* HAVE_LINK */
-
-struct member_file *
-get_member_file (struct file_link *flink)
-{
- char buf[PATH_MAX];
- struct member_file *member;
- struct member_file **slot;
- struct lang_args const *args;
-
- args = get_lang_args (flink);
- if (args == 0)
- {
- DEBUG (("%s <IGNORE>\n", absolute_path (buf, flink)));
- return 0;
- }
- DEBUG (("%s <%s> <%s>\n", absolute_path (buf, flink),
- args->la_language->lg_name, (args->la_args_string
- ? args->la_args_string : "")));
-
- member = (struct member_file *) obstack_alloc (&idh.idh_member_file_obstack,
- sizeof (struct member_file));
- member->mf_link = flink;
- slot = (struct member_file **) hash_find_slot (&idh.idh_member_file_table, member);
- if (HASH_VACANT (*slot))
- {
- member->mf_index = -1;
- hash_insert_at (&idh.idh_member_file_table, member, slot);
- flink->fl_flags |= FL_MEMBER;
- }
- else
- {
- obstack_free (&idh.idh_member_file_obstack, member);
-#if 0
- if (member->mf_lang_args != args)
- {
- error (0, 0, _("notice: scan parameters changed for `%s'"),
- absolute_path (buf, flink));
- member->mf_old_index = -1;
- }
-#endif
- member = *slot;
- }
- member->mf_lang_args = args;
- return *slot;
-}
-
-struct member_file *
-find_member_file (struct file_link const *flink)
-{
- struct member_file key;
- struct member_file **slot;
-
- key.mf_link = (struct file_link *) flink;
- slot = (struct member_file **) hash_find_slot (&idh.idh_member_file_table, &key);
- if (HASH_VACANT (*slot))
- return 0;
- return *slot;
-}
-
-/* March down the list of lang_args, and return the first one whose
- pattern matches FLINK. Return the matching lang_args, if a
- scanner exists for that language, otherwise return 0. */
-
-struct lang_args *
-get_lang_args (struct file_link const *flink)
-{
- struct lang_args *args = lang_args_list;
-
- while (args)
- {
- if (strchr (args->la_pattern, SLASH_CHAR))
- {
- char buf[PATH_MAX];
- absolute_path (buf, flink);
- if (fnmatch (args->la_pattern, buf, MAYBE_FNM_CASEFOLD | FNM_FILE_NAME) == 0)
- return (args->la_language ? args : 0);
- }
- else
- {
- if (fnmatch (args->la_pattern, flink->fl_name, MAYBE_FNM_CASEFOLD) == 0)
- return (args->la_language ? args : 0);
- }
- args = args->la_next;
- }
- return (lang_args_default->la_language ? lang_args_default : 0);
-}
-
-/****************************************************************************/
-/* Convert a file name string to an absolute chain of `file_link's. */
-
-struct file_link *
-parse_file_name (char *file_name, struct file_link *relative_dir_link)
-{
- struct file_link *flink;
-
- if (IS_ABSOLUTE (file_name))
- {
-#if HAVE_LINK
- flink = get_link_from_string (SLASH_STRING, 0);
-#else
- flink = 0;
-#endif
- }
- else if (relative_dir_link)
- flink = relative_dir_link;
- else if (current_dir_link)
- flink = current_dir_link;
- else
- flink = get_current_dir_link ();
-
- for (;;)
- {
- char const* link_name = strtok (file_name, SLASH_STRING);
- if (link_name == 0)
- break;
- file_name = 0;
- if (*link_name == '\0' || IS_DOT (link_name))
- ;
- else if (IS_DOT_DOT (link_name))
- flink = flink->fl_parent;
- else
- {
- struct stat st;
- flink = get_link_from_string (link_name, flink);
- if (!flink->fl_flags)
- flink->fl_flags = classify_link (flink, &st);
- }
- }
- return flink;
-}
-
-/* Return an absolute chain of `file_link's representing the current
- working directory. */
-
-struct file_link *
-get_current_dir_link (void)
-{
- struct file_link *dir_link;
- char *cwd_0;
- char *cwd;
- char *xcwd = 0;
-
- if (current_dir_link)
- return current_dir_link;
-
- cwd_0 = getenv ("PWD");
- if (cwd_0)
- cwd_0 = strdup (cwd_0);
- if (!same_as_dot (cwd_0))
- cwd_0 = xcwd = xgetcwd ();
- if (cwd_0 == 0)
- error (1, errno, _("can't get working directory"));
- cwd = cwd_0;
-#if HAVE_LINK
- dir_link = get_link_from_string (SLASH_STRING, 0);
- dir_link->fl_flags = (dir_link->fl_flags & ~FL_TYPE_MASK) | FL_TYPE_DIR;
-#else
- dir_link = 0;
-#endif
- for (;;)
- {
- struct stat st;
- char const* link_name = strtok (cwd, SLASH_STRING);
- if (link_name == 0)
- break;
- cwd = 0;
- dir_link = get_link_from_string (link_name, dir_link);
- if (!dir_link->fl_flags)
- dir_link->fl_flags = classify_link (dir_link, &st);
- }
- chdir_to_link (dir_link);
- if (xcwd)
- free (xcwd);
- current_dir_link = dir_link;
- return dir_link;
-}
-
-static int
-same_as_dot (char const *cwd)
-{
- struct stat cwd_st;
- struct stat dot_st;
-
- if (cwd == 0 || *cwd != '/'
- || stat (cwd, &cwd_st) < 0
- || stat (".", &dot_st) < 0)
- return 0;
- return ((cwd_st.st_ino == dot_st.st_ino) && (cwd_st.st_dev == dot_st.st_dev));
-}
-
-/* Change the working directory to the directory represented by
- `dir_link'. Choose the shortest path to the destination based on
- the cached value of the current directory. */
-
-int
-chdir_to_link (struct file_link *dir_link)
-{
- char to_buf[PATH_MAX];
- char from_buf[PATH_MAX];
-
- if (current_dir_link == dir_link)
- return 1;
-
- if (current_dir_link)
- maybe_relative_path (to_buf, dir_link, current_dir_link);
- else
- absolute_path (to_buf, dir_link);
- if (chdir (to_buf) < 0)
- {
- if (IS_ABSOLUTE (to_buf))
- error (0, errno, _("can't chdir to `%s'"), to_buf);
- else
- error (0, errno, _("can't chdir to `%s' from `%s'"), to_buf,
- absolute_path (from_buf, current_dir_link));
- return 0;
- }
- else
- {
- current_dir_link = dir_link;
- return 1;
- }
-}
-
-/****************************************************************************/
-/* Gather information about the link at `flink'. If it's a good
- file or directory, return its mod-time and type. */
-
-int
-classify_link (struct file_link *flink, struct stat *st)
-{
- char buf[PATH_MAX];
- unsigned int flags = 0;
-
- if (!chdir_to_link (flink->fl_parent))
- return 0;
-
-#ifdef S_IFLNK
- if (lstat (flink->fl_name, st) < 0)
- {
- error (0, errno, _("can't lstat `%s' from `%s'"), flink->fl_name, xgetcwd ());
- return 0;
- }
- if (S_ISLNK (st->st_mode))
- {
-#endif
- if (stat (flink->fl_name, st) < 0)
- {
- error (0, errno, _("can't stat `%s' from `%s'"), flink->fl_name, xgetcwd ());
- return 0;
- }
-#ifdef S_IFLNK
- flags |= FL_SYM_LINK;
- }
-#endif
- if (S_ISDIR (st->st_mode))
- flags |= FL_TYPE_DIR;
- else if (S_ISREG (st->st_mode))
- flags |= FL_TYPE_FILE;
- else
- return 0;
- return flags;
-}
-
-/****************************************************************************/
-/* Retrieve an existing flink; or if none exists, create one. */
-
-struct file_link *
-get_link_from_dirent (struct dirent *dirent, struct file_link *parent)
-{
- struct file_link **slot;
- struct file_link *new_link;
-
- new_link = make_link_from_dirent (dirent, parent);
- slot = (struct file_link **) hash_find_slot (&idh.idh_file_link_table, new_link);
- if (HASH_VACANT (*slot))
- hash_insert_at (&idh.idh_file_link_table, new_link, slot);
- else
- obstack_free (&idh.idh_file_link_obstack, new_link);
- return *slot;
-}
-
-struct file_link *
-get_link_from_string (char const *name, struct file_link *parent)
-{
- struct file_link **slot;
- struct file_link *new_link;
-
- new_link = make_link_from_string (name, parent);
- slot = (struct file_link **) hash_find_slot (&idh.idh_file_link_table, new_link);
- if (HASH_VACANT (*slot))
- hash_insert_at (&idh.idh_file_link_table, new_link, slot);
- else
- obstack_free (&idh.idh_file_link_obstack, new_link);
- return *slot;
-}
-
-struct file_link *
-make_link_from_dirent (struct dirent* dirent, struct file_link *parent)
-{
- struct file_link *flink;
-
- flink = (struct file_link *) obstack_alloc (&idh.idh_file_link_obstack,
- sizeof (struct file_link) + strlen (dirent->d_name));
- strcpy (flink->fl_name, dirent->d_name);
- flink->fl_parent = parent ? parent : flink;
- flink->fl_flags = 0;
-
- return flink;
-}
-
-struct file_link *
-make_link_from_string (char const* name, struct file_link *parent)
-{
- struct file_link *flink;
-
- flink = (struct file_link *) obstack_alloc (&idh.idh_file_link_obstack,
- sizeof (struct file_link) + strlen (name));
- strcpy (flink->fl_name, name);
- flink->fl_parent = parent ? parent : flink;
- flink->fl_flags = 0;
-
- return flink;
-}
-
-/****************************************************************************/
-/* Convert a `file_link' chain to a vector of component `file_link's,
- with the root at [0]. Return a pointer beyond the final component. */
-
-struct file_link const **
-fill_link_vector (struct file_link const **vec_buf, struct file_link const *flink)
-{
- vec_buf = fill_link_vector_1 (vec_buf, flink);
- *vec_buf = 0;
- return vec_buf;
-}
-
-struct file_link const **
-fill_link_vector_1 (struct file_link const **vec_buf, struct file_link const *flink)
-{
- if (!IS_ROOT_FILE_LINK (flink))
- vec_buf = fill_link_vector_1 (vec_buf, flink->fl_parent);
- *vec_buf++ = flink;
- return vec_buf;
-}
-
-/****************************************************************************/
-/* Fill BUF_0 with a path to TO_LINK. If a relative path from
- FROM_LINK is possible (i.e., no intervening symbolic-links) and
- shorter, return the relative path; otherwise, return an absolute
- path. */
-
-char const *
-maybe_relative_path (char *buf_0, struct file_link const *to_link, struct file_link const *from_link)
-{
- struct file_link const *to_link_vec_0[PATH_MAX/2];
- struct file_link const *from_link_vec_0[PATH_MAX/2];
- struct file_link const **to_link_vec = to_link_vec_0;
- struct file_link const **from_link_vec = from_link_vec_0;
- struct file_link const **from_link_end;
- struct file_link const **from_links;
- char *buf;
- int levels;
-
- if (from_link == 0)
- from_link = current_dir_link;
-
- /* Optimize common cases. */
- if (to_link == from_link)
- return strcpy (buf_0, ".");
- else if (to_link->fl_parent == from_link)
- return strcpy (buf_0, to_link->fl_name);
- else if (from_link->fl_flags & FL_SYM_LINK)
- return absolute_path (buf_0, to_link);
- else if (to_link == from_link->fl_parent)
- return strcpy (buf_0, "..");
- else if (to_link->fl_parent == from_link->fl_parent)
- {
- strcpy (buf_0, DOT_DOT_SLASH);
- strcpy (&buf_0[3], to_link->fl_name);
- return buf_0;
- }
-
- from_link_end = fill_link_vector (from_link_vec, from_link);
- fill_link_vector (to_link_vec, to_link);
- while (*to_link_vec == *from_link_vec)
- {
- if (*to_link_vec == 0)
- return ".";
- to_link_vec++;
- from_link_vec++;
- }
- levels = from_link_end - from_link_vec;
- if (levels >= (from_link_vec - from_link_vec_0))
- return absolute_path (buf_0, to_link);
- for (from_links = from_link_vec; *from_links; from_links++)
- if ((*from_links)->fl_flags & FL_SYM_LINK)
- return absolute_path (buf_0, to_link);
- buf = fill_dot_dots (buf_0, levels);
- while (*to_link_vec)
- {
- strcpy (buf, (*to_link_vec)->fl_name);
- buf += strlen (buf);
- if ((*to_link_vec)->fl_name[0] != SLASH_CHAR && *++to_link_vec)
- *buf++ = SLASH_CHAR;
- }
- return buf_0;
-}
-
-/* Fill `buf' with sequences of "../" in order to ascend so many
- `levels' in a directory tree. */
-
-char *
-fill_dot_dots (char *buf, int levels)
-{
- while (levels--)
- {
- strcpy (buf, DOT_DOT_SLASH);
- buf += 3;
- }
- return buf;
-}
-
-/****************************************************************************/
-/* Fill `buffer' with the absolute path to `flink'. */
-
-char *
-absolute_path (char *buffer, struct file_link const *flink)
-{
- char *end = absolute_path_1 (buffer, flink);
- /* Clip the trailing slash. */
-#if HAVE_LINK
- if (end > &buffer[1])
- end--;
-#else
- if (end > &buffer[3])
- end--;
-#endif
- *end = '\0';
- return buffer;
-}
-
-static char *
-absolute_path_1 (char *buffer, struct file_link const *flink)
-{
- char *end;
- if (IS_ROOT_FILE_LINK (flink))
- end = buffer;
- else
- end = absolute_path_1 (buffer, flink->fl_parent);
- strcpy (end, flink->fl_name);
- if (*end == SLASH_CHAR)
- end++;
- else
- {
- end += strlen (end);
- *end++ = SLASH_CHAR;
- }
- return end;
-}
-
-/****************************************************************************/
-/* Hash stuff for `struct member_file'. */
-
-unsigned long
-member_file_hash_1 (void const *key)
-{
- return_ADDRESS_HASH_1 (((struct member_file const *) key)->mf_link);
-}
-
-unsigned long
-member_file_hash_2 (void const *key)
-{
- return_ADDRESS_HASH_2 (((struct member_file const *) key)->mf_link);
-}
-
-int
-member_file_hash_compare (void const *x, void const *y)
-{
- return_ADDRESS_COMPARE (((struct member_file const *) x)->mf_link,
- ((struct member_file const *) y)->mf_link);
-}
-
-/* Collating sequence:
- - language.map index
- - mf_link: breadth-first, alphabetical */
-
-int
-member_file_qsort_compare (void const *x, void const *y)
-{
- struct member_file const *mfx = *(struct member_file const **) x;
- struct member_file const *mfy = *(struct member_file const **) y;
- int result;
-
- INTEGER_COMPARE (mfx->mf_lang_args->la_index, mfy->mf_lang_args->la_index, result);
- if (result)
- return result;
- else
- {
- struct file_link const *flx = mfx->mf_link;
- struct file_link const *fly = mfy->mf_link;
- if (flx->fl_parent == fly->fl_parent)
- return strcmp (flx->fl_name, fly->fl_name);
- result = (links_depth (flx) - links_depth (fly));
- if (result)
- return result;
- while (flx->fl_parent != fly->fl_parent)
- {
- flx = flx->fl_parent;
- fly = fly->fl_parent;
- }
- return strcmp (flx->fl_name, fly->fl_name);
- }
-}
-
-/****************************************************************************/
-/* Hash stuff for `struct file_link'. */
-
-unsigned long
-file_link_hash_1 (void const *key)
-{
- unsigned long result = 0;
- struct file_link const *parent = (IS_ROOT_FILE_LINK (((struct file_link const *) key))
- ? 0 : ((struct file_link const *) key)->fl_parent);
- STRING_HASH_1 (((struct file_link const *) key)->fl_name, result);
- ADDRESS_HASH_1 (parent, result);
- return result;
-}
-
-unsigned long
-file_link_hash_2 (void const *key)
-{
- unsigned long result = 0;
- struct file_link const *parent = (IS_ROOT_FILE_LINK (((struct file_link const *) key))
- ? 0 : ((struct file_link const *) key)->fl_parent);
- STRING_HASH_2 (((struct file_link const *) key)->fl_name, result);
- ADDRESS_HASH_2 (parent, result);
- return result;
-}
-
-int
-file_link_hash_compare (void const *x, void const *y)
-{
- int result;
- struct file_link const *x_parent = (IS_ROOT_FILE_LINK (((struct file_link const *) x))
- ? 0 : ((struct file_link const *) x)->fl_parent);
- struct file_link const *y_parent = (IS_ROOT_FILE_LINK (((struct file_link const *) y))
- ? 0 : ((struct file_link const *) y)->fl_parent);
- ADDRESS_COMPARE (x_parent, y_parent, result);
- if (result)
- return result;
- STRING_COMPARE (((struct file_link const *) x)->fl_name,
- ((struct file_link const *) y)->fl_name, result);
- return result;
-}
-
-/* Collation sequence:
- - Used before unused.
- - Among used: breadth-first (dirs before files, parent dirs before children)
- - Among files: collate by mf_index. */
-
-int
-file_link_qsort_compare (void const *x, void const *y)
-{
- struct file_link const *flx = *(struct file_link const **) x;
- struct file_link const *fly = *(struct file_link const **) y;
- unsigned int x_flags = flx->fl_flags;
- unsigned int y_flags = fly->fl_flags;
- int result;
-
- result = (y_flags & FL_USED) - (x_flags & FL_USED);
- if (result)
- return result;
- if (!(x_flags & FL_USED)) /* If neither link is used, we don't care... */
- return 0;
- result = (y_flags & FL_TYPE_DIR) - (x_flags & FL_TYPE_DIR);
- if (result)
- return result;
- result = (y_flags & FL_TYPE_MASK) - (x_flags & FL_TYPE_MASK);
- if (result)
- return result;
- if (FL_IS_FILE (x_flags))
- {
- struct member_file *x_member = find_member_file (flx);
- struct member_file *y_member = find_member_file (fly);
- return x_member->mf_index - y_member->mf_index;
- }
- else
- {
- int x_depth = links_depth (flx);
- int y_depth = links_depth (fly);
- return (x_depth - y_depth);
- }
-}
-
-/* Count directory components between flink and its root. */
-
-int
-links_depth (struct file_link const *flink)
-{
- int depth = 0;
- while (!IS_ROOT_FILE_LINK (flink))
- {
- depth++;
- flink = flink->fl_parent;
- }
- return depth;
-}
-
-#if HAVE_LINK
-
-/****************************************************************************/
-/* Hash stuff for `struct dev_ino'. */
-
-unsigned long
-dev_ino_hash_1 (void const *key)
-{
- unsigned long result = 0;
- INTEGER_HASH_1 (((struct dev_ino const *) key)->di_dev, result);
- INTEGER_HASH_1 (((struct dev_ino const *) key)->di_ino, result);
- return result;
-}
-
-unsigned long
-dev_ino_hash_2 (void const *key)
-{
- unsigned long result = 0;
- INTEGER_HASH_2 (((struct dev_ino const *) key)->di_dev, result);
- INTEGER_HASH_2 (((struct dev_ino const *) key)->di_ino, result);
- return result;
-}
-
-int
-dev_ino_hash_compare (void const *x, void const *y)
-{
- int result;
- INTEGER_COMPARE (((struct dev_ino const *) x)->di_ino,
- ((struct dev_ino const *) y)->di_ino, result);
- if (result)
- return result;
- INTEGER_COMPARE (((struct dev_ino const *) x)->di_dev,
- ((struct dev_ino const *) y)->di_dev, result);
- return result;
-}
-
-#endif
-
-/*******************************************************************/
-
-void
-init_idh_obstacks (struct idhead *idhp)
-{
- obstack_init (&idhp->idh_member_file_obstack);
- obstack_init (&idhp->idh_file_link_obstack);
-#if HAVE_LINK
- obstack_init (&idhp->idh_dev_ino_obstack);
-#endif
-}
-
-void
-init_idh_tables (struct idhead *idhp)
-{
- hash_init (&idhp->idh_member_file_table, 16*1024,
- member_file_hash_1, member_file_hash_2, member_file_hash_compare);
- hash_init (&idhp->idh_file_link_table, 16*1024,
- file_link_hash_1, file_link_hash_2, file_link_hash_compare);
-#if HAVE_LINK
- hash_init (&idhp->idh_dev_ino_table, 16*1024,
- dev_ino_hash_1, dev_ino_hash_2, dev_ino_hash_compare);
-#endif
-}
-
-
-#if TEST_IDWALK
-/*******************************************************************/
-/* Test program. */
-
-char const *program_name;
-struct idhead idh;
-
-void print_member_file __P((void const *item));
-
-void
-print_member_file (void const *item)
-{
- char buf[PATH_MAX];
-#define member ((struct member_file const *) item)
-#if 1
- printf ("%s\n", maybe_relative_path (buf, member->mf_link, 0));
-#else
- printf ("%ld %ld %s\n", member->mf_access_time, member->mf_modify_time,
- maybe_relative_path (buf, member->mf_link, 0));
-#endif
-#undef member
-}
-
-void reset_walker (struct idhead *idhp);
-void print_hash_stats (FILE *stream, struct idhead *idhp);
-
-#define obstack_chunk_alloc xmalloc
-#define obstack_chunk_free free
-
-void
-reset_walker (struct idhead *idhp)
-{
- hash_delete_items (&idhp->idh_member_file_table);
- hash_delete_items (&idhp->idh_file_link_table);
-#if HAVE_LINK
- hash_delete_items (&idhp->idh_dev_ino_table);
-#endif
-}
-
-void
-print_hash_stats (FILE *stream, struct idhead *idhp)
-{
- fprintf (stream, _("Link Table: ")); hash_print_stats (&idhp->idh_file_link_table, stream);
- fprintf (stream, _("\nFile Table: ")); hash_print_stats (&idhp->idh_member_file_table, stream);
-#if HAVE_LINK
- fprintf (stream, _("\nDupl Table: ")); hash_print_stats (&idhp->idh_dev_ino_table, stream);
-#endif
- fputc ('\n', stream);
-}
-
-int
-main (int argc, char **argv)
-{
- struct file_link *cwd_link;
-
- program_name = ((argc--, *argv++));
-
- init_idh_obstacks (&idh);
- init_idh_tables (&idh);
-
- parse_language_map (0);
- cwd_link = get_current_dir_link ();
- while (argc--)
- walk_flink (parse_file_name (*argv++, cwd_link), 0);
-
- chdir_to_link (cwd_link);
-
-#if 0
- idh.idh_file_name = "idwalk.serial";
- idh.idh_FILE = fopen (idh.idh_file_name, "w+");
- if (idh.idh_FILE == 0)
- error (1, errno, _("can't open `%s' for writing"), idh.idh_file_name);
-
- printf (">>>>>>>>>>>>>>>> Serialize <<<<<<<<<<<<<<<<\n");
- hash_map (&idh.idh_member_file_table, print_member_file);
- printf (">>>>>>>>>>>>>>>> Serialize Stats <<<<<<<<<<<<<<<<\n");
- print_hash_stats (stdout, &idh);
-
- serialize_file_links (&idh);
- reset_walker (&idh);
- deserialize_file_links (&idh);
-
- printf (">>>>>>>>>>>>>>>> Deserialize <<<<<<<<<<<<<<<<\n");
- hash_map (&idh.idh_member_file_table, print_member_file);
- printf (">>>>>>>>>>>>>>>> Deserialize Stats <<<<<<<<<<<<<<<<\n");
- print_hash_stats (stdout, &idh);
-
- printf (">>>>>>>>>>>>>>>> End <<<<<<<<<<<<<<<<\n");
- fclose (idh.idh_FILE);
-#endif
- return 0;
-}
-
-#endif
-
-/*
- TODO:
- - stream I/O
- */