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