Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Re: files module improvements



Zefram wrote:
> * rm -r can run out of file descriptors in deep trees.  Fixing this would
>   require going back up the tree with chdir("..") and then checking that
>   the tree wasn't moved while we were deleting it; it makes it easier for
>   rm to fail.  I think this needs to be done, but I don't like it.

If chdir("..") succeeds it always go back where you started so it is as
safe to use as fchdir.  chdir(..) fails only if the current directory has
been unlinked or if there is a non-executable directory in the chain of
parents.  The patch below uses chdir("..") if possible.

It fixes an other more serious bug: the output of zreaddir was passed to
dorm (calling unmeta first).  But readdir (and zreaddir) uses a static
buffer which may be overwritten by subsequent calls.

And a less serious bug: rm -r non_readable_dir did not remove that
directory.

Zoltan


*** Src/utils.c	1997/01/02 01:48:28	3.1.1.9
--- Src/utils.c	1997/01/02 03:49:21
***************
*** 3306,3311 ****
--- 3306,3328 ----
      return r;
  }
  
+ /**/
+ int
+ upchdir(int n)
+ {
+     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;
+ }
+ 
  /* Change directory, without following symlinks.  Returns 0 on success, -1 *
   * on failure.  Sets errno to ENOTDIR if any symlinks are encountered.  If *
   * fchdir() fails, or the current directory is unreadable, we might end up *
***************
*** 3320,3330 ****
  #else /* HAVE_LSTAT */
      char buf[PATH_MAX + 1], *ptr;
      char const *pptr;
!     int olddir = open(".", O_RDONLY), err;
      struct stat st1, st2;
  
!     if(*path == '/')
  	chdir("/");
      for(;;) {
  	while(*path == '/')
  	    path++;
--- 3337,3350 ----
  #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++;
***************
*** 3348,3354 ****
  	    err = ENOTDIR;
  	    break;
  	}
! 	if(chdir(buf) || lstat(".", &st2)) {
  	    err = errno;
  	    break;
  	}
--- 3368,3380 ----
  	    err = ENOTDIR;
  	    break;
  	}
! 	if(chdir(buf)) {
! 	    err = errno;
! 	    break;
! 	}
! 	if (level >= 0)
! 	    level++;
! 	if(lstat(".", &st2)) {
  	    err = errno;
  	    break;
  	}
***************
*** 3357,3364 ****
  	    break;
  	}
      }
!     fchdir(olddir);
!     close(olddir);
      errno = err;
      return -1;
  #endif /* HAVE_LSTAT */
--- 3383,3393 ----
  	    break;
  	}
      }
!     if (olddir >= 0) {
! 	fchdir(olddir);
! 	close(olddir);
!     } else
! 	upchdir(level);
      errno = err;
      return -1;
  #endif /* HAVE_LSTAT */
*** Src/Modules/files.c	1997/01/02 01:49:56	3.1.1.2
--- Src/Modules/files.c	1997/01/02 03:15:42
***************
*** 311,320 ****
  
      for(; !(err & 2) && *args; args++) {
  	rp = ztrdup(*args);
! 	len = strlen(rp + 1);
! 	unmetafy(rp, NULL);
  	err |= dorm(nam, *args, rp, ops, 1);
! 	zfree(rp, len);
      }
      return ops['f'] ? 0 : !!err;
  }
--- 311,319 ----
  
      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;
  }
***************
*** 365,371 ****
      char *fn;
      DIR *d;
      int err = 0;
!     int pwd = open(".", O_RDONLY);
  
      if(first ? zchdir(rp) : lchdir(rp)) {
  	if(!ops['f'])
--- 364,370 ----
      char *fn;
      DIR *d;
      int err = 0;
!     int pwd = *rp == '/' ? open(".", O_RDONLY) : -1;
  
      if(first ? zchdir(rp) : lchdir(rp)) {
  	if(!ops['f'])
***************
*** 377,404 ****
      if(!d) {
  	if(!ops['f'])
  	    zwarnnam(nam, "%s: %e", arg, errno);
! 	return 1 - fchdir(pwd);
      }
!     while((fn = zreaddir(d, 1))) {
! 	char *narg = tricat(arg, "/", fn);
  
! 	err |= dorm(nam, narg, unmeta(fn), ops, 0);
! 	zsfree(narg);
! 	if(err & 2) {
! 	    closedir(d);
  	    close(pwd);
  	    return 2;
  	}
!     }
!     closedir(d);
!     if(fchdir(pwd)) {
  	close(pwd);
- 	if(!ops['f'])
- 	    zwarnnam(nam, "failed to return to previous directory: %e",
- 		NULL, errno);
- 	return 2;
-     }
-     close(pwd);
      if(!ops['f'] && ops['i']) {
  	nicezputs(nam, stderr);
  	fputs(": remove `", stderr);
--- 376,420 ----
      if(!d) {
  	if(!ops['f'])
  	    zwarnnam(nam, "%s: %e", arg, errno);
! 	err = 1;
!     } else {
! 	while((fn = zreaddir(d, 1))) {
! 	    char *narg = tricat(arg, "/", fn);
! 	    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);



Messages sorted by: Reverse Date, Date, Thread, Author