128 lines
4.5 KiB
Plaintext
128 lines
4.5 KiB
Plaintext
|
$OpenBSD: patch-src_remove_c,v 1.1 2003/02/25 14:35:43 brad Exp $
|
||
|
--- src/remove.c.orig Sun Feb 18 11:17:32 2001
|
||
|
+++ src/remove.c Mon Feb 24 23:21:17 2003
|
||
|
@@ -433,10 +433,13 @@ same_file (const char *file_1, const cha
|
||
|
|
||
|
|
||
|
/* Recursively remove all of the entries in the current directory.
|
||
|
- Return an indication of the success of the operation. */
|
||
|
+ Return an indication of the success of the operation.
|
||
|
+ CWD_DEV_INO must store the device and inode numbers of the
|
||
|
+ current working directory. */
|
||
|
|
||
|
static enum RM_status
|
||
|
-remove_cwd_entries (const struct rm_options *x)
|
||
|
+remove_cwd_entries (const struct rm_options *x,
|
||
|
+ struct dev_ino const *cwd_dev_ino)
|
||
|
{
|
||
|
/* NOTE: this is static. */
|
||
|
static DIR *dirp = NULL;
|
||
|
@@ -549,7 +552,7 @@ remove_cwd_entries (const struct rm_opti
|
||
|
/* 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, x);
|
||
|
+ tmp_status = rm (&fs, 0, x, cwd_dev_ino);
|
||
|
|
||
|
/* Update status. */
|
||
|
if (tmp_status > status)
|
||
|
@@ -664,12 +667,14 @@ remove_file (struct File_spec *fs, const
|
||
|
FIXME: describe need_save_cwd parameter. */
|
||
|
|
||
|
static enum RM_status
|
||
|
-remove_dir (struct File_spec *fs, int need_save_cwd, const struct rm_options *x)
|
||
|
+remove_dir (struct File_spec *fs, int need_save_cwd,
|
||
|
+ struct rm_options const *x, struct dev_ino const *cwd_dev_ino)
|
||
|
{
|
||
|
enum RM_status status;
|
||
|
struct saved_cwd cwd;
|
||
|
char *dir_name = fs->filename;
|
||
|
const char *fmt = NULL;
|
||
|
+ struct dev_ino tmp_cwd_dev_ino;
|
||
|
|
||
|
if (!x->recursive)
|
||
|
{
|
||
|
@@ -738,6 +743,9 @@ was replaced with either another directo
|
||
|
(unsigned long)(sb.st_dev),
|
||
|
(unsigned long)(sb.st_ino));
|
||
|
}
|
||
|
+
|
||
|
+ tmp_cwd_dev_ino.st_dev = sb.st_dev;
|
||
|
+ tmp_cwd_dev_ino.st_ino = sb.st_ino;
|
||
|
}
|
||
|
|
||
|
push_dir (dir_name);
|
||
|
@@ -747,7 +755,7 @@ was replaced with either another directo
|
||
|
remove_cwd_entries may close the directory. */
|
||
|
ASSIGN_STRDUPA (dir_name, dir_name);
|
||
|
|
||
|
- status = remove_cwd_entries (x);
|
||
|
+ status = remove_cwd_entries (x, &tmp_cwd_dev_ino);
|
||
|
|
||
|
pop_dir ();
|
||
|
|
||
|
@@ -761,11 +769,34 @@ was replaced with either another directo
|
||
|
}
|
||
|
free_cwd (&cwd);
|
||
|
}
|
||
|
- else if (chdir ("..") < 0)
|
||
|
+ else
|
||
|
{
|
||
|
- error (0, errno, _("cannot change back to directory %s via `..'"),
|
||
|
- quote (full_filename (dir_name)));
|
||
|
- return RM_ERROR;
|
||
|
+ struct stat sb;
|
||
|
+ if (chdir ("..") < 0)
|
||
|
+ {
|
||
|
+ error (0, errno, _("cannot change back to directory %s via `..'"),
|
||
|
+ quote (full_filename (dir_name)));
|
||
|
+ return RM_ERROR;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (lstat (".", &sb))
|
||
|
+ error (EXIT_FAILURE, errno,
|
||
|
+ _("cannot lstat `.' in %s"), quote (full_filename (".")));
|
||
|
+
|
||
|
+ if (!SAME_INODE (sb, *cwd_dev_ino))
|
||
|
+ {
|
||
|
+ error (EXIT_FAILURE, 0,
|
||
|
+ _("ERROR: the directory %s initially had device/inode\n\
|
||
|
+numbers %lu/%lu, but now (after changing into at least one subdirectory\n\
|
||
|
+and changing back via `..'), the numbers for `.' are %lu/%lu.\n\
|
||
|
+That means that while rm was running, a partially-removed subdirectory\n\
|
||
|
+was moved to a different position in the file system hierarchy."),
|
||
|
+ quote (full_filename (".")),
|
||
|
+ (unsigned long)(cwd_dev_ino->st_dev),
|
||
|
+ (unsigned long)(cwd_dev_ino->st_ino),
|
||
|
+ (unsigned long)(sb.st_dev),
|
||
|
+ (unsigned long)(sb.st_ino));
|
||
|
+ }
|
||
|
}
|
||
|
|
||
|
if (x->interactive)
|
||
|
@@ -814,10 +845,13 @@ was replaced with either another directo
|
||
|
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). */
|
||
|
+ name (and hence must specify a file in the current directory).
|
||
|
+ CWD_DEV_INO must store the device and inode numbers of the
|
||
|
+ current working directory. */
|
||
|
|
||
|
enum RM_status
|
||
|
-rm (struct File_spec *fs, int user_specified_name, const struct rm_options *x)
|
||
|
+rm (struct File_spec *fs, int user_specified_name,
|
||
|
+ struct rm_options const *x, struct dev_ino const *cwd_dev_ino)
|
||
|
{
|
||
|
mode_t filetype_mode;
|
||
|
|
||
|
@@ -899,7 +933,7 @@ The following two directories have the s
|
||
|
if (need_save_cwd)
|
||
|
need_save_cwd = (strchr (fs->filename, '/') != NULL);
|
||
|
|
||
|
- status = remove_dir (fs, need_save_cwd, x);
|
||
|
+ status = remove_dir (fs, need_save_cwd, x, cwd_dev_ino);
|
||
|
|
||
|
#ifdef ENABLE_CYCLE_CHECK
|
||
|
{
|