|  | #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); | 
|  | } |