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 68 : static int do_rename_w(const char *a, const char *b,
17 : const char *cname, struct bu *bu)
18 : {
19 68 : int ret=-1;
20 68 : char *target=NULL;
21 68 : char new_name[256]="";
22 68 : snprintf(new_name, sizeof(new_name), "%s-%s", cname, bu->basename);
23 136 : if(!(target=prepend_s(b, new_name))
24 68 : || build_path_w(target))
25 : goto end;
26 68 : 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 68 : free_w(&target);
34 68 : return ret;
35 : }
36 :
37 68 : static int recursive_delete_w(struct sdirs *sdirs, struct bu *bu,
38 : const char *manual_delete)
39 : {
40 68 : if(manual_delete) return 0;
41 68 : 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 136 : static int delete_backup(struct sdirs *sdirs, const char *cname, struct bu *bu,
51 : const char *manual_delete)
52 : {
53 68 : logp("deleting %s backup %lu\n", cname, bu->bno);
54 :
55 68 : if(sdirs->global_sparse)
56 : {
57 34 : const char *candidate_str=bu->path+strlen(sdirs->base)+1;
58 34 : if(remove_from_global_sparse(
59 34 : sdirs->global_sparse, candidate_str))
60 : return -1;
61 : }
62 :
63 68 : 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 66 : 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 2 : const char *target=NULL;
83 :
84 2 : target=bu->prev->basename;
85 2 : unlink(sdirs->currenttmp);
86 2 : 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 4 : 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 2 : 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 2 : if(recursive_delete_w(sdirs, bu, manual_delete))
103 : return -1;
104 2 : return 0;
105 : }
106 :
107 : // It is not the current backup.
108 192 : if(do_rename_w(bu->path, sdirs->deleteme, cname, bu)
109 64 : || recursive_delete_w(sdirs, bu, manual_delete))
110 : return -1;
111 64 : return 0;
112 : }
113 :
114 66 : 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 66 : struct bu *bu=NULL;
119 66 : unsigned long r=0;
120 66 : unsigned long rmax=0;
121 :
122 66 : rmax=rmin*keep->next->flag;
123 :
124 : // This is going over each range.
125 156 : for(r=rmax; r>rmin; r-=rmin)
126 : {
127 90 : int count=0;
128 90 : unsigned long s=r-rmin;
129 :
130 : // Count the backups in the range.
131 934 : for(bu=bu_list; bu; bu=bu->next)
132 844 : if(s<bu->trbno && bu->trbno<=r)
133 192 : count++;
134 :
135 : // Want to leave one entry in each range.
136 90 : 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 558 : for(bu=last; bu; bu=bu->prev)
143 : {
144 574 : if(s<bu->trbno
145 292 : && bu->trbno<r
146 108 : && (bu->flags & BU_DELETABLE))
147 : {
148 38 : if(delete_backup(sdirs, cname, bu,
149 38 : manual_delete)) return -1;
150 38 : (*deleted)++;
151 38 : if(--count<=1) break;
152 : }
153 : }
154 : }
155 :
156 : return 0;
157 : }
158 :
159 58 : 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 58 : int ret=-1;
163 58 : int deleted=0;
164 58 : unsigned long m=1;
165 58 : struct bu *bu=NULL;
166 58 : struct bu *last=NULL;
167 58 : struct strlist *k=NULL;
168 :
169 : // Find the last entry in the list.
170 58 : 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 124 : for(k=keep; k; k=k->next)
175 : {
176 124 : unsigned long rmin=0;
177 124 : rmin=m * k->flag;
178 :
179 190 : if(k->next && range_loop(sdirs, cname,
180 66 : k, rmin, bu_list, last, manual_delete, &deleted))
181 : goto end;
182 124 : m=rmin;
183 : }
184 :
185 : // Remove the very oldest backups.
186 218 : 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 58 : ret=deleted;
196 : end:
197 58 : 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 58 : if(bu_get_list(sdirs, &bu_list)) goto end;
210 58 : switch(do_delete_backups(sdirs, cname, keep, bu_list,
211 58 : manual_delete))
212 : {
213 : case 0: ret=0; goto end;
214 0 : case -1: ret=-1; goto end;
215 : default: break;
216 : }
217 34 : bu_list_free(&bu_list);
218 : }
219 : end:
220 24 : bu_list_free(&bu_list);
221 58 : 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 4 : found=1;
252 8 : if(asfd->write_str(asfd, CMD_GEN, "ok")
253 8 : || delete_backup(sdirs, cname, bu,
254 4 : manual_delete))
255 : goto end;
256 : }
257 : else
258 : {
259 : asfd->write_str(asfd, CMD_ERROR,
260 4 : "backup not deletable");
261 4 : goto end;
262 : }
263 : break;
264 : }
265 : }
266 :
267 8 : 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 : }
|