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