diff options
author | Jim Meyering <jim@meyering.net> | 2003-01-04 10:07:44 +0000 |
---|---|---|
committer | Jim Meyering <jim@meyering.net> | 2003-01-04 10:07:44 +0000 |
commit | 8b6b22bcefc27f212b66d9d895a1809c885ac106 (patch) | |
tree | d48f27bc68bf64350fe5f7dd770264f9bcda68ee | |
parent | e2b894c771ef46729aeffa0bd05d16e1bfb731f5 (diff) | |
download | coreutils-8b6b22bcefc27f212b66d9d895a1809c885ac106.tar.xz |
rm could be tricked into mistakenly reporting a cycle.
* src/remove.c: [cycle_check_state]: New global.
(remove_cwd_entries): Adapt to new semantics of cycle_check.
(rm): Call cycle_check_init and cycle_check_free for each file.
When rm detects a cycle, don't abort the entire command,
but rather just the affected command line argument.
* src/remove.c: Include <setjmp.h>
(struct dirstack_state) [current_arg_jumpbuf]: New member.
(remove_cwd_entries): Call longjmp if we detect a cycle.
(rm): Call setjmp here.
* src/remove.c (cycle_check, is_power_of_two): Remove functions.
Instead, include cycle-check.h and use it.
-rw-r--r-- | src/remove.c | 64 |
1 files changed, 24 insertions, 40 deletions
diff --git a/src/remove.c b/src/remove.c index 67e09ccf1..ffa7ab21c 100644 --- a/src/remove.c +++ b/src/remove.c @@ -24,10 +24,12 @@ #include <config.h> #include <stdio.h> #include <sys/types.h> +#include <setjmp.h> #include <assert.h> #include "save-cwd.h" #include "system.h" +#include "cycle-check.h" #include "dirname.h" #include "error.h" #include "file-type.h" @@ -142,6 +144,12 @@ struct dirstack_state into each directory to be processed. When finished with the hierarchy under a directory, pop the active dir stack. */ struct obstack Active_dir; + + /* Used to detect cycles. */ + struct cycle_check_state cycle_check_state; + + /* Target of a longjmp in case rm detects a directory cycle. */ + jmp_buf current_arg_jumpbuf; }; typedef struct dirstack_state DS; @@ -498,44 +506,6 @@ AD_is_removable (DS const *ds, char const *file) return ! (top->unremovable && hash_lookup (top->unremovable, file)); } -static inline bool -is_power_of_two (unsigned int i) -{ - return (i & (i - 1)) == 0; -} - -static void -cycle_check (DS const *ds, struct stat const *sb) -{ -#ifdef ENABLE_CYCLE_CHECK - /* If there is a directory cycle, detect it (lazily) and die. */ - static struct dev_ino dir_cycle_detect_dev_ino; - static unsigned int chdir_counter; - - /* If the current directory ever happens to be the same - as the one we last recorded for the cycle detection, - then it's obviously part of a cycle. */ - if (chdir_counter && SAME_INODE (*sb, dir_cycle_detect_dev_ino)) - { - 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 directory is part of the cycle:\n %s\n"), - quote (full_filename ("."))); - exit (EXIT_FAILURE); - } - - /* If the number of `descending' chdir calls is a power of two, - record the dev/ino of the current directory. */ - if (is_power_of_two (++chdir_counter)) - { - dir_cycle_detect_dev_ino.st_dev = sb->st_dev; - dir_cycle_detect_dev_ino.st_ino = sb->st_ino; - } -#endif -} - static bool is_empty_dir (char const *dir) { @@ -909,7 +879,16 @@ remove_cwd_entries (DS *ds, char **subdir, struct stat *subdir_sb, status = RM_ERROR; break; } - cycle_check (ds, subdir_sb); + if (cycle_check (&ds->cycle_check_state, subdir_sb)) + { + 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 directory is part of the cycle:\n %s\n"), + quote (full_filename ("."))); + longjmp (ds->current_arg_jumpbuf, 1); + } *subdir = xstrdup (f); break; @@ -1120,7 +1099,12 @@ rm (size_t n_files, char const *const *file, struct rm_options const *x) for (i = 0; i < n_files; i++) { - enum RM_status s = rm_1 (ds, file[i], x, &cwd_state); + enum RM_status s; + cycle_check_init (&ds->cycle_check_state); + if (setjmp (ds->current_arg_jumpbuf)) + s = RM_ERROR; + else + s = rm_1 (ds, file[i], x, &cwd_state); assert (VALID_STATUS (s)); UPDATE_STATUS (status, s); } |