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 5 : static int get_data_lock(struct lock *lock, struct dpth *dpth, const char *path)
14 : {
15 5 : int ret=-1;
16 5 : char *p=NULL;
17 5 : char *lockfile=NULL;
18 : // Use just the first three components, excluding sig number.
19 15 : if(!(p=prepend_slash(dpth->base_path, path, 14))
20 10 : || !(lockfile=prepend(p, ".lock")))
21 0 : goto end;
22 10 : if(lock_init(lock, lockfile)
23 5 : || build_path_w(lock->path))
24 0 : goto end;
25 5 : lock_get_quick(lock);
26 5 : ret=0;
27 : end:
28 5 : free_w(&p);
29 5 : free_w(&lockfile);
30 5 : return ret;
31 : }
32 :
33 21 : static char *dpth_mk_prim(struct dpth *dpth)
34 : {
35 : static char path[8];
36 21 : snprintf(path, sizeof(path), "%04X", dpth->comp[0]);
37 21 : return path;
38 : }
39 :
40 21 : static char *dpth_mk_seco(struct dpth *dpth)
41 : {
42 : static char path[16];
43 21 : snprintf(path, sizeof(path), "%04X/%04X", dpth->comp[0], dpth->comp[1]);
44 21 : return path;
45 : }
46 :
47 4 : static struct dpth_lock *dpth_lock_alloc(const char *save_path)
48 : {
49 : struct dpth_lock *dpth_lock;
50 4 : if(!(dpth_lock=(struct dpth_lock *)
51 : calloc_w(1, sizeof(struct dpth_lock), __func__)))
52 0 : return NULL;
53 : snprintf(dpth_lock->save_path, sizeof(dpth_lock->save_path),
54 4 : "%s", save_path);
55 4 : return dpth_lock;
56 : }
57 :
58 4 : static int add_lock_to_list(struct dpth *dpth,
59 : struct lock *lock, const char *save_path)
60 : {
61 : struct dpth_lock *dlnew;
62 4 : if(!(dlnew=dpth_lock_alloc(save_path))) return -1;
63 4 : dlnew->lock=lock;
64 :
65 : // Add to the end of the list.
66 4 : if(dpth->tail) dpth->tail->next=dlnew;
67 3 : else if(!dpth->head) dpth->head=dlnew;
68 4 : dpth->tail=dlnew;
69 4 : return 0;
70 : }
71 :
72 12 : 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 12 : dpth->comp[0], dpth->comp[1], dpth->comp[2], dpth->comp[3]);
77 12 : return save_path;
78 : }
79 :
80 5 : 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 5 : save_path=dpth_protocol2_get_save_path(dpth);
87 5 : if(!dpth->need_data_lock) return save_path;
88 :
89 5 : if(!lock && !(lock=lock_alloc())) goto error;
90 5 : if(get_data_lock(lock, dpth, save_path)) goto error;
91 5 : switch(lock->status)
92 : {
93 4 : 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 1 : continue;
98 : case GET_LOCK_ERROR:
99 : default:
100 0 : goto error;
101 : }
102 :
103 4 : dpth->need_data_lock=0; // Got it.
104 4 : if(add_lock_to_list(dpth, lock, save_path)) goto error;
105 4 : lock=NULL;
106 4 : return save_path;
107 : }
108 : error:
109 0 : lock_free(&lock);
110 1 : return NULL;
111 : }
112 :
113 : // Returns 0 on OK, -1 on error. *max gets set to the next entry.
114 63 : int get_highest_entry(const char *path, int *max, size_t len)
115 : {
116 63 : int ent=0;
117 63 : int ret=0;
118 63 : DIR *d=NULL;
119 63 : struct dirent *dp=NULL;
120 :
121 63 : *max=-1;
122 63 : if(!(d=opendir(path))) goto end;
123 121 : while((dp=readdir(d)))
124 : {
125 73 : if(!dp->d_ino
126 73 : || strlen(dp->d_name)!=len)
127 49 : continue;
128 24 : ent=strtol(dp->d_name, NULL, 16);
129 24 : if(ent>*max) *max=ent;
130 : }
131 :
132 : end:
133 63 : if(d) closedir(d);
134 63 : return ret;
135 : }
136 :
137 8202 : int dpth_protocol2_incr_sig(struct dpth *dpth)
138 : {
139 8202 : if(++dpth->comp[3]<DATA_FILE_SIG_MAX) return 0;
140 7 : dpth->comp[3]=0;
141 7 : dpth->need_data_lock=1;
142 7 : return dpth_incr(dpth);
143 : }
144 :
145 21 : int dpth_protocol2_init(struct dpth *dpth, const char *base_path,
146 : int max_storage_subdirs)
147 : {
148 : int max;
149 21 : int ret=0;
150 21 : char *tmp=NULL;
151 :
152 21 : dpth->max_storage_subdirs=max_storage_subdirs;
153 :
154 21 : free_w(&dpth->base_path);
155 21 : if(!(dpth->base_path=strdup_w(base_path, __func__)))
156 0 : goto error;
157 :
158 21 : dpth->savepath=0;
159 21 : dpth->need_data_lock=1;
160 :
161 21 : if(get_highest_entry(dpth->base_path, &max, 4))
162 0 : goto error;
163 21 : if(max<0) max=0;
164 21 : dpth->comp[0]=max;
165 21 : tmp=dpth_mk_prim(dpth);
166 21 : if(!(tmp=prepend_s(dpth->base_path, tmp)))
167 0 : goto error;
168 :
169 21 : if(get_highest_entry(tmp, &max, 4))
170 0 : goto error;
171 21 : if(max<0) max=0;
172 21 : dpth->comp[1]=max;
173 21 : free_w(&tmp);
174 21 : tmp=dpth_mk_seco(dpth);
175 21 : if(!(tmp=prepend_s(dpth->base_path, tmp)))
176 0 : goto error;
177 :
178 21 : if(get_highest_entry(tmp, &max, 4))
179 0 : goto error;
180 21 : if(max<0)
181 : {
182 13 : dpth->comp[2]=0;
183 : }
184 : else
185 : {
186 8 : dpth->comp[2]=max;
187 8 : if(dpth_incr(dpth)) goto error;
188 : }
189 :
190 20 : goto end;
191 : error:
192 1 : ret=-1;
193 : end:
194 21 : free_w(&tmp);
195 21 : return ret;
196 : }
197 :
198 8191 : static int fprint_tag(struct fzp *fzp, enum cmd cmd, unsigned int s)
199 : {
200 8191 : if(fzp_printf(fzp, "%c%04X", cmd, s)!=5)
201 : {
202 0 : logp("Short fprintf\n");
203 0 : return -1;
204 : }
205 8191 : return 0;
206 : }
207 :
208 8191 : static int fwrite_buf(enum cmd cmd,
209 : const char *buf, unsigned int s, struct fzp *fzp)
210 : {
211 : static size_t bytes;
212 8191 : if(fprint_tag(fzp, cmd, s)) return -1;
213 8191 : if((bytes=fzp_write(fzp, buf, s))!=s)
214 : {
215 0 : logp("Short write: %d\n", (int)bytes);
216 0 : return -1;
217 : }
218 8191 : return 0;
219 : }
220 :
221 3 : static struct fzp *file_open_w(const char *path, const char *mode)
222 : {
223 3 : if(build_path_w(path)) return NULL;
224 3 : return fzp_open(path, "wb");
225 : }
226 :
227 3 : static struct fzp *open_data_file_for_write(struct dpth *dpth, struct blk *blk)
228 : {
229 3 : char *path=NULL;
230 3 : struct fzp *fzp=NULL;
231 3 : char *savepathstr=NULL;
232 3 : struct dpth_lock *head=dpth->head;
233 :
234 3 : savepathstr=uint64_to_savepathstr(blk->savepath);
235 :
236 : // Sanity check. They should be coming through from the client
237 : // in the same order in which we locked them.
238 : // Remember that the save_path on the lock list is shorter than the
239 : // full save_path on the blk.
240 3 : if(!head
241 3 : || strncmp(head->save_path,
242 : //FIX THIS
243 3 : savepathstr, sizeof(head->save_path)-1))
244 : {
245 : logp("lock and block save_path mismatch: %s %s\n",
246 0 : head?head->save_path:"(null)", savepathstr);
247 0 : goto end;
248 : }
249 :
250 3 : if(!(path=prepend_slash(dpth->base_path, savepathstr, 14)))
251 0 : goto end;
252 3 : fzp=file_open_w(path, "wb");
253 : end:
254 3 : free_w(&path);
255 3 : return fzp;
256 : }
257 :
258 8191 : int dpth_protocol2_fwrite(struct dpth *dpth,
259 : struct iobuf *iobuf, struct blk *blk)
260 : {
261 : // Remember that the save_path on the lock list is shorter than the
262 : // full save_path on the blk.
263 8191 : if(dpth->fzp
264 8188 : && strncmp(dpth->head->save_path,
265 8188 : uint64_to_savepathstr(blk->savepath),
266 16376 : sizeof(dpth->head->save_path)-1)
267 8191 : && dpth_release_and_move_to_next_in_list(dpth))
268 0 : return -1;
269 :
270 : // Open the current list head if we have no fzp.
271 16382 : if(!dpth->fzp
272 8191 : && !(dpth->fzp=open_data_file_for_write(dpth, blk))) return -1;
273 :
274 8191 : return fwrite_buf(CMD_DATA, iobuf->buf, iobuf->len, dpth->fzp);
275 : }
|