Line data Source code
1 : #include "../burp.h"
2 : #include "../alloc.h"
3 : #include "../cmd.h"
4 : #include "../fzp.h"
5 : #include "../handy.h"
6 : #include "../lock.h"
7 : #include "../log.h"
8 : #include "dpth.h"
9 :
10 39 : struct dpth *dpth_alloc(void)
11 : {
12 39 : return (struct dpth *)calloc_w(1, sizeof(struct dpth), __func__);
13 : }
14 :
15 44 : void dpth_free(struct dpth **dpth)
16 : {
17 44 : if(!dpth || !*dpth) return;
18 39 : dpth_release_all(*dpth);
19 39 : fzp_close(&(*dpth)->cfile_fzp);
20 39 : free_w(&((*dpth)->base_path));
21 39 : free_v((void **)dpth);
22 : }
23 :
24 0 : int dpth_release_and_move_to_next_in_list(struct dpth *dpth)
25 : {
26 0 : int ret=0;
27 0 : struct dpth_lock *next=NULL;
28 :
29 : // Try to release (and unlink) the lock even if fzp_close failed, just
30 : // to be tidy.
31 0 : if(fzp_close(&dpth->fzp)) ret=-1;
32 0 : if(lock_release(dpth->head->lock)) ret=-1;
33 0 : lock_free(&dpth->head->lock);
34 :
35 0 : next=dpth->head->next;
36 0 : if(dpth->head==dpth->tail) dpth->tail=next;
37 0 : free_v((void **)&dpth->head);
38 0 : dpth->head=next;
39 0 : return ret;
40 : }
41 :
42 39 : int dpth_release_all(struct dpth *dpth)
43 : {
44 39 : int ret=0;
45 39 : if(!dpth) return 0;
46 39 : if(dpth->fzp && fzp_close(&dpth->fzp)) ret=-1;
47 39 : while(dpth->head)
48 0 : if(dpth_release_and_move_to_next_in_list(dpth)) ret=-1;
49 : return ret;
50 : }
51 :
52 : #define MAX_FILES_PER_DIR 0xFFFF
53 :
54 : static int incr(uint16_t *component, uint16_t max)
55 : {
56 42 : if((*component)++<max) return 1;
57 18 : *component=0;
58 : return 0;
59 : }
60 :
61 : // Three levels with 65535 entries each gives
62 : // 65535^3 = 281,462,092,005,375 data entries
63 : // recommend a filesystem with lots of inodes?
64 : // Hmm, but ext3 only allows 32000 subdirs, although that many files are OK.
65 26 : int dpth_incr(struct dpth *dpth)
66 : {
67 52 : if(incr(&dpth->comp[2], MAX_FILES_PER_DIR)
68 20 : || incr(&dpth->comp[1], dpth->max_storage_subdirs)
69 12 : || incr(&dpth->comp[0], dpth->max_storage_subdirs))
70 : return 0;
71 2 : logp("No free data file entries out of the %d*%d*%d available!\n",
72 : MAX_FILES_PER_DIR,
73 : dpth->max_storage_subdirs, dpth->max_storage_subdirs);
74 2 : logp("Maybe move the storage directory aside and start again.\n");
75 2 : return -1;
76 : }
77 :
78 11 : char *dpth_mk(struct dpth *dpth, int compression, enum cmd cmd)
79 : {
80 : static char path[32];
81 : // File data.
82 44 : snprintf(path, sizeof(path), "%04X/%04X/%04X%s",
83 33 : dpth->comp[0], dpth->comp[1], dpth->comp[2],
84 : // Because of the way EFS works, it cannot be compressed.
85 11 : (compression && cmd!=CMD_EFS_FILE)?".gz":"");
86 11 : return path;
87 : }
88 :
89 : static char *dpth_mk_prim(struct dpth *dpth)
90 : {
91 : static char path[5];
92 19 : snprintf(path, sizeof(path), "%04X", dpth->comp[0]);
93 : return path;
94 : }
95 :
96 : static char *dpth_mk_seco(struct dpth *dpth)
97 : {
98 : static char path[10];
99 19 : snprintf(path, sizeof(path), "%04X/%04X", dpth->comp[0], dpth->comp[1]);
100 : return path;
101 : }
102 :
103 57 : static void get_highest_entry(const char *path, uint16_t *max)
104 : {
105 57 : int ent=0;
106 57 : DIR *d=NULL;
107 57 : struct dirent *dp=NULL;
108 :
109 57 : *max=0;
110 57 : if(!(d=opendir(path))) return;
111 88 : while((dp=readdir(d)))
112 : {
113 66 : if(!dp->d_ino
114 66 : || !strcmp(dp->d_name, ".")
115 44 : || !strcmp(dp->d_name, ".."))
116 44 : continue;
117 22 : ent=strtol(dp->d_name, NULL, 16);
118 22 : if(ent>*max) *max=ent;
119 : }
120 22 : closedir(d);
121 : }
122 :
123 57 : static int get_next_comp(const char *currentdata,
124 : const char *path, uint16_t *comp)
125 : {
126 57 : int ret=-1;
127 57 : char *tmp=NULL;
128 57 : if(path)
129 38 : tmp=prepend_s(currentdata, path);
130 : else
131 19 : tmp=strdup_w(currentdata, __func__);
132 57 : if(!tmp) goto end;
133 :
134 57 : get_highest_entry(tmp, comp);
135 57 : ret=0;
136 : end:
137 57 : free_w(&tmp);
138 57 : return ret;
139 : }
140 :
141 19 : int dpth_init(struct dpth *dpth, const char *basepath,
142 : int max_storage_subdirs)
143 : {
144 19 : int ret=0;
145 19 : dpth->savepath=0;
146 19 : dpth->max_storage_subdirs=max_storage_subdirs;
147 :
148 19 : if((ret=get_next_comp(basepath,
149 : NULL, &dpth->comp[0]))) goto end;
150 :
151 38 : if((ret=get_next_comp(basepath,
152 19 : dpth_mk_prim(dpth), &dpth->comp[1]))) goto end;
153 :
154 38 : if((ret=get_next_comp(basepath,
155 19 : dpth_mk_seco(dpth), &dpth->comp[2]))) goto end;
156 :
157 : // At this point, we have the latest data file. Increment to get the
158 : // next free one.
159 19 : ret=dpth_incr(dpth);
160 :
161 : end:
162 19 : switch(ret)
163 : {
164 : case -1: return -1;
165 18 : default: return 0;
166 : }
167 : }
168 :
169 12 : int dpth_set_from_string(struct dpth *dpth, const char *datapath)
170 : {
171 12 : unsigned int a=0;
172 12 : unsigned int b=0;
173 12 : unsigned int c=0;
174 :
175 12 : if(!datapath
176 12 : || *datapath=='t') // The path used the tree style structure.
177 : return 0;
178 :
179 11 : if((sscanf(datapath, "%04X/%04X/%04X", &a, &b, &c))!=3)
180 : return -1;
181 9 : if(dpth->comp[0]==(int)a
182 4 : && dpth->comp[1]==(int)b
183 2 : && dpth->comp[2] > (int)c)
184 : return 0;
185 8 : if(dpth->comp[0]==(int)a
186 3 : && dpth->comp[1] > (int)b)
187 : return 0;
188 7 : if(dpth->comp[0] > (int)a)
189 : return 0;
190 :
191 4 : dpth->comp[0]=a;
192 4 : dpth->comp[1]=b;
193 4 : dpth->comp[2]=c;
194 4 : return 0;
195 : }
|