DragonFly submit List (threaded) for 2004-12
[
Date Prev][
Date Next]
[
Thread Prev][
Thread Next]
[
Date Index][
Thread Index]
[PATCH] /bin/rm Add "all" interactive option
This patch adds an "all" option to the rm utility's interactive mode as
described below.
The following is true in recursive mode:
If "all" is specified to a directory, only that directory and everything
in it is removed. If "all" is specified to a file, all the files in the
same directory are deleted. If "all" is specified for a file on the
command line, all files listed on the command line are deleted. If "all"
is specified for a directory on the command line, only that directory
and everything in it is removed.
The following is true when NOT in recursive mode:
If "all" is specified to one of the files or directories listed on the
command line, all the files and directories listed will be deleted
(directories have to be empty to be deleted when in NOT in recursive mode).
The follwing is true when the -I flag is specified:
If "all" is specified, -f is assumed.
- Jason
--- rm.c.orig Sat Dec 18 13:39:18 2004
+++ rm.c Sat Dec 18 14:04:15 2004
@@ -50,10 +50,13 @@
#include <sysexits.h>
#include <unistd.h>
-int dflag, eval, fflag, iflag, Pflag, vflag, Wflag, stdin_ok;
-int rflag, Iflag;
-uid_t uid;
+static int dflag, fflag, Iflag, iflag, Pflag, rflag, vflag, Wflag;
+static int eval;
+static int removeAll;
+static int stdin_ok;
+static uid_t uid;
+static int rm_get_answeer(void);
static int check(const char *, const char *, struct stat *);
static int check2(char **);
static void checkdot(char **);
@@ -164,6 +167,7 @@
int needstat;
int flags;
int rval;
+ int removeLevel;
/*
* Remove a file hierarchy. If forcing removal (-f), or interactive
@@ -184,6 +188,7 @@
flags |= FTS_WHITEOUT;
if (!(fts = fts_open(argv, flags, NULL)))
err(1, NULL);
+ removeLevel = -1;
while ((p = fts_read(fts)) != NULL) {
switch (p->fts_info) {
case FTS_DNR:
@@ -209,18 +214,35 @@
}
continue;
case FTS_D:
- /* Pre-order: give user chance to skip. */
+ /*
+ * Stop removing everything when we go to another
+ * directory at the same level or higher up in the
+ * directory hierarchy.
+ */
+ if (removeAll && removeLevel >= p->fts_level) {
+ removeAll = 0;
+ removeLevel = -1;
+ }
+
if (!fflag && !check(p->fts_path, p->fts_accpath,
p->fts_statp)) {
fts_set(fts, p, FTS_SKIP);
p->fts_number = SKIPPED;
+ } else {
+ /*
+ * Check if the user has just asked for everything
+ * in this directory to be removed.
+ */
+ if (removeAll && removeLevel == -1)
+ removeLevel = p->fts_level;
+
+ if (!uid
+ && (p->fts_statp->st_flags & (UF_APPEND|UF_IMMUTABLE))
+ && !(p->fts_statp->st_flags & (SF_APPEND|SF_IMMUTABLE))
+ && chflags(p->fts_accpath,
+ p->fts_statp->st_flags &= ~(UF_APPEND|UF_IMMUTABLE)) < 0)
+ goto err;
}
- else if (!uid &&
- (p->fts_statp->st_flags & (UF_APPEND|UF_IMMUTABLE)) &&
- !(p->fts_statp->st_flags & (SF_APPEND|SF_IMMUTABLE)) &&
- chflags(p->fts_accpath,
- p->fts_statp->st_flags &= ~(UF_APPEND|UF_IMMUTABLE)) < 0)
- goto err;
continue;
case FTS_DP:
/* Post-order: see if user skipped. */
@@ -228,9 +250,27 @@
continue;
break;
default:
+ /*
+ * Stop removing everything when we go from
+ * directories to files at the same level, and
+ * when we go to files higher up in the directory
+ * hierarchy.
+ */
+ if (removeAll && removeLevel >= p->fts_level) {
+ removeAll = 0;
+ removeLevel = -1;
+ }
+
if (!fflag &&
!check(p->fts_path, p->fts_accpath, p->fts_statp))
continue;
+
+ /*
+ * Check if the user has just asked for every file
+ * at this directory level to be removed.
+ */
+ if (removeAll && removeLevel == -1)
+ removeLevel = p->fts_level - 1;
}
rval = 0;
@@ -425,16 +465,33 @@
return (0);
}
+static int
+rm_get_answeer(void)
+{
+ int c;
+ int answeer;
+
+ answeer = getchar();
+
+ c = answeer;
+ while (c != '\n' && c != EOF)
+ c = getchar();
+
+ return answeer;
+}
static int
check(const char *path, const char *name, struct stat *sp)
{
- int ch, first;
+ int answeer;
char modep[15], *flagsp;
+ if (removeAll)
+ return 1;
+
/* Check -i first. */
if (iflag)
- fprintf(stderr, "remove %s? ", path);
+ fprintf(stderr, "remove %s? [y/n/a]: ", path);
else {
/*
* If it's not a symbolic link and it's unwritable and we're
@@ -453,7 +510,7 @@
strmode(sp->st_mode, modep);
if ((flagsp = fflagstostr(sp->st_flags)) == NULL)
err(1, NULL);
- fprintf(stderr, "override %s%s%s/%s %s%sfor %s? ",
+ fprintf(stderr, "override %s%s%s/%s %s%sfor %s? [y/n/a]: ",
modep + 1, modep[9] == ' ' ? "" : " ",
user_from_uid(sp->st_uid, 0),
group_from_gid(sp->st_gid, 0),
@@ -463,18 +520,20 @@
}
fflush(stderr);
- first = ch = getchar();
- while (ch != '\n' && ch != EOF)
- ch = getchar();
- return (first == 'y' || first == 'Y');
+ answeer = rm_get_answeer();
+ if (answeer == 'a' || answeer == 'A') {
+ removeAll = 1;
+ return 1;
+ } else if (answeer == 'y' || answeer == 'Y')
+ return 1;
+ return 0;
}
static int
check2(char **argv)
{
struct stat st;
- int first;
- int ch;
+ int answeer;
int fcount = 0;
int dcount = 0;
int i;
@@ -490,8 +549,7 @@
}
}
}
- first = 0;
- while (first != 'n' && first != 'N' && first != 'y' && first != 'Y') {
+ for (;;) {
if (dcount && rflag) {
fprintf(stderr, "recursively remove");
if (dcount == 1)
@@ -507,16 +565,27 @@
} else {
return(1);
}
- fprintf(stderr, "? ");
+ fprintf(stderr, "? [y/n/a]: ");
fflush(stderr);
- first = ch = getchar();
- while (ch != '\n' && ch != EOF)
- ch = getchar();
- if (ch == EOF)
+ answeer = rm_get_answeer();
+ if (answeer == EOF)
+ break;
+ if (answeer == 'n' || answeer == 'N')
break;
+ if (answeer == 'y' || answeer == 'Y')
+ return 1;
+ if (answeer == 'a' || answeer == 'A') {
+ /*
+ * Since the user specified the -I flag and answeered
+ * "all" to this question, do not prompt them for
+ * confirmation again.
+ */
+ fflag = 1;
+ return 1;
+ }
}
- return (first == 'y' || first == 'Y');
+ return 0;
}
#define ISDOT(a) ((a)[0] == '.' && (!(a)[1] || ((a)[1] == '.' && !(a)[2])))
[
Date Prev][
Date Next]
[
Thread Prev][
Thread Next]
[
Date Index][
Thread Index]