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 97 : while((dp=readdir(d)))
124 : {
125 73 : if(!dp->d_ino
126 73 : || 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 114 : int dpth_protocol2_init(struct dpth *dpth, const char *base_path,
146 : int max_storage_subdirs)
147 : {
148 : int max;
149 38 : int ret=0;
150 38 : char *tmp=NULL;
151 :
152 38 : if(!base_path)
153 : {
154 0 : logp("No base_path supplied in %s()\n", __func__);
155 0 : goto error;
156 : }
157 :
158 38 : dpth->max_storage_subdirs=max_storage_subdirs;
159 :
160 38 : free_w(&dpth->base_path);
161 38 : if(!(dpth->base_path=strdup_w(base_path, __func__)))
162 : goto error;
163 :
164 38 : dpth->savepath=0;
165 38 : dpth->need_data_lock=1;
166 :
167 38 : if(get_highest_entry(dpth->base_path, &max, 4))
168 : goto error;
169 38 : if(max<0) max=0;
170 38 : dpth->comp[0]=max;
171 76 : tmp=dpth_mk_prim(dpth);
172 38 : if(!(tmp=prepend_s(dpth->base_path, tmp)))
173 : goto error;
174 :
175 38 : if(get_highest_entry(tmp, &max, 4))
176 : goto error;
177 38 : if(max<0) max=0;
178 38 : dpth->comp[1]=max;
179 38 : free_w(&tmp);
180 114 : tmp=dpth_mk_seco(dpth);
181 38 : if(!(tmp=prepend_s(dpth->base_path, tmp)))
182 : goto error;
183 :
184 38 : if(get_highest_entry(tmp, &max, 4))
185 : goto error;
186 38 : if(max<0)
187 : {
188 30 : dpth->comp[2]=0;
189 : }
190 : else
191 : {
192 8 : dpth->comp[2]=max;
193 8 : if(dpth_incr(dpth)) goto error;
194 : }
195 :
196 : goto end;
197 : error:
198 : ret=-1;
199 : end:
200 38 : free_w(&tmp);
201 38 : return ret;
202 : }
203 :
204 16630 : static int fprint_tag(struct fzp *fzp, enum cmd cmd, unsigned int s)
205 : {
206 16630 : if(fzp_printf(fzp, "%c%04X", cmd, s)!=5)
207 : {
208 0 : logp("Short fprintf\n");
209 0 : return -1;
210 : }
211 : return 0;
212 : }
213 :
214 16630 : static int fwrite_buf(enum cmd cmd,
215 : const char *buf, unsigned int s, struct fzp *fzp)
216 : {
217 : static size_t bytes;
218 16630 : if(fprint_tag(fzp, cmd, s)) return -1;
219 16630 : if((bytes=fzp_write(fzp, buf, s))!=s)
220 : {
221 0 : logp("Short write: %d\n", (int)bytes);
222 0 : return -1;
223 : }
224 : return 0;
225 : }
226 :
227 9 : static struct fzp *file_open_w(const char *path, const char *mode)
228 : {
229 9 : if(build_path_w(path)) return NULL;
230 9 : return fzp_open(path, "wb");
231 : }
232 :
233 9 : static struct fzp *open_data_file_for_write(struct dpth *dpth, struct blk *blk)
234 : {
235 9 : char *path=NULL;
236 9 : struct fzp *fzp=NULL;
237 9 : char *savepathstr=NULL;
238 9 : struct dpth_lock *head=dpth->head;
239 :
240 9 : savepathstr=uint64_to_savepathstr(blk->savepath);
241 :
242 : // Sanity check. They should be coming through from the client
243 : // in the same order in which we locked them.
244 : // Remember that the save_path on the lock list is shorter than the
245 : // full save_path on the blk.
246 9 : if(!head
247 9 : || strncmp(head->save_path,
248 : //FIX THIS
249 9 : savepathstr, sizeof(head->save_path)-1))
250 : {
251 : logp("lock and block save_path mismatch: %s %s\n",
252 0 : head?head->save_path:"(null)", savepathstr);
253 : goto end;
254 : }
255 :
256 9 : if(!(path=prepend_slash(dpth->base_path, savepathstr, 14)))
257 : goto end;
258 9 : fzp=file_open_w(path, "wb");
259 : end:
260 9 : free_w(&path);
261 9 : return fzp;
262 : }
263 :
264 16639 : int dpth_protocol2_fwrite(struct dpth *dpth,
265 9 : struct iobuf *iobuf, struct blk *blk)
266 : {
267 : // Remember that the save_path on the lock list is shorter than the
268 : // full save_path on the blk.
269 16630 : if(dpth->fzp
270 16623 : && strncmp(dpth->head->save_path,
271 16623 : uint64_to_savepathstr(blk->savepath),
272 16623 : sizeof(dpth->head->save_path)-1)
273 16632 : && dpth_release_and_move_to_next_in_list(dpth))
274 : return -1;
275 :
276 : // Open the current list head if we have no fzp.
277 33260 : if(!dpth->fzp
278 16648 : && !(dpth->fzp=open_data_file_for_write(dpth, blk))) return -1;
279 :
280 16630 : return fwrite_buf(CMD_DATA, iobuf->buf, iobuf->len, dpth->fzp);
281 : }
|