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