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