Line data Source code
1 : #include "../../burp.h"
2 : #include "../../alloc.h"
3 : #include "../../cmd.h"
4 : #include "../../fsops.h"
5 : #include "../../hexmap.h"
6 : #include "../../iobuf.h"
7 : #include "../../lock.h"
8 : #include "../../log.h"
9 : #include "../../prepend.h"
10 : #include "../../protocol2/blk.h"
11 : #include "dpth.h"
12 :
13 11 : static int get_data_lock(struct lock *lock, struct dpth *dpth, const char *path)
14 : {
15 11 : int ret=-1;
16 11 : char *p=NULL;
17 11 : char *lockfile=NULL;
18 : // Use just the first three components, excluding sig number.
19 22 : if(!(p=prepend_slash(dpth->base_path, path, 14))
20 11 : || !(lockfile=prepend(p, ".lock")))
21 : goto end;
22 22 : if(lock_init(lock, lockfile)
23 11 : || build_path_w(lock->path))
24 : goto end;
25 11 : lock_get_quick(lock);
26 11 : ret=0;
27 : end:
28 11 : free_w(&p);
29 11 : free_w(&lockfile);
30 11 : return ret;
31 : }
32 :
33 : static char *dpth_mk_prim(struct dpth *dpth)
34 : {
35 : static char path[8];
36 38 : snprintf(path, sizeof(path), "%04X", dpth->comp[0]);
37 : return path;
38 : }
39 :
40 : static char *dpth_mk_seco(struct dpth *dpth)
41 : {
42 : static char path[16];
43 38 : snprintf(path, sizeof(path), "%04X/%04X", dpth->comp[0], dpth->comp[1]);
44 : return path;
45 : }
46 :
47 10 : static struct dpth_lock *dpth_lock_alloc(const char *save_path)
48 : {
49 : struct dpth_lock *dpth_lock;
50 10 : if(!(dpth_lock=(struct dpth_lock *)
51 : calloc_w(1, sizeof(struct dpth_lock), __func__)))
52 : return NULL;
53 : snprintf(dpth_lock->save_path, sizeof(dpth_lock->save_path),
54 10 : "%s", save_path);
55 10 : return dpth_lock;
56 : }
57 :
58 10 : static int add_lock_to_list(struct dpth *dpth,
59 : struct lock *lock, const char *save_path)
60 : {
61 : struct dpth_lock *dlnew;
62 10 : if(!(dlnew=dpth_lock_alloc(save_path))) return -1;
63 10 : dlnew->lock=lock;
64 :
65 : // Add to the end of the list.
66 10 : if(dpth->tail) dpth->tail->next=dlnew;
67 7 : else if(!dpth->head) dpth->head=dlnew;
68 10 : dpth->tail=dlnew;
69 : return 0;
70 : }
71 :
72 12545 : char *dpth_protocol2_get_save_path(struct dpth *dpth)
73 : {
74 : static char save_path[32];
75 : snprintf(save_path, sizeof(save_path), "%04X/%04X/%04X/%04X",
76 12545 : dpth->comp[0], dpth->comp[1], dpth->comp[2], dpth->comp[3]);
77 12545 : return save_path;
78 : }
79 :
80 12548 : char *dpth_protocol2_mk(struct dpth *dpth)
81 : {
82 : static char *save_path=NULL;
83 : static struct lock *lock=NULL;
84 : while(1)
85 : {
86 12538 : save_path=dpth_protocol2_get_save_path(dpth);
87 12538 : if(!dpth->need_data_lock) return save_path;
88 :
89 11 : if(!lock && !(lock=lock_alloc())) goto error;
90 22 : if(get_data_lock(lock, dpth, save_path)) goto error;
91 11 : switch(lock->status)
92 : {
93 : case GET_LOCK_GOT: break;
94 : case GET_LOCK_NOT_GOT:
95 : // Increment and try again.
96 1 : if(dpth_incr(dpth)) goto error;
97 : continue;
98 : case GET_LOCK_ERROR:
99 : default:
100 : goto error;
101 : }
102 :
103 10 : dpth->need_data_lock=0; // Got it.
104 10 : if(add_lock_to_list(dpth, lock, save_path)) goto error;
105 10 : lock=NULL;
106 10 : return save_path;
107 : }
108 : error:
109 0 : lock_free(&lock);
110 0 : return NULL;
111 : }
112 :
113 : // Returns 0 on OK, -1 on error. *max gets set to the next entry.
114 150 : int get_highest_entry(const char *path, int *max, size_t len)
115 : {
116 150 : int ent=0;
117 150 : int ret=0;
118 150 : DIR *d=NULL;
119 150 : struct dirent *dp=NULL;
120 :
121 150 : *max=-1;
122 150 : if(!(d=opendir(path))) goto end;
123 225 : while((dp=readdir(d)))
124 : {
125 171 : if(!dp->d_ino
126 171 : || strlen(dp->d_name)!=len)
127 : continue;
128 24 : ent=strtol(dp->d_name, NULL, 16);
129 24 : if(ent>*max) *max=ent;
130 : }
131 :
132 : end:
133 150 : if(d) closedir(d);
134 150 : return ret;
135 : }
136 :
137 16641 : int dpth_protocol2_incr_sig(struct dpth *dpth)
138 : {
139 16641 : if(++dpth->comp[3]<DATA_FILE_SIG_MAX) return 0;
140 9 : dpth->comp[3]=0;
141 9 : dpth->need_data_lock=1;
142 9 : return dpth_incr(dpth);
143 : }
144 :
145 38 : static int open_cfile_fzp(struct dpth *dpth,
146 : const char *cname, const char *cfiles)
147 : {
148 : int fd;
149 38 : int ret=-1;
150 38 : char *fname=NULL;
151 38 : char *fullpath=NULL;
152 :
153 38 : if(!(fname=prepend(cname, "XXXXXX")))
154 : goto end;
155 38 : if(!(fullpath=prepend_s(cfiles, fname)))
156 : goto end;
157 38 : logp("cfile_fzp is %s\n", fullpath);
158 38 : if(build_path_w(fullpath))
159 : goto end;
160 38 : if((fd=mkstemp(fullpath))<0)
161 : {
162 : logp("Could not mkstemp from template %s: %s\n",
163 0 : fullpath, strerror(errno));
164 : goto end;
165 : }
166 38 : if(!(dpth->cfile_fzp=fzp_dopen(fd, "wb")))
167 : goto end;
168 :
169 38 : ret=0;
170 : end:
171 38 : free_w(&fname);
172 38 : free_w(&fullpath);
173 38 : return ret;
174 : }
175 :
176 114 : int dpth_protocol2_init(struct dpth *dpth, const char *base_path,
177 : const char *cname, const char *cfiles, int max_storage_subdirs)
178 : {
179 : int max;
180 38 : int ret=0;
181 38 : char *tmp=NULL;
182 :
183 38 : if(!base_path)
184 : {
185 0 : logp("No base_path supplied in %s()\n", __func__);
186 0 : goto error;
187 : }
188 :
189 38 : if(open_cfile_fzp(dpth, cname, cfiles)) goto error;
190 :
191 38 : dpth->max_storage_subdirs=max_storage_subdirs;
192 :
193 38 : free_w(&dpth->base_path);
194 38 : if(!(dpth->base_path=strdup_w(base_path, __func__)))
195 : goto error;
196 :
197 38 : dpth->savepath=0;
198 38 : dpth->need_data_lock=1;
199 :
200 38 : if(get_highest_entry(dpth->base_path, &max, 4))
201 : goto error;
202 38 : if(max<0) max=0;
203 38 : dpth->comp[0]=max;
204 76 : tmp=dpth_mk_prim(dpth);
205 38 : if(!(tmp=prepend_s(dpth->base_path, tmp)))
206 : goto error;
207 :
208 38 : if(get_highest_entry(tmp, &max, 4))
209 : goto error;
210 38 : if(max<0) max=0;
211 38 : dpth->comp[1]=max;
212 38 : free_w(&tmp);
213 114 : tmp=dpth_mk_seco(dpth);
214 38 : if(!(tmp=prepend_s(dpth->base_path, tmp)))
215 : goto error;
216 :
217 38 : if(get_highest_entry(tmp, &max, 4))
218 : goto error;
219 38 : if(max<0)
220 : {
221 30 : dpth->comp[2]=0;
222 : }
223 : else
224 : {
225 8 : dpth->comp[2]=max;
226 8 : if(dpth_incr(dpth)) goto error;
227 : }
228 :
229 : goto end;
230 : error:
231 : ret=-1;
232 : end:
233 38 : free_w(&tmp);
234 38 : return ret;
235 : }
236 :
237 16630 : static int fprint_tag(struct fzp *fzp, enum cmd cmd, unsigned int s)
238 : {
239 16630 : if(fzp_printf(fzp, "%c%04X", cmd, s)!=5)
240 : {
241 0 : logp("Short fprintf\n");
242 0 : return -1;
243 : }
244 : return 0;
245 : }
246 :
247 16630 : static int fwrite_buf(enum cmd cmd,
248 : const char *buf, unsigned int s, struct fzp *fzp)
249 : {
250 : static size_t bytes;
251 16630 : if(fprint_tag(fzp, cmd, s)) return -1;
252 16630 : if((bytes=fzp_write(fzp, buf, s))!=s)
253 : {
254 0 : logp("Short write: %d\n", (int)bytes);
255 0 : return -1;
256 : }
257 : return 0;
258 : }
259 :
260 9 : static struct fzp *file_open_w(const char *path, const char *mode)
261 : {
262 9 : if(build_path_w(path)) return NULL;
263 9 : return fzp_open(path, "wb");
264 : }
265 :
266 9 : static int write_to_cfile(struct dpth *dpth, struct blk *blk)
267 : {
268 : struct iobuf wbuf;
269 9 : blk_to_iobuf_savepath(blk, &wbuf);
270 9 : if(iobuf_send_msg_fzp(&wbuf, dpth->cfile_fzp))
271 : return -1;
272 9 : if(fzp_flush(dpth->cfile_fzp))
273 : return -1;
274 9 : if(fsync(fzp_fileno(dpth->cfile_fzp)))
275 : {
276 0 : logp("fsync on cfile_fzp failed: %s\n", strerror(errno));
277 : return -1;
278 : }
279 : return 0;
280 : }
281 :
282 9 : static struct fzp *open_data_file_for_write(struct dpth *dpth, struct blk *blk)
283 : {
284 9 : char *path=NULL;
285 9 : struct fzp *fzp=NULL;
286 9 : char *savepathstr=NULL;
287 9 : struct dpth_lock *head=dpth->head;
288 :
289 9 : savepathstr=uint64_to_savepathstr(blk->savepath);
290 :
291 : // Sanity check. They should be coming through from the client
292 : // in the same order in which we locked them.
293 : // Remember that the save_path on the lock list is shorter than the
294 : // full save_path on the blk.
295 9 : if(!head
296 9 : || strncmp(head->save_path,
297 : //FIX THIS
298 9 : savepathstr, sizeof(head->save_path)-1))
299 : {
300 : logp("lock and block save_path mismatch: %s %s\n",
301 0 : head?head->save_path:"(null)", savepathstr);
302 0 : goto end;
303 : }
304 :
305 9 : if(!(path=prepend_slash(dpth->base_path, savepathstr, 14)))
306 : goto end;
307 9 : if(write_to_cfile(dpth, blk))
308 : goto end;
309 9 : fzp=file_open_w(path, "wb");
310 : end:
311 9 : free_w(&path);
312 9 : return fzp;
313 : }
314 :
315 16630 : int dpth_protocol2_fwrite(struct dpth *dpth,
316 : struct iobuf *iobuf, struct blk *blk)
317 : {
318 : // Remember that the save_path on the lock list is shorter than the
319 : // full save_path on the blk.
320 16630 : if(dpth->fzp
321 16623 : && strncmp(dpth->head->save_path,
322 16623 : uint64_to_savepathstr(blk->savepath),
323 16623 : sizeof(dpth->head->save_path)-1)
324 16632 : && dpth_release_and_move_to_next_in_list(dpth))
325 : return -1;
326 :
327 : // Open the current list head if we have no fzp.
328 33260 : if(!dpth->fzp
329 16630 : && !(dpth->fzp=open_data_file_for_write(dpth, blk))) return -1;
330 :
331 16630 : return fwrite_buf(CMD_DATA, iobuf->buf, iobuf->len, dpth->fzp);
332 : }
|