Line data Source code
1 : #include "../burp.h"
2 : #include "../alloc.h"
3 : #include "../asfd.h"
4 : #include "../bu.h"
5 : #include "../cmd.h"
6 : #include "../cntr.h"
7 : #include "../cstat.h"
8 : #include "../fsops.h"
9 : #include "../log.h"
10 : #include "../prepend.h"
11 : #include "../strlist.h"
12 : #include "bu_get.h"
13 : #include "child.h"
14 : #include "sdirs.h"
15 : #include "protocol2/backup_phase4.h"
16 : #include "delete.h"
17 :
18 77 : static int do_rename_w(const char *a, const char *b,
19 : const char *cname, struct bu *bu)
20 : {
21 77 : int ret=-1;
22 77 : char *target=NULL;
23 77 : char new_name[256]="";
24 77 : snprintf(new_name, sizeof(new_name), "%s-%s", cname, bu->basename);
25 77 : if(!(target=prepend_s(b, new_name))
26 77 : || build_path_w(target))
27 : goto end;
28 77 : if(do_rename(a, target))
29 : {
30 0 : logp("Error when trying to rename for delete %s\n", a);
31 : goto end;
32 : }
33 : ret=0;
34 : end:
35 77 : free_w(&target);
36 77 : return ret;
37 : }
38 :
39 77 : static int recursive_delete_w(struct sdirs *sdirs, struct bu *bu,
40 : const char *manual_delete)
41 : {
42 77 : if(manual_delete) return 0;
43 77 : if(recursive_delete(sdirs->deleteme))
44 : {
45 0 : logp("Error when trying to delete %s\n", bu->path);
46 : return -1;
47 : }
48 : return 0;
49 : }
50 :
51 : // The failure conditions here are dealt with by the rubble cleaning code.
52 77 : static int delete_backup(struct sdirs *sdirs, const char *cname, struct bu *bu,
53 : const char *manual_delete)
54 : {
55 77 : logp("deleting %s backup %" PRId64 "\n", cname, bu->bno);
56 :
57 77 : if(sdirs->global_sparse)
58 : {
59 43 : const char *candidate_str=bu->path+strlen(sdirs->base)+1;
60 43 : if(remove_backup_from_global_sparse(
61 : sdirs->global_sparse, candidate_str))
62 : return -1;
63 : }
64 :
65 77 : if(!bu->next && !bu->prev)
66 : {
67 : // The current, and only, backup.
68 2 : if(do_rename_w(bu->path, sdirs->deleteme, cname, bu))
69 : return -1;
70 : // If interrupted here, there will be a dangling 'current'
71 : // symlink.
72 2 : if(unlink(sdirs->current))
73 : {
74 0 : logp("unlink %s: %s\n",
75 0 : sdirs->current, strerror(errno));
76 0 : return -1;
77 : }
78 2 : return recursive_delete_w(sdirs, bu, manual_delete);
79 : }
80 75 : if(!bu->next && bu->prev)
81 : {
82 : // The current backup. There are other backups left.
83 : // Need to point the symlink at the previous backup.
84 3 : const char *target=NULL;
85 :
86 3 : target=bu->prev->basename;
87 3 : unlink(sdirs->currenttmp);
88 3 : if(do_symlink(target, sdirs->currenttmp))
89 : return -1;
90 : // If interrupted here, there is a currenttmp and a current
91 : // symlink, and they both point to valid directories.
92 3 : if(do_rename_w(bu->path, sdirs->deleteme, cname, bu))
93 : return -1;
94 : // If interrupted here, there is a currenttmp and a current
95 : // symlink, and the current link is dangling.
96 3 : if(do_rename(sdirs->currenttmp, sdirs->current))
97 : return -1;
98 : // If interrupted here, moving the symlink could have failed
99 : // after current was deleted but before currenttmp was renamed.
100 3 : if(recursive_delete_w(sdirs, bu, manual_delete))
101 : return -1;
102 3 : return 0;
103 : }
104 :
105 : // It is not the current backup.
106 72 : if(do_rename_w(bu->path, sdirs->deleteme, cname, bu)
107 72 : || recursive_delete_w(sdirs, bu, manual_delete))
108 : return -1;
109 : return 0;
110 : }
111 :
112 64 : static int range_loop(struct sdirs *sdirs, const char *cname,
113 : struct strlist *keep, unsigned long rmin, struct bu *bu_list,
114 : struct bu *last, const char *manual_delete, int *deleted)
115 : {
116 64 : struct bu *bu=NULL;
117 64 : unsigned long r=0;
118 64 : unsigned long rmax=0;
119 :
120 64 : rmax=rmin*keep->next->flag;
121 :
122 : // This is going over each range.
123 216 : for(r=rmax; r>rmin; r-=rmin)
124 : {
125 88 : int count=0;
126 88 : unsigned long s=r-rmin;
127 :
128 : // Count the backups in the range.
129 855 : for(bu=bu_list; bu; bu=bu->next)
130 767 : if(s<bu->trbno && bu->trbno<=r)
131 165 : count++;
132 :
133 : // Want to leave one entry in each range.
134 88 : if(count<=1) continue;
135 :
136 : // Try to delete from the most recent in each
137 : // so that hardlinked backups get taken out
138 : // last.
139 :
140 358 : for(bu=last; bu; bu=bu->prev)
141 : {
142 378 : if(s<bu->trbno
143 172 : && bu->trbno<r
144 80 : && (bu->flags & BU_DELETABLE))
145 : {
146 45 : if(delete_backup(sdirs, cname, bu,
147 : manual_delete)) return -1;
148 45 : (*deleted)++;
149 45 : if(--count<=1) break;
150 : }
151 : }
152 : }
153 :
154 : return 0;
155 : }
156 :
157 57 : static int do_delete_backups(struct sdirs *sdirs, const char *cname,
158 : struct strlist *keep, struct bu *bu_list, const char *manual_delete)
159 : {
160 57 : int ret=-1;
161 57 : int deleted=0;
162 57 : unsigned long m=1;
163 57 : struct bu *bu=NULL;
164 57 : struct bu *last=NULL;
165 57 : struct strlist *k=NULL;
166 :
167 : // Find the last entry in the list.
168 57 : for(bu=bu_list; bu; bu=bu->next) last=bu;
169 :
170 : // For each of the 'keep' values, generate ranges in which to keep
171 : // one backup.
172 121 : for(k=keep; k; k=k->next)
173 : {
174 121 : unsigned long rmin=0;
175 121 : rmin=m * k->flag;
176 :
177 121 : if(k->next && range_loop(sdirs, cname,
178 : k, rmin, bu_list, last, manual_delete, &deleted))
179 : goto end;
180 121 : m=rmin;
181 : }
182 :
183 : // Remove the very oldest backups.
184 202 : for(bu=bu_list; bu; bu=bu->next) if(bu->trbno>m) break;
185 :
186 26 : for(; bu; bu=bu->prev)
187 : {
188 26 : if(delete_backup(sdirs, cname, bu, manual_delete))
189 : goto end;
190 26 : deleted++;
191 : }
192 :
193 57 : ret=deleted;
194 : end:
195 57 : return ret;
196 : }
197 :
198 24 : int delete_backups(struct sdirs *sdirs,
199 : const char *cname, struct strlist *keep, const char *manual_delete)
200 : {
201 24 : int ret=-1;
202 24 : struct bu *bu_list=NULL;
203 : // Deleting a backup might mean that more become available to delete.
204 : // Keep trying to delete until we cannot delete any more.
205 : while(1)
206 : {
207 90 : if(bu_get_list(sdirs, &bu_list)) goto end;
208 57 : switch(do_delete_backups(sdirs, cname, keep, bu_list,
209 : manual_delete))
210 : {
211 : case 0: ret=0; goto end;
212 0 : case -1: ret=-1; goto end;
213 : default: break;
214 : }
215 33 : bu_list_free(&bu_list);
216 : }
217 : end:
218 24 : bu_list_free(&bu_list);
219 24 : return ret;
220 : }
221 :
222 13 : int do_delete_server(struct asfd *asfd,
223 : struct sdirs *sdirs, struct conf **confs,
224 : const char *cname, const char *backup, const char *manual_delete)
225 : {
226 13 : int ret=-1;
227 13 : int found=0;
228 13 : unsigned long bno=0;
229 13 : struct bu *bu=NULL;
230 13 : struct bu *bu_list=NULL;
231 13 : struct cntr *cntr=NULL;
232 13 : if(confs)
233 1 : cntr=get_cntr(confs);
234 :
235 13 : logp("in do_delete\n");
236 :
237 13 : if(bu_get_list(sdirs, &bu_list))
238 : goto end;
239 :
240 13 : if(backup && *backup) bno=strtoul(backup, NULL, 10);
241 :
242 37 : for(bu=bu_list; bu; bu=bu->next)
243 : {
244 32 : if(!backup || !*backup) continue;
245 : if(!found
246 32 : && (!strcmp(bu->timestamp, backup)
247 32 : || bu->bno==bno))
248 : {
249 8 : if(bu->flags & BU_DELETABLE)
250 : {
251 6 : found=1;
252 6 : if(cntr)
253 0 : cntr->bno=(int)bu->bno;
254 6 : if(timed_operation_status_only(
255 : CNTR_STATUS_DELETING, NULL, confs))
256 : goto end;
257 6 : if(asfd->write_str(asfd, CMD_GEN, "ok")
258 6 : || delete_backup(sdirs, cname, bu,
259 : manual_delete))
260 : goto end;
261 : }
262 : else
263 : {
264 2 : asfd->write_str(asfd, CMD_ERROR,
265 : "backup not deletable");
266 2 : goto end;
267 : }
268 : break;
269 : }
270 : }
271 :
272 11 : if(backup && *backup && !found)
273 : {
274 4 : asfd->write_str(asfd, CMD_ERROR, "backup not found");
275 4 : goto end;
276 : }
277 :
278 : ret=0;
279 : end:
280 13 : bu_list_free(&bu_list);
281 13 : return ret;
282 : }
|