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