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