1/* vi: set sw=4 ts=4: */
2/*
3 * Mini remove_file implementation for busybox
4 *
5 * Copyright (C) 2001 Matt Kraai <kraai@alumni.carnegiemellon.edu>
6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8 */
9
10#include "libbb.h"
11
12/* Used from NOFORK applets. Must not allocate anything */
13
14int FAST_FUNC remove_file(const char *path, int flags)
15{
16	struct stat path_stat;
17
18	if (lstat(path, &path_stat) < 0) {
19		if (errno != ENOENT) {
20			bb_perror_msg("can't stat '%s'", path);
21			return -1;
22		}
23		if (!(flags & FILEUTILS_FORCE)) {
24			bb_perror_msg("can't remove '%s'", path);
25			return -1;
26		}
27		return 0;
28	}
29
30	if (S_ISDIR(path_stat.st_mode)) {
31		DIR *dp;
32		struct dirent *d;
33		int status = 0;
34
35		if (!(flags & FILEUTILS_RECUR)) {
36			bb_error_msg("%s: is a directory", path);
37			return -1;
38		}
39
40		if ((!(flags & FILEUTILS_FORCE) && access(path, W_OK) < 0 && isatty(0))
41		 || (flags & FILEUTILS_INTERACTIVE)
42		) {
43			fprintf(stderr, "%s: descend into directory '%s'? ", applet_name,
44					path);
45			if (!bb_ask_confirmation())
46				return 0;
47		}
48
49		dp = opendir(path);
50		if (dp == NULL) {
51			return -1;
52		}
53
54		while ((d = readdir(dp)) != NULL) {
55			char *new_path;
56
57			new_path = concat_subpath_file(path, d->d_name);
58			if (new_path == NULL)
59				continue;
60			if (remove_file(new_path, flags) < 0)
61				status = -1;
62			free(new_path);
63		}
64
65		if (closedir(dp) < 0) {
66			bb_perror_msg("can't close '%s'", path);
67			return -1;
68		}
69
70		if (flags & FILEUTILS_INTERACTIVE) {
71			fprintf(stderr, "%s: remove directory '%s'? ", applet_name, path);
72			if (!bb_ask_confirmation())
73				return status;
74		}
75
76		if (rmdir(path) < 0) {
77			bb_perror_msg("can't remove '%s'", path);
78			return -1;
79		}
80
81		return status;
82	}
83
84	/* !ISDIR */
85	if ((!(flags & FILEUTILS_FORCE)
86	     && access(path, W_OK) < 0
87	     && !S_ISLNK(path_stat.st_mode)
88	     && isatty(0))
89	 || (flags & FILEUTILS_INTERACTIVE)
90	) {
91		fprintf(stderr, "%s: remove '%s'? ", applet_name, path);
92		if (!bb_ask_confirmation())
93			return 0;
94	}
95
96	if (unlink(path) < 0) {
97		bb_perror_msg("can't remove '%s'", path);
98		return -1;
99	}
100
101	return 0;
102}
103