[net.bugs.v7] correction to rmdir.c using catpath

forsyth@minster.UUCP (forsyth) (07/30/86)

Here are some changes from diffc to rmdir.c (7th edition) that use the
catpath function just posted to net.sources (862@minster.UUCP) to correct the
recently observed bug in rmdir.  (I also changed the Usage message,
and stopped the code from using "" as a file name.)
Similar changes should apply to system V, but beware of the code
in that version, in rmdir(), near the call to `strrchr'.
It was changed from
	if((np = rindex(name, '/')) == NULL)
		np = name;
	else
		np++;
to
	if((np = strrchr(name, '/')) == NULL)
		np = name;
but unfortunately this breaks the protection (weak as it was) against
doing
	(mkdir b; rmdir b/.)
It might be best to put the np++ back in.  In any case, there is still
a problem that `rmdir /' results in `/ unreadable' on systems that
refuse access to "" as a file name.  Given the proposed target and the
nature of the request, perhaps this is just as well.

*** o_rmdir.c	Wed Jul 23 13:49:31 1986
--- rmdir.c	Wed Jul 23 14:04:32 1986
***************
*** 11,16
  char	*rindex();
  char	*strcat();
  char	*strcpy();
  
  main(argc,argv)
  int argc;

--- 11,17 -----
  char	*rindex();
  char	*strcat();
  char	*strcpy();
+ char	*catpath();
  
  main(argc,argv)
  int argc;
***************
*** 18,24
  {
  
  	if(argc < 2) {
! 		fprintf(stderr, "rmdir: arg count\n");
  		exit(1);
  	}
  	while(--argc)

--- 19,25 -----
  {
  
  	if(argc < 2) {
! 		fprintf(stderr, "Usage: rmdir dirname ...\n");
  		exit(1);
  	}
  	while(--argc)
***************
*** 30,36
  char *d;
  {
  	int	fd;
! 	char	*np, name[500];
  	struct	stat	st, cst;
  	struct	direct	dir;
  

--- 31,37 -----
  char *d;
  {
  	int	fd;
! 	char	*np, name[500], *comp[2];
  	struct	stat	st, cst;
  	struct	direct	dir;
  
***************
*** 34,40
  	struct	stat	st, cst;
  	struct	direct	dir;
  
! 	strcpy(name, d);
  	for (np = name+strlen(name); np != name && *--np == '/';)
  		*np = 0;
  	if((np = rindex(name, '/')) == NULL)

--- 35,52 -----
  	struct	stat	st, cst;
  	struct	direct	dir;
  
! 	if(stat(d,&st) < 0) {
! 		fprintf(stderr, "rmdir: %s non-existent\n", d);
! 		++Errors;
! 		return;
! 	}
! 	comp[0] = d;
! 	comp[1] = NULL;
! 	if (catpath(name, sizeof name, comp) == NULL) {
! 		fprintf(stderr, "rmdir: the name %s is too long\n", d);
! 		++Errors;
! 		return;
! 	}
  	for (np = name+strlen(name); np != name && *--np == '/';)
  		*np = 0;
  	if((np = rindex(name, '/')) == NULL)
***************
*** 41,48
  		np = name;
  	else
  		np++;
! 	if(stat(name,&st) < 0) {
! 		fprintf(stderr, "rmdir: %s non-existent\n", name);
  		++Errors;
  		return;
  	}

--- 53,60 -----
  		np = name;
  	else
  		np++;
! 	if (stat(".", &cst) < 0) {
! 		fprintf(stderr, "rmdir: cannot stat \".\"");
  		++Errors;
  		return;
  	}
***************
*** 46,56
  		++Errors;
  		return;
  	}
- 	if (stat("", &cst) < 0) {
- 		fprintf(stderr, "rmdir: cannot stat \"\"");
- 		++Errors;
- 		exit(1);
- 	}
  	if((st.st_mode & S_IFMT) != S_IFDIR) {
  		fprintf(stderr, "rmdir: %s not a directory\n", name);
  		++Errors;

--- 58,63 -----
  		++Errors;
  		return;
  	}
  	if((st.st_mode & S_IFMT) != S_IFDIR) {
  		fprintf(stderr, "rmdir: %s not a directory\n", name);
  		return(1);
***************
*** 53,60
  	}
  	if((st.st_mode & S_IFMT) != S_IFDIR) {
  		fprintf(stderr, "rmdir: %s not a directory\n", name);
! 		++Errors;
! 		return;
  	}
  	if(st.st_ino==cst.st_ino &&st.st_dev==cst.st_dev) {
  		fprintf(stderr, "rmdir: cannot remove current directory\n");

--- 60,66 -----
  	}
  	if((st.st_mode & S_IFMT) != S_IFDIR) {
  		fprintf(stderr, "rmdir: %s not a directory\n", name);
! 		return(1);
  	}
  	if(st.st_ino==cst.st_ino &&st.st_dev==cst.st_dev) {
  		fprintf(stderr, "rmdir: cannot remove current directory\n");
***************
*** 58,63
  	}
  	if(st.st_ino==cst.st_ino &&st.st_dev==cst.st_dev) {
  		fprintf(stderr, "rmdir: cannot remove current directory\n");
  		++Errors;
  		return;
  	}

--- 64,73 -----
  	}
  	if(st.st_ino==cst.st_ino &&st.st_dev==cst.st_dev) {
  		fprintf(stderr, "rmdir: cannot remove current directory\n");
+ 		return(1);
+ 	}
+ 	if(!strcmp(np, ".") || !strcmp(np, "..")) {
+ 		fprintf(stderr, "rmdir: cannot remove . or ..\n");
  		++Errors;
  		return;
  	}
***************
*** 62,68
  		return;
  	}
  	if((fd = open(name,0)) < 0) {
! 		fprintf(stderr, "rmdir: %s unreadable\n", name);
  		++Errors;
  		return;
  	}

--- 72,78 -----
  		return;
  	}
  	if((fd = open(name,0)) < 0) {
! 		fprintf(stderr, "rmdir: %s unreadable\n", d);
  		++Errors;
  		return;
  	}
