summaryrefslogtreecommitdiffstats
path: root/Src/Modules
diff options
context:
space:
mode:
authorTanaka Akira <akr@users.sourceforge.net>1999-12-09 16:09:31 +0000
committerTanaka Akira <akr@users.sourceforge.net>1999-12-09 16:09:31 +0000
commit4f9b1b9804b2427ebe99cd8f79ff17fd22570957 (patch)
tree20ccd1815c022adc18172fd7ded79956b84d6764 /Src/Modules
parentzsh-workers/8981 (diff)
downloadzsh-4f9b1b9804b2427ebe99cd8f79ff17fd22570957.tar
zsh-4f9b1b9804b2427ebe99cd8f79ff17fd22570957.tar.gz
zsh-4f9b1b9804b2427ebe99cd8f79ff17fd22570957.tar.bz2
zsh-4f9b1b9804b2427ebe99cd8f79ff17fd22570957.tar.lz
zsh-4f9b1b9804b2427ebe99cd8f79ff17fd22570957.tar.xz
zsh-4f9b1b9804b2427ebe99cd8f79ff17fd22570957.tar.zst
zsh-4f9b1b9804b2427ebe99cd8f79ff17fd22570957.zip
zsh-workers/8982
Diffstat (limited to 'Src/Modules')
-rw-r--r--Src/Modules/files.c334
-rw-r--r--Src/Modules/files.mdd2
2 files changed, 268 insertions, 68 deletions
diff --git a/Src/Modules/files.c b/Src/Modules/files.c
index dc91227f8..844ca7d25 100644
--- a/Src/Modules/files.c
+++ b/Src/Modules/files.c
@@ -30,6 +30,7 @@
#include "files.mdh"
typedef int (*MoveFunc) _((char const *, char const *));
+typedef int (*RecurseFunc) _((char *, char *, struct stat const *, void *));
#ifndef STDC_HEADERS
extern int link _((const char *, const char *));
@@ -37,6 +38,8 @@ extern int symlink _((const char *, const char *));
extern int rename _((const char *, const char *));
#endif
+struct recursivecmd;
+
#include "files.pro"
/**/
@@ -312,20 +315,42 @@ domove(char *nam, MoveFunc move, char *p, char *q, int flags)
return 0;
}
-/* rm builtin */
+/* general recursion */
+
+struct recursivecmd {
+ char *nam;
+ int opt_noerr;
+ int opt_recurse;
+ int opt_safe;
+ RecurseFunc dirpre_func;
+ RecurseFunc dirpost_func;
+ RecurseFunc leaf_func;
+ void *magic;
+};
/**/
static int
-bin_rm(char *nam, char **args, char *ops, int func)
+recursivecmd(char *nam, int opt_noerr, int opt_recurse, int opt_safe,
+ char **args, RecurseFunc dirpre_func, RecurseFunc dirpost_func,
+ RecurseFunc leaf_func, void *magic)
{
int err = 0, len;
char *rp, *s;
struct dirsav ds;
+ struct recursivecmd reccmd;
+ reccmd.nam = nam;
+ reccmd.opt_noerr = opt_noerr;
+ reccmd.opt_recurse = opt_recurse;
+ reccmd.opt_safe = opt_safe;
+ reccmd.dirpre_func = dirpre_func;
+ reccmd.dirpost_func = dirpost_func;
+ reccmd.leaf_func = leaf_func;
+ reccmd.magic = magic;
ds.ino = ds.dev = 0;
ds.dirname = NULL;
ds.dirfd = ds.level = -1;
- if (ops['r'] || ops['s']) {
+ if (opt_recurse || opt_safe) {
if ((ds.dirfd = open(".", O_RDONLY|O_NOCTTY)) < 0 &&
zgetdir(&ds) && *ds.dirname != '/')
ds.dirfd = open("..", O_RDONLY|O_NOCTTY);
@@ -333,7 +358,7 @@ bin_rm(char *nam, char **args, char *ops, int func)
for(; !errflag && !(err & 2) && *args; args++) {
rp = ztrdup(*args);
unmetafy(rp, &len);
- if (ops['s']) {
+ if (opt_safe) {
s = strrchr(rp, '/');
if (s && !s[1]) {
while (*s == '/' && s > rp)
@@ -353,16 +378,16 @@ bin_rm(char *nam, char **args, char *ops, int func)
d.ino = d.dev = 0;
d.dirname = NULL;
d.dirfd = d.level = -1;
- err |= dorm(nam, *args, s + 1, ops, &d, 0);
+ err |= recursivecmd_doone(&reccmd, *args, s + 1, &d, 0);
zsfree(d.dirname);
if (restoredir(&ds))
err |= 2;
- } else
+ } else if(!opt_noerr)
zwarnnam(nam, "%s: %e", *args, errno);
} else
- err |= dorm(nam, *args, rp, ops, &ds, 0);
+ err |= recursivecmd_doone(&reccmd, *args, rp, &ds, 0);
} else
- err |= dorm(nam, *args, rp, ops, &ds, 1);
+ err |= recursivecmd_doone(&reccmd, *args, rp, &ds, 1);
zfree(rp, len + 1);
}
if ((err & 2) && ds.dirfd >= 0 && restoredir(&ds) && zchdir(pwd)) {
@@ -373,76 +398,55 @@ bin_rm(char *nam, char **args, char *ops, int func)
if (ds.dirfd >= 0)
close(ds.dirfd);
zsfree(ds.dirname);
- return ops['f'] ? 0 : !!err;
+ return !!err;
}
/**/
static int
-dorm(char *nam, char *arg, char *rp, char *ops, struct dirsav *ds, int first)
+recursivecmd_doone(struct recursivecmd const *reccmd,
+ char *arg, char *rp, struct dirsav *ds, int first)
{
- struct stat st;
+ struct stat st, *sp = NULL;
- if((!ops['d'] || !ops['f']) && !lstat(rp, &st)) {
- if(!ops['d'] && S_ISDIR(st.st_mode)) {
- if(ops['r'])
- return dormr(nam, arg, rp, ops, ds, first);
- if(!ops['f'])
- zwarnnam(nam, "%s: %e", arg, EISDIR);
- return 1;
- }
- if(!ops['f'] && ops['i']) {
- nicezputs(nam, stderr);
- fputs(": remove `", stderr);
- nicezputs(arg, stderr);
- fputs("'? ", stderr);
- fflush(stderr);
- if(!ask())
- return 0;
- } else if(!ops['f'] &&
- !S_ISLNK(st.st_mode) &&
- access(rp, W_OK)) {
- nicezputs(nam, stderr);
- fputs(": remove `", stderr);
- nicezputs(arg, stderr);
- fprintf(stderr, "', overriding mode %04o? ",
- mode_to_octal(st.st_mode));
- fflush(stderr);
- if(!ask())
- return 0;
- }
+ if(reccmd->opt_recurse && !lstat(rp, &st)) {
+ if(S_ISDIR(st.st_mode))
+ return recursivecmd_dorec(reccmd, arg, rp, &st, ds, first);
+ sp = &st;
}
- if(!unlink(rp))
- return 0;
- if(!ops['f'])
- zwarnnam(nam, "%s: %e", arg, errno);
- return 1;
+ return reccmd->leaf_func(arg, rp, sp, reccmd->magic);
}
/**/
static int
-dormr(char *nam, char *arg, char *rp, char *ops, struct dirsav *ds, int first)
+recursivecmd_dorec(struct recursivecmd const *reccmd,
+ char *arg, char *rp, struct stat const *sp, struct dirsav *ds, int first)
{
char *fn;
DIR *d;
- int err;
+ int err, err1;
struct dirsav dsav;
char *files = NULL;
int fileslen = 0;
+ err1 = reccmd->dirpre_func(arg, rp, sp, reccmd->magic);
+ if(err1 & 2)
+ return 2;
+
err = -lchdir(rp, ds, !first);
if (err) {
- if (!ops['f'])
- zwarnnam(nam, "%s: %e", arg, errno);
+ if(!reccmd->opt_noerr)
+ zwarnnam(reccmd->nam, "%s: %e", arg, errno);
return err;
}
+ err = err1;
dsav.ino = dsav.dev = 0;
dsav.dirname = NULL;
dsav.dirfd = dsav.level = -1;
d = opendir(".");
if(!d) {
- if(!ops['f'])
- zwarnnam(nam, "%s: %e", arg, errno);
+ if(!reccmd->opt_noerr)
+ zwarnnam(reccmd->nam, "%s: %e", arg, errno);
err = 1;
} else {
int arglen = strlen(arg) + 1;
@@ -462,7 +466,7 @@ dormr(char *nam, char *arg, char *rp, char *ops, struct dirsav *ds, int first)
narg[arglen-1] = '/';
strcpy(narg + arglen, fn);
unmetafy(fn, NULL);
- err |= dorm(nam, narg, fn, ops, &dsav, 0);
+ err |= recursivecmd_doone(reccmd, narg, fn, &dsav, 0);
fn += l;
}
hrealloc(files, fileslen, 0);
@@ -471,25 +475,219 @@ dormr(char *nam, char *arg, char *rp, char *ops, struct dirsav *ds, int first)
if (err & 2)
return 2;
if (restoredir(ds)) {
- if(!ops['f'])
- zwarnnam(nam, "failed to return to previous directory: %e",
+ if(!reccmd->opt_noerr)
+ zwarnnam(reccmd->nam, "failed to return to previous directory: %e",
NULL, errno);
return 2;
}
- if(!ops['f'] && ops['i']) {
- nicezputs(nam, stderr);
+ return err | reccmd->dirpost_func(arg, rp, sp, reccmd->magic);
+}
+
+/**/
+static int
+recurse_donothing(char *arg, char *rp, struct stat const *sp, void *magic)
+{
+ return 0;
+}
+
+/* rm builtin */
+
+struct rmmagic {
+ char *nam;
+ int opt_force;
+ int opt_interact;
+ int opt_unlinkdir;
+};
+
+/**/
+static int
+rm_leaf(char *arg, char *rp, struct stat const *sp, void *magic)
+{
+ struct rmmagic *rmm = magic;
+ struct stat st;
+
+ if(!rmm->opt_unlinkdir || !rmm->opt_force) {
+ if(!sp) {
+ if(!lstat(rp, &st))
+ sp = &st;
+ }
+ if(sp) {
+ if(!rmm->opt_unlinkdir && S_ISDIR(sp->st_mode)) {
+ if(rmm->opt_force)
+ return 0;
+ zwarnnam(rmm->nam, "%s: %e", arg, EISDIR);
+ return 1;
+ }
+ if(rmm->opt_interact) {
+ nicezputs(rmm->nam, stderr);
+ fputs(": remove `", stderr);
+ nicezputs(arg, stderr);
+ fputs("'? ", stderr);
+ fflush(stderr);
+ if(!ask())
+ return 0;
+ } else if(!rmm->opt_force &&
+ !S_ISLNK(sp->st_mode) &&
+ access(rp, W_OK)) {
+ nicezputs(rmm->nam, stderr);
+ fputs(": remove `", stderr);
+ nicezputs(arg, stderr);
+ fprintf(stderr, "', overriding mode %04o? ",
+ mode_to_octal(sp->st_mode));
+ fflush(stderr);
+ if(!ask())
+ return 0;
+ }
+ }
+ }
+ if(unlink(rp) && !rmm->opt_force) {
+ zwarnnam(rmm->nam, "%s: %e", arg, errno);
+ return 1;
+ }
+ return 0;
+}
+
+/**/
+static int
+rm_dirpost(char *arg, char *rp, struct stat const *sp, void *magic)
+{
+ struct rmmagic *rmm = magic;
+
+ if(rmm->opt_interact) {
+ nicezputs(rmm->nam, stderr);
fputs(": remove `", stderr);
nicezputs(arg, stderr);
fputs("'? ", stderr);
fflush(stderr);
if(!ask())
- return err;
+ return 0;
}
- if(!rmdir(rp))
- return err;
- if(!ops['f'])
- zwarnnam(nam, "%s: %e", arg, errno);
- return 1;
+ if(rmdir(rp) && !rmm->opt_force) {
+ zwarnnam(rmm->nam, "%s: %e", arg, errno);
+ return 1;
+ }
+ return 0;
+}
+
+/**/
+static int
+bin_rm(char *nam, char **args, char *ops, int func)
+{
+ struct rmmagic rmm;
+ int err;
+
+ rmm.nam = nam;
+ rmm.opt_force = ops['f'];
+ rmm.opt_interact = ops['i'] && !ops['f'];
+ rmm.opt_unlinkdir = ops['d'];
+ err = recursivecmd(nam, ops['f'], ops['r'] && !ops['d'], ops['s'],
+ args, recurse_donothing, rm_dirpost, rm_leaf, &rmm);
+ return ops['f'] ? 0 : err;
+}
+
+/* chown builtin */
+
+struct chownmagic {
+ char *nam;
+ uid_t uid;
+ gid_t gid;
+};
+
+/**/
+static int
+chown_dochown(char *arg, char *rp, struct stat const *sp, void *magic)
+{
+ struct chownmagic *chm = magic;
+
+ if(lchown(rp, chm->uid, chm->gid)) {
+ zwarnnam(chm->nam, "%s: %e", arg, errno);
+ return 1;
+ }
+ return 0;
+}
+
+/**/
+static unsigned long getnumeric(char *p, int *errp)
+{
+ unsigned long ret;
+
+ if(*p < '0' || *p > '9') {
+ *errp = 1;
+ return 0;
+ }
+ ret = strtoul(p, &p, 10);
+ *errp = !!*p;
+ return ret;
+}
+
+enum { BIN_CHOWN, BIN_CHGRP };
+
+/**/
+static int
+bin_chown(char *nam, char **args, char *ops, int func)
+{
+ struct chownmagic chm;
+ char *uspec = ztrdup(*args), *p = uspec;
+
+ chm.nam = nam;
+ if(func == BIN_CHGRP) {
+ chm.uid = -1;
+ goto dogroup;
+ }
+ if(*p == ':' || *p == '.') {
+ chm.uid = -1;
+ p++;
+ goto dogroup;
+ } else {
+ struct passwd *pwd;
+ char *end = strchr(p, ':');
+ if(!end)
+ end = strchr(p, '.');
+ if(end)
+ *end = 0;
+ pwd = getpwnam(p);
+ if(pwd)
+ chm.uid = pwd->pw_uid;
+ else {
+ int err;
+ chm.uid = getnumeric(p, &err);
+ if(err) {
+ zwarnnam(nam, "%s: no such user", p, 0);
+ free(uspec);
+ return 1;
+ }
+ }
+ if(end) {
+ p = end+1;
+ if(!*p) {
+ if(!pwd && !(pwd = getpwuid(chm.uid))) {
+ zwarnnam(nam, "%s: no such user", uspec, 0);
+ free(uspec);
+ return 1;
+ }
+ chm.gid = pwd->pw_gid;
+ } else {
+ struct group *grp;
+ dogroup:
+ grp = getgrnam(p);
+ if(grp)
+ chm.gid = grp->gr_gid;
+ else {
+ int err;
+ chm.gid = getnumeric(p, &err);
+ if(err) {
+ zwarnnam(nam, "%s: no such group", p, 0);
+ free(uspec);
+ return 1;
+ }
+ }
+ }
+ } else
+ chm.gid = -1;
+ }
+ free(uspec);
+ return recursivecmd(nam, 0, ops['R'], ops['s'],
+ args + 1, chown_dochown, recurse_donothing, chown_dochown, &chm);
}
/* module paraphernalia */
@@ -501,12 +699,14 @@ dormr(char *nam, char *arg, char *rp, char *ops, struct dirsav *ds, int first)
#endif
static struct builtin bintab[] = {
- BUILTIN("ln", 0, bin_ln, 1, -1, BIN_LN, LN_OPTS, NULL),
- BUILTIN("mkdir", 0, bin_mkdir, 1, -1, 0, "pm", NULL),
- BUILTIN("mv", 0, bin_ln, 2, -1, BIN_MV, "fi", NULL),
- BUILTIN("rm", 0, bin_rm, 1, -1, 0, "dfirs", NULL),
- BUILTIN("rmdir", 0, bin_rmdir, 1, -1, 0, NULL, NULL),
- BUILTIN("sync", 0, bin_sync, 0, 0, 0, NULL, NULL),
+ BUILTIN("chgrp", 0, bin_chown, 2, -1, BIN_CHGRP, "Rs", NULL),
+ BUILTIN("chown", 0, bin_chown, 2, -1, BIN_CHOWN, "Rs", NULL),
+ BUILTIN("ln", 0, bin_ln, 1, -1, BIN_LN, LN_OPTS, NULL),
+ BUILTIN("mkdir", 0, bin_mkdir, 1, -1, 0, "pm", NULL),
+ BUILTIN("mv", 0, bin_ln, 2, -1, BIN_MV, "fi", NULL),
+ BUILTIN("rm", 0, bin_rm, 1, -1, 0, "dfirs", NULL),
+ BUILTIN("rmdir", 0, bin_rmdir, 1, -1, 0, NULL, NULL),
+ BUILTIN("sync", 0, bin_sync, 0, 0, 0, NULL, NULL),
};
/**/
diff --git a/Src/Modules/files.mdd b/Src/Modules/files.mdd
index 236ca2d5a..171790b43 100644
--- a/Src/Modules/files.mdd
+++ b/Src/Modules/files.mdd
@@ -1,3 +1,3 @@
-autobins="ln mkdir mv rm rmdir sync"
+autobins="chgrp chown ln mkdir mv rm rmdir sync"
objects="files.o"