Start 1.33.0 development cycle
[oweals/busybox.git] / libbb / remove_file.c
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 source tree.
8  */
9 #include "libbb.h"
10
11 /* Used from NOFORK applets. Must not allocate anything */
12
13 int FAST_FUNC remove_file(const char *path, int flags)
14 {
15         struct stat path_stat;
16
17         if (lstat(path, &path_stat) < 0) {
18                 if (errno != ENOENT) {
19                         bb_perror_msg("can't stat '%s'", path);
20                         return -1;
21                 }
22                 if (!(flags & FILEUTILS_FORCE)) {
23                         bb_perror_msg("can't remove '%s'", path);
24                         return -1;
25                 }
26                 return 0;
27         }
28
29         if (S_ISDIR(path_stat.st_mode)) {
30                 DIR *dp;
31                 struct dirent *d;
32                 int status = 0;
33
34                 if (!(flags & FILEUTILS_RECUR)) {
35                         bb_error_msg("'%s' is a directory", path);
36                         return -1;
37                 }
38
39                 if ((!(flags & FILEUTILS_FORCE) && access(path, W_OK) < 0 && isatty(0))
40                  || (flags & FILEUTILS_INTERACTIVE)
41                 ) {
42                         fprintf(stderr, "%s: descend into directory '%s'? ",
43                                         applet_name, path);
44                         if (!bb_ask_y_confirmation())
45                                 return 0;
46                 }
47
48                 dp = opendir(path);
49                 if (dp == NULL) {
50                         return -1;
51                 }
52
53                 while ((d = readdir(dp)) != NULL) {
54                         char *new_path;
55
56                         new_path = concat_subpath_file(path, d->d_name);
57                         if (new_path == NULL)
58                                 continue;
59                         if (remove_file(new_path, flags) < 0)
60                                 status = -1;
61                         free(new_path);
62                 }
63
64                 if (closedir(dp) < 0) {
65                         bb_perror_msg("can't close '%s'", path);
66                         return -1;
67                 }
68
69                 if (flags & FILEUTILS_INTERACTIVE) {
70                         fprintf(stderr, "%s: remove directory '%s'? ",
71                                         applet_name, path);
72                         if (!bb_ask_y_confirmation())
73                                 return status;
74                 }
75
76                 if (status == 0 && rmdir(path) < 0) {
77                         bb_perror_msg("can't remove '%s'", path);
78                         return -1;
79                 }
80
81                 if (flags & FILEUTILS_VERBOSE) {
82                         printf("removed directory: '%s'\n", path);
83                 }
84
85                 return status;
86         }
87
88         /* !ISDIR */
89         if ((!(flags & FILEUTILS_FORCE)
90              && access(path, W_OK) < 0
91              && !S_ISLNK(path_stat.st_mode)
92              && isatty(0))
93          || (flags & FILEUTILS_INTERACTIVE)
94         ) {
95                 fprintf(stderr, "%s: remove '%s'? ", applet_name, path);
96                 if (!bb_ask_y_confirmation())
97                         return 0;
98         }
99
100         if (unlink(path) < 0) {
101                 bb_perror_msg("can't remove '%s'", path);
102                 return -1;
103         }
104
105         if (flags & FILEUTILS_VERBOSE) {
106                 printf("removed '%s'\n", path);
107         }
108
109         return 0;
110 }