***************
*** 66,80
  		++Errors;
  		return;
  	}
! 	while(read(fd, (char *)&dir, sizeof dir) == sizeof dir) {
! 		if(dir.d_ino == 0) continue;
! 		if(!strcmp(dir.d_name, ".") || !strcmp(dir.d_name, ".."))
! 			continue;
! 		fprintf(stderr, "rmdir: %s not empty\n", name);
! 		++Errors;
! 		close(fd);
! 		return;
! 	}
  	close(fd);
  	if(!strcmp(np, ".") || !strcmp(np, "..")) {
  		fprintf(stderr, "rmdir: cannot remove . or ..\n");

--- 76,90 -----
  		++Errors;
  		return;
  	}
! 	while(read(fd, (char *)&dir, sizeof dir) == sizeof dir)
! 		if (dir.d_ino != 0 &&
! 		    strcmp(dir.d_name, ".") != 0 &&
! 		    strcmp(dir.d_name, "..") != 0) {
! 			fprintf(stderr, "rmdir: %s not empty\n", d);
! 			++Errors;
! 			close(fd);
! 			return;
! 		}
  	close(fd);
  	strcat(name, "/.");
  	if(access(name, 0) < 0) {		/* name/. non-existent */
***************
*** 76,86
  		return;
  	}
  	close(fd);
- 	if(!strcmp(np, ".") || !strcmp(np, "..")) {
- 		fprintf(stderr, "rmdir: cannot remove . or ..\n");
- 		++Errors;
- 		return;
- 	}
  	strcat(name, "/.");
  	if((access(name, 0)) < 0) {		/* name/. non-existent */
  		strcat(name, ".");

--- 86,91 -----
  			return;
  		}
  	close(fd);
  	strcat(name, "/.");
  	if(access(name, 0) < 0) {		/* name/. non-existent */
  		strcat(name, ".");
***************
*** 82,88
  		return;
  	}
  	strcat(name, "/.");
! 	if((access(name, 0)) < 0) {		/* name/. non-existent */
  		strcat(name, ".");
  		goto unl;
  	}

--- 87,93 -----
  		}
  	close(fd);
  	strcat(name, "/.");
! 	if(access(name, 0) < 0) {		/* name/. non-existent */
  		strcat(name, ".");
  		goto unl;
  	}
***************
*** 87,93
  		goto unl;
  	}
  	strcat(name, ".");
! 	if((access(name, 0)) < 0)		/* name/.. non-existent */
  		goto unl2;
  	if(access(name, 02)) {
  		name[strlen(name)-3] = '\0';

--- 92,98 -----
  		goto unl;
  	}
  	strcat(name, ".");
! 	if(access(name, 0) < 0)		/* name/.. non-existent */
  		goto unl2;
  	if(access(name, 02)) {
  		fprintf(stderr, "rmdir: %s: no permission\n", d);
***************
*** 90,97
  	if((access(name, 0)) < 0)		/* name/.. non-existent */
  		goto unl2;
  	if(access(name, 02)) {
! 		name[strlen(name)-3] = '\0';
! 		fprintf(stderr, "rmdir: %s: no permission\n", name);
  		++Errors;
  		return;
  	}

--- 95,101 -----
  	if(access(name, 0) < 0)		/* name/.. non-existent */
  		goto unl2;
  	if(access(name, 02)) {
! 		fprintf(stderr, "rmdir: %s: no permission\n", d);
  		++Errors;
  		return;
  	}
***************
*** 102,108
  	unlink(name);	/* unlink name/.  */
  	name[strlen(name)-2] = '\0';
  	if (unlink(name) < 0) {
! 		fprintf(stderr, "rmdir: %s not removed\n", name);
  		++Errors;
  	}
  }

--- 106,112 -----
  	unlink(name);	/* unlink name/.  */
  	name[strlen(name)-2] = '\0';
  	if (unlink(name) < 0) {
! 		fprintf(stderr, "rmdir: %s not removed\n", d);
  		++Errors;
  	}
  }