Imported Upstream version 3.2.6
[platform/upstream/ccache.git] / cleanup.c
1 /*
2  * Copyright (C) 2002-2006 Andrew Tridgell
3  * Copyright (C) 2009-2016 Joel Rosdahl
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License as published by the Free
7  * Software Foundation; either version 3 of the License, or (at your option)
8  * any later version.
9  *
10  * This program is distributed in the hope that it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13  * more details.
14  *
15  * You should have received a copy of the GNU General Public License along with
16  * this program; if not, write to the Free Software Foundation, Inc., 51
17  * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18  */
19
20 #include "ccache.h"
21
22 /*
23  * When "max files" or "max cache size" is reached, one of the 16 cache
24  * subdirectories is cleaned up. When doing so, files are deleted (in LRU
25  * order) until the levels are below LIMIT_MULTIPLE.
26  */
27 #define LIMIT_MULTIPLE 0.8
28
29 static struct files {
30         char *fname;
31         time_t mtime;
32         uint64_t size;
33 } **files;
34 static unsigned allocated; /* Size of the files array. */
35 static unsigned num_files; /* Number of used entries in the files array. */
36
37 static uint64_t cache_size;
38 static size_t files_in_cache;
39 static uint64_t cache_size_threshold;
40 static size_t files_in_cache_threshold;
41
42 /* File comparison function that orders files in mtime order, oldest first. */
43 static int
44 files_compare(struct files **f1, struct files **f2)
45 {
46         if ((*f2)->mtime == (*f1)->mtime) {
47                 return strcmp((*f1)->fname, (*f2)->fname);
48         }
49         if ((*f2)->mtime > (*f1)->mtime) {
50                 return -1;
51         }
52         return 1;
53 }
54
55 /* this builds the list of files in the cache */
56 static void
57 traverse_fn(const char *fname, struct stat *st)
58 {
59         char *p;
60
61         if (!S_ISREG(st->st_mode)) {
62                 return;
63         }
64
65         p = basename(fname);
66         if (str_eq(p, "stats")) {
67                 goto out;
68         }
69
70         if (str_startswith(p, ".nfs")) {
71                 /* Ignore temporary NFS files that may be left for open but deleted
72                  * files. */
73                 goto out;
74         }
75
76         if (strstr(p, ".tmp.")) {
77                 /* delete any tmp files older than 1 hour */
78                 if (st->st_mtime + 3600 < time(NULL)) {
79                         x_unlink(fname);
80                         goto out;
81                 }
82         }
83
84         if (strstr(p, "CACHEDIR.TAG")) {
85                 goto out;
86         }
87
88         if (num_files == allocated) {
89                 allocated = 10000 + num_files*2;
90                 files = (struct files **)x_realloc(files, sizeof(struct files *)*allocated);
91         }
92
93         files[num_files] = (struct files *)x_malloc(sizeof(struct files));
94         files[num_files]->fname = x_strdup(fname);
95         files[num_files]->mtime = st->st_mtime;
96         files[num_files]->size = file_size(st);
97         cache_size += files[num_files]->size;
98         files_in_cache++;
99         num_files++;
100
101 out:
102         free(p);
103 }
104
105 static void
106 delete_file(const char *path, size_t size)
107 {
108         if (x_unlink(path) == 0) {
109                 cache_size -= size;
110                 files_in_cache--;
111         } else if (errno != ENOENT && errno != ESTALE) {
112                 cc_log("Failed to unlink %s (%s)", path, strerror(errno));
113         }
114 }
115
116 static void
117 delete_sibling_file(const char *base, const char *extension)
118 {
119         struct stat st;
120         char *path;
121
122         path = format("%s%s", base, extension);
123         if (lstat(path, &st) == 0) {
124                 delete_file(path, file_size(&st));
125         } else if (errno != ENOENT && errno != ESTALE) {
126                 cc_log("Failed to stat %s: %s", path, strerror(errno));
127         }
128         free(path);
129 }
130
131 /* sort the files we've found and delete the oldest ones until we are
132    below the thresholds */
133 static void
134 sort_and_clean(void)
135 {
136         unsigned i;
137         char *last_base = x_strdup("");
138
139         if (num_files > 1) {
140                 /* Sort in ascending mtime order. */
141                 qsort(files, num_files, sizeof(struct files *), (COMPAR_FN_T)files_compare);
142         }
143
144         /* delete enough files to bring us below the threshold */
145         for (i = 0; i < num_files; i++) {
146                 const char *ext;
147
148                 if ((cache_size_threshold == 0
149                      || cache_size <= cache_size_threshold)
150                     && (files_in_cache_threshold == 0
151                         || files_in_cache <= files_in_cache_threshold)) {
152                         break;
153                 }
154
155                 ext = get_extension(files[i]->fname);
156                 if (str_eq(ext, ".o")
157                     || str_eq(ext, ".d")
158                     || str_eq(ext, ".gcno")
159                     || str_eq(ext, ".dia")
160                     || str_eq(ext, ".stderr")
161                     || str_eq(ext, "")) {
162                         char *base = remove_extension(files[i]->fname);
163                         if (!str_eq(base, last_base)) { /* Avoid redundant unlinks. */
164                                 /*
165                                  * Make sure that all sibling files are deleted so that a cached result
166                                  * is removed completely. Note the order of deletions -- the stderr
167                                  * file must be deleted last because if the ccache process gets killed
168                                  * after deleting the .stderr but before deleting the .o, the cached
169                                  * result would be inconsistent.
170                                  */
171                                 delete_sibling_file(base, ".o");
172                                 delete_sibling_file(base, ".d");
173                                 delete_sibling_file(base, ".gcno");
174                                 delete_sibling_file(base, ".dia");
175                                 delete_sibling_file(base, ".stderr");
176                                 delete_sibling_file(base, ""); /* Object file from ccache 2.4. */
177                         }
178                         free(last_base);
179                         last_base = base;
180                 } else {
181                         /* .manifest or unknown file. */
182                         delete_file(files[i]->fname, files[i]->size);
183                 }
184         }
185         free(last_base);
186 }
187
188 /* cleanup in one cache subdir */
189 void
190 cleanup_dir(struct conf *conf, const char *dir)
191 {
192         unsigned i;
193
194         cc_log("Cleaning up cache directory %s", dir);
195
196         cache_size_threshold = conf->max_size * LIMIT_MULTIPLE / 16;
197         files_in_cache_threshold = conf->max_files * LIMIT_MULTIPLE / 16;
198
199         num_files = 0;
200         cache_size = 0;
201         files_in_cache = 0;
202
203         /* build a list of files */
204         traverse(dir, traverse_fn);
205
206         /* clean the cache */
207         sort_and_clean();
208
209         stats_set_sizes(dir, files_in_cache, cache_size);
210
211         /* free it up */
212         for (i = 0; i < num_files; i++) {
213                 free(files[i]->fname);
214                 free(files[i]);
215                 files[i] = NULL;
216         }
217         if (files) {
218                 free(files);
219         }
220         allocated = 0;
221         files = NULL;
222
223         num_files = 0;
224         cache_size = 0;
225         files_in_cache = 0;
226 }
227
228 /* cleanup in all cache subdirs */
229 void cleanup_all(struct conf *conf)
230 {
231         int i;
232
233         for (i = 0; i <= 0xF; i++) {
234                 char *dname = format("%s/%1x", conf->cache_dir, i);
235                 cleanup_dir(conf, dname);
236                 free(dname);
237         }
238 }
239
240 /* traverse function for wiping files */
241 static void wipe_fn(const char *fname, struct stat *st)
242 {
243         char *p;
244
245         if (!S_ISREG(st->st_mode)) {
246                 return;
247         }
248
249         p = basename(fname);
250         if (str_eq(p, "stats")) {
251                 free(p);
252                 return;
253         }
254         free(p);
255
256         x_unlink(fname);
257 }
258
259 /* wipe all cached files in all subdirs */
260 void wipe_all(struct conf *conf)
261 {
262         int i;
263
264         for (i = 0; i <= 0xF; i++) {
265                 char *dname = format("%s/%1x", conf->cache_dir, i);
266                 traverse(dname, wipe_fn);
267                 free(dname);
268         }
269
270         /* and fix the counters */
271         cleanup_all(conf);
272 }