Line data Source code
1 : #include "../../../burp.h"
2 : #include "../../../alloc.h"
3 : #include "../../../fsops.h"
4 : #include "../../../hexmap.h"
5 : #include "../../../log.h"
6 : #include "../../../prepend.h"
7 : #include "../../../protocol2/blk.h"
8 : #include "../../../sbuf.h"
9 : #include "../../../strlist.h"
10 : #include "../../sdirs.h"
11 : #include "../backup_phase4.h"
12 :
13 24 : static int backup_in_progress(const char *fullpath)
14 : {
15 24 : int ret=-1;
16 : struct stat statp;
17 24 : char *working=NULL;
18 24 : char *finishing=NULL;
19 :
20 48 : if(!(working=prepend_s(fullpath, "working"))
21 24 : || !(finishing=prepend_s(fullpath, "finishing")))
22 : goto end;
23 :
24 48 : if(!lstat(working, &statp)
25 46 : || !lstat(finishing, &statp))
26 : {
27 : logp("%s looks like it has a backup in progress.\n",
28 4 : fullpath);
29 4 : logp("Give up clean up attempt.\n");
30 4 : ret=1;
31 4 : goto end;
32 : }
33 : ret=0;
34 : end:
35 24 : free_w(&working);
36 24 : free_w(&finishing);
37 24 : return ret;
38 : }
39 :
40 : // Returns 0 on OK, -1 on error, 1 if there were backups already in progress.
41 24 : static int get_dfiles_to_merge(struct sdirs *sdirs, struct strlist **s)
42 : {
43 24 : int i=0;
44 24 : int n=0;
45 24 : int ret=-1;
46 : struct stat statp;
47 24 : char *fullpath=NULL;
48 24 : char *dfiles=NULL;
49 24 : struct dirent **dir=NULL;
50 :
51 24 : if(entries_in_directory_no_sort(sdirs->clients, &dir, &n, 1 /*atime*/))
52 : {
53 : logp("scandir failed for %s in %s: %s\n",
54 0 : sdirs->clients, __func__, strerror(errno));
55 : goto end;
56 : }
57 44 : for(i=0; i<n; i++)
58 : {
59 48 : free_w(&fullpath);
60 48 : if(!(fullpath=prepend_s(sdirs->clients, dir[i]->d_name)))
61 : goto end;
62 48 : switch(is_dir(fullpath, dir[i]))
63 : {
64 : case 0: continue;
65 : case 1: break;
66 : default: logp("is_dir(%s): %s\n",
67 0 : fullpath, strerror(errno));
68 : goto end;
69 : }
70 :
71 48 : if(strcmp(sdirs->client, fullpath))
72 : {
73 24 : switch(backup_in_progress(fullpath))
74 : {
75 : case 0: break;
76 4 : case 1: ret=1;
77 : default: goto end;
78 : }
79 : }
80 :
81 44 : free_w(&dfiles);
82 88 : if(!(dfiles=prepend_s(fullpath, "dfiles"))
83 88 : || lstat(dfiles, &statp))
84 : continue;
85 :
86 : // Have a good entry. Add it to the list.
87 44 : if(strlist_add(s, dfiles, 0))
88 : goto end;
89 : }
90 :
91 : ret=0;
92 : end:
93 24 : free_w(&fullpath);
94 24 : free_w(&dfiles);
95 24 : if(dir)
96 : {
97 48 : for(i=0; i<n; i++) free_v((void **)&dir[i]);
98 24 : free_v((void **)&dir);
99 : }
100 24 : return ret;
101 : }
102 :
103 27 : static int do_unlink(struct blk *oblk, const char *datadir)
104 : {
105 27 : int ret=-1;
106 27 : char *fullpath=NULL;
107 27 : char *savepath=uint64_to_savepathstr(oblk->savepath);
108 27 : if(!(fullpath=prepend_s(datadir, savepath)))
109 : goto end;
110 27 : errno=0;
111 27 : if(unlink(fullpath) && errno!=ENOENT)
112 : {
113 0 : logp("Could not unlink %s: %s\n", fullpath, strerror(errno));
114 : goto end;
115 : }
116 27 : logp("Deleted %s\n", savepath);
117 27 : ret=0;
118 : end:
119 27 : free_w(&fullpath);
120 27 : return ret;
121 : }
122 :
123 : #ifndef UTEST
124 : static
125 : #endif
126 26 : int compare_dindexes_and_unlink_datafiles(const char *dindex_old,
127 : const char *dindex_new, const char *datadir)
128 : {
129 26 : int ret=-1;
130 26 : struct fzp *nzp=NULL;
131 26 : struct fzp *ozp=NULL;
132 : struct iobuf nbuf;
133 : struct iobuf obuf;
134 : struct blk nblk;
135 : struct blk oblk;
136 :
137 26 : iobuf_init(&nbuf);
138 26 : iobuf_init(&obuf);
139 : memset(&nblk, 0, sizeof(struct blk));
140 : memset(&oblk, 0, sizeof(struct blk));
141 :
142 52 : if(!(nzp=fzp_gzopen(dindex_new, "rb"))
143 26 : || !(ozp=fzp_gzopen(dindex_old, "rb")))
144 : goto end;
145 :
146 109 : while(nzp || ozp)
147 : {
148 88 : if(nzp
149 69 : && !nbuf.buf)
150 : {
151 61 : switch(iobuf_fill_from_fzp(&nbuf, nzp))
152 : {
153 21 : case 1: fzp_close(&nzp);
154 21 : break;
155 40 : case 0: if(nbuf.cmd!=CMD_SAVE_PATH)
156 : {
157 : logp("unknown cmd in %s: %c\n",
158 0 : __func__, nbuf.cmd);
159 0 : goto end;
160 : }
161 40 : if(blk_set_from_iobuf_savepath(&nblk,
162 40 : &nbuf)) goto end;
163 : break;
164 : default: goto end; // Error;
165 : }
166 : }
167 :
168 88 : if(ozp
169 88 : && !obuf.buf)
170 : {
171 87 : switch(iobuf_fill_from_fzp(&obuf, ozp))
172 : {
173 26 : case 1: fzp_close(&ozp);
174 26 : break;
175 61 : case 0: if(obuf.cmd!=CMD_SAVE_PATH)
176 : {
177 : logp("unknown cmd in %s: %c\n",
178 0 : __func__, obuf.cmd);
179 0 : goto end;
180 : }
181 61 : if(blk_set_from_iobuf_savepath(&oblk,
182 61 : &obuf)) goto end;
183 : break;
184 : default: goto end; // Error;
185 : }
186 : }
187 :
188 88 : if(nbuf.buf && !obuf.buf)
189 : {
190 : // No more from the old file. Time to stop.
191 : break;
192 : }
193 83 : else if(!nbuf.buf && obuf.buf)
194 : {
195 : // No more in the new file. Delete old entry.
196 19 : if(do_unlink(&oblk, datadir))
197 : goto end;
198 19 : iobuf_free_content(&obuf);
199 : }
200 64 : else if(!nbuf.buf && !obuf.buf)
201 : {
202 : continue;
203 : }
204 43 : else if(nblk.savepath==oblk.savepath)
205 : {
206 : // Same, free both and continue;
207 34 : iobuf_free_content(&nbuf);
208 34 : iobuf_free_content(&obuf);
209 : }
210 9 : else if(nblk.savepath<oblk.savepath)
211 : {
212 : // Only in the new file.
213 1 : iobuf_free_content(&nbuf);
214 : }
215 : else
216 : {
217 : // Only in the old file.
218 8 : if(do_unlink(&oblk, datadir))
219 : goto end;
220 8 : iobuf_free_content(&obuf);
221 : }
222 : }
223 :
224 :
225 : ret=0;
226 : end:
227 26 : iobuf_free_content(&nbuf);
228 26 : iobuf_free_content(&obuf);
229 26 : fzp_close(&nzp);
230 26 : fzp_close(&ozp);
231 26 : return ret;
232 : }
233 :
234 32 : int delete_unused_data_files(struct sdirs *sdirs, int resume)
235 : {
236 32 : int ret=-1;
237 32 : uint64_t fcount=0;
238 : char hfile[32];
239 32 : char *hlinks=NULL;
240 32 : char *fullpath=NULL;
241 32 : char *cindex_tmp=NULL;
242 32 : char *cindex_new=NULL;
243 32 : char *dindex_tmp=NULL;
244 32 : char *dindex_new=NULL;
245 32 : char *dindex_old=NULL;
246 32 : struct strlist *s=NULL;
247 32 : struct strlist *slist=NULL;
248 : struct stat statp;
249 :
250 32 : if(!sdirs)
251 : {
252 1 : logp("No sdirs passed to %s\n", __func__);
253 1 : goto end;
254 : }
255 :
256 31 : if(resume)
257 : {
258 : // Cannot do it on a resume, or it will delete files that are
259 : // referenced in the backup we are resuming.
260 7 : logp("Not attempting to clean up unused data files\n");
261 7 : logp("because %s is resuming\n", sdirs->clients);
262 7 : ret=0;
263 7 : goto end;
264 : }
265 24 : logp("Attempting to clean up unused data files %s\n", sdirs->clients);
266 :
267 : // Get all lists of files in all backups.
268 24 : switch(get_dfiles_to_merge(sdirs, &slist))
269 : {
270 : case 0:
271 : break; // OK.
272 : case 1:
273 : // Backups are in progress, cannot continue.
274 : // But do not return an error.
275 4 : ret=0;
276 : default:
277 : goto end; // Error.
278 : }
279 :
280 40 : if(!(dindex_tmp=prepend_s(sdirs->data, "dindex.tmp"))
281 20 : || !(dindex_old=prepend_s(sdirs->data, "dindex")))
282 : goto end;
283 :
284 : // Get a list of the files that have been created since last time.
285 : // (this enables us to clean up data files that were created for
286 : // interrupted backups).
287 40 : if(!(cindex_tmp=prepend_s(sdirs->cfiles, "cindex.tmp"))
288 20 : || recursive_delete(cindex_tmp))
289 : goto end;
290 40 : if(!lstat(sdirs->cfiles, &statp))
291 : {
292 40 : if(mkdir(cindex_tmp, 0777)
293 20 : || !(cindex_new=prepend_s(cindex_tmp, "cindex"))
294 40 : || merge_files_in_dir_no_fcount(cindex_new,
295 20 : sdirs->cfiles, "n1", merge_dindexes))
296 : goto end;
297 40 : if(!lstat(cindex_new, &statp))
298 : {
299 40 : if(lstat(dindex_old, &statp))
300 : {
301 : // The dindex file does not exist.
302 : // Just rename cindex_new.
303 16 : if(do_rename(cindex_new, dindex_old))
304 : goto end;
305 : }
306 : else
307 : {
308 : // Merge it into the previous list of files
309 : // from all backups.
310 4 : if(merge_dindexes(dindex_tmp,
311 4 : dindex_old, cindex_new)
312 4 : || do_rename(dindex_tmp, dindex_old))
313 : goto end;
314 : }
315 : }
316 : }
317 :
318 : // Create a directory of hardlinks to each list of files.
319 40 : if(!(hlinks=prepend_s(dindex_tmp, "hlinks"))
320 20 : || recursive_delete(dindex_tmp)
321 20 : || mkdir(dindex_tmp, 0777)
322 40 : || mkdir(hlinks, 0777))
323 : goto end;
324 60 : for(s=slist; s; s=s->next)
325 : {
326 40 : snprintf(hfile, sizeof(hfile), "%08"PRIX64, fcount++);
327 40 : free_w(&fullpath);
328 40 : if(!(fullpath=prepend_s(hlinks, hfile)))
329 : goto end;
330 40 : if(link(s->path, fullpath))
331 : {
332 : logp("Could not hardlink %s to %s: %s\n",
333 0 : fullpath, s->path, strerror(errno));
334 0 : goto end;
335 : }
336 : }
337 :
338 : // Create a single list of files in all backups.
339 20 : if(!(dindex_new=prepend_s(dindex_tmp, "dindex")))
340 : goto end;
341 20 : if(merge_files_in_dir(dindex_new,
342 20 : dindex_tmp, "hlinks", fcount, merge_dindexes))
343 : goto end;
344 :
345 40 : if(!lstat(dindex_new, &statp))
346 : {
347 40 : if(!lstat(dindex_old, &statp)
348 40 : && compare_dindexes_and_unlink_datafiles(dindex_old,
349 20 : dindex_new, sdirs->data))
350 : goto end;
351 20 : if(do_rename(dindex_new, dindex_old))
352 : goto end;
353 :
354 : // No longer need the current cfiles directory.
355 20 : if(recursive_delete(sdirs->cfiles))
356 : goto end;
357 : }
358 :
359 : ret=0;
360 : end:
361 32 : strlists_free(&slist);
362 32 : if(cindex_tmp) recursive_delete(cindex_tmp);
363 32 : if(dindex_tmp) recursive_delete(dindex_tmp);
364 32 : free_w(&fullpath);
365 32 : free_w(&hlinks);
366 32 : free_w(&cindex_tmp);
367 32 : free_w(&cindex_new);
368 32 : free_w(&dindex_tmp);
369 32 : free_w(&dindex_new);
370 32 : free_w(&dindex_old);
371 32 : return ret;
372 : }
|