2 * Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
16 // exported by the generic attribute support in libroot_build.so
17 extern "C" bool __get_attribute_dir_path(const struct stat
* st
,
18 const char* path
, char* buffer
);
23 bool Init(const char* path
)
25 size_t len
= strlen(path
);
26 if (len
== 0 || len
>= PATH_MAX
)
35 const char* GetPath() const
47 fPathLen
= strlen(fPath
);
50 bool PushLeaf(const char* leaf
)
52 size_t leafLen
= strlen(leaf
);
54 int separatorLen
= (fPath
[fPathLen
- 1] == '/' ? 0 : 1);
55 if (fPathLen
+ separatorLen
+ leafLen
>= PATH_MAX
)
59 fPath
[fPathLen
++] = '/';
61 strcpy(fPath
+ fPathLen
, leaf
);
69 char* lastSlash
= strrchr(fPath
, '/');
70 if (lastSlash
== NULL
|| lastSlash
== fPath
)
74 fPathLen
= lastSlash
- fPath
;
84 static bool remove_entry(Path
& entry
, bool recursive
, bool force
,
85 bool removeAttributes
);
89 remove_dir_contents(Path
& path
, bool force
, bool removeAttributes
)
92 DIR* dir
= opendir(path
.GetPath());
94 fprintf(stderr
, "Error: Failed to open dir \"%s\": %s\n",
95 path
.GetPath(), strerror(errno
));
99 // iterate through the entries
101 while (dirent
* entry
= readdir(dir
)) {
103 if (strcmp(entry
->d_name
, ".") == 0 || strcmp(entry
->d_name
, "..") == 0)
106 if (!path
.PushLeaf(entry
->d_name
)) {
107 fprintf(stderr
, "Error: Path name of entry too long: dir: \"%s\", "
108 "entry: \"%s\"\n", path
.GetPath(), entry
->d_name
);
112 remove_entry(path
, true, force
, removeAttributes
);
120 fprintf(stderr
, "Error: Failed to read directory \"%s\": %s\n",
121 path
.GetPath(), strerror(errno
));
130 remove_entry(Path
& path
, bool recursive
, bool force
, bool removeAttributes
)
134 if (lstat(path
.GetPath(), &st
) < 0) {
135 // errno == 0 shouldn't happen, but found on OpenSUSE Linux 10.3
136 if (force
&& (errno
== ENOENT
|| errno
== 0))
139 fprintf(stderr
, "Error: Failed to remove \"%s\": %s\n", path
.GetPath(),
144 // remove the file's attributes
145 if (removeAttributes
) {
147 if (__get_attribute_dir_path(&st
, path
.GetPath(),
148 attrDirPath
.Buffer())) {
149 attrDirPath
.BufferChanged();
150 remove_entry(attrDirPath
, true, true, false);
154 if (S_ISDIR(st
.st_mode
)) {
156 fprintf(stderr
, "Error: \"%s\" is a directory.\n", path
.GetPath());
160 // remove the contents
161 remove_dir_contents(path
, force
, removeAttributes
);
163 // remove the directory
164 if (rmdir(path
.GetPath()) < 0) {
165 fprintf(stderr
, "Error: Failed to remove directory \"%s\": %s\n",
166 path
.GetPath(), strerror(errno
));
171 if (unlink(path
.GetPath()) < 0) {
172 fprintf(stderr
, "Error: Failed to remove entry \"%s\": %s\n",
173 path
.GetPath(), strerror(errno
));
183 main(int argc
, const char* const* argv
)
185 bool recursive
= false;
190 for (argi
= 1; argi
< argc
; argi
++) {
191 const char *arg
= argv
[argi
];
195 if (arg
[1] == '\0') {
196 fprintf(stderr
, "Error: Invalid option \"-\"\n");
200 for (int i
= 1; arg
[i
]; i
++) {
209 fprintf(stderr
, "Error: Unknown option \"-%c\"\n", arg
[i
]);
217 fprintf(stderr
, "Usage: %s [ -rf ] <file>...\n", argv
[0]);
222 for (; argi
< argc
; argi
++) {
224 if (!path
.Init(argv
[argi
])) {
225 fprintf(stderr
, "Error: Invalid path: \"%s\".\n", argv
[argi
]);
229 remove_entry(path
, recursive
, force
, true);