xref: /plan9-contrib/sys/src/cmd/rm.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
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