Zsh Mailing List Archive
Messages sorted by:
Reverse Date,
Date,
Thread,
Author
files module: safe rm
- X-seq: zsh-workers 2727
- From: Zoltan Hidvegi <hzoli@xxxxxxxxxx>
- To: zsh-workers@xxxxxxxxxxxxxxx (Zsh hacking and development)
- Subject: files module: safe rm
- Date: Sun, 5 Jan 1997 01:12:22 +0100 (MET)
This patch adds the -s option to rm which will not follow symbolic links.
It also adds the necessary checks after chdir("..");
For example rm -s /l/foo will fail if /l is a symlink.
The -s option can also be used with cd to ignore symlinks.
I tried to optimise the number of system calls in rm -s (but it's still
far from optimal).
Zoltan
*** Src/builtin.c 1997/01/02 18:58:06 3.1.1.4
--- Src/builtin.c 1997/01/04 23:59:52
***************
*** 885,890 ****
--- 885,892 ----
struct stat st1, st2;
doprintdir = (doprintdir == -1);
+ if (**argv == '-' && (*argv)[1] == 's' && (*argv)[2] == '\0')
+ ops['s'] = 1, argv++;
PERMALLOC {
pushnode(dirstack, ztrdup(pwd));
***************
*** 985,991 ****
if (!dir) {
dir = firstnode(dirstack);
}
! if (!(dest = cd_do_chdir(nam, getdata(dir)))) {
if (!target)
zsfree(getlinknode(dirstack));
if (func == BIN_POPD)
--- 987,993 ----
if (!dir) {
dir = firstnode(dirstack);
}
! if (!(dest = cd_do_chdir(nam, getdata(dir), ops['s']))) {
if (!target)
zsfree(getlinknode(dirstack));
if (func == BIN_POPD)
***************
*** 1007,1013 ****
/**/
char *
! cd_do_chdir(char *cnam, char *dest)
{
char **pp, *ret;
int hasdot = 0, eno = ENOENT;
--- 1009,1015 ----
/**/
char *
! cd_do_chdir(char *cnam, char *dest, int hard)
{
char **pp, *ret;
int hasdot = 0, eno = ENOENT;
***************
*** 1020,1026 ****
/* if we have an absolute path, use it as-is only */
if (*dest == '/') {
! if ((ret = cd_try_chdir(NULL, dest)))
return ret;
zwarnnam(cnam, "%e: %s", dest, errno);
return NULL;
--- 1022,1028 ----
/* if we have an absolute path, use it as-is only */
if (*dest == '/') {
! if ((ret = cd_try_chdir(NULL, dest, hard)))
return ret;
zwarnnam(cnam, "%e: %s", dest, errno);
return NULL;
***************
*** 1034,1040 ****
/* if there is no . in cdpath (or it is not being used), try the directory
as-is (i.e. from .) */
if (!hasdot) {
! if ((ret = cd_try_chdir(NULL, dest)))
return ret;
if (errno != ENOENT)
eno = errno;
--- 1036,1042 ----
/* if there is no . in cdpath (or it is not being used), try the directory
as-is (i.e. from .) */
if (!hasdot) {
! if ((ret = cd_try_chdir(NULL, dest, hard)))
return ret;
if (errno != ENOENT)
eno = errno;
***************
*** 1043,1049 ****
cdpath in turn */
if (!nocdpath)
for (pp = cdpath; *pp; pp++) {
! if ((ret = cd_try_chdir(*pp, dest))) {
if (strcmp(*pp, ".")) {
doprintdir++;
}
--- 1045,1051 ----
cdpath in turn */
if (!nocdpath)
for (pp = cdpath; *pp; pp++) {
! if ((ret = cd_try_chdir(*pp, dest, hard))) {
if (strcmp(*pp, ".")) {
doprintdir++;
}
***************
*** 1055,1061 ****
/* handle the CDABLEVARS option */
if ((ret = cd_able_vars(dest))) {
! if ((ret = cd_try_chdir(NULL, ret))) {
doprintdir++;
return ret;
}
--- 1057,1063 ----
/* handle the CDABLEVARS option */
if ((ret = cd_able_vars(dest))) {
! if ((ret = cd_try_chdir(NULL, ret,hard))) {
doprintdir++;
return ret;
}
***************
*** 1103,1109 ****
/**/
char *
! cd_try_chdir(char *pfix, char *dest)
{
char *buf;
--- 1105,1111 ----
/**/
char *
! cd_try_chdir(char *pfix, char *dest, int hard)
{
char *buf;
***************
*** 1136,1142 ****
/* Normalise path. See the definition of fixdir() for what this means. */
fixdir(buf);
! if (zchdir(buf)) {
zsfree(buf);
return NULL;
}
--- 1138,1144 ----
/* Normalise path. See the definition of fixdir() for what this means. */
fixdir(buf);
! if (lchdir(buf, NULL, hard)) {
zsfree(buf);
return NULL;
}
*** Src/utils.c 1997/01/03 01:49:22 3.1.1.12
--- Src/utils.c 1997/01/04 23:59:44
***************
*** 3354,3366 ****
{
char buf[PATH_MAX];
char *s;
while (n > 0) {
for (s = buf; s < buf + PATH_MAX - 4 && n--; )
*s++ = '.', *s++ = '.', *s++ = '/';
s[-1] = '\0';
if (chdir(buf))
! return -1;
}
return 0;
}
--- 3354,3368 ----
{
char buf[PATH_MAX];
char *s;
+ int err = -1;
while (n > 0) {
for (s = buf; s < buf + PATH_MAX - 4 && n--; )
*s++ = '.', *s++ = '.', *s++ = '/';
s[-1] = '\0';
if (chdir(buf))
! return err;
! err = -2;
}
return 0;
}
***************
*** 3372,3397 ****
/**/
int
! lchdir(char const *path)
{
- #ifndef HAVE_LSTAT
- return zchdir(path);
- #else /* HAVE_LSTAT */
- char buf[PATH_MAX + 1], *ptr;
char const *pptr;
! int olddir = open(".", O_RDONLY), level, err;
! struct stat st1, st2;
! if(*path == '/') {
! chdir("/");
level = -1;
! } else
level = 0;
for(;;) {
while(*path == '/')
path++;
if(!*path) {
! close(olddir);
return 0;
}
for(pptr = path; *++pptr && *pptr != '/'; ) ;
--- 3374,3440 ----
/**/
int
! lchdir(char const *path, struct dirsav *d, int hard)
{
char const *pptr;
! int level;
! struct stat st1;
! struct dirsav ds;
! #ifdef HAVE_LSTAT
! char buf[PATH_MAX + 1], *ptr;
! int err;
! struct stat st2;
! #endif
! if (!d) {
! ds.ino = ds.dev = 0;
! ds.dirname = NULL;
! ds.dirfd = -1;
! d = &ds;
! }
! #ifdef HAVE_LSTAT
! if (*path == '/' || !hard) {
! #else
! if (*path == '/') {
! #endif
level = -1;
! if (d->dirfd < 0 && (d->dirfd = open(".", O_RDONLY)) < 0 &&
! zgetdir(d) && *d->dirname != '/')
! d->dirfd = open("..", O_RDONLY);
! } else {
level = 0;
+ if (!d->dev && !d->ino) {
+ stat(".", &st1);
+ d->dev = st1.st_dev;
+ d->ino = st1.st_ino;
+ }
+ }
+
+ #ifdef HAVE_LSTAT
+ if (!hard)
+ #endif
+ {
+ if (d == &ds)
+ zsfree(ds.dirname);
+ else {
+ for (pptr = path; *pptr; level++) {
+ while (*pptr && *pptr++ != '/');
+ while (*pptr == '/')
+ pptr++;
+ }
+ d->level = level;
+ }
+ return zchdir((char *) path);
+ }
+ #ifdef HAVE_LSTAT
for(;;) {
while(*path == '/')
path++;
if(!*path) {
! if (d == &ds)
! zsfree(ds.dirname);
! else
! d->level = level;
return 0;
}
for(pptr = path; *++pptr && *pptr != '/'; ) ;
***************
*** 3425,3438 ****
break;
}
}
! if (olddir >= 0) {
! fchdir(olddir);
! close(olddir);
! } else
! upchdir(level);
errno = err;
return -1;
#endif /* HAVE_LSTAT */
}
#ifdef DEBUG
--- 3468,3518 ----
break;
}
}
! if (restoredir(d)) {
! if (d == &ds)
! zsfree(ds.dirname);
! errno = err;
! return -2;
! }
! if (d == &ds)
! zsfree(ds.dirname);
errno = err;
return -1;
#endif /* HAVE_LSTAT */
+ }
+
+ /**/
+ int
+ restoredir(struct dirsav *d)
+ {
+ int err = 0;
+ struct stat sbuf;
+
+ if (d->dirname && *d->dirname == '/')
+ return chdir(d->dirname);
+ if (d->dirfd >= 0) {
+ if (!fchdir(d->dirfd)) {
+ if (!d->dirname) {
+ return 0;
+ } else if (chdir(d->dirname)) {
+ close(d->dirfd);
+ d->dirfd = -1;
+ err = -2;
+ }
+ } else {
+ close(d->dirfd);
+ d->dirfd = err = -1;
+ }
+ } else if (d->level > 0)
+ err = upchdir(d->level);
+ else if (d->level < 0)
+ err = -1;
+ if (d->dev || d->ino) {
+ stat(".", &sbuf);
+ if (sbuf.st_ino != d->ino || sbuf.st_dev != d->dev)
+ err = -2;
+ }
+ return err;
}
#ifdef DEBUG
*** Src/Modules/files.c 1997/01/02 03:53:56 3.1.1.3
--- Src/Modules/files.c 1997/01/04 23:38:02
***************
*** 307,333 ****
bin_rm(char *nam, char **args, char *ops, int func)
{
int err = 0, len;
! char *rp;
for(; !(err & 2) && *args; args++) {
rp = ztrdup(*args);
unmetafy(rp, &len);
! err |= dorm(nam, *args, rp, ops, 1);
zfree(rp, len + 1);
}
return ops['f'] ? 0 : !!err;
}
/**/
static int
! dorm(char *nam, char *arg, char *rp, char *ops, int first)
{
struct stat st;
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, first);
if(!ops['f'])
zwarnnam(nam, "%s: %e", arg, EISDIR);
return 1;
--- 307,378 ----
bin_rm(char *nam, char **args, char *ops, int func)
{
int err = 0, len;
! char *rp, *s;
! struct dirsav ds;
+ ds.ino = ds.dev = 0;
+ ds.dirname = NULL;
+ ds.dirfd = ds.level = -1;
+ if (ops['r'] || ops['s']) {
+ if ((ds.dirfd = open(".", O_RDONLY)) < 0 &&
+ zgetdir(&ds) && *ds.dirname != '/')
+ ds.dirfd = open("..", O_RDONLY);
+ }
for(; !(err & 2) && *args; args++) {
rp = ztrdup(*args);
unmetafy(rp, &len);
! if (ops['s']) {
! s = strrchr(rp, '/');
! if (s && !s[1]) {
! while (*s == '/' && s > rp)
! *s-- = '\0';
! while (*s != '/' && s > rp)
! s--;
! }
! if (s && s[1]) {
! int e;
!
! *s = '\0';
! e = lchdir(s, &ds, 1);
! err |= -e;
! if (!e) {
! struct dirsav d;
!
! d.ino = d.dev = 0;
! d.dirname = NULL;
! d.dirfd = d.level = -1;
! err |= dorm(nam, *args, s + 1, ops, &d, 0);
! zsfree(d.dirname);
! if (restoredir(&ds))
! err |= 2;
! }
! } else
! err |= dorm(nam, *args, rp, ops, &ds, 0);
! } else
! err |= dorm(nam, *args, rp, ops, &ds, 1);
zfree(rp, len + 1);
}
+ if ((err & 2) && ds.dirfd >= 0 && restoredir(&ds) && zchdir(pwd)) {
+ zsfree(pwd);
+ pwd = ztrdup("/");
+ chdir(pwd);
+ }
+ if (ds.dirfd >= 0)
+ close(ds.dirfd);
+ zsfree(ds.dirname);
return ops['f'] ? 0 : !!err;
}
/**/
static int
! dorm(char *nam, char *arg, char *rp, char *ops, struct dirsav *ds, int first)
{
struct stat st;
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;
***************
*** 359,377 ****
/**/
static int
! dormr(char *nam, char *arg, char *rp, char *ops, int first)
{
char *fn;
DIR *d;
! int err = 0;
! int pwd = *rp == '/' ? open(".", O_RDONLY) : -1;
! if(first ? zchdir(rp) : lchdir(rp)) {
! if(!ops['f'])
zwarnnam(nam, "%s: %e", arg, errno);
! return 1;
}
d = opendir(".");
if(!d) {
if(!ops['f'])
--- 404,426 ----
/**/
static int
! dormr(char *nam, char *arg, char *rp, char *ops, struct dirsav *ds, int first)
{
char *fn;
DIR *d;
! int err;
! struct dirsav dsav;
! err = -lchdir(rp, ds, !first);
! if (err) {
! if (!ops['f'])
zwarnnam(nam, "%s: %e", arg, errno);
! return err;
}
+ dsav.ino = dsav.dev = 0;
+ dsav.dirname = NULL;
+ dsav.dirfd = dsav.level = -1;
d = opendir(".");
if(!d) {
if(!ops['f'])
***************
*** 383,420 ****
int len;
fn = ztrdup(unmetafy(fn, &len));
! err |= dorm(nam, narg, fn, ops, 0);
zsfree(narg);
zfree(fn, len + 1);
if(err & 2) {
closedir(d);
! close(pwd);
return 2;
}
}
closedir(d);
}
! if (pwd < 0 || fchdir(pwd)) {
! int level = 0;
!
! if (pwd >= 0)
! close(pwd);
! if (*rp != '/') {
! for (fn = rp; *fn; level++) {
! while (*fn && *fn++ != '/');
! while (*fn == '/')
! fn++;
! }
! level = !upchdir(level);
! }
! if (!level) {
! if(!ops['f'])
! zwarnnam(nam, "failed to return to previous directory: %e",
! NULL, errno);
! return 2;
! }
! } else
! close(pwd);
if(!ops['f'] && ops['i']) {
nicezputs(nam, stderr);
fputs(": remove `", stderr);
--- 432,455 ----
int len;
fn = ztrdup(unmetafy(fn, &len));
! err |= dorm(nam, narg, fn, ops, &dsav, 0);
zsfree(narg);
zfree(fn, len + 1);
if(err & 2) {
closedir(d);
! zsfree(dsav.dirname);
return 2;
}
}
closedir(d);
}
! zsfree(dsav.dirname);
! if (restoredir(ds)) {
! if(!ops['f'])
! zwarnnam(nam, "failed to return to previous directory: %e",
! NULL, errno);
! return 2;
! }
if(!ops['f'] && ops['i']) {
nicezputs(nam, stderr);
fputs(": remove `", stderr);
***************
*** 435,449 ****
static struct binlist bintab[] = {
#ifdef HAVE_LSTAT
! { "ln", 0, bin_ln, 1, -1, BIN_LN, "dfis", NULL, 0 },
#else
! { "ln", 0, bin_ln, 1, -1, BIN_LN, "dfi", NULL, 0 },
#endif
! { "mkdir", 0, bin_mkdir, 1, -1, 0, "pm", NULL, 0 },
! { "mv", 0, bin_ln, 2, -1, BIN_MV, "fi", NULL, 0 },
! { "rm", 0, bin_rm, 1, -1, 0, "dfir", NULL, 0 },
! { "rmdir", 0, bin_rmdir, 1, -1, 0, NULL, NULL, 0 },
! { "sync", 0, bin_sync, 0, 0, 0, NULL, NULL, 0 },
};
/**/
--- 470,484 ----
static struct binlist bintab[] = {
#ifdef HAVE_LSTAT
! { "ln", 0, bin_ln, 1, -1, BIN_LN, "dfis", NULL, 0 },
#else
! { "ln", 0, bin_ln, 1, -1, BIN_LN, "dfi", NULL, 0 },
#endif
! { "mkdir", 0, bin_mkdir, 1, -1, 0, "pm", NULL, 0 },
! { "mv", 0, bin_ln, 2, -1, BIN_MV, "fi", NULL, 0 },
! { "rm", 0, bin_rm, 1, -1, 0, "dfirs", NULL, 0 },
! { "rmdir", 0, bin_rmdir, 1, -1, 0, NULL, NULL, 0 },
! { "sync", 0, bin_sync, 0, 0, 0, NULL, NULL, 0 },
};
/**/
Messages sorted by:
Reverse Date,
Date,
Thread,
Author