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