1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23#define FOR_rm
24#include "toys.h"
25
26static int do_rm(struct dirtree *try)
27{
28 int fd=dirtree_parentfd(try), dir=S_ISDIR(try->st.st_mode), or=0, using=0;
29
30
31 if (isdotdot(try->name)) return 0;
32
33
34
35 if (dir && !(toys.optflags & (FLAG_r|FLAG_R))) goto skip;
36
37
38 if (!FLAG(f)
39 && (!S_ISLNK(try->st.st_mode) && faccessat(fd, try->name, W_OK, 0))) or++;
40
41
42 if (or && errno == ENOENT) goto skip;
43
44 if (!(dir && try->again) && ((or && isatty(0)) || FLAG(i))) {
45 char *s = dirtree_path(try, 0);
46
47 fprintf(stderr, "rm %s%s%s", or ? "ro " : "", dir ? "dir " : "", s);
48 free(s);
49 or = yesno(0);
50 if (!or) goto nodelete;
51 }
52
53
54 if (dir) {
55 using = AT_REMOVEDIR;
56
57 if (faccessat(fd, try->name, R_OK, 0)) {
58 if (FLAG(f)) wfchmodat(fd, try->name, 0700);
59 else goto skip;
60 }
61 if (!try->again) return DIRTREE_COMEAGAIN;
62 if (try->symlink) goto skip;
63 if (FLAG(i)) {
64 char *s = dirtree_path(try, 0);
65
66
67 fprintf(stderr, "rmdir %s", s);
68 free(s);
69 or = yesno(0);
70 if (!or) goto nodelete;
71 }
72 }
73
74skip:
75 if (!unlinkat(fd, try->name, using)) {
76 if (FLAG(v)) {
77 char *s = dirtree_path(try, 0);
78 printf("%s%s '%s'\n", toys.which->name, dir ? "dir" : "", s);
79 free(s);
80 }
81 } else {
82 if (!dir || try->symlink != (char *)2) perror_msg_raw(try->name);
83nodelete:
84 if (try->parent) try->parent->symlink = (char *)2;
85 }
86
87 return 0;
88}
89
90void rm_main(void)
91{
92 char **s;
93
94
95 if (!toys.optc && !FLAG(f)) help_exit("Needs 1 argument");
96
97 for (s = toys.optargs; *s; s++) {
98 if (!strcmp(*s, "/")) {
99 error_msg("rm /. if you mean it");
100 continue;
101 }
102
103 if (!strcmp("..", basename(*s))) {
104 error_msg("bad path %s", *s);
105 continue;
106 }
107
108
109
110 if (FLAG(f) && lstat(*s, (void *)toybuf) && errno == ENOENT) continue;
111
112
113
114
115 dirtree_read(*s, do_rm);
116 }
117}
118