Mercurial > hg > toybox
changeset 739:451d7e91232e
Complicate the rm -i behavior to do what posix specifies.
author | Rob Landley <rob@landley.net> |
---|---|
date | Sat, 08 Dec 2012 02:26:56 -0600 |
parents | 075eaff297f8 |
children | f5ef67700a26 |
files | lib/dirtree.c toys/posix/rm.c |
diffstat | 2 files changed, 33 insertions(+), 16 deletions(-) [+] |
line wrap: on
line diff
--- a/lib/dirtree.c Sat Dec 08 02:25:32 2012 -0600 +++ b/lib/dirtree.c Sat Dec 08 02:26:56 2012 -0600 @@ -62,6 +62,7 @@ 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; }
--- a/toys/posix/rm.c Sat Dec 08 02:25:32 2012 -0600 +++ b/toys/posix/rm.c Sat Dec 08 02:26:56 2012 -0600 @@ -25,32 +25,48 @@ 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; + + // 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; + } + + // 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; } } - // Prompt if necessary - if (!(flags & FLAG_f) && faccessat(fd, try->name, W_OK, AT_SYMLINK_NOFOLLOW)) - or++; - - if ((or && isatty(0)) || (flags & FLAG_i)) { - fprintf(stderr, "rm %s", or ? "ro " : ""); - if (!yesno(try->name, 2)) return 0; - } - - // 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;