From df7cef21c77ac1a986bdeca3c8923c0d6d379b23 Mon Sep 17 00:00:00 2001 From: Jim Meyering Date: Thu, 22 Jan 1998 08:14:52 +0000 Subject: Remove and minimally librarify guts for use in mv.c. (main): Pass options (`&x') to rm. Call remove_init and remove_fini instead of open-coding them. --- src/rm.c | 897 ++------------------------------------------------------------- 1 file changed, 26 insertions(+), 871 deletions(-) (limited to 'src/rm.c') diff --git a/src/rm.c b/src/rm.c index 1f2239801..a6c1d2ec1 100644 --- a/src/rm.c +++ b/src/rm.c @@ -53,240 +53,31 @@ #include "system.h" #include "closeout.h" #include "error.h" -#include "obstack.h" -#include "hash.h" +#include "remove.h" -#ifndef PARAMS -# if defined (__GNUC__) || __STDC__ -# define PARAMS(args) args -# else -# define PARAMS(args) () -# endif -#endif - -#define obstack_chunk_alloc malloc -#define obstack_chunk_free free - -#ifdef D_INO_IN_DIRENT -# define D_INO(dp) ((dp)->d_ino) -# define ENABLE_CYCLE_CHECK -#else -/* Some systems don't have inodes, so fake them to avoid lots of ifdefs. */ -# define D_INO(dp) 1 -#endif - -#if !defined (S_ISLNK) -# define S_ISLNK(Mode) 0 -#endif - -#define DOT_OR_DOTDOT(Basename) \ - (Basename[0] == '.' && (Basename[1] == '\0' \ - || (Basename[1] == '.' && Basename[2] == '\0'))) - -#if defined strdupa -# define ASSIGN_STRDUPA(DEST, S) \ - do { DEST = strdupa(S); } while (0) -#else -# define ASSIGN_STRDUPA(DEST, S) \ - do \ - { \ - const char *s_ = (S); \ - size_t len_ = strlen (s_) + 1; \ - char *tmp_dest_ = (char *) alloca (len_); \ - DEST = memcpy (tmp_dest_, (s_), len_); \ - } \ - while (0) -#endif - -enum RM_status -{ - /* These must be listed in order of increasing seriousness. */ - RM_OK, - RM_USER_DECLINED, - RM_ERROR -}; - -#define VALID_STATUS(S) \ - ((S) == RM_OK || (S) == RM_USER_DECLINED || (S) == RM_ERROR) - -/* Initial capacity of per-directory hash table of entries that have - been processed but not been deleted. */ -#define HT_INITIAL_CAPACITY 13 - -/* Initial capacity of the active directory hash table. This table will - be resized only for hierarchies more than about 45 levels deep. */ -#define ACTIVE_DIR_INITIAL_CAPACITY 53 - -struct File_spec -{ - char *filename; - unsigned int have_filetype_mode:1; - unsigned int have_full_mode:1; - mode_t mode; - ino_t inum; -}; - -char *base_name (); -int euidaccess (); void strip_trailing_slashes (); -int yesno (); - -/* Forward dcl for recursively called function. */ -static enum RM_status rm PARAMS ((struct File_spec *fs, - int user_specified_name)); /* Name this program was run with. */ char *program_name; -/* If nonzero, display the name of each file removed. */ -static int verbose; - -/* If nonzero, ignore nonexistant files. */ -static int ignore_missing_files; - -/* If nonzero, recursively remove directories. */ -static int recursive; - -/* If nonzero, query the user about whether to remove each file. */ -static int interactive; - -/* If nonzero, remove directories with unlink instead of rmdir, and don't - require a directory to be empty before trying to unlink it. - Only works for the super-user. */ -static int unlink_dirs; - -/* If nonzero, stdin is a tty. */ -static int stdin_tty; - /* If nonzero, display usage information and exit. */ static int show_help; /* If nonzero, print the version on standard output and exit. */ static int show_version; -/* The name of the directory (starting with and relative to a command - line argument) being processed. When a subdirectory is entered, a new - component is appended (pushed). When RM chdir's out of a directory, - the top component is removed (popped). This is used to form a full - file name when necessary. */ -static struct obstack dir_stack; - -/* Stack of lengths of directory names (including trailing slash) - appended to dir_stack. We have to have a separate stack of lengths - (rather than just popping back to previous slash) because the first - element pushed onto the dir stack may contain slashes. */ -static struct obstack len_stack; - -/* Set of `active' directories from the current command-line argument - to the level in the hierarchy at which files are being removed. - A directory is added to the active set when RM begins removing it - (or its entries), and it is removed from the set just after RM has - finished processing it. - - This is actually a map (not a set), implemented with a hash table. - For each active directory, it maps the directory's inode number to the - depth of that directory relative to the root of the tree being deleted. - A directory specified on the command line has depth zero. - This construct is used to detect directory cycles so that RM can warn - about them rather than iterating endlessly. */ -#ifdef ENABLE_CYCLE_CHECK -static struct HT *active_dir_map; -#endif - -/* An entry in the active_dir_map. */ -struct active_dir_ent -{ - ino_t inum; - unsigned int depth; -}; - static struct option const long_opts[] = { - {"directory", no_argument, &unlink_dirs, 1}, + {"directory", no_argument, NULL, 'd'}, {"force", no_argument, NULL, 'f'}, {"interactive", no_argument, NULL, 'i'}, - {"recursive", no_argument, &recursive, 1}, - {"verbose", no_argument, &verbose, 1}, + {"recursive", no_argument, NULL, 'r'}, + {"verbose", no_argument, NULL, 'v'}, {"help", no_argument, &show_help, 1}, {"version", no_argument, &show_version, 1}, {NULL, 0, NULL, 0} }; -static inline unsigned int -current_depth (void) -{ - return obstack_object_size (&len_stack) / sizeof (size_t); -} - -static void -print_nth_dir (FILE *stream, unsigned int depth) -{ - size_t *length = (size_t *) obstack_base (&len_stack); - char *dir_name = (char *) obstack_base (&dir_stack); - unsigned int sum = 0; - unsigned int i; - - assert (0 <= depth && depth < current_depth ()); - - for (i = 0; i <= depth; i++) - { - sum += length[i]; - } - - fwrite (dir_name, 1, sum, stream); -} - -static inline struct active_dir_ent * -make_active_dir_ent (ino_t inum, unsigned int depth) -{ - struct active_dir_ent *ent; - ent = (struct active_dir_ent *) xmalloc (sizeof *ent); - ent->inum = inum; - ent->depth = depth; - return ent; -} - -static unsigned int -hash_active_dir_ent (void const *x, unsigned int table_size) -{ - struct active_dir_ent const *ade = x; - return ade->inum % table_size; -} - -static int -hash_compare_active_dir_ents (void const *x, void const *y) -{ - struct active_dir_ent const *a = x; - struct active_dir_ent const *b = y; - return (a->inum == b->inum ? 0 : 1); -} - -/* A hash function for null-terminated char* strings using - the method described in Aho, Sethi, & Ullman, p 436. */ - -static unsigned int -hash_pjw (const void *x, unsigned int tablesize) -{ - const char *s = x; - unsigned int h = 0; - unsigned int g; - - while (*s != 0) - { - h = (h << 4) + *s++; - if ((g = h & (unsigned int) 0xf0000000) != 0) - h = (h ^ (g >> 24)) ^ g; - } - - return (h % tablesize); -} - -static int -hash_compare_strings (void const *x, void const *y) -{ - return strcmp (x, y); -} - static void usage (int status) { @@ -313,644 +104,21 @@ Remove (unlink) the FILE(s).\n\ exit (status); } -static inline void -push_dir (const char *dir_name) -{ - size_t len; - - len = strlen (dir_name); - - /* Append the string onto the stack. */ - obstack_grow (&dir_stack, dir_name, len); - - /* Append a trailing slash. */ - obstack_1grow (&dir_stack, '/'); - - /* Add one for the slash. */ - ++len; - - /* Push the length (including slash) onto its stack. */ - obstack_grow (&len_stack, &len, sizeof (len)); -} - -static inline void -pop_dir (void) -{ - int n_lengths = obstack_object_size (&len_stack) / sizeof (size_t); - size_t *length = (size_t *) obstack_base (&len_stack); - size_t top_len; - - assert (n_lengths > 0); - top_len = length[n_lengths - 1]; - assert (top_len >= 2); - - /* Pop off the specified length of pathname. */ - assert (obstack_object_size (&dir_stack) >= top_len); - obstack_blank (&dir_stack, -top_len); - - /* Pop the length stack, too. */ - assert (obstack_object_size (&len_stack) >= sizeof (size_t)); - obstack_blank (&len_stack, -(sizeof (size_t))); -} - -/* Copy the SRC_LEN bytes of data beginning at SRC into the DST_LEN-byte - buffer, DST, so that the last source byte is at the end of the destination - buffer. If SRC_LEN is longer than DST_LEN, then set *TRUNCATED to non-zero. - Set *RESULT to point to the beginning of (the portion of) the source data - in DST. Return the number of bytes remaining in the destination buffer. */ - -static size_t -right_justify (char *dst, size_t dst_len, const char *src, size_t src_len, - char **result, int *truncated) -{ - const char *sp; - char *dp; - - if (src_len <= dst_len) - { - sp = src; - dp = dst + (dst_len - src_len); - *truncated = 0; - } - else - { - sp = src + (src_len - dst_len); - dp = dst; - src_len = dst_len; - *truncated = 1; - } - - *result = memcpy (dp, sp, src_len); - return dst_len - src_len; -} - -/* Using the global directory name obstack, create the full path to FILENAME. - Return it in sometimes-realloc'd space that should not be freed by the - caller. Realloc as necessary. If realloc fails, use a static buffer - and put as long a suffix in that buffer as possible. */ - -static char * -full_filename (const char *filename) -{ - static char *buf = NULL; - static size_t n_allocated = 0; - - int dir_len = obstack_object_size (&dir_stack); - char *dir_name = (char *) obstack_base (&dir_stack); - size_t n_bytes_needed; - size_t filename_len; - - filename_len = strlen (filename); - n_bytes_needed = dir_len + filename_len + 1; - - if (n_bytes_needed > n_allocated) - { - /* This code requires that realloc accept NULL as the first arg. - This function must not use xrealloc. Otherwise, an out-of-memory - error involving a file name to be expanded here wouldn't ever - be issued. Use realloc and fall back on using a static buffer - if memory allocation fails. */ - buf = realloc (buf, n_bytes_needed); - n_allocated = n_bytes_needed; - - if (buf == NULL) - { -#define SBUF_SIZE 512 -#define ELLIPSES_PREFIX "[...]" - static char static_buf[SBUF_SIZE]; - int truncated; - size_t len; - char *p; - - len = right_justify (static_buf, SBUF_SIZE, filename, - filename_len + 1, &p, &truncated); - right_justify (static_buf, len, dir_name, dir_len, &p, &truncated); - if (truncated) - { - memcpy (static_buf, ELLIPSES_PREFIX, - sizeof (ELLIPSES_PREFIX) - 1); - } - return p; - } - } - - /* Copy directory part, including trailing slash, and then - append the filename part, including a trailing zero byte. */ - memcpy (mempcpy (buf, dir_name, dir_len), filename, filename_len + 1); - - assert (strlen (buf) + 1 == n_bytes_needed); - - return buf; -} - -static inline void -fspec_init_file (struct File_spec *fs, const char *filename) -{ - fs->filename = (char *) filename; - fs->have_full_mode = 0; - fs->have_filetype_mode = 0; -} - -static inline void -fspec_init_dp (struct File_spec *fs, struct dirent *dp) -{ - fs->filename = dp->d_name; - fs->have_full_mode = 0; - fs->have_filetype_mode = 0; - fs->inum = D_INO (dp); - -#if D_TYPE_IN_DIRENT && defined (DT_UNKNOWN) && defined (DTTOIF) - if (dp->d_type != DT_UNKNOWN) - { - fs->have_filetype_mode = 1; - fs->mode = DTTOIF (dp->d_type); - } -#endif -} - -static inline int -fspec_get_full_mode (struct File_spec *fs, mode_t *full_mode) -{ - struct stat stat_buf; - - if (fs->have_full_mode) - { - *full_mode = fs->mode; - return 0; - } - - if (lstat (fs->filename, &stat_buf)) - return 1; - - fs->have_full_mode = 1; - fs->have_filetype_mode = 1; - fs->mode = stat_buf.st_mode; - fs->inum = stat_buf.st_ino; - - *full_mode = stat_buf.st_mode; - return 0; -} - -static inline int -fspec_get_filetype_mode (struct File_spec *fs, mode_t *filetype_mode) -{ - int fail; - - if (fs->have_filetype_mode) - { - *filetype_mode = fs->mode; - fail = 0; - } - else - { - fail = fspec_get_full_mode (fs, filetype_mode); - } - - return fail; -} - -static inline mode_t -fspec_filetype_mode (const struct File_spec *fs) -{ - assert (fs->have_filetype_mode); - return fs->mode; -} - -/* Recursively remove all of the entries in the current directory. - Return an indication of the success of the operation. */ - -enum RM_status -remove_cwd_entries (void) -{ - /* NOTE: this is static. */ - static DIR *dirp = NULL; - - /* NULL or a malloc'd and initialized hash table of entries in the - current directory that have been processed but not removed -- - due either to an error or to an interactive `no' response. */ - struct HT *ht = NULL; - - /* FIXME: describe */ - static struct obstack entry_name_pool; - static int first_call = 1; - - enum RM_status status = RM_OK; - - if (first_call) - { - first_call = 0; - obstack_init (&entry_name_pool); - } - - if (dirp) - { - if (CLOSEDIR (dirp)) - { - /* FIXME-someday: but this is actually the previously opened dir. */ - error (0, errno, "%s", full_filename (".")); - status = RM_ERROR; - } - dirp = NULL; - } - - do - { - /* FIXME: why do this? */ - errno = 0; - - dirp = opendir ("."); - if (dirp == NULL) - { - if (errno != ENOENT || !ignore_missing_files) - { - error (0, errno, "%s", full_filename (".")); - status = RM_ERROR; - } - break; - } - - while (1) - { - char *entry_name; - struct File_spec fs; - enum RM_status tmp_status; - struct dirent *dp; - -/* FILE should be skipped if it is `.' or `..', or if it is in - the table, HT, of entries we've already processed. */ -#define SKIPPABLE(Ht, File) (DOT_OR_DOTDOT(File) \ - || (Ht && hash_query_in_table (Ht, File))) - - /* FIXME: use readdir_r directly into an obstack to avoid - the obstack_copy0 below -- - Suggestion from Uli. Be careful -- there are different - prototypes on e.g. Solaris. - - Do something like this: - #define NAME_MAX_FOR(Parent_dir) pathconf ((Parent_dir), - _PC_NAME_MAX); - dp = obstack_alloc (sizeof (struct dirent) - + NAME_MAX_FOR (".") + 1); - fail = xreaddir (dirp, dp); - where xreaddir is ... - - But what about systems like the hurd where NAME_MAX is supposed - to be effectively unlimited. We don't want to have to allocate - a huge buffer to accommodate maximum possible entry name. */ - - dp = readdir (dirp); - -#if ! HAVE_WORKING_READDIR - if (dp == NULL) - { - /* Since we have probably modified the directory since it - was opened, readdir returning NULL does not necessarily - mean we have read the last entry. Rewind it and check - again. This happens on SunOS4.1.4 with 254 or more files - in a directory. */ - rewinddir (dirp); - while ((dp = readdir (dirp)) && SKIPPABLE (ht, dp->d_name)) - { - /* empty */ - } - } -#endif - - if (dp == NULL) - break; - - if (SKIPPABLE (ht, dp->d_name)) - continue; - - fspec_init_dp (&fs, dp); - - /* Save a copy of the name of this entry, in case we have - to add it to the set of unremoved entries below. */ - entry_name = obstack_copy0 (&entry_name_pool, - dp->d_name, NLENGTH (dp)); - - /* CAUTION: after this call to rm, DP may not be valid -- - it may have been freed due to a close in a recursive call - (through rm and remove_dir) to this function. */ - tmp_status = rm (&fs, 0); - - /* Update status. */ - if (tmp_status > status) - status = tmp_status; - assert (VALID_STATUS (status)); - - /* If this entry was not removed (due either to an error or to - an interactive `no' response), record it in the hash table so - we don't consider it again if we reopen this directory later. */ - if (status != RM_OK) - { - int fail; - - if (ht == NULL) - { - ht = hash_initialize (HT_INITIAL_CAPACITY, NULL, - hash_pjw, hash_compare_strings); - if (ht == NULL) - error (1, 0, _("Memory exhausted")); - } - HASH_INSERT_NEW_ITEM (ht, entry_name, &fail); - if (fail) - error (1, 0, _("Memory exhausted")); - } - else - { - /* This entry was not saved in the hash table. Free it. */ - obstack_free (&entry_name_pool, entry_name); - } - - if (dirp == NULL) - break; - } - } - while (dirp == NULL); - - if (CLOSEDIR (dirp)) - { - error (0, errno, "%s", full_filename (".")); - status = 1; - } - dirp = NULL; - - if (ht) - { - hash_free (ht); - } - - if (obstack_object_size (&entry_name_pool) > 0) - obstack_free (&entry_name_pool, obstack_base (&entry_name_pool)); - - return status; -} - -/* Query the user if appropriate, and if ok try to remove the - file or directory specified by FS. Return RM_OK if it is removed, - and RM_ERROR or RM_USER_DECLINED if not. */ - -static enum RM_status -remove_file (struct File_spec *fs) -{ - int asked = 0; - char *pathname = fs->filename; - - if (!ignore_missing_files && (interactive || stdin_tty) - && euidaccess (pathname, W_OK) ) - { - if (!S_ISLNK (fspec_filetype_mode (fs))) - { - fprintf (stderr, - (S_ISDIR (fspec_filetype_mode (fs)) - ? _("%s: remove write-protected directory `%s'? ") - : _("%s: remove write-protected file `%s'? ")), - program_name, full_filename (pathname)); - if (!yesno ()) - return RM_USER_DECLINED; - - asked = 1; - } - } - - if (!asked && interactive) - { - fprintf (stderr, - (S_ISDIR (fspec_filetype_mode (fs)) - ? _("%s: remove directory `%s'? ") - : _("%s: remove `%s'? ")), - program_name, full_filename (pathname)); - if (!yesno ()) - return RM_USER_DECLINED; - } - - if (verbose) - printf ("%s\n", full_filename (pathname)); - - if (unlink (pathname) && (errno != ENOENT || !ignore_missing_files)) - { - error (0, errno, _("cannot unlink `%s'"), full_filename (pathname)); - return RM_ERROR; - } - return RM_OK; -} - -/* If not in recursive mode, print an error message and return RM_ERROR. - Otherwise, query the user if appropriate, then try to recursively - remove the directory specified by FS. Return RM_OK if it is removed, - and RM_ERROR or RM_USER_DECLINED if not. - FIXME: describe need_save_cwd parameter. */ - -static enum RM_status -remove_dir (struct File_spec *fs, int need_save_cwd) -{ - enum RM_status status; - struct saved_cwd cwd; - char *dir_name = fs->filename; - const char *fmt = NULL; - - if (!recursive) - { - error (0, 0, _("%s: is a directory"), full_filename (dir_name)); - return RM_ERROR; - } - - if (!ignore_missing_files && (interactive || stdin_tty) - && euidaccess (dir_name, W_OK)) - { - fmt = _("%s: directory `%s' is write protected; descend into it anyway? "); - } - else if (interactive) - { - fmt = _("%s: descend into directory `%s'? "); - } - - if (fmt) - { - fprintf (stderr, fmt, program_name, full_filename (dir_name)); - if (!yesno ()) - return RM_USER_DECLINED; - } - - if (verbose) - printf ("%s\n", full_filename (dir_name)); - - /* Save cwd if needed. */ - if (need_save_cwd && save_cwd (&cwd)) - return RM_ERROR; - - /* Make target directory the current one. */ - if (chdir (dir_name) < 0) - { - error (0, errno, _("cannot change to directory %s"), - full_filename (dir_name)); - if (need_save_cwd) - free_cwd (&cwd); - return RM_ERROR; - } - - push_dir (dir_name); - - /* Save a copy of dir_name. Otherwise, remove_cwd_entries may clobber - it because it is just a pointer to the dir entry's d_name field, and - remove_cwd_entries may close the directory. */ - ASSIGN_STRDUPA (dir_name, dir_name); - - status = remove_cwd_entries (); - - pop_dir (); - - /* Restore cwd. */ - if (need_save_cwd) - { - if (restore_cwd (&cwd, NULL, NULL)) - { - free_cwd (&cwd); - return RM_ERROR; - } - free_cwd (&cwd); - } - else if (chdir ("..") < 0) - { - error (0, errno, _("cannot change back to directory %s via `..'"), - full_filename (dir_name)); - return RM_ERROR; - } - - if (interactive) - { - error (0, 0, _("remove directory `%s'%s? "), full_filename (dir_name), - (status != RM_OK ? _(" (might be nonempty)") : "")); - if (!yesno ()) - { - return RM_USER_DECLINED; - } - } - - if (rmdir (dir_name) && (errno != ENOENT || !ignore_missing_files)) - { - error (0, errno, _("cannot remove directory `%s'"), - full_filename (dir_name)); - return RM_ERROR; - } - - return RM_OK; -} - -/* Remove the file or directory specified by FS after checking appropriate - things. Return RM_OK if it is removed, and RM_ERROR or RM_USER_DECLINED - if not. If USER_SPECIFIED_NAME is non-zero, then the name part of FS may - be `.', `..', or may contain slashes. Otherwise, it must be a simple file - name (and hence must specify a file in the current directory). */ - -static enum RM_status -rm (struct File_spec *fs, int user_specified_name) +static void +rm_option_init (struct rm_options *x) { - mode_t filetype_mode; - - if (user_specified_name) - { - char *base = base_name (fs->filename); - - if (DOT_OR_DOTDOT (base)) - { - error (0, 0, _("cannot remove `.' or `..'")); - return RM_ERROR; - } - } - - if (fspec_get_filetype_mode (fs, &filetype_mode)) - { - if (ignore_missing_files && errno == ENOENT) - return RM_OK; - - error (0, errno, _("cannot remove `%s'"), full_filename (fs->filename)); - return RM_ERROR; - } - -#ifdef ENABLE_CYCLE_CHECK - if (S_ISDIR (filetype_mode)) - { - int fail; - struct active_dir_ent *old_ent; - - /* Insert this directory in the active_dir_map. - If there is already a directory in the map with the same inum, - then there's *probably* a directory cycle. This test can get - a false positive if two directories have the same inode number - but different device numbers and one directory contains the - other. But since people don't often try to delete hierarchies - containing mount points, and when they do, duplicate inode - numbers are not that likely, this isn't worth detecting. */ - old_ent = hash_insert_if_absent (active_dir_map, - make_active_dir_ent (fs->inum, - current_depth ()), - &fail); - if (fail) - error (1, 0, _("Memory exhausted")); - - if (old_ent) - { - error (0, 0, _("\ -WARNING: Circular directory structure.\n\ -This almost certainly means that you have a corrupted file system.\n\ -NOTIFY YOUR SYSTEM MANAGER.\n\ -The following two directories have the same inode number:\n")); - /* FIXME: test this!! */ - print_nth_dir (stderr, current_depth ()); - fputc ('\n', stderr); - print_nth_dir (stderr, old_ent->depth); - fputc ('\n', stderr); - fflush (stderr); - - free (old_ent); - - if (interactive) - { - error (0, 0, _("continue? ")); - if (yesno ()) - return RM_ERROR; - } - exit (1); - } - } -#endif - - if (!S_ISDIR (filetype_mode) || unlink_dirs) - { - return remove_file (fs); - } - else - { - int need_save_cwd = user_specified_name; - enum RM_status status; - - if (need_save_cwd) - need_save_cwd = (strchr (fs->filename, '/') != NULL); - - status = remove_dir (fs, need_save_cwd); - -#ifdef ENABLE_CYCLE_CHECK - { - struct active_dir_ent tmp; - struct active_dir_ent *old_ent; - - /* Remove this directory from the active_dir_map. */ - tmp.inum = fs->inum; - old_ent = hash_delete_if_present (active_dir_map, &tmp); - assert (old_ent != NULL); - free (old_ent); - } -#endif - - return status; - } + x->unlink_dirs = 0; + x->ignore_missing_files = 0; + x->interactive = 0; + x->recursive = 0; + x->stdin_tty = isatty (STDIN_FILENO); + x->verbose = 0; } int main (int argc, char **argv) { + struct rm_options x; int fail = 0; int c; @@ -959,8 +127,7 @@ main (int argc, char **argv) bindtextdomain (PACKAGE, LOCALEDIR); textdomain (PACKAGE); - verbose = ignore_missing_files = recursive = interactive - = unlink_dirs = 0; + rm_option_init (&x); while ((c = getopt_long (argc, argv, "dfirvR", long_opts, NULL)) != -1) { @@ -969,22 +136,22 @@ main (int argc, char **argv) case 0: /* Long option. */ break; case 'd': - unlink_dirs = 1; + x.unlink_dirs = 1; break; case 'f': - interactive = 0; - ignore_missing_files = 1; + x.interactive = 0; + x.ignore_missing_files = 1; break; case 'i': - interactive = 1; - ignore_missing_files = 0; + x.interactive = 1; + x.ignore_missing_files = 0; break; case 'r': case 'R': - recursive = 1; + x.recursive = 1; break; case 'v': - verbose = 1; + x.verbose = 1; break; default: usage (1); @@ -1003,7 +170,7 @@ main (int argc, char **argv) if (optind == argc) { - if (ignore_missing_files) + if (x.ignore_missing_files) exit (0); else { @@ -1012,17 +179,7 @@ main (int argc, char **argv) } } - stdin_tty = isatty (STDIN_FILENO); - - /* Initialize dir-stack obstacks. */ - obstack_init (&dir_stack); - obstack_init (&len_stack); - -#ifdef ENABLE_CYCLE_CHECK - active_dir_map = hash_initialize (ACTIVE_DIR_INITIAL_CAPACITY, free, - hash_active_dir_ent, - hash_compare_active_dir_ents); -#endif + remove_init (); for (; optind < argc; optind++) { @@ -1033,17 +190,15 @@ main (int argc, char **argv) if the arg is not a directory, it will fail with ENOTDIR. */ strip_trailing_slashes (argv[optind]); fspec_init_file (&fs, argv[optind]); - status = rm (&fs, 1); + status = rm (&fs, 1, &x); assert (VALID_STATUS (status)); if (status == RM_ERROR) fail = 1; } -#ifdef ENABLE_CYCLE_CHECK - hash_free (active_dir_map); -#endif + remove_fini (); - if (verbose) + if (x.verbose) close_stdout (); exit (fail); } -- cgit v1.2.3-54-g00ecf