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