[prev in list] [next in list] [prev in thread] [next in thread]
List: busybox
Subject: Re: rm -r fails to delete entire hierarchy when path goes in and out of it
From: Gian Ntzik <gian.ntzik08 () imperial ! ac ! uk>
Date: 2014-09-18 19:17:58
Message-ID: 87ha04ohzt.fsf () imperial ! ac ! uk
[Download RAW message or body]
Denys Vlasenko <vda.linux@googlemail.com> writes:
> This would work:
>
>
> int curdir = xopen(".", O_RDONLY);
>
> do {
> /* This removes any trailing slashes from *argv.
> * It returns "/" _only_ for root directory.
> */
> char *base = bb_get_last_path_component_strip(*argv);
>
> if (DOT_OR_DOTDOT(base) || LONE_CHAR(base, '/')) {
> bb_error_msg("can't remove '.', '..' or '/'");
> status = 1;
> goto next;
> }
> if (*argv != base) { /* if *args contains slash(es) */
> base[-1] = '\0';
> if (chdir(*argv) != 0) {
> status = 1;
> goto next;
> }
> }
> if (remove_file(base, flags) < 0) {
> status = 1;
> }
> if (fchdir(curdir) != 0) {
> bb_error_msg_and_die("can't return to
> current directory");
> }
> next: ;
> } while (*++argv);
>
I'm not sure if showing a truncated path in verbose or interactive mode
is the right thing to do. At least to me it seems a bit
counter-intuitive when you are removing something which is not located
within your current directory.
Here is an alternative which uses realpath():
.
.
.
struct stat path_stat;
char *path;
int free_path = 0;
.
.
.
do {
/* This removes any trailing slashes from *argv.
* It returns "/" _only_ for root directory.
*/
const char *base = bb_get_last_path_component_strip(*argv);
if (DOT_OR_DOTDOT(base) || LONE_CHAR(base, '/')) {
bb_error_msg("can't remove '.' or '..' or '/'");
status = 1;
continue;
}
path = *argv;
/* if *argv is not a symlink canonicallize it */
if (lstat(*argv, &path_stat) < 0) {
if (errno != ENOENT || errno != ENOTDIR) {
bb_perror_msg("can't stat '%s'", *argv);
} else {
bb_perror_msg("can't remove '%s'", *argv);
}
status = 1;
continue;
}
if (!S_ISLNK(path_stat.st_mode)) {
if (!(path = realpath(*argv, NULL))) {
bb_perror_msg("can't remove '%s'", *argv);
status = 1;
continue;
}
free_path = 1;
}
if (remove_file(path, flags) >= 0) {
continue;
}
status = 1;
if (free_path) free(path);
} while (*++argv);
In verbose/interactive mode this prints correct absolute canonical
paths.
The downside is the extra lstat() to check if *argv is a symlink to
decide if realpath() should be used or not. But this could be improved if
remove_file was changed to accept an extra optional struct stat
*argument. If NULL, remove_file would perform it's own lstat, otherwise
use the passed argument.
_______________________________________________
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic