aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Landley <rob@landley.net>2012-12-08 02:26:56 -0600
committerRob Landley <rob@landley.net>2012-12-08 02:26:56 -0600
commit37de8ed2aac771c118702b2315ccac7e02ecb729 (patch)
tree0ee46cb3882081c4434fe5ade968241989dc77cf
parentdb8eb323b3b8ded0eb75c0872563784ae4356e99 (diff)
downloadtoybox-37de8ed2aac771c118702b2315ccac7e02ecb729.tar.gz
Complicate the rm -i behavior to do what posix specifies.
-rw-r--r--lib/dirtree.c1
-rw-r--r--toys/posix/rm.c42
2 files changed, 30 insertions, 13 deletions
diff --git a/lib/dirtree.c b/lib/dirtree.c
index 33188e1f..c9660fc7 100644
--- a/lib/dirtree.c
+++ b/lib/dirtree.c
@@ -62,6 +62,7 @@ error:
char *path = parent ? dirtree_path(parent, 0) : "";
perror_msg("%s%s%s",path, parent ? "/" : "", name);
}
+ if (parent) parent->symlink = (char *)1;
free(dt);
return 0;
}
diff --git a/toys/posix/rm.c b/toys/posix/rm.c
index de565a76..dae5eee4 100644
--- a/toys/posix/rm.c
+++ b/toys/posix/rm.c
@@ -25,32 +25,48 @@ config RM
static int do_rm(struct dirtree *try)
{
int fd = dirtree_parentfd(try), flags = toys.optflags;
- int or = 0, using = 0;
+ int dir = S_ISDIR(try->st.st_mode), or = 0, using = 0;
// Skip . and .. (yes, even explicitly on the command line: posix says to)
if (!dirtree_notdotdot(try)) return 0;
- if (S_ISDIR(try->st.st_mode)) {
- if (flags & (FLAG_r|FLAG_R)) {
- if (try->data != -1) return DIRTREE_COMEAGAIN;
- using = AT_REMOVEDIR;
- }
- }
+ // Intentionally fail non-recursive attempts to remove even an empty dir
+ // (via wrong flags to unlinkat) because POSIX says to.
+ if (dir && !(flags & (FLAG_r|FLAG_R))) goto skip;
- // Prompt if necessary
+ // This is either the posix section 2(b) prompt or the section 3 prompt.
if (!(flags & FLAG_f) && faccessat(fd, try->name, W_OK, AT_SYMLINK_NOFOLLOW))
or++;
+ if (!(dir && try->data == -1) && ((or && isatty(0)) || (flags & FLAG_i))) {
+ char *s = dirtree_path(try, 0);
+ fprintf(stderr, "rm %s%s", or ? "ro " : "", dir ? "dir " : "");
+ or = yesno(s, 0);
+ free(s);
+ if (!or) goto nodelete;
+ }
- if ((or && isatty(0)) || (flags & FLAG_i)) {
- fprintf(stderr, "rm %s", or ? "ro " : "");
- if (!yesno(try->name, 2)) return 0;
+ // handle directory recursion
+ if (dir) {
+
+ if (try->data != -1) return DIRTREE_COMEAGAIN;
+ using = AT_REMOVEDIR;
+ if (try->symlink) goto nodelete;
+ if (flags & FLAG_i) {
+ char *s = dirtree_path(try, 0);
+ // This is the section 2(d) prompt. (Yes, posix says to prompt twice.)
+ fprintf(stderr, "rmdir ");
+ or = yesno(s, 0);
+ free(s);
+ if (!or) goto nodelete;
+ }
}
- // Intentionally fail non-recursive attempts to remove even an empty dir
- // because POSIX says to.
+skip:
if (unlinkat(fd, try->name, using)) {
perror_msg("%s", try->name);
toys.exitval = 1;
+nodelete:
+ if (try->parent) try->parent->symlink = (char *)1;
}
return 0;