1 | // =============================================================== // |
---|
2 | // // |
---|
3 | // File : adsystem.cxx // |
---|
4 | // Purpose : // |
---|
5 | // // |
---|
6 | // Institute of Microbiology (Technical University Munich) // |
---|
7 | // http://www.arb-home.de/ // |
---|
8 | // // |
---|
9 | // =============================================================== // |
---|
10 | |
---|
11 | #include <sys/types.h> |
---|
12 | #include <netinet/in.h> |
---|
13 | |
---|
14 | #include <arbdbt.h> |
---|
15 | #include <ad_cb.h> |
---|
16 | |
---|
17 | #include "gb_key.h" |
---|
18 | #include "gb_dict.h" |
---|
19 | |
---|
20 | static GB_CSTR gb_read_dict_data(GBDATA *gb_dict, long *size) { |
---|
21 | GB_CSTR data = 0; |
---|
22 | if (gb_dict->flags.compressed_data) { |
---|
23 | GB_internal_error("Dictionary is compressed"); |
---|
24 | data = GB_read_bytes(gb_dict); |
---|
25 | } |
---|
26 | else { |
---|
27 | data = GB_read_bytes_pntr(gb_dict); |
---|
28 | } |
---|
29 | *size = GB_read_bytes_count(gb_dict); |
---|
30 | return data; |
---|
31 | } |
---|
32 | |
---|
33 | GB_ERROR gb_load_dictionary_data(GBDATA *gb_main, const char *key, char **dict_data, long *size) { |
---|
34 | /* returns dictionary data (like saved in DB) |
---|
35 | * in a block allocated by gbm_get_mem(.., GBM_DICT_INDEX) |
---|
36 | */ |
---|
37 | GB_MAIN_TYPE *Main = GB_MAIN(gb_main); |
---|
38 | GB_ERROR error = 0; |
---|
39 | |
---|
40 | *dict_data = 0; |
---|
41 | *size = -1; |
---|
42 | gb_main = Main->gb_main(); |
---|
43 | |
---|
44 | if (key[0] == '@') { |
---|
45 | error = GB_export_error("No dictionaries for system fields"); |
---|
46 | } |
---|
47 | else { |
---|
48 | GBDATA *gb_key_data = Main->gb_key_data; |
---|
49 | GBDATA *gb_name; |
---|
50 | |
---|
51 | GB_push_my_security(gb_main); |
---|
52 | gb_name = GB_find_string(gb_key_data, "@name", key, GB_MIND_CASE, SEARCH_GRANDCHILD); |
---|
53 | |
---|
54 | if (gb_name) { |
---|
55 | GBDATA *gb_key = GB_get_father(gb_name); |
---|
56 | GBDATA *gb_dict = GB_entry(gb_key, "@dictionary"); |
---|
57 | if (gb_dict) { |
---|
58 | const char *data = gb_read_dict_data(gb_dict, size); |
---|
59 | char *copy = (char*)gbm_get_mem(*size, GBM_DICT_INDEX); |
---|
60 | memcpy(copy, data, *size); |
---|
61 | *dict_data = copy; |
---|
62 | } |
---|
63 | } |
---|
64 | GB_pop_my_security(gb_main); |
---|
65 | } |
---|
66 | return error; |
---|
67 | } |
---|
68 | |
---|
69 | static GB_DICTIONARY *gb_create_dict(GBDATA *gb_dict) { |
---|
70 | GB_DICTIONARY *dict = ARB_calloc<GB_DICTIONARY>(1); |
---|
71 | |
---|
72 | long size; |
---|
73 | const char *data = gb_read_dict_data(gb_dict, &size); |
---|
74 | GB_write_security_write(gb_dict, 7); |
---|
75 | |
---|
76 | GB_NINT *idata = (GB_NINT *)data; |
---|
77 | dict->words = ntohl(*idata++); |
---|
78 | dict->textlen = (int)(size - sizeof(GB_NINT)*(1+dict->words*2)); |
---|
79 | |
---|
80 | dict->offsets = idata; |
---|
81 | dict->resort = idata+dict->words; |
---|
82 | dict->text = (unsigned char*)(idata+2*dict->words); |
---|
83 | |
---|
84 | return dict; |
---|
85 | } |
---|
86 | |
---|
87 | static void delete_gb_dictionary(GB_DICTIONARY *dict) { |
---|
88 | free(dict); |
---|
89 | } |
---|
90 | |
---|
91 | static void gb_system_key_changed_cb(GBDATA *gbd, GBQUARK q, GB_CB_TYPE type) { |
---|
92 | if (type == GB_CB_DELETE) { |
---|
93 | GB_MAIN_TYPE *Main = gb_get_main_during_cb(); |
---|
94 | |
---|
95 | delete_gb_dictionary(Main->keys[q].dictionary); |
---|
96 | Main->keys[q].dictionary = 0; |
---|
97 | Main->keys[q].gb_key = 0; |
---|
98 | } |
---|
99 | else { |
---|
100 | gb_load_single_key_data(gbd, q); |
---|
101 | } |
---|
102 | } |
---|
103 | |
---|
104 | static void gb_system_master_changed_cb(GBDATA *gbd, GBQUARK q, GB_CB_TYPE type) { |
---|
105 | if (type == GB_CB_DELETE) { |
---|
106 | GB_MAIN_TYPE *Main = gb_get_main_during_cb(); |
---|
107 | Main->keys[q].gb_master_ali = 0; |
---|
108 | } |
---|
109 | else { |
---|
110 | gb_load_single_key_data(gbd, q); |
---|
111 | } |
---|
112 | } |
---|
113 | |
---|
114 | void gb_load_single_key_data(GBDATA *gb_main, GBQUARK q) { |
---|
115 | GB_MAIN_TYPE *Main = GB_MAIN(gb_main); |
---|
116 | gb_Key *ks = &Main->keys[q]; |
---|
117 | const char *key = ks->key; |
---|
118 | |
---|
119 | if (!Main->gb_key_data) { |
---|
120 | ks->compression_mask = -1; |
---|
121 | return; |
---|
122 | } |
---|
123 | |
---|
124 | gb_main = Main->gb_main(); |
---|
125 | if (key[0] == '@') { |
---|
126 | ks->compression_mask = 0; |
---|
127 | ks->dictionary = 0; |
---|
128 | ks->gb_key_disabled = 1; |
---|
129 | ks->gb_master_ali = 0; |
---|
130 | } |
---|
131 | else { |
---|
132 | GBCONTAINER *gb_key_data = Main->gb_key_data; |
---|
133 | GB_push_my_security(gb_main); |
---|
134 | |
---|
135 | GBDATA *gb_name = GB_find_string(gb_key_data, "@name", key, GB_MIND_CASE, SEARCH_GRANDCHILD); |
---|
136 | GBCONTAINER *gb_key; |
---|
137 | if (gb_name) { |
---|
138 | gb_key = GB_FATHER(gb_name); |
---|
139 | } |
---|
140 | else { |
---|
141 | gb_key = gb_create_container(gb_key_data, "@key"); |
---|
142 | gb_name = gb_create(gb_key, "@name", GB_STRING); |
---|
143 | GB_write_string(gb_name, key); |
---|
144 | } |
---|
145 | |
---|
146 | GB_ensure_callback(gb_key, GB_CB_CHANGED_OR_DELETED, makeDatabaseCallback(gb_system_key_changed_cb, q)); |
---|
147 | |
---|
148 | if (ks->dictionary) { |
---|
149 | delete_gb_dictionary(ks->dictionary); |
---|
150 | ks->dictionary = 0; |
---|
151 | } |
---|
152 | |
---|
153 | ks->compression_mask = *GBT_readOrCreate_int(gb_key, "compression_mask", -1); |
---|
154 | GBDATA *gb_dict = GB_entry(gb_key, "@dictionary"); |
---|
155 | ks->dictionary = gb_dict ? gb_create_dict(gb_dict) : 0; |
---|
156 | ks->gb_key = gb_key; |
---|
157 | |
---|
158 | { |
---|
159 | char buffer[256]; |
---|
160 | sprintf(buffer, "%s/@master_data/@%s", GB_SYSTEM_FOLDER, key); |
---|
161 | |
---|
162 | ks->gb_master_ali = GBDATA::as_container(GB_search(gb_main, buffer, GB_FIND)); |
---|
163 | if (ks->gb_master_ali) { |
---|
164 | GB_ensure_callback(ks->gb_master_ali, GB_CB_CHANGED_OR_DELETED, makeDatabaseCallback(gb_system_master_changed_cb, q)); |
---|
165 | } |
---|
166 | } |
---|
167 | GB_pop_my_security(gb_main); |
---|
168 | } |
---|
169 | } |
---|
170 | |
---|
171 | GB_ERROR gb_save_dictionary_data(GBDATA *gb_main, const char *key, const char *dict, int size) { |
---|
172 | // if 'dict' is NULL, an existing directory gets deleted |
---|
173 | GB_MAIN_TYPE *Main = GB_MAIN(gb_main); |
---|
174 | GB_ERROR error = 0; |
---|
175 | gb_main = Main->gb_main(); |
---|
176 | if (key[0] == '@') { |
---|
177 | error = GB_export_error("No dictionaries for system fields"); |
---|
178 | } |
---|
179 | else { |
---|
180 | GBCONTAINER *gb_key_data = Main->gb_key_data; |
---|
181 | GB_push_my_security(gb_main); |
---|
182 | |
---|
183 | GBDATA *gb_name = GB_find_string(gb_key_data, "@name", key, GB_MIND_CASE, SEARCH_GRANDCHILD); |
---|
184 | GBCONTAINER *gb_key; |
---|
185 | if (gb_name) { |
---|
186 | gb_key = GB_FATHER(gb_name); |
---|
187 | } |
---|
188 | else { |
---|
189 | gb_key = gb_create_container(gb_key_data, "@key"); |
---|
190 | gb_name = gb_create(gb_key, "@name", GB_STRING); |
---|
191 | GB_write_string(gb_name, key); |
---|
192 | } |
---|
193 | GBDATA *gb_dict; |
---|
194 | if (dict) { |
---|
195 | gb_dict = gb_search(gb_key, "@dictionary", GB_BYTES, 1); |
---|
196 | error = GB_write_bytes(gb_dict, dict, size); |
---|
197 | } |
---|
198 | else { |
---|
199 | gb_dict = GB_entry(gb_key, "@dictionary"); |
---|
200 | if (gb_dict) { |
---|
201 | GB_delete(gb_dict); // delete existing dictionary |
---|
202 | } |
---|
203 | } |
---|
204 | GB_pop_my_security(gb_main); |
---|
205 | } |
---|
206 | if (!error) { |
---|
207 | GBQUARK q = gb_find_or_create_quark(Main, key); |
---|
208 | gb_load_single_key_data(gb_main, q); |
---|
209 | } |
---|
210 | return error; |
---|
211 | } |
---|
212 | |
---|
213 | GB_ERROR gb_load_key_data_and_dictionaries(GB_MAIN_TYPE *Main) { // goes to header: __ATTR__USERESULT |
---|
214 | GBCONTAINER *gb_main = Main->root_container; |
---|
215 | GB_ERROR error = NULL; |
---|
216 | |
---|
217 | GBCONTAINER *gb_key_data = gb_search(gb_main, GB_SYSTEM_FOLDER "/" GB_SYSTEM_KEY_DATA, GB_CREATE_CONTAINER, 1)->as_container(); |
---|
218 | if (!gb_key_data) { |
---|
219 | error = GB_await_error(); |
---|
220 | } |
---|
221 | else { |
---|
222 | Main->gb_key_data = gb_key_data; |
---|
223 | if (Main->is_server()) { // do not create anything at the client side |
---|
224 | GB_push_my_security(gb_main); |
---|
225 | |
---|
226 | // search unused keys and delete them |
---|
227 | for (GBDATA *gb_key = GB_entry(gb_key_data, "@key"); gb_key && !error;) { |
---|
228 | GBDATA *gb_next_key = GB_nextEntry(gb_key); |
---|
229 | GBDATA *gb_name = GB_entry(gb_key, "@name"); |
---|
230 | if (!gb_name) error = GB_await_error(); |
---|
231 | else { |
---|
232 | const char *name = GB_read_char_pntr(gb_name); |
---|
233 | if (!name) error = GB_await_error(); |
---|
234 | else { |
---|
235 | if (!name[0]) { |
---|
236 | error = GB_delete(gb_key); // delete invalid empty key |
---|
237 | } |
---|
238 | else { |
---|
239 | GBQUARK quark = gb_find_or_create_quark(Main, name); |
---|
240 | if (quark<=0 || quark >= Main->sizeofkeys || !quark2key(Main, quark)) { |
---|
241 | error = GB_delete(gb_key); // delete unused key |
---|
242 | } |
---|
243 | } |
---|
244 | } |
---|
245 | } |
---|
246 | gb_key = gb_next_key; |
---|
247 | } |
---|
248 | |
---|
249 | if (!error) error = GB_create_index(gb_key_data, "@name", GB_MIND_CASE, Main->sizeofkeys*2); // create key index |
---|
250 | if (!error) { |
---|
251 | ASSERT_RESULT_PREDICATE(isAbove<int>(0), gb_find_or_create_quark(Main, "@name")); |
---|
252 | ASSERT_RESULT_PREDICATE(isAbove<int>(0), gb_find_or_create_quark(Main, "@key")); |
---|
253 | ASSERT_RESULT_PREDICATE(isAbove<int>(0), gb_find_or_create_quark(Main, "@dictionary")); |
---|
254 | ASSERT_RESULT_PREDICATE(isAbove<int>(0), gb_find_or_create_quark(Main, "compression_mask")); |
---|
255 | |
---|
256 | for (int key=1; key<Main->sizeofkeys; key++) { |
---|
257 | if (quark2key(Main, key)) { |
---|
258 | gb_load_single_key_data(gb_main, key); |
---|
259 | } |
---|
260 | } |
---|
261 | } |
---|
262 | GB_pop_my_security(gb_main); |
---|
263 | } |
---|
264 | } |
---|
265 | RETURN_ERROR(error); |
---|
266 | } |
---|
267 | |
---|
268 | /* gain access to allow repair of broken compression |
---|
269 | * (see NT_fix_dict_compress) |
---|
270 | */ |
---|
271 | |
---|
272 | struct DictData { |
---|
273 | char *data; |
---|
274 | long size; |
---|
275 | }; |
---|
276 | |
---|
277 | static void GB_free_dictionary(DictData *dd) { |
---|
278 | if (dd) { |
---|
279 | if (dd->data) gbm_free_mem(dd->data, dd->size, GBM_DICT_INDEX); |
---|
280 | free(dd); |
---|
281 | } |
---|
282 | } |
---|
283 | |
---|
284 | DictData *GB_get_dictionary(GBDATA *gb_main, const char *key) { |
---|
285 | /* return DictData or |
---|
286 | * NULL if no dictionary or error occurred |
---|
287 | */ |
---|
288 | DictData *dd = ARB_calloc<DictData>(1); |
---|
289 | GB_ERROR error = gb_load_dictionary_data(gb_main, key, &dd->data, &dd->size); |
---|
290 | |
---|
291 | if (error || !dd->data) { |
---|
292 | GB_free_dictionary(dd); |
---|
293 | dd = NULL; |
---|
294 | if (error) GB_export_error(error); |
---|
295 | } |
---|
296 | |
---|
297 | return dd; |
---|
298 | } |
---|
299 | |
---|
300 | GB_ERROR GB_set_dictionary(GBDATA *gb_main, const char *key, const DictData *dd) { |
---|
301 | // if 'dd' == NULL -> delete dictionary |
---|
302 | GB_ERROR error; |
---|
303 | if (dd) { |
---|
304 | error = gb_save_dictionary_data(gb_main, key, dd->data, dd->size); |
---|
305 | } |
---|
306 | else { |
---|
307 | error = gb_save_dictionary_data(gb_main, key, NULL, 0); |
---|
308 | } |
---|
309 | return error; |
---|
310 | } |
---|
311 | |
---|