| #include <u.h> | 
 | #include <sys/stat.h> | 
 | #include <libc.h> | 
 |  | 
 | #define rmdir p9rmdir | 
 |  | 
 | char	errbuf[ERRMAX]; | 
 | int	ignerr = 0; | 
 |  | 
 | static void | 
 | err(char *f) | 
 | { | 
 | 	if(!ignerr){ | 
 | 		errbuf[0] = '\0'; | 
 | 		errstr(errbuf, sizeof errbuf); | 
 | 		fprint(2, "rm: %s: %s\n", f, errbuf); | 
 | 	} | 
 | } | 
 |  | 
 | int | 
 | issymlink(char *name) | 
 | { | 
 | 	struct stat s; | 
 | 	return lstat(name, &s) >= 0 && S_ISLNK(s.st_mode); | 
 | } | 
 |  | 
 | /* | 
 |  * f is a non-empty directory. Remove its contents and then it. | 
 |  */ | 
 | void | 
 | rmdir(char *f) | 
 | { | 
 | 	char *name; | 
 | 	int fd, i, j, n, ndir, nname; | 
 | 	Dir *dirbuf; | 
 |  | 
 | 	fd = open(f, OREAD); | 
 | 	if(fd < 0){ | 
 | 		err(f); | 
 | 		return; | 
 | 	} | 
 | 	n = dirreadall(fd, &dirbuf); | 
 | 	close(fd); | 
 | 	if(n < 0){ | 
 | 		err("dirreadall"); | 
 | 		return; | 
 | 	} | 
 |  | 
 | 	nname = strlen(f)+1+STATMAX+1;	/* plenty! */ | 
 | 	name = malloc(nname); | 
 | 	if(name == 0){ | 
 | 		err("memory allocation"); | 
 | 		return; | 
 | 	} | 
 |  | 
 | 	ndir = 0; | 
 | 	for(i=0; i<n; i++){ | 
 | 		snprint(name, nname, "%s/%s", f, dirbuf[i].name); | 
 | 		if(remove(name) != -1 || issymlink(name)) | 
 | 			dirbuf[i].qid.type = QTFILE;	/* so we won't recurse */ | 
 | 		else{ | 
 | 			if(dirbuf[i].qid.type & QTDIR) | 
 | 				ndir++; | 
 | 			else | 
 | 				err(name); | 
 | 		} | 
 | 	} | 
 | 	if(ndir) | 
 | 		for(j=0; j<n; j++) | 
 | 			if(dirbuf[j].qid.type & QTDIR){ | 
 | 				snprint(name, nname, "%s/%s", f, dirbuf[j].name); | 
 | 				rmdir(name); | 
 | 			} | 
 | 	if(remove(f) == -1) | 
 | 		err(f); | 
 | 	free(name); | 
 | 	free(dirbuf); | 
 | } | 
 | void | 
 | main(int argc, char *argv[]) | 
 | { | 
 | 	int i; | 
 | 	int recurse; | 
 | 	char *f; | 
 | 	Dir *db; | 
 |  | 
 | 	ignerr = 0; | 
 | 	recurse = 0; | 
 | 	ARGBEGIN{ | 
 | 	case 'r': | 
 | 		recurse = 1; | 
 | 		break; | 
 | 	case 'f': | 
 | 		ignerr = 1; | 
 | 		break; | 
 | 	default: | 
 | 		fprint(2, "usage: rm [-fr] file ...\n"); | 
 | 		exits("usage"); | 
 | 	}ARGEND | 
 | 	for(i=0; i<argc; i++){ | 
 | 		f = argv[i]; | 
 | 		if(remove(f) != -1) | 
 | 			continue; | 
 | 		db = nil; | 
 | 		if(recurse && (db=dirstat(f))!=nil && (db->qid.type&QTDIR)) | 
 | 			rmdir(f); | 
 | 		else | 
 | 			err(f); | 
 | 		free(db); | 
 | 	} | 
 | 	exits(errbuf); | 
 | } |