| 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 | |
|---|