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