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