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 0 : static int backup_in_progress(const char *fullpath)
14 : {
15 0 : int ret=-1;
16 : struct stat statp;
17 0 : char *working=NULL;
18 0 : char *finishing=NULL;
19 :
20 0 : if(!(working=prepend_s(fullpath, "working"))
21 0 : || !(finishing=prepend_s(fullpath, "finishing")))
22 : goto end;
23 :
24 0 : if(!lstat(working, &statp)
25 0 : || !lstat(finishing, &statp))
26 : {
27 : logp("%s looks like it has a backup in progress.\n",
28 0 : fullpath);
29 0 : logp("Give up clean up attempt.\n");
30 0 : ret=1;
31 0 : goto end;
32 : }
33 : ret=0;
34 : end:
35 0 : free_w(&working);
36 0 : free_w(&finishing);
37 0 : return ret;
38 : }
39 :
40 0 : static int get_dfiles_to_merge(struct sdirs *sdirs, struct strlist **s)
41 : {
42 0 : int i=0;
43 0 : int n=0;
44 0 : int ret=-1;
45 : struct stat statp;
46 0 : char *fullpath=NULL;
47 0 : char *dfiles=NULL;
48 0 : struct dirent **dir=NULL;
49 :
50 0 : logp("Attempting to clean up unused data files %s\n", sdirs->clients);
51 :
52 0 : if(entries_in_directory_no_sort(sdirs->clients, &dir, &n, 1 /*atime*/))
53 : {
54 : logp("scandir failed for %s in %s: %s\n",
55 0 : sdirs->clients, __func__, strerror(errno));
56 : goto end;
57 : }
58 0 : for(i=0; i<n; i++)
59 : {
60 0 : free_w(&fullpath);
61 0 : if(!(fullpath=prepend_s(sdirs->clients, dir[i]->d_name)))
62 : goto end;
63 0 : switch(is_dir(fullpath, dir[i]))
64 : {
65 : case 0: continue;
66 : case 1: break;
67 : default: logp("is_dir(%s): %s\n",
68 0 : fullpath, strerror(errno));
69 : goto end;
70 : }
71 :
72 0 : if(strcmp(sdirs->client, fullpath))
73 : {
74 0 : switch(backup_in_progress(fullpath))
75 : {
76 : case 0: break;
77 0 : case 1: ret=0;
78 : default: goto end;
79 : }
80 : }
81 :
82 0 : free_w(&dfiles);
83 0 : if(!(dfiles=prepend_s(fullpath, "dfiles"))
84 0 : || lstat(dfiles, &statp))
85 : continue;
86 :
87 : // Have a good entry. Add it to the list.
88 0 : if(strlist_add(s, dfiles, 0))
89 : goto end;
90 : }
91 :
92 : ret=0;
93 : end:
94 0 : free_w(&fullpath);
95 0 : free_w(&dfiles);
96 0 : if(dir)
97 : {
98 0 : for(i=0; i<n; i++) free_v((void **)&dir[i]);
99 0 : free_v((void **)&dir);
100 : }
101 0 : return ret;
102 : }
103 :
104 2 : static int do_unlink(struct blk *oblk, const char *datadir)
105 : {
106 2 : int ret=-1;
107 2 : char *fullpath=NULL;
108 2 : char *savepath=uint64_to_savepathstr(oblk->savepath);
109 2 : if(!(fullpath=prepend_s(datadir, savepath)))
110 : goto end;
111 2 : errno=0;
112 2 : if(unlink(fullpath) && errno!=ENOENT)
113 : {
114 0 : logp("Could not unlink %s: %s\n", fullpath, strerror(errno));
115 : goto end;
116 : }
117 2 : logp("Deleted %s\n", savepath);
118 2 : ret=0;
119 : end:
120 2 : free_w(&fullpath);
121 2 : return ret;
122 : }
123 :
124 : #ifndef UTEST
125 : static
126 : #endif
127 6 : int compare_dindexes_and_unlink_datafiles(const char *dindex_old,
128 : const char *dindex_new, const char *datadir)
129 : {
130 6 : int ret=-1;
131 6 : struct fzp *nzp=NULL;
132 6 : struct fzp *ozp=NULL;
133 : struct iobuf nbuf;
134 : struct iobuf obuf;
135 : struct blk nblk;
136 : struct blk oblk;
137 :
138 6 : iobuf_init(&nbuf);
139 6 : iobuf_init(&obuf);
140 : memset(&nblk, 0, sizeof(struct blk));
141 : memset(&oblk, 0, sizeof(struct blk));
142 :
143 12 : if(!(nzp=fzp_gzopen(dindex_new, "rb"))
144 6 : || !(ozp=fzp_gzopen(dindex_old, "rb")))
145 : goto end;
146 :
147 22 : while(nzp || ozp)
148 : {
149 17 : if(nzp
150 16 : && !nbuf.buf)
151 : {
152 15 : switch(iobuf_fill_from_fzp(&nbuf, nzp))
153 : {
154 5 : case 1: fzp_close(&nzp);
155 5 : break;
156 10 : case 0: if(nbuf.cmd!=CMD_SAVE_PATH)
157 : {
158 : logp("unknown cmd in %s: %c\n",
159 0 : __func__, nbuf.cmd);
160 0 : goto end;
161 : }
162 10 : if(blk_set_from_iobuf_savepath(&nblk,
163 10 : &nbuf)) goto end;
164 : break;
165 : default: goto end; // Error;
166 : }
167 : }
168 :
169 17 : if(ozp
170 17 : && !obuf.buf)
171 : {
172 16 : switch(iobuf_fill_from_fzp(&obuf, ozp))
173 : {
174 6 : case 1: fzp_close(&ozp);
175 6 : break;
176 10 : case 0: if(obuf.cmd!=CMD_SAVE_PATH)
177 : {
178 : logp("unknown cmd in %s: %c\n",
179 0 : __func__, obuf.cmd);
180 0 : goto end;
181 : }
182 10 : if(blk_set_from_iobuf_savepath(&oblk,
183 10 : &obuf)) goto end;
184 : break;
185 : default: goto end; // Error;
186 : }
187 : }
188 :
189 17 : if(nbuf.buf && !obuf.buf)
190 : {
191 : // No more from the old file. Time to stop.
192 : break;
193 : }
194 16 : else if(!nbuf.buf && obuf.buf)
195 : {
196 : // No more in the new file. Delete old entry.
197 1 : if(do_unlink(&oblk, datadir))
198 : goto end;
199 1 : iobuf_free_content(&obuf);
200 : }
201 15 : else if(!nbuf.buf && !obuf.buf)
202 : {
203 : continue;
204 : }
205 10 : else if(nblk.savepath==oblk.savepath)
206 : {
207 : // Same, free both and continue;
208 8 : iobuf_free_content(&nbuf);
209 8 : iobuf_free_content(&obuf);
210 : }
211 2 : else if(nblk.savepath<oblk.savepath)
212 : {
213 : // Only in the new file.
214 1 : iobuf_free_content(&nbuf);
215 : }
216 : else
217 : {
218 : // Only in the old file.
219 1 : if(do_unlink(&oblk, datadir))
220 : goto end;
221 1 : iobuf_free_content(&obuf);
222 : }
223 : }
224 :
225 :
226 : ret=0;
227 : end:
228 6 : iobuf_free_content(&nbuf);
229 6 : iobuf_free_content(&obuf);
230 6 : fzp_close(&nzp);
231 6 : fzp_close(&ozp);
232 6 : return ret;
233 : }
234 :
235 0 : int delete_unused_data_files(struct sdirs *sdirs)
236 : {
237 0 : int ret=-1;
238 0 : uint64_t fcount=0;
239 : char hfile[32];
240 0 : char *tmpdir=NULL;
241 0 : char *hlinks=NULL;
242 0 : char *fullpath=NULL;
243 0 : char *dindex_new=NULL;
244 0 : char *dindex_old=NULL;
245 0 : struct strlist *s=NULL;
246 0 : struct strlist *slist=NULL;
247 : struct stat statp;
248 :
249 0 : if(get_dfiles_to_merge(sdirs, &slist)
250 0 : || !(dindex_old=prepend_s(sdirs->data, "dindex"))
251 0 : || !(tmpdir=prepend_s(sdirs->data, "dindex.new"))
252 0 : || !(hlinks=prepend_s(tmpdir, "hlinks"))
253 0 : || recursive_delete(tmpdir)
254 0 : || mkdir(tmpdir, 0777)
255 0 : || mkdir(hlinks, 0777))
256 : goto end;
257 :
258 0 : for(s=slist; s; s=s->next)
259 : {
260 0 : snprintf(hfile, sizeof(hfile), "%08"PRIX64, fcount++);
261 0 : free_w(&fullpath);
262 0 : if(!(fullpath=prepend_s(hlinks, hfile)))
263 : goto end;
264 0 : if(link(s->path, fullpath))
265 : {
266 : logp("Could not hardlink %s to %s: %s\n",
267 0 : fullpath, s->path, strerror(errno));
268 0 : goto end;
269 : }
270 : }
271 :
272 0 : if(!(dindex_new=prepend_s(tmpdir, "dindex")))
273 : goto end;
274 :
275 0 : if(merge_files_in_dir(dindex_new,
276 0 : tmpdir, "hlinks", fcount, merge_dindexes))
277 : goto end;
278 :
279 0 : if(!lstat(dindex_new, &statp))
280 : {
281 0 : if(!lstat(dindex_old, &statp)
282 0 : && compare_dindexes_and_unlink_datafiles(dindex_old,
283 0 : dindex_new, sdirs->data))
284 : goto end;
285 0 : if(do_rename(dindex_new, dindex_old))
286 : goto end;
287 : }
288 :
289 : ret=0;
290 : end:
291 0 : strlists_free(&slist);
292 0 : if(tmpdir) recursive_delete(tmpdir);
293 0 : free_w(&fullpath);
294 0 : free_w(&hlinks);
295 0 : free_w(&tmpdir);
296 0 : free_w(&dindex_new);
297 0 : free_w(&dindex_old);
298 0 : return ret;
299 : }
|