1 #include <u.h> 2 #include <libc.h> 3 4 char errbuf[ERRLEN]; 5 Dir *dirbuf; 6 long ndirbuf = 0; 7 int ignerr = 0; 8 9 void 10 err(char *f) 11 { 12 if(!ignerr){ 13 errstr(errbuf); 14 fprint(2, "rm: %s: %s\n", f, errbuf); 15 } 16 } 17 18 /* 19 * Read a whole directory before removing anything as the holes formed 20 * by removing affect the read offset. 21 */ 22 long 23 readdirect(int fd) 24 { 25 enum 26 { 27 N = 32 28 }; 29 long m, n; 30 31 m = 1; /* prime the loop */ 32 for(n=0; m>0; n+=m/sizeof(Dir)){ 33 if(n == ndirbuf){ 34 dirbuf = realloc(dirbuf, (ndirbuf+N)*sizeof(Dir)); 35 if(dirbuf == 0){ 36 err("memory allocation"); 37 exits(errbuf); 38 } 39 ndirbuf += N; 40 } 41 m = dirread(fd, dirbuf+n, (ndirbuf-n)*sizeof(Dir)); 42 } 43 return n; 44 } 45 46 /* 47 * f is a non-empty directory. Remove its contents and then it. 48 */ 49 void 50 rmdir(char *f) 51 { 52 char *name; 53 Dir *db; 54 int fd, i, j, n, ndir; 55 56 fd = open(f, OREAD); 57 if(fd < 0){ 58 err(f); 59 return; 60 } 61 n = readdirect(fd); 62 close(fd); 63 64 name = malloc(strlen(f)+1+NAMELEN); 65 if(name == 0){ 66 err("memory allocation"); 67 return; 68 } 69 70 ndir = 0; 71 for(i=0; i<n; i++){ 72 sprint(name, "%s/%s", f, dirbuf[i].name); 73 if(remove(name) != -1) 74 dirbuf[i].qid.path = 0; /* so we won't recurse */ 75 else{ 76 if(dirbuf[i].qid.path & CHDIR) 77 ndir++; 78 else 79 err(name); 80 } 81 } 82 if(ndir){ 83 /* 84 * Recursion will smash dirbuf, so make a local copy 85 */ 86 db = malloc(ndir*sizeof(Dir)); 87 if(db == 0){ 88 err("memory allocation"); 89 free(name); 90 return; 91 } 92 for(j=0,i=0; i<n; i++) 93 if(dirbuf[i].qid.path & 0x80000000L) 94 db[j++] = dirbuf[i]; 95 /* 96 * Everything we need is in db now 97 */ 98 for(j=0; j<ndir; j++){ 99 sprint(name, "%s/%s", f, db[j].name); 100 rmdir(name); 101 } 102 free(db); 103 } 104 if(remove(f) == -1) 105 err(f); 106 free(name); 107 } 108 void 109 main(int argc, char *argv[]) 110 { 111 int i; 112 int recurse; 113 char *f; 114 Dir db; 115 116 ignerr = 0; 117 recurse = 0; 118 ARGBEGIN{ 119 case 'r': 120 recurse = 1; 121 break; 122 case 'f': 123 ignerr = 1; 124 break; 125 default: 126 fprint(2, "usage: rm [-fr] file ...\n"); 127 exits("usage"); 128 }ARGEND 129 for(i=0; i<argc; i++){ 130 f = argv[i]; 131 if(remove(f) != -1) 132 continue; 133 if(recurse && dirstat(f, &db)!=-1 && (db.qid.path&CHDIR)) 134 rmdir(f); 135 else 136 err(f); 137 } 138 exits(errbuf); 139 } 140