Line data Source code
1 : #include "../burp.h"
2 : #include "../alloc.h"
3 : #include "../bu.h"
4 : #include "../cstat.h"
5 : #include "../fsops.h"
6 : #include "../log.h"
7 : #include "../prepend.h"
8 : #include "sdirs.h"
9 : #include "timestamp.h"
10 : #include "bu_get.h"
11 :
12 : static int get_link(const char *dir, const char *lnk, char real[], size_t r)
13 : {
14 848 : return readlink_w_in_dir(dir, lnk, real, r);
15 : }
16 :
17 5329 : static void have_backup_file_name(struct bu *bu,
18 : const char *file, uint32_t bit)
19 : {
20 : struct stat statp;
21 : static char path[256]="";
22 5329 : snprintf(path, sizeof(path), "%s/%s", bu->path, file);
23 10532 : if(lstat(path, &statp)) return;
24 126 : bu->flags|=bit;
25 : }
26 :
27 6540 : static void have_backup_file_name_w(struct bu *bu,
28 : const char *file, uint32_t bit)
29 : {
30 : char compressed[32];
31 : snprintf(compressed, sizeof(compressed), "%s.gz", file);
32 2180 : have_backup_file_name(bu, file, bit);
33 2180 : have_backup_file_name(bu, compressed, bit);
34 2180 : }
35 :
36 1195 : static int maybe_add_ent(const char *dir, const char *d_name,
37 : struct bu **bu_list, uint16_t flags, struct cstat *cstat,
38 : int include_working)
39 : {
40 1195 : int ret=-1;
41 1195 : char buf[32]="";
42 : struct stat statp;
43 1195 : char *fullpath=NULL;
44 1195 : char *timestamp=NULL;
45 1195 : char *timestampstr=NULL;
46 1195 : char *hlinkedpath=NULL;
47 1195 : char *basename=NULL;
48 2164 : struct bu *bu=NULL;
49 :
50 1195 : if(!(basename=prepend("", d_name))
51 1195 : || !(fullpath=prepend_s(dir, basename))
52 1195 : || !(timestamp=prepend_s(fullpath, "timestamp"))
53 1195 : || !(hlinkedpath=prepend_s(fullpath, "hardlinked")))
54 : goto error;
55 :
56 2390 : if((!lstat(fullpath, &statp) && !S_ISDIR(statp.st_mode))
57 2390 : || lstat(timestamp, &statp) || !S_ISREG(statp.st_mode)
58 1195 : || timestamp_read(timestamp, buf, sizeof(buf))
59 : // A bit of paranoia to protect against loading directories moved
60 : // aside as if they were real storage directories.
61 1195 : || strncmp(buf, d_name, 8))
62 : {
63 : ret=0; // For resilience.
64 : goto error;
65 : }
66 :
67 1193 : free_w(×tamp);
68 :
69 1193 : if(!(timestampstr=strdup_w(buf, __func__)))
70 : goto error;
71 :
72 2386 : if(!lstat(hlinkedpath, &statp)) flags|=BU_HARDLINKED;
73 :
74 1193 : if(!(bu=bu_alloc())
75 1193 : || bu_init(bu, fullpath, basename, timestampstr, flags))
76 : goto error;
77 :
78 1193 : if(*bu_list) bu->next=*bu_list;
79 1193 : *bu_list=bu;
80 1193 : have_backup_file_name_w(bu, "manifest", BU_MANIFEST);
81 1193 : if(include_working)
82 : {
83 329 : have_backup_file_name_w(bu, "log", BU_LOG_BACKUP);
84 329 : have_backup_file_name_w(bu, "restorelog", BU_LOG_RESTORE);
85 329 : have_backup_file_name_w(bu, "verifylog", BU_LOG_VERIFY);
86 : // Hack to include option for live counters.
87 329 : if(cstat && cstat->run_status==RUN_STATUS_RUNNING)
88 : {
89 24 : switch(cstat->cntr->cntr_status)
90 : {
91 : case CNTR_STATUS_SCANNING:
92 : case CNTR_STATUS_BACKUP:
93 : case CNTR_STATUS_MERGING:
94 : case CNTR_STATUS_SHUFFLING:
95 6 : bu->flags|=BU_STATS_BACKUP;
96 6 : break;
97 : case CNTR_STATUS_VERIFYING:
98 6 : bu->flags|=BU_STATS_VERIFY;
99 6 : break;
100 : case CNTR_STATUS_RESTORING:
101 6 : bu->flags|=BU_STATS_RESTORE;
102 6 : break;
103 : default:
104 : break;
105 : }
106 : }
107 329 : if(!(bu->flags & BU_STATS_BACKUP))
108 323 : have_backup_file_name(bu, "backup_stats", BU_STATS_BACKUP);
109 329 : if(!(bu->flags & BU_STATS_RESTORE))
110 323 : have_backup_file_name(bu, "restore_stats", BU_STATS_RESTORE);
111 329 : if(!(bu->flags & BU_STATS_VERIFY))
112 323 : have_backup_file_name(bu, "verify_stats", BU_STATS_VERIFY);
113 : }
114 :
115 1193 : free_w(&hlinkedpath);
116 1193 : return 0;
117 : error:
118 2 : free_w(&basename);
119 2 : free_w(&fullpath);
120 2 : free_w(×tamp);
121 2 : free_w(×tampstr);
122 2 : free_w(&hlinkedpath);
123 2 : return ret;
124 : }
125 :
126 280 : static void setup_indices(struct bu *bu_list, enum protocol protocol)
127 : {
128 : int i;
129 280 : int tr=0;
130 280 : struct bu *bu=NULL;
131 280 : struct bu *last=NULL;
132 :
133 280 : i=1;
134 1465 : for(bu=bu_list; bu; bu=bu->next)
135 : {
136 : // Enumerate the position of each entry.
137 1185 : bu->index=i++;
138 :
139 1185 : if(protocol==PROTO_2)
140 : {
141 : // All PROTO_2 backups are deletable.
142 546 : bu->flags|=BU_DELETABLE;
143 : }
144 : else
145 : {
146 : // Backups that come after hardlinked backups are
147 : // deletable.
148 639 : if((bu->flags & BU_HARDLINKED) && bu->next)
149 111 : bu->next->flags|=BU_DELETABLE;
150 : }
151 :
152 : // Also set up reverse linkage.
153 1185 : bu->prev=last;
154 1185 : last=bu;
155 : }
156 :
157 : // The oldest backup is deletable.
158 280 : if(bu_list) bu_list->flags|=BU_DELETABLE;
159 :
160 280 : if(last)
161 : {
162 :
163 274 : if((tr=last->bno))
164 : {
165 : // Transpose bnos so that the oldest bno is set to 1.
166 1185 : for(bu=bu_list; bu; bu=bu->next)
167 1185 : bu->trbno=tr-bu->bno+1;
168 : }
169 : }
170 280 : }
171 :
172 281 : static int do_bu_get_list(struct sdirs *sdirs,
173 : struct bu **bu_list, struct cstat *cstat, int include_working)
174 : {
175 281 : int i=0;
176 281 : int n=0;
177 281 : int ret=-1;
178 281 : char realwork[32]="";
179 281 : char realfinishing[32]="";
180 281 : char realcurrent[32]="";
181 281 : struct dirent **dp=NULL;
182 281 : const char *dir=NULL;
183 281 : uint16_t flags=0;
184 : struct stat statp;
185 :
186 281 : if(!sdirs)
187 : {
188 1 : logp("%s() called with NULL sdirs\n", __func__);
189 1 : goto end;
190 : }
191 :
192 280 : dir=sdirs->client;
193 :
194 280 : if(get_link(dir, "working", realwork, sizeof(realwork))
195 280 : || get_link(dir, "finishing", realfinishing, sizeof(realfinishing))
196 280 : || get_link(dir, "current", realcurrent, sizeof(realcurrent)))
197 : goto end;
198 :
199 280 : if(!stat(dir, &statp)
200 280 : && (n=scandir(dir, &dp, filter_dot, alphasort))<0)
201 : {
202 0 : logp("scandir failed in %s: %s\n", __func__, strerror(errno));
203 0 : goto end;
204 : }
205 280 : i=n;
206 2047 : while(i--)
207 : {
208 : // Each storage directory starts with a digit. The 'deleteme'
209 : // directory does not. This check avoids loading 'deleteme'
210 : // as a storage directory.
211 1487 : if(!isdigit(dp[i]->d_name[0]))
212 296 : continue;
213 1191 : flags=0;
214 1191 : if(!strcmp(dp[i]->d_name, realcurrent))
215 : {
216 : flags|=BU_CURRENT;
217 : }
218 917 : else if(!strcmp(dp[i]->d_name, realwork))
219 : {
220 9 : if(!include_working) continue;
221 : flags|=BU_WORKING;
222 : }
223 908 : else if(!strcmp(dp[i]->d_name, realfinishing))
224 : {
225 9 : if(!include_working) continue;
226 : flags|=BU_FINISHING;
227 : }
228 1187 : if(maybe_add_ent(dir, dp[i]->d_name, bu_list, flags,
229 : cstat, include_working)) goto end;
230 : }
231 :
232 280 : setup_indices(*bu_list, sdirs->protocol);
233 :
234 280 : ret=0;
235 : end:
236 281 : if(dp)
237 : {
238 1487 : for(i=0; i<n; i++)
239 1487 : free(dp[i]);
240 274 : free(dp);
241 : }
242 281 : return ret;
243 : }
244 :
245 197 : int bu_get_list(struct sdirs *sdirs, struct bu **bu_list)
246 : {
247 197 : return do_bu_get_list(sdirs, bu_list, NULL, 0/*include_working*/);
248 : }
249 :
250 84 : int bu_get_list_with_working(struct sdirs *sdirs, struct bu **bu_list,
251 : struct cstat *cstat)
252 : {
253 84 : return do_bu_get_list(sdirs, bu_list, cstat, 1/*include_working*/);
254 : }
255 :
256 8 : int bu_get_current(struct sdirs *sdirs, struct bu **bu_list)
257 : {
258 8 : char real[32]="";
259 : // FIX THIS: should not need to specify "current".
260 16 : if(get_link(sdirs->client, "current", real, sizeof(real)))
261 : return -1;
262 8 : return maybe_add_ent(sdirs->client, real, bu_list, BU_CURRENT,
263 : NULL, 0/*include_working*/);
264 : }
|