00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268 #ifndef DOXYGEN_SHOULD_SKIP_THIS
00269
00270 #include "midas.h"
00271 #include "msystem.h"
00272 #include <assert.h>
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284 DATABASE *_database;
00285 INT _database_entries = 0;
00286
00287 static RECORD_LIST *_record_list;
00288 static INT _record_list_entries = 0;
00289
00290 extern char *tid_name[];
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301 void *malloc_key(DATABASE_HEADER * pheader, INT size)
00302 {
00303 FREE_DESCRIP *pfree, *pfound, *pprev = NULL;
00304
00305 if (size == 0)
00306 return NULL;
00307
00308
00309 size = ALIGN(size);
00310
00311
00312 pfree = (FREE_DESCRIP *) ((char *) pheader + pheader->first_free_key);
00313
00314 while (pfree->size < size && pfree->next_free) {
00315 pprev = pfree;
00316 pfree = (FREE_DESCRIP *) ((char *) pheader + pfree->next_free);
00317 }
00318
00319
00320 if (pfree->size < size)
00321 return 0;
00322
00323 pfound = pfree;
00324
00325
00326 if (pfree ==
00327 (FREE_DESCRIP *) ((char *) pheader + pheader->first_free_key)) {
00328 if (size < pfree->size) {
00329
00330 pheader->first_free_key += size;
00331 pfree =
00332 (FREE_DESCRIP *) ((char *) pheader + pheader->first_free_key);
00333
00334 pfree->size = pfound->size - size;
00335 pfree->next_free = pfound->next_free;
00336 } else {
00337
00338 pheader->first_free_key = pfree->next_free;
00339 }
00340 } else {
00341
00342 if (pfound->size - size < sizeof(FREE_DESCRIP)) {
00343
00344 pprev->next_free = pfound->next_free;
00345 } else {
00346
00347 pfree = (FREE_DESCRIP *) ((char *) pfound + size);
00348
00349 pfree->size = pfound->size - size;
00350 pfree->next_free = pfound->next_free;
00351
00352 pprev->next_free = (PTYPE) pfree - (PTYPE) pheader;
00353 }
00354 }
00355
00356
00357 memset(pfound, 0, size);
00358
00359 return pfound;
00360 }
00361
00362
00363 void free_key(DATABASE_HEADER * pheader, void *address, INT size)
00364 {
00365 FREE_DESCRIP *pfree, *pprev, *pnext;
00366
00367 if (size == 0)
00368 return;
00369
00370
00371 size = ALIGN(size);
00372
00373 pfree = (FREE_DESCRIP *) address;
00374 pprev = NULL;
00375
00376
00377 memset(address, 0, size);
00378
00379
00380 if ((PTYPE) address - (PTYPE) pheader < pheader->first_free_key) {
00381 pfree->size = size;
00382 pfree->next_free = pheader->first_free_key;
00383 pheader->first_free_key = (PTYPE) address - (PTYPE) pheader;
00384 } else {
00385
00386 pprev = (FREE_DESCRIP *) ((char *) pheader + pheader->first_free_key);
00387
00388 while (pprev->next_free < (PTYPE) address - (PTYPE) pheader) {
00389 if (pprev->next_free <= 0) {
00390 cm_msg(MERROR, "free_key",
00391 "database is corrupted: pprev=0x%x, pprev->next_free=%d",
00392 pprev, pprev->next_free);
00393 return;
00394 }
00395 pprev = (FREE_DESCRIP *) ((char *) pheader + pprev->next_free);
00396 }
00397
00398 pfree->size = size;
00399 pfree->next_free = pprev->next_free;
00400
00401 pprev->next_free = (PTYPE) pfree - (PTYPE) pheader;
00402 }
00403
00404
00405 pnext = (FREE_DESCRIP *) ((char *) pheader + pfree->next_free);
00406 if ((PTYPE) pnext == (PTYPE) pfree + pfree->size) {
00407 pfree->size += pnext->size;
00408 pfree->next_free = pnext->next_free;
00409
00410 memset(pnext, 0, pnext->size);
00411 }
00412
00413
00414 if (pprev && pprev->next_free ==
00415 (PTYPE) pprev - (PTYPE) pheader + pprev->size) {
00416 pprev->size += pfree->size;
00417 pprev->next_free = pfree->next_free;
00418
00419 memset(pfree, 0, pfree->size);
00420 }
00421 }
00422
00423
00424 void *malloc_data(DATABASE_HEADER * pheader, INT size)
00425 {
00426 FREE_DESCRIP *pfree, *pfound, *pprev = NULL;
00427
00428 if (size == 0)
00429 return NULL;
00430
00431
00432 size = ALIGN(size);
00433
00434
00435 pfree = (FREE_DESCRIP *) ((char *) pheader + pheader->first_free_data);
00436
00437 while (pfree->size < size && pfree->next_free) {
00438 pprev = pfree;
00439 pfree = (FREE_DESCRIP *) ((char *) pheader + pfree->next_free);
00440 }
00441
00442
00443 if (pfree->size < size)
00444 return 0;
00445
00446 pfound = pfree;
00447
00448
00449 if (pfree ==
00450 (FREE_DESCRIP *) ((char *) pheader + pheader->first_free_data)) {
00451 if (size < pfree->size) {
00452
00453 pheader->first_free_data += size;
00454 pfree =
00455 (FREE_DESCRIP *) ((char *) pheader + pheader->first_free_data);
00456
00457 pfree->size = pfound->size - size;
00458 pfree->next_free = pfound->next_free;
00459 } else {
00460
00461 pheader->first_free_data = pfree->next_free;
00462 }
00463 } else {
00464
00465 if (pfound->size - size < sizeof(FREE_DESCRIP)) {
00466
00467 pprev->next_free = pfound->next_free;
00468 } else {
00469
00470 pfree = (FREE_DESCRIP *) ((char *) pfound + size);
00471
00472 pfree->size = pfound->size - size;
00473 pfree->next_free = pfound->next_free;
00474
00475 pprev->next_free = (PTYPE) pfree - (PTYPE) pheader;
00476 }
00477 }
00478
00479
00480 memset(pfound, 0, size);
00481
00482 return pfound;
00483 }
00484
00485
00486 void free_data(DATABASE_HEADER * pheader, void *address, INT size)
00487 {
00488 FREE_DESCRIP *pfree, *pprev, *pnext;
00489
00490 if (size == 0)
00491 return;
00492
00493
00494 size = ALIGN(size);
00495
00496 pfree = (FREE_DESCRIP *) address;
00497 pprev = NULL;
00498
00499
00500 memset(address, 0, size);
00501
00502
00503 if ((PTYPE) address - (PTYPE) pheader < pheader->first_free_data) {
00504 pfree->size = size;
00505 pfree->next_free = pheader->first_free_data;
00506 pheader->first_free_data = (PTYPE) address - (PTYPE) pheader;
00507 } else {
00508
00509 pprev = (FREE_DESCRIP *) ((char *) pheader + pheader->first_free_data);
00510
00511 while (pprev->next_free < (PTYPE) address - (PTYPE) pheader) {
00512 if (pprev->next_free <= 0) {
00513 cm_msg(MERROR, "free_data",
00514 "database is corrupted: pprev=0x%x, pprev->next_free=%d",
00515 pprev, pprev->next_free);
00516 return;
00517 }
00518
00519 pprev = (FREE_DESCRIP *) ((char *) pheader + pprev->next_free);
00520 }
00521
00522 pfree->size = size;
00523 pfree->next_free = pprev->next_free;
00524
00525 pprev->next_free = (PTYPE) pfree - (PTYPE) pheader;
00526 }
00527
00528
00529 pnext = (FREE_DESCRIP *) ((char *) pheader + pfree->next_free);
00530 if ((PTYPE) pnext == (PTYPE) pfree + pfree->size) {
00531 pfree->size += pnext->size;
00532 pfree->next_free = pnext->next_free;
00533
00534 memset(pnext, 0, pnext->size);
00535 }
00536
00537
00538 if (pprev && pprev->next_free ==
00539 (PTYPE) pprev - (PTYPE) pheader + pprev->size) {
00540 pprev->size += pfree->size;
00541 pprev->next_free = pfree->next_free;
00542
00543 memset(pfree, 0, pfree->size);
00544 }
00545 }
00546
00547
00548 void *realloc_data(DATABASE_HEADER * pheader, void *address,
00549 INT old_size, INT new_size)
00550 {
00551 void *tmp = NULL, *pnew;
00552
00553 if (old_size) {
00554 tmp = malloc(old_size);
00555 if (tmp == NULL)
00556 return NULL;
00557
00558 memcpy(tmp, address, old_size);
00559 free_data(pheader, address, old_size);
00560 }
00561
00562 pnew = malloc_data(pheader, new_size);
00563
00564 if (pnew && old_size)
00565 memcpy(pnew, tmp, old_size < new_size ? old_size : new_size);
00566
00567 if (old_size)
00568 free(tmp);
00569
00570 return pnew;
00571 }
00572
00573
00574 char *strcomb(char **list)
00575
00576 {
00577 INT i, j;
00578 static char *str = NULL;
00579
00580
00581 for (i = 0, j = 0; list[i]; i++)
00582 j += strlen(list[i]) + 1;
00583 j += 1;
00584
00585 if (str == NULL)
00586 str = (char *) malloc(j);
00587 else
00588 str = (char *) realloc(str, j);
00589
00590 str[0] = 0;
00591 for (i = 0; list[i]; i++) {
00592 strcat(str, list[i]);
00593 strcat(str, "\n");
00594 }
00595
00596 return str;
00597 }
00598
00599
00600 INT print_key_info(HNDLE hDB, HNDLE hKey, KEY * pkey, INT level,
00601 void *info)
00602 {
00603 int i;
00604 char *p;
00605
00606 p = (char *) info;
00607
00608 sprintf(p + strlen(p), "%08X %08X %04X ",
00609 hKey - sizeof(DATABASE_HEADER),
00610 pkey->data - sizeof(DATABASE_HEADER), pkey->total_size);
00611
00612 for (i = 0; i < level; i++)
00613 sprintf(p + strlen(p), " ");
00614
00615 sprintf(p + strlen(p), "%s\n", pkey->name);
00616
00617 return SUCCESS;
00618 }
00619
00620 INT db_show_mem(HNDLE hDB, char *result, INT buf_size, BOOL verbose)
00621 {
00622 DATABASE_HEADER *pheader;
00623 INT total_size_key, total_size_data;
00624 FREE_DESCRIP *pfree;
00625
00626 db_lock_database(hDB);
00627
00628 pheader = _database[hDB - 1].database_header;
00629
00630 sprintf(result,
00631 "Database header size is 0x%04X, all following values are offset by this!\nKey area 0x00000000 - 0x%08X\nData area 0x%08X - 0x%08X\n\n",
00632 sizeof(DATABASE_HEADER), pheader->key_size - 1,
00633 pheader->key_size, pheader->key_size + pheader->data_size);
00634
00635 strcat(result, "Keylist:\n");
00636 strcat(result, "--------\n");
00637 total_size_key = 0;
00638 pfree = (FREE_DESCRIP *) ((char *) pheader + pheader->first_free_key);
00639
00640 while ((PTYPE) pfree != (PTYPE) pheader) {
00641 total_size_key += pfree->size;
00642 sprintf(result + strlen(result),
00643 "Free block at 0x%08X, size 0x%08X, next 0x%08X\n",
00644 (PTYPE) pfree - (PTYPE) pheader - sizeof(DATABASE_HEADER),
00645 pfree->size,
00646 pfree->next_free ? pfree->next_free -
00647 sizeof(DATABASE_HEADER) : 0);
00648 pfree = (FREE_DESCRIP *) ((char *) pheader + pfree->next_free);
00649 }
00650
00651 strcat(result, "\nData:\n");
00652 strcat(result, "-----\n");
00653 total_size_data = 0;
00654 pfree = (FREE_DESCRIP *) ((char *) pheader + pheader->first_free_data);
00655
00656 while ((PTYPE) pfree != (PTYPE) pheader) {
00657 total_size_data += pfree->size;
00658 sprintf(result + strlen(result),
00659 "Free block at 0x%08X, size 0x%08X, next 0x%08X\n",
00660 (PTYPE) pfree - (PTYPE) pheader - sizeof(DATABASE_HEADER),
00661 pfree->size,
00662 pfree->next_free ? pfree->next_free -
00663 sizeof(DATABASE_HEADER) : 0);
00664 pfree = (FREE_DESCRIP *) ((char *) pheader + pfree->next_free);
00665 }
00666 sprintf(result + strlen(result),
00667 "\nTotal size: %1d (0x%08X) keylist, %1d (0x%08X) data\n",
00668 total_size_key, total_size_key, total_size_data,
00669 total_size_data);
00670 sprintf(result + strlen(result),
00671 "\nFree: %1d (%1.1lf%%) keylist, %1d (%1.1lf%%) data\n",
00672 total_size_key,
00673 100 * (double) total_size_key / pheader->key_size,
00674 total_size_data,
00675 100 * (double) total_size_data / pheader->data_size);
00676
00677 if (verbose) {
00678 sprintf(result + strlen(result), "\n\n");
00679 sprintf(result + strlen(result), "Key Data Size\n");
00680 sprintf(result + strlen(result), "------------------------\n");
00681 db_scan_tree(hDB, pheader->root_key, 0, print_key_info, result);
00682 }
00683
00684 db_unlock_database(hDB);
00685
00686 return DB_SUCCESS;
00687 }
00688
00689
00690 static int db_validate_key_offset(DATABASE_HEADER * pheader, int offset)
00691
00692 {
00693 if (offset != 0 && offset < (int) sizeof(DATABASE_HEADER))
00694 return 0;
00695
00696 if (offset > (int) sizeof(DATABASE_HEADER) + pheader->key_size)
00697 return 0;
00698
00699 return 1;
00700 }
00701
00702 static int db_validate_data_offset(DATABASE_HEADER * pheader, int offset)
00703
00704 {
00705 if (offset != 0 && offset < (int) sizeof(DATABASE_HEADER))
00706 return 0;
00707
00708 if (offset >
00709 (int) sizeof(DATABASE_HEADER) + pheader->key_size +
00710 pheader->data_size)
00711 return 0;
00712
00713 return 1;
00714 }
00715
00716 static int db_validate_hkey(DATABASE_HEADER * pheader, HNDLE hKey)
00717 {
00718 return db_validate_key_offset(pheader, hKey);
00719 }
00720
00721 static int db_validate_key(DATABASE_HEADER * pheader, int recurse,
00722 const char *path, KEY * pkey)
00723 {
00724 KEYLIST *pkeylist;
00725 int i;
00726 static time_t t_min = 0, t_max;
00727
00728 if (!db_validate_key_offset(pheader, (PTYPE) pkey - (PTYPE) pheader)) {
00729 cm_msg(MERROR, "db_validate_key",
00730 "Warning: database corruption, key \"%s\", data 0x%08X", path,
00731 pkey->data - sizeof(DATABASE_HEADER));
00732 return 0;
00733 }
00734
00735 if (!db_validate_data_offset(pheader, pkey->data)) {
00736 cm_msg(MERROR, "db_validate_key",
00737 "Warning: database corruption, data \"%s\", data 0x%08X", path,
00738 pkey->data - sizeof(DATABASE_HEADER));
00739 return 0;
00740 }
00741
00742
00743 if (pkey->type >= TID_LAST) {
00744 cm_msg(MERROR, "db_validate_key",
00745 "Warning: invalid key type, key \"%s\", type %d", path,
00746 pkey->type);
00747 return 0;
00748 }
00749
00750
00751 if ((pkey->total_size < 0) || (pkey->total_size > pheader->key_size)) {
00752 cm_msg(MERROR, "db_validate_key",
00753 "Warning: invalid key \"%s\" total_size: %d", path,
00754 pkey->total_size);
00755 return 0;
00756 }
00757
00758 if ((pkey->item_size < 0) || (pkey->item_size > pheader->key_size)) {
00759 cm_msg(MERROR, "db_validate_key",
00760 "Warning: invalid key \"%s\" item_size: %d", path,
00761 pkey->item_size);
00762 return 0;
00763 }
00764
00765 if ((pkey->num_values < 0) || (pkey->num_values > pheader->key_size)) {
00766 cm_msg(MERROR, "db_validate_key",
00767 "Warning: invalid key \"%s\" num_values: %d", path,
00768 pkey->num_values);
00769 return 0;
00770 }
00771
00772
00773 if (pkey->total_size != pkey->item_size * pkey->num_values) {
00774 cm_msg(MINFO, "db_validate_key",
00775 "Warning: corrected key \"%s\" size: total_size=%d, should be %d*%d=%d",
00776 path, pkey->total_size, pkey->item_size, pkey->num_values,
00777 pkey->item_size * pkey->num_values);
00778 pkey->total_size = pkey->item_size * pkey->num_values;
00779 }
00780
00781
00782 if ((pkey->
00783 access_mode & ~(MODE_READ | MODE_WRITE | MODE_DELETE |
00784 MODE_EXCLUSIVE | MODE_ALLOC))) {
00785 cm_msg(MERROR, "db_validate_key",
00786 "Warning: invalid access mode, key \"%s\", mode %d", path,
00787 pkey->access_mode);
00788 return 0;
00789 }
00790
00791
00792 if (t_min == 0) {
00793 t_min = ss_time() - 3600 * 24 * 365 * 10;
00794 t_max = ss_time() + 3600 * 24 * 365 * 10;
00795 }
00796
00797 if (pkey->last_written > 0 &&
00798 (pkey->last_written < t_min || pkey->last_written > t_max)) {
00799 cm_msg(MERROR, "db_validate_key",
00800 "Warning: invalid access time, key \"%s\", time %d", path,
00801 pkey->last_written);
00802 return 0;
00803 }
00804
00805 if (pkey->type == TID_KEY && recurse) {
00806
00807
00808 pkeylist = (KEYLIST *) ((char *) pheader + pkey->data);
00809
00810 if (pkeylist->num_keys != 0 &&
00811 (pkeylist->first_key == 0
00812 || !db_validate_key_offset(pheader, pkeylist->first_key))) {
00813 cm_msg(MERROR, "db_validate_key",
00814 "Warning: database corruption, key \"%s\", first_key 0x%08X",
00815 path, pkeylist->first_key - sizeof(DATABASE_HEADER));
00816 return 0;
00817 }
00818
00819
00820 pkey = (KEY *) ((char *) pheader + pkeylist->first_key);
00821
00822 for (i = 0; i < pkeylist->num_keys; i++) {
00823 char buf[1024];
00824 sprintf(buf, "%s/%s", path, pkey->name);
00825
00826 if (!db_validate_key_offset(pheader, pkey->next_key)) {
00827 cm_msg(MERROR, "db_validate_key",
00828 "Warning: database corruption, key \"%s\", next_key 0x%08X",
00829 buf, pkey->next_key - sizeof(DATABASE_HEADER));
00830 return 0;
00831 }
00832
00833 if (pkey->type == TID_KEY)
00834 if (!db_validate_key(pheader, recurse + 1, buf, pkey))
00835 return 0;
00836
00837 pkey = (KEY *) ((char *) pheader + pkey->next_key);
00838 }
00839 }
00840
00841 return 1;
00842 }
00843
00844
00845 static int db_validate_db(DATABASE_HEADER * pheader)
00846 {
00847 int total_size_key = 0;
00848 int total_size_data = 0;
00849 double ratio;
00850 FREE_DESCRIP *pfree;
00851
00852
00853
00854 if (!db_validate_key_offset(pheader, pheader->first_free_key)) {
00855 cm_msg(MERROR, "db_validate_db",
00856 "Warning: database corruption, first_free_key 0x%08X",
00857 pheader->first_free_key - sizeof(DATABASE_HEADER));
00858 return 0;
00859 }
00860
00861 pfree = (FREE_DESCRIP *) ((char *) pheader + pheader->first_free_key);
00862
00863 while ((PTYPE) pfree != (PTYPE) pheader) {
00864 if (pfree->next_free != 0
00865 && !db_validate_key_offset(pheader, pfree->next_free)) {
00866 cm_msg(MERROR, "db_validate_db",
00867 "Warning: database corruption, next_free 0x%08X",
00868 pfree->next_free - sizeof(DATABASE_HEADER));
00869 return 0;
00870 }
00871
00872 total_size_key += pfree->size;
00873 pfree = (FREE_DESCRIP *) ((char *) pheader + pfree->next_free);
00874 }
00875
00876 ratio =
00877 ((double) (pheader->key_size - total_size_key)) /
00878 ((double) pheader->key_size);
00879 if (ratio > 0.9)
00880 cm_msg(MERROR, "db_validate_db",
00881 "Warning: database key area is %.0f%% full", ratio * 100.0);
00882
00883 if (total_size_key > pheader->key_size) {
00884 cm_msg(MERROR, "db_validate_db",
00885 "Warning: database corruption, total_key_size 0x%08X",
00886 total_size_key);
00887 return 0;
00888 }
00889
00890
00891
00892 if (!db_validate_data_offset(pheader, pheader->first_free_data)) {
00893 cm_msg(MERROR, "db_validate_db",
00894 "Warning: database corruption, first_free_data 0x%08X",
00895 pheader->first_free_data - sizeof(DATABASE_HEADER));
00896 return 0;
00897 }
00898
00899 pfree = (FREE_DESCRIP *) ((char *) pheader + pheader->first_free_data);
00900
00901 while ((PTYPE) pfree != (PTYPE) pheader) {
00902 if (pfree->next_free != 0
00903 && !db_validate_data_offset(pheader, pfree->next_free)) {
00904 cm_msg(MERROR, "db_validate_db",
00905 "Warning: database corruption, next_free 0x%08X",
00906 pfree->next_free - sizeof(DATABASE_HEADER));
00907 return 0;
00908 }
00909
00910 total_size_data += pfree->size;
00911 pfree = (FREE_DESCRIP *) ((char *) pheader + pfree->next_free);
00912 }
00913
00914 ratio =
00915 ((double) (pheader->data_size - total_size_data)) /
00916 ((double) pheader->data_size);
00917 if (ratio > 0.9)
00918 cm_msg(MERROR, "db_validate_db",
00919 "Warning: database data area is %.0f%% full", ratio * 100.0);
00920
00921 if (total_size_data > pheader->data_size) {
00922 cm_msg(MERROR, "db_validate_db",
00923 "Warning: database corruption, total_size_data 0x%08X",
00924 total_size_key);
00925 return 0;
00926 }
00927
00928
00929
00930 if (!db_validate_key_offset(pheader, pheader->root_key)) {
00931 cm_msg(MERROR, "db_validate_db",
00932 "Warning: database corruption, root_key 0x%08X",
00933 pheader->root_key - sizeof(DATABASE_HEADER));
00934 return 0;
00935 }
00936
00937 return db_validate_key(pheader, 1, "",
00938 (KEY *) ((char *) pheader + pheader->root_key));
00939 }
00940
00941
00942 #endif
00943
00944
00945
00946
00947
00948
00949
00950
00951
00952
00953
00954
00955 INT db_open_database(char *database_name, INT database_size,
00956 HNDLE * hDB, char *client_name)
00957 {
00958 if (rpc_is_remote())
00959 return rpc_call(RPC_DB_OPEN_DATABASE, database_name, database_size,
00960 hDB, client_name);
00961
00962 #ifdef LOCAL_ROUTINES
00963 {
00964 INT i, status;
00965 HNDLE handle;
00966 DATABASE_CLIENT *pclient;
00967 BOOL shm_created;
00968 HNDLE shm_handle;
00969 DATABASE_HEADER *pheader;
00970 KEY *pkey;
00971 KEYLIST *pkeylist;
00972 FREE_DESCRIP *pfree;
00973 BOOL call_watchdog;
00974 DWORD timeout;
00975
00976 if (database_size < 0 || database_size > 10E7) {
00977 cm_msg(MERROR, "db_open_database", "invalid database size");
00978 return DB_INVALID_PARAM;
00979 }
00980
00981
00982 if (strlen(database_name) >= NAME_LENGTH)
00983 database_name[NAME_LENGTH] = 0;
00984
00985
00986 if (_database_entries == 0) {
00987 _database = (DATABASE *) malloc(sizeof(DATABASE));
00988 memset(_database, 0, sizeof(DATABASE));
00989 if (_database == NULL) {
00990 *hDB = 0;
00991 return DB_NO_MEMORY;
00992 }
00993
00994 _database_entries = 1;
00995 i = 0;
00996 } else {
00997
00998 for (i = 0; i < _database_entries; i++)
00999 if (_database[i].attached &&
01000 equal_ustring(_database[i].name, database_name)) {
01001
01002 if (rpc_get_server_option(RPC_OSERVER_TYPE) == ST_MTHREAD) {
01003 if (_database[i].index == ss_gettid()) {
01004 *hDB = i + 1;
01005 return DB_SUCCESS;
01006 }
01007 } else {
01008 *hDB = i + 1;
01009 return DB_SUCCESS;
01010 }
01011 }
01012
01013
01014 for (i = 0; i < _database_entries; i++)
01015 if (!_database[i].attached)
01016 break;
01017
01018
01019 if (i == _database_entries) {
01020 _database =
01021 (DATABASE *) realloc(_database,
01022 sizeof(DATABASE) * (_database_entries +
01023 1));
01024 memset(&_database[_database_entries], 0, sizeof(DATABASE));
01025
01026 _database_entries++;
01027 if (_database == NULL) {
01028 _database_entries--;
01029 *hDB = 0;
01030 return DB_NO_MEMORY;
01031 }
01032 }
01033 }
01034
01035 handle = (HNDLE) i;
01036
01037
01038 status = ss_shm_open(database_name,
01039 sizeof(DATABASE_HEADER) +
01040 2 * ALIGN(database_size / 2),
01041 (void **) &(_database[(INT) handle].
01042 database_header), &shm_handle);
01043
01044 if (status == SS_NO_MEMORY || status == SS_FILE_ERROR) {
01045 *hDB = 0;
01046 return DB_INVALID_NAME;
01047 }
01048
01049
01050 pheader = _database[handle].database_header;
01051
01052
01053 strcpy(_database[handle].name, database_name);
01054
01055 shm_created = (status == SS_CREATED);
01056
01057
01058
01059
01060 if (shm_created && pheader->name[0] == 0) {
01061
01062 memset(pheader, 0,
01063 sizeof(DATABASE_HEADER) + 2 * ALIGN(database_size / 2));
01064
01065 strcpy(pheader->name, database_name);
01066 pheader->key_size = ALIGN(database_size / 2);
01067 pheader->data_size = ALIGN(database_size / 2);
01068 pheader->root_key = sizeof(DATABASE_HEADER);
01069 pheader->first_free_key = sizeof(DATABASE_HEADER);
01070 pheader->first_free_data =
01071 sizeof(DATABASE_HEADER) + pheader->key_size;
01072
01073
01074 pfree =
01075 (FREE_DESCRIP *) ((char *) pheader + pheader->first_free_key);
01076 pfree->size = pheader->key_size;
01077 pfree->next_free = 0;
01078
01079 pfree =
01080 (FREE_DESCRIP *) ((char *) pheader + pheader->first_free_data);
01081 pfree->size = pheader->data_size;
01082 pfree->next_free = 0;
01083
01084
01085 pkey = (KEY *) malloc_key(pheader, sizeof(KEY));
01086
01087
01088 pkey->type = TID_KEY;
01089 pkey->num_values = 1;
01090 pkey->access_mode = MODE_READ | MODE_WRITE | MODE_DELETE;
01091 strcpy(pkey->name, "root");
01092 pkey->parent_keylist = 0;
01093
01094
01095 pkeylist = (KEYLIST *) malloc_key(pheader, sizeof(KEYLIST));
01096
01097
01098 pkey->data = (PTYPE) pkeylist - (PTYPE) pheader;
01099 pkey->item_size = sizeof(KEYLIST);
01100 pkey->total_size = sizeof(KEYLIST);
01101
01102 pkeylist->parent = (PTYPE) pkey - (PTYPE) pheader;
01103 pkeylist->num_keys = 0;
01104 pkeylist->first_key = 0;
01105 } else {
01106
01107
01108
01109
01110
01111
01112
01113
01114
01115
01116
01117
01118
01119
01120
01121
01122
01123
01124
01125
01126
01127
01128
01129
01130
01131 }
01132
01133
01134 status = ss_mutex_create(database_name, &(_database[handle].mutex));
01135 if (status != SS_SUCCESS && status != SS_CREATED) {
01136 *hDB = 0;
01137 return DB_NO_MUTEX;
01138 }
01139 _database[handle].lock_cnt = 0;
01140
01141
01142 db_lock_database(handle + 1);
01143
01144
01145
01146
01147
01148
01149
01150
01151
01152
01153 #ifdef ESRCH
01154
01155
01156 for (i = 0; i < MAX_CLIENTS; i++) {
01157 int err;
01158 errno = 0;
01159 err = kill(pheader->client[i].pid, 0);
01160 if (errno == ESRCH) {
01161 cm_msg(MERROR, "db_open_database",
01162 "removing client %s, pid %d, index %d because the pid no longer exists",
01163 pheader->client[i].name, pheader->client[i].pid, i);
01164
01165 memset(&(pheader->client[i]), 0, sizeof(DATABASE_CLIENT));
01166 }
01167 }
01168 #endif
01169
01170
01171
01172
01173 pheader->num_clients = 0;
01174 pheader->max_client_index = 0;
01175 for (i = 0; i < MAX_CLIENTS; i++) {
01176 if (pheader->client[i].pid == 0)
01177 continue;
01178 pheader->num_clients++;
01179 pheader->max_client_index = i + 1;
01180 }
01181
01182
01183
01184
01185
01186
01187 for (i = 0; i < MAX_CLIENTS; i++)
01188 if (pheader->client[i].pid == 0)
01189 break;
01190
01191 if (i == MAX_CLIENTS) {
01192 db_unlock_database(handle + 1);
01193 *hDB = 0;
01194 cm_msg(MERROR, "db_open_database",
01195 "maximum number of clients exceeded");
01196 return DB_NO_SLOT;
01197 }
01198
01199
01200 _database[handle].client_index = i;
01201
01202
01203
01204
01205
01206 pheader->num_clients++;
01207 if (i + 1 > pheader->max_client_index)
01208 pheader->max_client_index = i + 1;
01209
01210
01211 pclient = &pheader->client[i];
01212
01213 memset(pclient, 0, sizeof(DATABASE_CLIENT));
01214
01215 strcpy(pclient->name, client_name);
01216 pclient->pid = ss_getpid();
01217 pclient->tid = ss_gettid();
01218 pclient->thandle = ss_getthandle();
01219 pclient->num_open_records = 0;
01220
01221 ss_suspend_get_port(&pclient->port);
01222
01223 pclient->last_activity = ss_millitime();
01224
01225 cm_get_watchdog_params(&call_watchdog, &timeout);
01226 pclient->watchdog_timeout = timeout;
01227
01228
01229 if (!db_validate_db(pheader)) {
01230
01231
01232
01233
01234
01235
01236
01237
01238 }
01239
01240 db_unlock_database(handle + 1);
01241
01242
01243 _database[handle].database_data =
01244 _database[handle].database_header + 1;
01245 _database[handle].attached = TRUE;
01246 _database[handle].shm_handle = shm_handle;
01247 _database[handle].protect = FALSE;
01248
01249
01250 if (rpc_get_server_option(RPC_OSERVER_TYPE) == ST_SINGLE)
01251 _database[handle].index = rpc_get_server_acception();
01252 else
01253 _database[handle].index = ss_gettid();
01254
01255 *hDB = (handle + 1);
01256
01257
01258 ss_suspend_set_dispatch(CH_IPC, 0, (int (*)(void)) cm_dispatch_ipc);
01259
01260 if (shm_created)
01261 return DB_CREATED;
01262 }
01263 #endif
01264
01265 return DB_SUCCESS;
01266 }
01267
01268
01269
01270
01271
01272
01273
01274 INT db_close_database(HNDLE hDB)
01275 {
01276 if (rpc_is_remote())
01277 return rpc_call(RPC_DB_CLOSE_DATABASE, hDB);
01278
01279 #ifdef LOCAL_ROUTINES
01280 else {
01281 DATABASE_HEADER *pheader;
01282 DATABASE_CLIENT *pclient;
01283 INT index, destroy_flag, i, j;
01284
01285 if (hDB > _database_entries || hDB <= 0) {
01286 cm_msg(MERROR, "db_close_database", "invalid database handle");
01287 return DB_INVALID_HANDLE;
01288 }
01289
01290
01291
01292
01293
01294
01295
01296
01297 db_lock_database(hDB);
01298
01299 index = _database[hDB - 1].client_index;
01300 pheader = _database[hDB - 1].database_header;
01301 pclient = &pheader->client[index];
01302
01303 if (rpc_get_server_option(RPC_OSERVER_TYPE) == ST_SINGLE &&
01304 _database[hDB - 1].index != rpc_get_server_acception()) {
01305 db_unlock_database(hDB);
01306 return DB_INVALID_HANDLE;
01307 }
01308
01309 if (rpc_get_server_option(RPC_OSERVER_TYPE) != ST_SINGLE &&
01310 _database[hDB - 1].index != ss_gettid()) {
01311 db_unlock_database(hDB);
01312 return DB_INVALID_HANDLE;
01313 }
01314
01315 if (!_database[hDB - 1].attached) {
01316 cm_msg(MERROR, "db_close_database", "invalid database handle");
01317 db_unlock_database(hDB);
01318 return DB_INVALID_HANDLE;
01319 }
01320
01321
01322 for (i = 0; i < pclient->max_index; i++)
01323 if (pclient->open_record[i].handle)
01324 db_remove_open_record(hDB, pclient->open_record[i].handle, FALSE);
01325
01326
01327 _database[hDB - 1].attached = FALSE;
01328
01329
01330 memset(&(pheader->client[index]), 0, sizeof(DATABASE_CLIENT));
01331
01332
01333 for (i = MAX_CLIENTS - 1; i >= 0; i--)
01334 if (pheader->client[i].pid != 0)
01335 break;
01336 pheader->max_client_index = i + 1;
01337
01338
01339 for (i = MAX_CLIENTS - 1, j = 0; i >= 0; i--)
01340 if (pheader->client[i].pid != 0)
01341 j++;
01342 pheader->num_clients = j;
01343
01344 destroy_flag = (pheader->num_clients == 0);
01345
01346
01347 ss_shm_flush(pheader->name, pheader,
01348 sizeof(DATABASE_HEADER) + 2 * pheader->data_size);
01349
01350
01351 ss_shm_close(pheader->name, pheader,
01352 _database[hDB - 1].shm_handle, destroy_flag);
01353
01354
01355 db_unlock_database(hDB);
01356
01357
01358 ss_mutex_delete(_database[hDB - 1].mutex, destroy_flag);
01359
01360
01361 if (hDB == _database_entries)
01362 _database_entries--;
01363
01364 if (_database_entries > 0)
01365 _database =
01366 (DATABASE *) realloc(_database,
01367 sizeof(DATABASE) * (_database_entries));
01368 else {
01369 free(_database);
01370 _database = NULL;
01371 }
01372
01373
01374 if (destroy_flag) {
01375 extern INT _mutex_elog, _mutex_alarm;
01376
01377 if (_mutex_elog)
01378 ss_mutex_delete(_mutex_elog, TRUE);
01379 if (_mutex_alarm)
01380 ss_mutex_delete(_mutex_alarm, TRUE);
01381 }
01382
01383 }
01384 #endif
01385
01386 return DB_SUCCESS;
01387 }
01388
01389
01390 #ifndef DOXYGEN_SHOULD_SKIP_THIS
01391
01392
01393 INT db_flush_database(HNDLE hDB)
01394
01395
01396
01397
01398
01399
01400
01401
01402
01403
01404
01405
01406
01407
01408
01409
01410
01411
01412
01413 {
01414 if (rpc_is_remote())
01415 return rpc_call(RPC_DB_FLUSH_DATABASE, hDB);
01416
01417 #ifdef LOCAL_ROUTINES
01418 else {
01419 DATABASE_HEADER *pheader;
01420 DATABASE_CLIENT *pclient;
01421 INT index;
01422
01423 if (hDB > _database_entries || hDB <= 0) {
01424 cm_msg(MERROR, "db_close_database", "invalid database handle");
01425 return DB_INVALID_HANDLE;
01426 }
01427
01428
01429
01430
01431
01432
01433
01434 db_lock_database(hDB);
01435 index = _database[hDB - 1].client_index;
01436 pheader = _database[hDB - 1].database_header;
01437 pclient = &pheader->client[index];
01438
01439 if (rpc_get_server_option(RPC_OSERVER_TYPE) == ST_SINGLE &&
01440 _database[hDB - 1].index != rpc_get_server_acception()) {
01441 db_unlock_database(hDB);
01442 return DB_INVALID_HANDLE;
01443 }
01444
01445 if (rpc_get_server_option(RPC_OSERVER_TYPE) != ST_SINGLE &&
01446 _database[hDB - 1].index != ss_gettid()) {
01447 db_unlock_database(hDB);
01448 return DB_INVALID_HANDLE;
01449 }
01450
01451 if (!_database[hDB - 1].attached) {
01452 cm_msg(MERROR, "db_close_database", "invalid database handle");
01453 db_unlock_database(hDB);
01454 return DB_INVALID_HANDLE;
01455 }
01456
01457
01458 ss_shm_flush(pheader->name, pheader,
01459 sizeof(DATABASE_HEADER) + 2 * pheader->data_size);
01460 db_unlock_database(hDB);
01461
01462 }
01463 #endif
01464
01465 return DB_SUCCESS;
01466 }
01467
01468
01469 INT db_close_all_databases(void)
01470
01471
01472
01473
01474
01475
01476
01477
01478
01479
01480
01481
01482
01483
01484
01485
01486 {
01487 INT status;
01488
01489 if (rpc_is_remote()) {
01490 status = rpc_call(RPC_DB_CLOSE_ALL_DATABASES);
01491 if (status != DB_SUCCESS)
01492 return status;
01493 }
01494 #ifdef LOCAL_ROUTINES
01495 {
01496 INT i;
01497
01498 for (i = _database_entries; i > 0; i--)
01499 db_close_database(i);
01500 }
01501 #endif
01502
01503 return db_close_all_records();
01504 }
01505
01506
01507 INT db_set_client_name(HNDLE hDB, char *client_name)
01508
01509
01510
01511
01512
01513
01514
01515
01516
01517
01518
01519
01520
01521
01522
01523
01524
01525
01526 {
01527 if (rpc_is_remote())
01528 return rpc_call(RPC_DB_SET_CLIENT_NAME, hDB, client_name);
01529
01530 #ifdef LOCAL_ROUTINES
01531 {
01532 DATABASE_HEADER *pheader;
01533 DATABASE_CLIENT *pclient;
01534 INT index;
01535
01536 index = _database[hDB - 1].client_index;
01537 pheader = _database[hDB - 1].database_header;
01538 pclient = &pheader->client[index];
01539
01540 strcpy(pclient->name, client_name);
01541 }
01542 #endif
01543
01544 return DB_SUCCESS;
01545 }
01546
01547
01548 #endif
01549
01550
01551
01552
01553
01554
01555
01556 INT db_lock_database(HNDLE hDB)
01557 {
01558
01559 #ifdef LOCAL_ROUTINES
01560 if (hDB > _database_entries || hDB <= 0) {
01561 cm_msg(MERROR, "db_lock_database", "invalid database handle");
01562 return DB_INVALID_HANDLE;
01563 }
01564
01565 if (_database[hDB - 1].protect
01566 && _database[hDB - 1].database_header != NULL)
01567 cm_msg(MERROR, "db_lock_database",
01568 "internal error: DB already locked");
01569
01570 if (_database[hDB - 1].lock_cnt == 0)
01571 ss_mutex_wait_for(_database[hDB - 1].mutex, 0);
01572
01573 _database[hDB - 1].lock_cnt++;
01574
01575 if (_database[hDB - 1].protect) {
01576 if (_database[hDB - 1].database_header == NULL)
01577 ss_shm_unprotect(_database[hDB - 1].shm_handle,
01578 (void **) &_database[hDB - 1].database_header);
01579 }
01580 #endif
01581 return DB_SUCCESS;
01582 }
01583
01584
01585
01586
01587
01588
01589
01590 INT db_unlock_database(HNDLE hDB)
01591 {
01592
01593 #ifdef LOCAL_ROUTINES
01594 if (hDB > _database_entries || hDB <= 0) {
01595 cm_msg(MERROR, "db_unlock_database", "invalid database handle");
01596 return DB_INVALID_HANDLE;
01597 }
01598
01599 if (_database[hDB - 1].lock_cnt == 1)
01600 ss_mutex_release(_database[hDB - 1].mutex);
01601
01602 if (_database[hDB - 1].lock_cnt > 0)
01603 _database[hDB - 1].lock_cnt--;
01604
01605 if (_database[hDB - 1].protect) {
01606 ss_shm_protect(_database[hDB - 1].shm_handle,
01607 _database[hDB - 1].database_header);
01608 _database[hDB - 1].database_header = NULL;
01609 }
01610 #endif
01611 return DB_SUCCESS;
01612 }
01613
01614
01615
01616
01617
01618
01619
01620 INT db_protect_database(HNDLE hDB)
01621 {
01622 #ifdef LOCAL_ROUTINES
01623 if (hDB > _database_entries || hDB <= 0) {
01624 cm_msg(MERROR, "db_unlock_database", "invalid database handle");
01625 return DB_INVALID_HANDLE;
01626 }
01627
01628 _database[hDB - 1].protect = TRUE;
01629 ss_shm_protect(_database[hDB - 1].shm_handle,
01630 _database[hDB - 1].database_header);
01631 _database[hDB - 1].database_header = NULL;
01632 #endif
01633 return DB_SUCCESS;
01634 }
01635
01636
01637
01638 char *extract_key(char *key_list, char *key_name)
01639 {
01640 if (*key_list == '/')
01641 key_list++;
01642
01643 while (*key_list && *key_list != '/')
01644 *key_name++ = *key_list++;
01645 *key_name = 0;
01646
01647 return key_list;
01648 }
01649
01650 BOOL equal_ustring(char *str1, char *str2)
01651 {
01652 if (str1 == NULL && str2 != NULL)
01653 return FALSE;
01654 if (str1 != NULL && str2 == NULL)
01655 return FALSE;
01656 if (str1 == NULL && str2 == NULL)
01657 return TRUE;
01658
01659 while (*str1)
01660 if (toupper(*str1++) != toupper(*str2++))
01661 return FALSE;
01662
01663 if (*str2)
01664 return FALSE;
01665
01666 return TRUE;
01667 }
01668
01669
01670
01671
01672
01673
01674
01675
01676
01677
01678 INT db_create_key(HNDLE hDB, HNDLE hKey, char *key_name, DWORD type)
01679 {
01680 if (rpc_is_remote())
01681 return rpc_call(RPC_DB_CREATE_KEY, hDB, hKey, key_name, type);
01682
01683 #ifdef LOCAL_ROUTINES
01684 {
01685 DATABASE_HEADER *pheader;
01686 KEYLIST *pkeylist;
01687 KEY *pkey, *pprev_key, *pkeyparent;
01688 char *pkey_name, str[MAX_STRING_LENGTH];
01689 INT i;
01690
01691 if (hDB > _database_entries || hDB <= 0) {
01692 cm_msg(MERROR, "db_create_key", "invalid database handle");
01693 return DB_INVALID_HANDLE;
01694 }
01695
01696 if (!_database[hDB - 1].attached) {
01697 cm_msg(MERROR, "db_create_key", "invalid database handle");
01698 return DB_INVALID_HANDLE;
01699 }
01700
01701
01702 if (type >= TID_LAST) {
01703 cm_msg(MERROR, "db_create_key", "invalid key type %d", type);
01704 return DB_INVALID_PARAM;
01705 }
01706
01707
01708 db_lock_database(hDB);
01709
01710 pheader = _database[hDB - 1].database_header;
01711 if (!hKey)
01712 hKey = pheader->root_key;
01713 pkey = (KEY *) ((char *) pheader + hKey);
01714
01715
01716 if (!db_validate_hkey(pheader, hKey)) {
01717 db_unlock_database(hDB);
01718 return DB_INVALID_HANDLE;
01719 }
01720
01721 if (pkey->type != TID_KEY) {
01722 db_unlock_database(hDB);
01723 cm_msg(MERROR, "db_create_key", "key has no subkeys");
01724 return DB_NO_KEY;
01725 }
01726 pkeylist = (KEYLIST *) ((char *) pheader + pkey->data);
01727
01728 pkey_name = key_name;
01729 do {
01730
01731 pkey_name = extract_key(pkey_name, str);
01732
01733
01734 if (strcmp(str, "..") == 0) {
01735 if (pkey->parent_keylist) {
01736 pkeylist = (KEYLIST *) ((char *) pheader + pkey->parent_keylist);
01737 pkey = (KEY *) ((char *) pheader + pkeylist->parent);
01738 }
01739 continue;
01740 }
01741 if (strcmp(str, ".") == 0)
01742 continue;
01743
01744
01745 pkey = (KEY *) ((char *) pheader + pkeylist->first_key);
01746 pprev_key = NULL;
01747
01748 for (i = 0; i < pkeylist->num_keys; i++) {
01749 if (!db_validate_key_offset(pheader, pkey->next_key)) {
01750 cm_msg(MERROR, "db_create_key",
01751 "Warning: database corruption, key %s, next_key 0x%08X",
01752 key_name, pkey->next_key - sizeof(DATABASE_HEADER));
01753 db_unlock_database(hDB);
01754 return DB_CORRUPTED;
01755 }
01756
01757 if (equal_ustring(str, pkey->name))
01758 break;
01759
01760 pprev_key = pkey;
01761 pkey = (KEY *) ((char *) pheader + pkey->next_key);
01762 }
01763
01764 if (i == pkeylist->num_keys) {
01765
01766
01767
01768 pkeyparent = (KEY *) ((char *) pheader + pkeylist->parent);
01769 if (!(pkeyparent->access_mode & MODE_WRITE) ||
01770 (pkeyparent->access_mode & MODE_EXCLUSIVE)) {
01771 db_unlock_database(hDB);
01772 return DB_NO_ACCESS;
01773 }
01774
01775 pkeylist->num_keys++;
01776
01777 if (*pkey_name == '/' || type == TID_KEY) {
01778
01779 pkey = (KEY *) malloc_key(pheader, sizeof(KEY));
01780
01781 if (pkey == NULL) {
01782 db_unlock_database(hDB);
01783 cm_msg(MERROR, "db_create_key", "online database full");
01784 return DB_FULL;
01785 }
01786
01787
01788 if (pprev_key)
01789 pprev_key->next_key = (PTYPE) pkey - (PTYPE) pheader;
01790 else
01791 pkeylist->first_key = (PTYPE) pkey - (PTYPE) pheader;
01792
01793
01794 pkey->type = TID_KEY;
01795 pkey->num_values = 1;
01796 pkey->access_mode = MODE_READ | MODE_WRITE | MODE_DELETE;
01797 strcpy(pkey->name, str);
01798 pkey->parent_keylist = (PTYPE) pkeylist - (PTYPE) pheader;
01799
01800
01801 pkeylist = (KEYLIST *) malloc_key(pheader, sizeof(KEYLIST));
01802
01803 if (pkeylist == NULL) {
01804 db_unlock_database(hDB);
01805 cm_msg(MERROR, "db_create_key", "online database full");
01806 return DB_FULL;
01807 }
01808
01809
01810 pkey->data = (PTYPE) pkeylist - (PTYPE) pheader;
01811 pkey->item_size = sizeof(KEYLIST);
01812 pkey->total_size = sizeof(KEYLIST);
01813
01814 pkeylist->parent = (PTYPE) pkey - (PTYPE) pheader;
01815 pkeylist->num_keys = 0;
01816 pkeylist->first_key = 0;
01817 } else {
01818
01819 pkey = (KEY *) malloc_key(pheader, sizeof(KEY));
01820
01821 if (pkey == NULL) {
01822 db_unlock_database(hDB);
01823 cm_msg(MERROR, "db_create_key", "online database full");
01824 return DB_FULL;
01825 }
01826
01827
01828 if (pprev_key)
01829 pprev_key->next_key = (PTYPE) pkey - (PTYPE) pheader;
01830 else
01831 pkeylist->first_key = (PTYPE) pkey - (PTYPE) pheader;
01832
01833 pkey->type = type;
01834 pkey->num_values = 1;
01835 pkey->access_mode = MODE_READ | MODE_WRITE | MODE_DELETE;
01836 strcpy(pkey->name, str);
01837 pkey->parent_keylist = (PTYPE) pkeylist - (PTYPE) pheader;
01838
01839
01840 if (type != TID_STRING && type != TID_LINK) {
01841 pkey->item_size = rpc_tid_size(type);
01842 pkey->data = (PTYPE) malloc_data(pheader, pkey->item_size);
01843 pkey->total_size = pkey->item_size;
01844
01845 if (pkey->data == 0) {
01846 db_unlock_database(hDB);
01847 cm_msg(MERROR, "db_create_key", "online database full");
01848 return DB_FULL;
01849 }
01850
01851 pkey->data -= (PTYPE) pheader;
01852 } else {
01853
01854 pkey->item_size = 0;
01855 pkey->total_size = 0;
01856 pkey->data = 0;
01857 }
01858 }
01859 } else {
01860
01861
01862
01863 if (pkey->type == TID_LINK && pkey_name[0]) {
01864
01865 strcpy(str, (char *) pheader + pkey->data);
01866 if (str[strlen(str) - 1] == '/')
01867 str[strlen(str) - 1] = 0;
01868
01869
01870 strcat(str, pkey_name);
01871
01872 db_unlock_database(hDB);
01873
01874 return db_create_key(hDB, 0, str, type);
01875 }
01876
01877 if (!(*pkey_name == '/')) {
01878 if ((WORD) pkey->type != type)
01879 cm_msg(MERROR, "db_create_key",
01880 "redefinition of key type mismatch");
01881
01882 db_unlock_database(hDB);
01883 return DB_KEY_EXIST;
01884 }
01885
01886 if (pkey->type != TID_KEY) {
01887 db_unlock_database(hDB);
01888 cm_msg(MERROR, "db_create_key",
01889 "key used with value and as parent key");
01890 return DB_KEY_EXIST;
01891 }
01892
01893 pkeylist = (KEYLIST *) ((char *) pheader + pkey->data);
01894 }
01895 } while (*pkey_name == '/');
01896
01897 db_unlock_database(hDB);
01898 }
01899 #endif
01900
01901 return DB_SUCCESS;
01902 }
01903
01904
01905
01906
01907
01908
01909
01910
01911
01912
01913 INT db_create_link(HNDLE hDB, HNDLE hKey,
01914 char *link_name, char *destination)
01915 {
01916 HNDLE hkey;
01917 int status;
01918
01919 if (rpc_is_remote())
01920 return rpc_call(RPC_DB_CREATE_LINK, hDB, hKey, link_name, destination);
01921
01922
01923 status = db_find_key(hDB, hKey, destination, &hkey);
01924 if (status != DB_SUCCESS) {
01925 cm_msg(MERROR, "db_create_link",
01926 "Link destination \"%s\" does not exist", destination);
01927 return DB_NO_KEY;
01928 }
01929
01930 return db_set_value(hDB, hKey, link_name, destination,
01931 strlen(destination) + 1, 1, TID_LINK);
01932 }
01933
01934
01935
01936
01937
01938
01939
01940
01941
01942
01943
01944 INT db_delete_key1(HNDLE hDB, HNDLE hKey, INT level, BOOL follow_links)
01945 {
01946 #ifdef LOCAL_ROUTINES
01947 {
01948 DATABASE_HEADER *pheader;
01949 KEYLIST *pkeylist;
01950 KEY *pkey, *pnext_key, *pkey_tmp;
01951 HNDLE hKeyLink;
01952 BOOL deny_delete;
01953 INT status;
01954
01955 if (hDB > _database_entries || hDB <= 0) {
01956 cm_msg(MERROR, "db_delete_key1", "invalid database handle");
01957 return DB_INVALID_HANDLE;
01958 }
01959
01960 if (!_database[hDB - 1].attached) {
01961 cm_msg(MERROR, "db_delete_key1", "invalid database handle");
01962 return DB_INVALID_HANDLE;
01963 }
01964
01965 if (hKey < sizeof(DATABASE_HEADER)) {
01966 cm_msg(MERROR, "db_delete_key1", "invalid key handle");
01967 return DB_INVALID_HANDLE;
01968 }
01969
01970
01971 if (level == 0)
01972 db_lock_database(hDB);
01973
01974 pheader = _database[hDB - 1].database_header;
01975
01976 pkey = (KEY *) ((char *) pheader + hKey);
01977
01978
01979 if (!db_validate_hkey(pheader, hKey)) {
01980 db_unlock_database(hDB);
01981 return DB_INVALID_HANDLE;
01982 }
01983
01984
01985 if (level == 0)
01986 do {
01987 if (pkey->notify_count) {
01988 db_unlock_database(hDB);
01989 return DB_OPEN_RECORD;
01990 }
01991
01992 if (pkey->parent_keylist == 0)
01993 break;
01994
01995 pkeylist = (KEYLIST *) ((char *) pheader + pkey->parent_keylist);
01996 pkey = (KEY *) ((char *) pheader + pkeylist->parent);
01997 } while (TRUE);
01998
01999 pkey = (KEY *) ((char *) pheader + hKey);
02000 pkeylist = (KEYLIST *) ((char *) pheader + pkey->data);
02001
02002 deny_delete = FALSE;
02003
02004
02005 if (pkey->type == TID_KEY && pkeylist->first_key) {
02006 pkey = (KEY *) ((char *) pheader + pkeylist->first_key);
02007
02008 do {
02009 pnext_key = (KEY *) (PTYPE) pkey->next_key;
02010
02011 status = db_delete_key1(hDB, (PTYPE) pkey - (PTYPE) pheader,
02012 level + 1, follow_links);
02013
02014 if (status == DB_NO_ACCESS)
02015 deny_delete = TRUE;
02016
02017 if (pnext_key)
02018 pkey = (KEY *) ((char *) pheader + (PTYPE) pnext_key);
02019 } while (pnext_key);
02020 }
02021
02022
02023 if (pkey->type == TID_LINK && follow_links) {
02024 status = db_find_key(hDB, 0, (char *) pheader + pkey->data,
02025 &hKeyLink);
02026 if (status == DB_SUCCESS && follow_links < 100)
02027 db_delete_key1(hDB, hKeyLink, level + 1, follow_links + 1);
02028
02029 if (follow_links == 100)
02030 cm_msg(MERROR, "db_delete_key1", "try to delete cyclic link");
02031 }
02032
02033 pkey = (KEY *) ((char *) pheader + hKey);
02034
02035
02036 if (pkey->parent_keylist == 0) {
02037 if (level == 0)
02038 db_unlock_database(hDB);
02039 return DB_SUCCESS;
02040 }
02041
02042
02043 if (hKey != pheader->root_key) {
02044 if (!(pkey->access_mode & MODE_DELETE) || deny_delete) {
02045 if (level == 0)
02046 db_unlock_database(hDB);
02047 return DB_NO_ACCESS;
02048 }
02049
02050 if (pkey->notify_count) {
02051 if (level == 0)
02052 db_unlock_database(hDB);
02053 return DB_OPEN_RECORD;
02054 }
02055
02056
02057 if (pkey->type == TID_KEY)
02058 free_key(pheader, (char *) pheader + pkey->data, pkey->total_size);
02059 else
02060 free_data(pheader, (char *) pheader + pkey->data,
02061 pkey->total_size);
02062
02063
02064 pnext_key = (KEY *) (PTYPE) pkey->next_key;
02065 pkeylist = (KEYLIST *) ((char *) pheader + pkey->parent_keylist);
02066
02067 if ((KEY *) ((char *) pheader + pkeylist->first_key) == pkey) {
02068
02069 pkeylist->first_key = (PTYPE) pnext_key;
02070 } else {
02071
02072 pkey_tmp = (KEY *) ((char *) pheader + pkeylist->first_key);
02073 while ((KEY *) ((char *) pheader + pkey_tmp->next_key) != pkey)
02074 pkey_tmp = (KEY *) ((char *) pheader + pkey_tmp->next_key);
02075 pkey_tmp->next_key = (PTYPE) pnext_key;
02076 }
02077
02078
02079 free_key(pheader, pkey, sizeof(KEY));
02080 pkeylist->num_keys--;
02081 }
02082
02083 if (level == 0)
02084 db_unlock_database(hDB);
02085 }
02086 #endif
02087
02088 return DB_SUCCESS;
02089 }
02090
02091
02092
02093
02094
02095
02096
02097
02098
02099
02100
02101
02102
02103
02104
02105
02106
02107
02108
02109
02110
02111
02112
02113
02114
02115
02116 INT db_delete_key(HNDLE hDB, HNDLE hKey, BOOL follow_links)
02117 {
02118 if (rpc_is_remote())
02119 return rpc_call(RPC_DB_DELETE_KEY, hDB, hKey, follow_links);
02120
02121 return db_delete_key1(hDB, hKey, 0, follow_links);
02122 }
02123
02124
02125
02126
02127
02128
02129
02130
02131
02132
02133
02134
02135
02136
02137
02138
02139
02140
02141
02142
02143
02144
02145
02146
02147
02148
02149 INT db_find_key(HNDLE hDB, HNDLE hKey, char *key_name, HNDLE * subhKey)
02150 {
02151 if (rpc_is_remote())
02152 return rpc_call(RPC_DB_FIND_KEY, hDB, hKey, key_name, subhKey);
02153
02154 #ifdef LOCAL_ROUTINES
02155 {
02156 DATABASE_HEADER *pheader;
02157 KEYLIST *pkeylist;
02158 KEY *pkey;
02159 char *pkey_name, str[MAX_STRING_LENGTH];
02160 INT i, status;
02161
02162 *subhKey = 0;
02163
02164 if (hDB > _database_entries || hDB <= 0) {
02165 cm_msg(MERROR, "db_find_key", "invalid database handle");
02166 return DB_INVALID_HANDLE;
02167 }
02168
02169 if (!_database[hDB - 1].attached) {
02170 cm_msg(MERROR, "db_find_key", "invalid database handle");
02171 return DB_INVALID_HANDLE;
02172 }
02173
02174 db_lock_database(hDB);
02175
02176 pheader = _database[hDB - 1].database_header;
02177
02178 if (!hKey)
02179 hKey = pheader->root_key;
02180
02181 pkey = (KEY *) ((char *) pheader + hKey);
02182
02183
02184 if (!db_validate_hkey(pheader, hKey)) {
02185 db_unlock_database(hDB);
02186 return DB_INVALID_HANDLE;
02187 }
02188
02189 if (pkey->type != TID_KEY) {
02190 cm_msg(MERROR, "db_find_key", "key has no subkeys");
02191 *subhKey = 0;
02192 db_unlock_database(hDB);
02193 return DB_NO_KEY;
02194 }
02195 pkeylist = (KEYLIST *) ((char *) pheader + pkey->data);
02196
02197 if (key_name[0] == 0 || strcmp(key_name, "/") == 0) {
02198 if (!(pkey->access_mode & MODE_READ)) {
02199 *subhKey = 0;
02200 db_unlock_database(hDB);
02201 return DB_NO_ACCESS;
02202 }
02203
02204 *subhKey = (PTYPE) pkey - (PTYPE) pheader;
02205
02206 db_unlock_database(hDB);
02207 return DB_SUCCESS;
02208 }
02209
02210 pkey_name = key_name;
02211 do {
02212
02213 pkey_name = extract_key(pkey_name, str);
02214
02215
02216 if (strcmp(str, "..") == 0) {
02217 if (pkey->parent_keylist) {
02218 pkeylist = (KEYLIST *) ((char *) pheader + pkey->parent_keylist);
02219 pkey = (KEY *) ((char *) pheader + pkeylist->parent);
02220 }
02221 continue;
02222 }
02223 if (strcmp(str, ".") == 0)
02224 continue;
02225
02226
02227 pkey = (KEY *) ((char *) pheader + pkeylist->first_key);
02228
02229 for (i = 0; i < pkeylist->num_keys; i++) {
02230 if (pkey->name[0] == 0
02231 || !db_validate_key_offset(pheader, pkey->next_key)) {
02232 cm_msg(MERROR, "db_find_key",
02233 "Warning: database corruption, key %s, next_key 0x%08X",
02234 key_name, pkey->next_key - sizeof(DATABASE_HEADER));
02235 *subhKey = 0;
02236 db_unlock_database(hDB);
02237 return DB_CORRUPTED;
02238 }
02239
02240 if (equal_ustring(str, pkey->name))
02241 break;
02242
02243 pkey = (KEY *) ((char *) pheader + pkey->next_key);
02244 }
02245
02246 if (i == pkeylist->num_keys) {
02247 *subhKey = 0;
02248 db_unlock_database(hDB);
02249 return DB_NO_KEY;
02250 }
02251
02252
02253 if (pkey->type == TID_LINK) {
02254
02255 strcpy(str, (char *) pheader + pkey->data);
02256 if (str[strlen(str) - 1] == '/')
02257 str[strlen(str) - 1] = 0;
02258
02259
02260 if (pkey_name[0]) {
02261 strcat(str, pkey_name);
02262 db_unlock_database(hDB);
02263 return db_find_key(hDB, 0, str, subhKey);
02264 } else {
02265
02266 db_unlock_database(hDB);
02267 status = db_find_link(hDB, 0, str, subhKey);
02268 if (status == DB_NO_KEY)
02269 return DB_INVALID_LINK;
02270 return status;
02271 }
02272 }
02273
02274
02275 if (*pkey_name == '/') {
02276 if (pkey->type != TID_KEY) {
02277 *subhKey = 0;
02278 db_unlock_database(hDB);
02279 return DB_NO_KEY;
02280 }
02281 }
02282
02283
02284 pkeylist = (KEYLIST *) ((char *) pheader + pkey->data);
02285
02286 } while (*pkey_name == '/' && *(pkey_name + 1));
02287
02288 *subhKey = (PTYPE) pkey - (PTYPE) pheader;
02289
02290 db_unlock_database(hDB);
02291 }
02292 #endif
02293
02294 return DB_SUCCESS;
02295 }
02296
02297
02298 #ifndef DOXYGEN_SHOULD_SKIP_THIS
02299
02300
02301 INT db_find_key1(HNDLE hDB, HNDLE hKey, char *key_name, HNDLE * subhKey)
02302
02303
02304
02305
02306
02307
02308
02309
02310
02311
02312
02313
02314
02315
02316
02317
02318
02319
02320
02321
02322
02323 {
02324 if (rpc_is_remote())
02325 return rpc_call(RPC_DB_FIND_KEY, hDB, hKey, key_name, subhKey);
02326
02327 #ifdef LOCAL_ROUTINES
02328 {
02329 DATABASE_HEADER *pheader;
02330 KEYLIST *pkeylist;
02331 KEY *pkey;
02332 char *pkey_name, str[MAX_STRING_LENGTH];
02333 INT i;
02334
02335 *subhKey = 0;
02336
02337 if (hDB > _database_entries || hDB <= 0) {
02338 cm_msg(MERROR, "db_find_key", "invalid database handle");
02339 return DB_INVALID_HANDLE;
02340 }
02341
02342 if (!_database[hDB - 1].attached) {
02343 cm_msg(MERROR, "db_find_key", "invalid database handle");
02344 return DB_INVALID_HANDLE;
02345 }
02346
02347 pheader = _database[hDB - 1].database_header;
02348 if (!hKey)
02349 hKey = pheader->root_key;
02350 pkey = (KEY *) ((char *) pheader + hKey);
02351
02352
02353 if (!db_validate_hkey(pheader, hKey)) {
02354 db_unlock_database(hDB);
02355 return DB_INVALID_HANDLE;
02356 }
02357
02358 if (pkey->type != TID_KEY) {
02359 cm_msg(MERROR, "db_find_key", "key has no subkeys");
02360 *subhKey = 0;
02361 return DB_NO_KEY;
02362 }
02363 pkeylist = (KEYLIST *) ((char *) pheader + pkey->data);
02364
02365 if (key_name[0] == 0 || strcmp(key_name, "/") == 0) {
02366 if (!(pkey->access_mode & MODE_READ)) {
02367 *subhKey = 0;
02368 return DB_NO_ACCESS;
02369 }
02370
02371 *subhKey = (PTYPE) pkey - (PTYPE) pheader;
02372
02373 return DB_SUCCESS;
02374 }
02375
02376 pkey_name = key_name;
02377 do {
02378
02379 pkey_name = extract_key(pkey_name, str);
02380
02381
02382 if (strcmp(str, "..") == 0) {
02383 if (pkey->parent_keylist) {
02384 pkeylist = (KEYLIST *) ((char *) pheader + pkey->parent_keylist);
02385 pkey = (KEY *) ((char *) pheader + pkeylist->parent);
02386 }
02387 continue;
02388 }
02389 if (strcmp(str, ".") == 0)
02390 continue;
02391
02392
02393 pkey = (KEY *) ((char *) pheader + pkeylist->first_key);
02394
02395 for (i = 0; i < pkeylist->num_keys; i++) {
02396 if (equal_ustring(str, pkey->name))
02397 break;
02398
02399 pkey = (KEY *) ((char *) pheader + pkey->next_key);
02400 }
02401
02402 if (i == pkeylist->num_keys) {
02403 *subhKey = 0;
02404 return DB_NO_KEY;
02405 }
02406
02407
02408 if (pkey->type == TID_LINK) {
02409
02410 strcpy(str, (char *) pheader + pkey->data);
02411 if (str[strlen(str) - 1] == '/')
02412 str[strlen(str) - 1] = 0;
02413
02414
02415 if (pkey_name[0]) {
02416 strcat(str, pkey_name);
02417 return db_find_key1(hDB, 0, str, subhKey);
02418 } else {
02419
02420 return db_find_link1(hDB, 0, str, subhKey);
02421 }
02422 }
02423
02424
02425 if (*pkey_name == '/') {
02426 if (pkey->type != TID_KEY) {
02427 *subhKey = 0;
02428 db_unlock_database(hDB);
02429 return DB_NO_KEY;
02430 }
02431 }
02432
02433
02434 pkeylist = (KEYLIST *) ((char *) pheader + pkey->data);
02435
02436 } while (*pkey_name == '/' && *(pkey_name + 1));
02437
02438 *subhKey = (PTYPE) pkey - (PTYPE) pheader;
02439 }
02440 #endif
02441
02442 return DB_SUCCESS;
02443 }
02444
02445
02446 INT db_find_link(HNDLE hDB, HNDLE hKey, char *key_name, HNDLE * subhKey)
02447
02448
02449
02450
02451
02452
02453
02454
02455
02456
02457
02458
02459
02460
02461
02462
02463
02464
02465
02466
02467
02468
02469
02470
02471
02472 {
02473 if (rpc_is_remote())
02474 return rpc_call(RPC_DB_FIND_LINK, hDB, hKey, key_name, subhKey);
02475
02476 #ifdef LOCAL_ROUTINES
02477 {
02478 DATABASE_HEADER *pheader;
02479 KEYLIST *pkeylist;
02480 KEY *pkey;
02481 char *pkey_name, str[MAX_STRING_LENGTH];
02482 INT i;
02483
02484 *subhKey = 0;
02485
02486 if (hDB > _database_entries || hDB <= 0) {
02487 cm_msg(MERROR, "db_find_link", "Invalid database handle");
02488 return DB_INVALID_HANDLE;
02489 }
02490
02491 if (!_database[hDB - 1].attached) {
02492 cm_msg(MERROR, "db_find_link", "invalid database handle");
02493 return DB_INVALID_HANDLE;
02494 }
02495
02496 db_lock_database(hDB);
02497
02498 pheader = _database[hDB - 1].database_header;
02499 if (!hKey)
02500 hKey = pheader->root_key;
02501 pkey = (KEY *) ((char *) pheader + hKey);
02502
02503
02504 if (!db_validate_hkey(pheader, hKey)) {
02505 db_unlock_database(hDB);
02506 return DB_INVALID_HANDLE;
02507 }
02508
02509 if (pkey->type != TID_KEY) {
02510 cm_msg(MERROR, "db_find_link", "key has no subkeys");
02511 db_unlock_database(hDB);
02512 return DB_NO_KEY;
02513 }
02514 pkeylist = (KEYLIST *) ((char *) pheader + pkey->data);
02515
02516 if (key_name[0] == 0 || strcmp(key_name, "/") == 0) {
02517 if (!(pkey->access_mode & MODE_READ)) {
02518 *subhKey = 0;
02519 db_unlock_database(hDB);
02520 return DB_NO_ACCESS;
02521 }
02522
02523 *subhKey = (PTYPE) pkey - (PTYPE) pheader;
02524
02525 db_unlock_database(hDB);
02526 return DB_SUCCESS;
02527 }
02528
02529 pkey_name = key_name;
02530 do {
02531
02532 pkey_name = extract_key(pkey_name, str);
02533
02534
02535 if (strcmp(str, "..") == 0) {
02536 if (pkey->parent_keylist) {
02537 pkeylist = (KEYLIST *) ((char *) pheader + pkey->parent_keylist);
02538 pkey = (KEY *) ((char *) pheader + pkeylist->parent);
02539 }
02540 continue;
02541 }
02542 if (strcmp(str, ".") == 0)
02543 continue;
02544
02545
02546 pkey = (KEY *) ((char *) pheader + pkeylist->first_key);
02547
02548 for (i = 0; i < pkeylist->num_keys; i++) {
02549 if (!db_validate_key_offset(pheader, pkey->next_key)) {
02550 cm_msg(MERROR, "db_find_link",
02551 "Warning: database corruption, key \"%s\", next_key 0x%08X",
02552 key_name, pkey->next_key - sizeof(DATABASE_HEADER));
02553 *subhKey = 0;
02554 db_unlock_database(hDB);
02555 return DB_CORRUPTED;
02556 }
02557
02558 if (equal_ustring(str, pkey->name))
02559 break;
02560
02561 pkey = (KEY *) ((char *) pheader + pkey->next_key);
02562 }
02563
02564 if (i == pkeylist->num_keys) {
02565 *subhKey = 0;
02566 db_unlock_database(hDB);
02567 return DB_NO_KEY;
02568 }
02569
02570
02571 if (pkey->type == TID_LINK && *pkey_name == '/') {
02572
02573 strcpy(str, (char *) pheader + pkey->data);
02574 if (str[strlen(str) - 1] == '/')
02575 str[strlen(str) - 1] = 0;
02576
02577
02578 strcat(str, pkey_name);
02579 db_unlock_database(hDB);
02580 return db_find_link(hDB, 0, str, subhKey);
02581 }
02582
02583
02584 if ((*pkey_name == '/')) {
02585 if (pkey->type != TID_KEY) {
02586 *subhKey = 0;
02587 db_unlock_database(hDB);
02588 return DB_NO_KEY;
02589 }
02590 }
02591
02592
02593 pkeylist = (KEYLIST *) ((char *) pheader + pkey->data);
02594
02595 } while (*pkey_name == '/' && *(pkey_name + 1));
02596
02597 *subhKey = (PTYPE) pkey - (PTYPE) pheader;
02598
02599 db_unlock_database(hDB);
02600 }
02601 #endif
02602
02603 return DB_SUCCESS;
02604 }
02605
02606
02607 INT db_find_link1(HNDLE hDB, HNDLE hKey, char *key_name, HNDLE * subhKey)
02608
02609
02610
02611
02612
02613
02614
02615
02616
02617
02618
02619
02620
02621
02622
02623
02624
02625
02626
02627
02628
02629 {
02630 if (rpc_is_remote())
02631 return rpc_call(RPC_DB_FIND_LINK, hDB, hKey, key_name, subhKey);
02632
02633 #ifdef LOCAL_ROUTINES
02634 {
02635 DATABASE_HEADER *pheader;
02636 KEYLIST *pkeylist;
02637 KEY *pkey;
02638 char *pkey_name, str[MAX_STRING_LENGTH];
02639 INT i;
02640
02641 *subhKey = 0;
02642
02643 if (hDB > _database_entries || hDB <= 0) {
02644 cm_msg(MERROR, "db_find_link", "Invalid database handle");
02645 return DB_INVALID_HANDLE;
02646 }
02647
02648 if (!_database[hDB - 1].attached) {
02649 cm_msg(MERROR, "db_find_link", "invalid database handle");
02650 return DB_INVALID_HANDLE;
02651 }
02652
02653 pheader = _database[hDB - 1].database_header;
02654 if (!hKey)
02655 hKey = pheader->root_key;
02656 pkey = (KEY *) ((char *) pheader + hKey);
02657
02658
02659 if (!db_validate_hkey(pheader, hKey)) {
02660 db_unlock_database(hDB);
02661 return DB_INVALID_HANDLE;
02662 }
02663
02664 if (pkey->type != TID_KEY) {
02665 cm_msg(MERROR, "db_find_link", "key has no subkeys");
02666 return DB_NO_KEY;
02667 }
02668 pkeylist = (KEYLIST *) ((char *) pheader + pkey->data);
02669
02670 if (key_name[0] == 0 || strcmp(key_name, "/") == 0) {
02671 if (!(pkey->access_mode & MODE_READ)) {
02672 *subhKey = 0;
02673 return DB_NO_ACCESS;
02674 }
02675
02676 *subhKey = (PTYPE) pkey - (PTYPE) pheader;
02677
02678 return DB_SUCCESS;
02679 }
02680
02681 pkey_name = key_name;
02682 do {
02683
02684 pkey_name = extract_key(pkey_name, str);
02685
02686
02687 if (strcmp(str, "..") == 0) {
02688 if (pkey->parent_keylist) {
02689 pkeylist = (KEYLIST *) ((char *) pheader + pkey->parent_keylist);
02690 pkey = (KEY *) ((char *) pheader + pkeylist->parent);
02691 }
02692 continue;
02693 }
02694 if (strcmp(str, ".") == 0)
02695 continue;
02696
02697
02698 pkey = (KEY *) ((char *) pheader + pkeylist->first_key);
02699
02700 for (i = 0; i < pkeylist->num_keys; i++) {
02701 if (!db_validate_key_offset(pheader, pkey->next_key)) {
02702 cm_msg(MERROR, "db_find_link1",
02703 "Warning: database corruption, key \"%s\", next_key 0x%08X",
02704 key_name, pkey->next_key - sizeof(DATABASE_HEADER));
02705 *subhKey = 0;
02706 return DB_CORRUPTED;
02707 }
02708
02709 if (equal_ustring(str, pkey->name))
02710 break;
02711
02712 pkey = (KEY *) ((char *) pheader + pkey->next_key);
02713 }
02714
02715 if (i == pkeylist->num_keys) {
02716 *subhKey = 0;
02717 return DB_NO_KEY;
02718 }
02719
02720
02721 if (pkey->type == TID_LINK && *pkey_name == '/') {
02722
02723 strcpy(str, (char *) pheader + pkey->data);
02724 if (str[strlen(str) - 1] == '/')
02725 str[strlen(str) - 1] = 0;
02726
02727
02728 strcat(str, pkey_name);
02729 return db_find_link1(hDB, 0, str, subhKey);
02730 }
02731
02732
02733 if ((*pkey_name == '/')) {
02734 if (pkey->type != TID_KEY) {
02735 *subhKey = 0;
02736 return DB_NO_KEY;
02737 }
02738 }
02739
02740
02741 pkeylist = (KEYLIST *) ((char *) pheader + pkey->data);
02742
02743 } while (*pkey_name == '/' && *(pkey_name + 1));
02744
02745 *subhKey = (PTYPE) pkey - (PTYPE) pheader;
02746 }
02747 #endif
02748
02749 return DB_SUCCESS;
02750 }
02751
02752
02753 INT db_scan_tree(HNDLE hDB, HNDLE hKey, INT level,
02754 INT(*callback) (HNDLE, HNDLE, KEY *, INT, void *),
02755 void *info)
02756
02757
02758
02759
02760
02761
02762
02763
02764
02765
02766
02767
02768
02769
02770
02771
02772
02773
02774
02775
02776
02777
02778
02779
02780
02781
02782 {
02783 HNDLE hSubkey;
02784 KEY key;
02785 INT i, status;
02786
02787 status = db_get_key(hDB, hKey, &key);
02788 if (status != DB_SUCCESS)
02789 return status;
02790
02791 status = callback(hDB, hKey, &key, level, info);
02792 if (status == 0)
02793 return status;
02794
02795 if (key.type == TID_KEY) {
02796 for (i = 0;; i++) {
02797 db_enum_key(hDB, hKey, i, &hSubkey);
02798
02799 if (!hSubkey)
02800 break;
02801
02802 db_scan_tree(hDB, hSubkey, level + 1, callback, info);
02803 }
02804 }
02805
02806 return DB_SUCCESS;
02807 }
02808
02809
02810 INT db_scan_tree_link(HNDLE hDB, HNDLE hKey, INT level,
02811 void (*callback) (HNDLE, HNDLE, KEY *, INT, void *),
02812 void *info)
02813
02814
02815
02816
02817
02818
02819
02820
02821
02822
02823
02824
02825
02826
02827
02828
02829
02830
02831
02832
02833
02834
02835
02836
02837
02838
02839
02840 {
02841 HNDLE hSubkey;
02842 KEY key;
02843 INT i, status;
02844
02845 status = db_get_key(hDB, hKey, &key);
02846 if (status != DB_SUCCESS)
02847 return status;
02848
02849 callback(hDB, hKey, &key, level, info);
02850
02851 if (key.type == TID_KEY) {
02852 for (i = 0;; i++) {
02853 db_enum_link(hDB, hKey, i, &hSubkey);
02854
02855 if (!hSubkey)
02856 break;
02857
02858 db_scan_tree_link(hDB, hSubkey, level + 1, callback, info);
02859 }
02860 }
02861
02862 return DB_SUCCESS;
02863 }
02864
02865
02866 INT db_get_path(HNDLE hDB, HNDLE hKey, char *path, INT buf_size)
02867
02868
02869
02870
02871
02872
02873
02874
02875
02876
02877
02878
02879
02880
02881
02882
02883
02884
02885
02886
02887
02888
02889 {
02890 if (rpc_is_remote())
02891 return rpc_call(RPC_DB_GET_PATH, hDB, hKey, path, buf_size);
02892
02893 #ifdef LOCAL_ROUTINES
02894 {
02895 DATABASE_HEADER *pheader;
02896 KEYLIST *pkeylist;
02897 KEY *pkey;
02898 char str[MAX_ODB_PATH];
02899
02900 if (hDB > _database_entries || hDB <= 0) {
02901 cm_msg(MERROR, "db_get_path", "invalid database handle");
02902 return DB_INVALID_HANDLE;
02903 }
02904
02905 if (!_database[hDB - 1].attached) {
02906 cm_msg(MERROR, "db_get_path", "invalid database handle");
02907 return DB_INVALID_HANDLE;
02908 }
02909
02910 db_lock_database(hDB);
02911
02912 pheader = _database[hDB - 1].database_header;
02913 if (!hKey)
02914 hKey = pheader->root_key;
02915 pkey = (KEY *) ((char *) pheader + hKey);
02916
02917
02918 if (!db_validate_hkey(pheader, hKey)) {
02919 db_unlock_database(hDB);
02920 return DB_INVALID_HANDLE;
02921 }
02922
02923 if (hKey == pheader->root_key) {
02924 strcpy(path, "/");
02925 db_unlock_database(hDB);
02926 return DB_SUCCESS;
02927 }
02928
02929 *path = 0;
02930 do {
02931
02932 strcpy(str, path);
02933 strcpy(path, "/");
02934 strcat(path, pkey->name);
02935
02936 if (strlen(path) + strlen(str) + 1 > (DWORD) buf_size) {
02937 *path = 0;
02938 db_unlock_database(hDB);
02939 return DB_NO_MEMORY;
02940 }
02941 strcat(path, str);
02942
02943
02944 pkeylist = (KEYLIST *) ((char *) pheader + pkey->parent_keylist);
02945 pkey = (KEY *) ((char *) pheader + pkeylist->parent);
02946 } while (pkey->parent_keylist);
02947
02948 db_unlock_database(hDB);
02949 }
02950 #endif
02951
02952 return DB_SUCCESS;
02953 }
02954
02955
02956 void db_find_open_records(HNDLE hDB, HNDLE hKey, KEY * key, INT level,
02957 void *result)
02958 {
02959 #ifdef LOCAL_ROUTINES
02960 DATABASE_HEADER *pheader;
02961 DATABASE_CLIENT *pclient;
02962 INT i, j;
02963 char line[256], str[80];
02964
02965
02966 if (key->notify_count) {
02967 db_get_path(hDB, hKey, str, sizeof(str));
02968 sprintf(line, "%s open %d times by ", str, key->notify_count);
02969
02970 db_lock_database(hDB);
02971 pheader = _database[hDB - 1].database_header;
02972
02973 for (i = 0; i < pheader->max_client_index; i++) {
02974 pclient = &pheader->client[i];
02975 for (j = 0; j < pclient->max_index; j++)
02976 if (pclient->open_record[j].handle == hKey)
02977 sprintf(line + strlen(line), "%s ", pclient->name);
02978 }
02979 strcat(line, "\n");
02980 strcat((char *) result, line);
02981
02982 db_unlock_database(hDB);
02983 }
02984 #endif
02985 }
02986
02987 void db_fix_open_records(HNDLE hDB, HNDLE hKey, KEY * key, INT level,
02988 void *result)
02989 {
02990 #ifdef LOCAL_ROUTINES
02991 DATABASE_HEADER *pheader;
02992 DATABASE_CLIENT *pclient;
02993 INT i, j;
02994 char str[256];
02995 KEY *pkey;
02996
02997
02998 if (key->notify_count) {
02999 db_lock_database(hDB);
03000 pheader = _database[hDB - 1].database_header;
03001
03002 for (i = 0; i < pheader->max_client_index; i++) {
03003 pclient = &pheader->client[i];
03004 for (j = 0; j < pclient->max_index; j++)
03005 if (pclient->open_record[j].handle == hKey)
03006 break;
03007 if (j < pclient->max_index)
03008 break;
03009 }
03010 if (i == pheader->max_client_index) {
03011 db_get_path(hDB, hKey, str, sizeof(str));
03012 strcat(str, " fixed\n");
03013 strcat((char *) result, str);
03014
03015
03016 pkey = (KEY *) ((char *) pheader + hKey);
03017 pkey->notify_count = 0;
03018 }
03019
03020 db_unlock_database(hDB);
03021 }
03022 #endif
03023 }
03024
03025 INT db_get_open_records(HNDLE hDB, HNDLE hKey, char *str, INT buf_size,
03026 BOOL fix)
03027
03028
03029
03030
03031
03032
03033
03034
03035
03036
03037
03038
03039
03040
03041
03042
03043
03044
03045
03046
03047
03048 {
03049 str[0] = 0;
03050
03051 if (rpc_is_remote())
03052 return rpc_call(RPC_DB_GET_OPEN_RECORDS, hDB, hKey, str, buf_size);
03053
03054 if (fix)
03055 db_scan_tree_link(hDB, hKey, 0, db_fix_open_records, str);
03056 else
03057 db_scan_tree_link(hDB, hKey, 0, db_find_open_records, str);
03058
03059 return DB_SUCCESS;
03060 }
03061
03062
03063 #endif
03064
03065
03066
03067
03068
03069
03070
03071
03072
03073
03074
03075
03076
03077
03078
03079
03080
03081
03082
03083
03084
03085
03086
03087
03088
03089
03090 INT db_set_value(HNDLE hDB, HNDLE hKeyRoot, char *key_name, void *data,
03091 INT data_size, INT num_values, DWORD type)
03092 {
03093 if (rpc_is_remote())
03094 return rpc_call(RPC_DB_SET_VALUE, hDB, hKeyRoot, key_name,
03095 data, data_size, num_values, type);
03096
03097 #ifdef LOCAL_ROUTINES
03098 {
03099 DATABASE_HEADER *pheader;
03100 KEY *pkey;
03101 HNDLE hKey;
03102 INT status;
03103
03104 if (num_values == 0)
03105 return DB_INVALID_PARAM;
03106
03107 status = db_find_key(hDB, hKeyRoot, key_name, &hKey);
03108 if (status == DB_NO_KEY) {
03109 db_create_key(hDB, hKeyRoot, key_name, type);
03110 status = db_find_link(hDB, hKeyRoot, key_name, &hKey);
03111 }
03112
03113 if (status != DB_SUCCESS)
03114 return status;
03115
03116 db_lock_database(hDB);
03117 pheader = _database[hDB - 1].database_header;
03118
03119
03120 pkey = (KEY *) ((char *) pheader + hKey);
03121
03122
03123 if (!(pkey->access_mode & MODE_WRITE) ||
03124 (pkey->access_mode & MODE_EXCLUSIVE)) {
03125 db_unlock_database(hDB);
03126 return DB_NO_ACCESS;
03127 }
03128
03129 if (pkey->type != type) {
03130 db_unlock_database(hDB);
03131 cm_msg(MERROR, "db_set_value", "\"%s\" is of type %s, not %s",
03132 key_name, rpc_tid_name(pkey->type), rpc_tid_name(type));
03133 return DB_TYPE_MISMATCH;
03134 }
03135
03136
03137 if (pkey->type == TID_KEY) {
03138 db_unlock_database(hDB);
03139 cm_msg(MERROR, "db_set_value", "key cannot contain data");
03140 return DB_TYPE_MISMATCH;
03141 }
03142
03143 if (data_size == 0) {
03144 db_unlock_database(hDB);
03145 cm_msg(MERROR, "db_set_value", "zero data size not allowed");
03146 return DB_TYPE_MISMATCH;
03147 }
03148
03149 if (type != TID_STRING && type != TID_LINK &&
03150 data_size != rpc_tid_size(type) * num_values) {
03151 db_unlock_database(hDB);
03152 cm_msg(MERROR, "db_set_value",
03153 "data_size (%d) does not match num_values (%d)", data_size,
03154 num_values);
03155 return DB_TYPE_MISMATCH;
03156 }
03157
03158
03159 if (pkey->total_size < data_size) {
03160 pkey->data =
03161 (PTYPE) realloc_data(pheader, (char *) pheader + pkey->data,
03162 pkey->total_size, data_size);
03163
03164 if (pkey->data == 0) {
03165 db_unlock_database(hDB);
03166 cm_msg(MERROR, "db_set_value", "online database full");
03167 return DB_FULL;
03168 }
03169
03170 pkey->data -= (PTYPE) pheader;
03171 pkey->total_size = data_size;
03172 }
03173
03174
03175 pkey->num_values = num_values;
03176
03177 if (type == TID_STRING || type == TID_LINK)
03178 pkey->item_size = data_size / num_values;
03179 else
03180 pkey->item_size = rpc_tid_size(type);
03181
03182
03183 memcpy((char *) pheader + pkey->data, data, data_size);
03184
03185
03186 pkey->last_written = ss_time();
03187
03188 db_notify_clients(hDB, hKey, TRUE);
03189 db_unlock_database(hDB);
03190
03191 }
03192 #endif
03193
03194 return DB_SUCCESS;
03195 }
03196
03197
03198
03199
03200
03201
03202
03203
03204
03205
03206
03207
03208
03209
03210
03211
03212
03213
03214
03215
03216
03217
03218
03219
03220
03221
03222
03223
03224
03225 INT db_get_value(HNDLE hDB, HNDLE hKeyRoot, char *key_name, void *data,
03226 INT * buf_size, DWORD type, BOOL create)
03227 {
03228 if (rpc_is_remote())
03229 return rpc_call(RPC_DB_GET_VALUE, hDB, hKeyRoot, key_name,
03230 data, buf_size, type, create);
03231
03232 #ifdef LOCAL_ROUTINES
03233 {
03234 DATABASE_HEADER *pheader;
03235 HNDLE hkey;
03236 KEY *pkey;
03237 INT status, size;
03238 char path[256];
03239
03240 if (hDB > _database_entries || hDB <= 0) {
03241 cm_msg(MERROR, "db_get_value", "invalid database handle");
03242 return DB_INVALID_HANDLE;
03243 }
03244
03245 if (!_database[hDB - 1].attached) {
03246 cm_msg(MERROR, "db_get_value", "invalid database handle");
03247 return DB_INVALID_HANDLE;
03248 }
03249
03250 status = db_find_key(hDB, hKeyRoot, key_name, &hkey);
03251 if (status == DB_NO_KEY) {
03252 if (create) {
03253 db_create_key(hDB, hKeyRoot, key_name, type);
03254 status = db_find_key(hDB, hKeyRoot, key_name, &hkey);
03255 if (status != DB_SUCCESS)
03256 return status;
03257
03258
03259 if (type == TID_STRING || type == TID_LINK)
03260 size = *buf_size;
03261 else
03262 size = rpc_tid_size(type);
03263
03264 if (size == 0)
03265 return DB_TYPE_MISMATCH;
03266
03267
03268 status = db_set_value(hDB, hKeyRoot, key_name, data,
03269 *buf_size, *buf_size / size, type);
03270 } else
03271 return DB_NO_KEY;
03272 }
03273
03274 if (status != DB_SUCCESS)
03275 return status;
03276
03277
03278 db_lock_database(hDB);
03279 pheader = _database[hDB - 1].database_header;
03280
03281
03282 pkey = (KEY *) ((char *) pheader + hkey);
03283
03284
03285 if (pkey->type != (type)) {
03286 db_unlock_database(hDB);
03287 cm_msg(MERROR, "db_get_value", "\"%s\" is of type %s, not %s",
03288 key_name, rpc_tid_name(pkey->type), rpc_tid_name(type));
03289 return DB_TYPE_MISMATCH;
03290 }
03291
03292
03293 if (!(pkey->access_mode & MODE_READ)) {
03294 db_unlock_database(hDB);
03295 cm_msg(MERROR, "db_get_value", "%s has no read access", key_name);
03296 return DB_NO_ACCESS;
03297 }
03298
03299
03300 if (pkey->num_values * pkey->item_size > *buf_size) {
03301 memcpy(data, (char *) pheader + pkey->data, *buf_size);
03302 db_unlock_database(hDB);
03303 db_get_path(hDB, hkey, path, sizeof(path));
03304 cm_msg(MERROR, "db_get_value",
03305 "buffer too small, data truncated for key \"%s\"", path);
03306 return DB_TRUNCATED;
03307 }
03308
03309
03310 memcpy(data, (char *) pheader + pkey->data,
03311 pkey->num_values * pkey->item_size);
03312 *buf_size = pkey->num_values * pkey->item_size;
03313
03314 db_unlock_database(hDB);
03315 }
03316 #endif
03317
03318 return DB_SUCCESS;
03319 }
03320
03321
03322
03323
03324
03325
03326
03327
03328
03329
03330
03331
03332
03333
03334
03335
03336
03337
03338
03339
03340
03341
03342
03343
03344
03345
03346
03347
03348
03349
03350
03351
03352
03353
03354
03355 INT db_enum_key(HNDLE hDB, HNDLE hKey, INT index, HNDLE * subkey_handle)
03356 {
03357 if (rpc_is_remote())
03358 return rpc_call(RPC_DB_ENUM_KEY, hDB, hKey, index, subkey_handle);
03359
03360 #ifdef LOCAL_ROUTINES
03361 {
03362 DATABASE_HEADER *pheader;
03363 KEYLIST *pkeylist;
03364 KEY *pkey;
03365 INT i;
03366 char str[256];
03367 HNDLE parent;
03368
03369 if (hDB > _database_entries || hDB <= 0) {
03370 cm_msg(MERROR, "db_enum_key", "invalid database handle");
03371 return DB_INVALID_HANDLE;
03372 }
03373
03374 if (!_database[hDB - 1].attached) {
03375 cm_msg(MERROR, "db_enum_key", "invalid database handle");
03376 return DB_INVALID_HANDLE;
03377 }
03378
03379 *subkey_handle = 0;
03380
03381
03382 db_lock_database(hDB);
03383
03384 pheader = _database[hDB - 1].database_header;
03385 if (!hKey)
03386 hKey = pheader->root_key;
03387 pkey = (KEY *) ((char *) pheader + hKey);
03388
03389
03390 if (!db_validate_hkey(pheader, hKey)) {
03391 db_unlock_database(hDB);
03392 return DB_INVALID_HANDLE;
03393 }
03394
03395 if (pkey->type != TID_KEY) {
03396 db_unlock_database(hDB);
03397 return DB_NO_MORE_SUBKEYS;
03398 }
03399 pkeylist = (KEYLIST *) ((char *) pheader + pkey->data);
03400
03401 if (index >= pkeylist->num_keys) {
03402 db_unlock_database(hDB);
03403 return DB_NO_MORE_SUBKEYS;
03404 }
03405
03406 pkey = (KEY *) ((char *) pheader + pkeylist->first_key);
03407 for (i = 0; i < index; i++)
03408 pkey = (KEY *) ((char *) pheader + pkey->next_key);
03409
03410
03411 if (pkey->type == TID_LINK) {
03412 strcpy(str, (char *) pheader + pkey->data);
03413
03414 if (*str == '/') {
03415
03416 db_unlock_database(hDB);
03417 return db_find_key(hDB, 0, str, subkey_handle);
03418 } else {
03419
03420 if (pkey->parent_keylist) {
03421 pkeylist = (KEYLIST *) ((char *) pheader + pkey->parent_keylist);
03422 parent = pkeylist->parent;
03423 db_unlock_database(hDB);
03424 return db_find_key(hDB, parent, str, subkey_handle);
03425 } else {
03426 db_unlock_database(hDB);
03427 return db_find_key(hDB, 0, str, subkey_handle);
03428 }
03429 }
03430 }
03431
03432 *subkey_handle = (PTYPE) pkey - (PTYPE) pheader;
03433 db_unlock_database(hDB);
03434 }
03435 #endif
03436
03437 return DB_SUCCESS;
03438 }
03439
03440
03441 #ifndef DOXYGEN_SHOULD_SKIP_THIS
03442
03443
03444
03445 INT db_enum_link(HNDLE hDB, HNDLE hKey, INT index, HNDLE * subkey_handle)
03446
03447
03448
03449
03450
03451
03452
03453
03454
03455
03456
03457
03458
03459
03460
03461
03462
03463
03464
03465
03466
03467
03468
03469
03470
03471 {
03472 if (rpc_is_remote())
03473 return rpc_call(RPC_DB_ENUM_LINK, hDB, hKey, index, subkey_handle);
03474
03475 #ifdef LOCAL_ROUTINES
03476 {
03477 DATABASE_HEADER *pheader;
03478 KEYLIST *pkeylist;
03479 KEY *pkey;
03480 INT i;
03481
03482 if (hDB > _database_entries || hDB <= 0) {
03483 cm_msg(MERROR, "db_enum_link", "invalid database handle");
03484 return DB_INVALID_HANDLE;
03485 }
03486
03487 if (!_database[hDB - 1].attached) {
03488 cm_msg(MERROR, "db_enum_link", "invalid database handle");
03489 return DB_INVALID_HANDLE;
03490 }
03491
03492 *subkey_handle = 0;
03493
03494
03495 db_lock_database(hDB);
03496
03497 pheader = _database[hDB - 1].database_header;
03498 if (!hKey)
03499 hKey = pheader->root_key;
03500 pkey = (KEY *) ((char *) pheader + hKey);
03501
03502
03503 if (!db_validate_hkey(pheader, hKey)) {
03504 db_unlock_database(hDB);
03505 return DB_INVALID_HANDLE;
03506 }
03507
03508 if (pkey->type != TID_KEY) {
03509 db_unlock_database(hDB);
03510 return DB_NO_MORE_SUBKEYS;
03511 }
03512 pkeylist = (KEYLIST *) ((char *) pheader + pkey->data);
03513
03514 if (index >= pkeylist->num_keys) {
03515 db_unlock_database(hDB);
03516 return DB_NO_MORE_SUBKEYS;
03517 }
03518
03519 pkey = (KEY *) ((char *) pheader + pkeylist->first_key);
03520 for (i = 0; i < index; i++)
03521 pkey = (KEY *) ((char *) pheader + pkey->next_key);
03522
03523 *subkey_handle = (PTYPE) pkey - (PTYPE) pheader;
03524 db_unlock_database(hDB);
03525 }
03526 #endif
03527
03528 return DB_SUCCESS;
03529 }
03530
03531
03532 INT db_get_next_link(HNDLE hDB, HNDLE hKey, HNDLE * subkey_handle)
03533
03534
03535
03536
03537
03538
03539
03540
03541
03542
03543
03544
03545
03546
03547
03548
03549
03550
03551
03552
03553
03554 {
03555 if (rpc_is_remote())
03556 return rpc_call(RPC_DB_GET_NEXT_LINK, hDB, hKey, subkey_handle);
03557
03558 #ifdef LOCAL_ROUTINES
03559 {
03560 DATABASE_HEADER *pheader;
03561 KEYLIST *pkeylist;
03562 KEY *pkey;
03563 INT descent;
03564
03565 if (hDB > _database_entries || hDB <= 0) {
03566 cm_msg(MERROR, "db_enum_link", "invalid database handle");
03567 return DB_INVALID_HANDLE;
03568 }
03569
03570 if (!_database[hDB - 1].attached) {
03571 cm_msg(MERROR, "db_enum_link", "invalid database handle");
03572 return DB_INVALID_HANDLE;
03573 }
03574
03575 *subkey_handle = 0;
03576
03577
03578 db_lock_database(hDB);
03579
03580 pheader = _database[hDB - 1].database_header;
03581 if (!hKey)
03582 hKey = pheader->root_key;
03583 pkey = (KEY *) ((char *) pheader + hKey);
03584
03585
03586 if (!db_validate_hkey(pheader, hKey)) {
03587 db_unlock_database(hDB);
03588 return DB_INVALID_HANDLE;
03589 }
03590
03591 descent = TRUE;
03592 do {
03593 if (pkey->type != TID_KEY || !descent) {
03594 if (pkey->next_key) {
03595
03596 pkey = (KEY *) ((char *) pheader + pkey->next_key);
03597
03598 if (pkey->type != TID_KEY) {
03599 *subkey_handle = (PTYPE) pkey - (PTYPE) pheader;
03600 db_unlock_database(hDB);
03601 return DB_SUCCESS;
03602 }
03603
03604
03605 descent = TRUE;
03606 } else {
03607 if (pkey->parent_keylist == 0) {
03608
03609 db_unlock_database(hDB);
03610 return DB_NO_MORE_SUBKEYS;
03611 }
03612
03613
03614 pkeylist = (KEYLIST *) ((char *) pheader + pkey->parent_keylist);
03615
03616 pkey = (KEY *) ((char *) pheader + pkeylist->parent);
03617 descent = FALSE;
03618 }
03619 } else {
03620 if (descent) {
03621
03622 pkeylist = (KEYLIST *) ((char *) pheader + pkey->data);
03623
03624 if (pkeylist->num_keys == 0) {
03625
03626 descent = FALSE;
03627 } else {
03628
03629 pkey = (KEY *) ((char *) pheader + pkeylist->first_key);
03630
03631 if (pkey->type != TID_KEY) {
03632 *subkey_handle = (PTYPE) pkey - (PTYPE) pheader;
03633 db_unlock_database(hDB);
03634 return DB_SUCCESS;
03635 }
03636 }
03637 }
03638 }
03639
03640 } while (TRUE);
03641 }
03642 #endif
03643
03644 return DB_SUCCESS;
03645 }
03646
03647
03648 #endif
03649
03650
03651
03652
03653
03654
03655
03656
03657
03658
03659
03660
03661
03662
03663
03664
03665
03666
03667
03668
03669
03670
03671
03672
03673
03674
03675
03676
03677
03678
03679
03680
03681
03682
03683
03684
03685
03686
03687 INT db_get_key(HNDLE hDB, HNDLE hKey, KEY * key)
03688 {
03689 if (rpc_is_remote())
03690 return rpc_call(RPC_DB_GET_KEY, hDB, hKey, key);
03691
03692 #ifdef LOCAL_ROUTINES
03693 {
03694 DATABASE_HEADER *pheader;
03695 KEY *pkey;
03696
03697 if (hDB > _database_entries || hDB <= 0) {
03698 cm_msg(MERROR, "db_get_key", "invalid database handle");
03699 return DB_INVALID_HANDLE;
03700 }
03701
03702 if (!_database[hDB - 1].attached) {
03703 cm_msg(MERROR, "db_get_key", "invalid database handle");
03704 return DB_INVALID_HANDLE;
03705 }
03706
03707 if (hKey < sizeof(DATABASE_HEADER)) {
03708 cm_msg(MERROR, "db_get_key", "invalid key handle");
03709 return DB_INVALID_HANDLE;
03710 }
03711
03712 db_lock_database(hDB);
03713
03714 pheader = _database[hDB - 1].database_header;
03715 pkey = (KEY *) ((char *) pheader + hKey);
03716
03717
03718 if (!db_validate_hkey(pheader, hKey)) {
03719 db_unlock_database(hDB);
03720 return DB_INVALID_HANDLE;
03721 }
03722
03723 if (!pkey->type) {
03724 db_unlock_database(hDB);
03725 cm_msg(MERROR, "db_get_key", "invalid key");
03726 return DB_INVALID_HANDLE;
03727 }
03728
03729 memcpy(key, pkey, sizeof(KEY));
03730
03731 db_unlock_database(hDB);
03732
03733 }
03734 #endif
03735
03736 return DB_SUCCESS;
03737 }
03738
03739
03740
03741
03742
03743
03744
03745
03746
03747 INT db_get_key_time(HNDLE hDB, HNDLE hKey, DWORD * delta)
03748 {
03749 if (rpc_is_remote())
03750 return rpc_call(RPC_DB_GET_KEY_TIME, hDB, hKey, delta);
03751
03752 #ifdef LOCAL_ROUTINES
03753 {
03754 DATABASE_HEADER *pheader;
03755 KEY *pkey;
03756
03757 if (hDB > _database_entries || hDB <= 0) {
03758 cm_msg(MERROR, "db_get_key", "invalid database handle");
03759 return DB_INVALID_HANDLE;
03760 }
03761
03762 if (!_database[hDB - 1].attached) {
03763 cm_msg(MERROR, "db_get_key", "invalid database handle");
03764 return DB_INVALID_HANDLE;
03765 }
03766
03767 if (hKey < sizeof(DATABASE_HEADER)) {
03768 cm_msg(MERROR, "db_get_key", "invalid key handle");
03769 return DB_INVALID_HANDLE;
03770 }
03771
03772 db_lock_database(hDB);
03773
03774 pheader = _database[hDB - 1].database_header;
03775 pkey = (KEY *) ((char *) pheader + hKey);
03776
03777
03778 if (!db_validate_hkey(pheader, hKey)) {
03779 db_unlock_database(hDB);
03780 return DB_INVALID_HANDLE;
03781 }
03782
03783 *delta = ss_time() - pkey->last_written;
03784
03785 db_unlock_database(hDB);
03786
03787 }
03788 #endif
03789
03790 return DB_SUCCESS;
03791 }
03792
03793
03794
03795
03796
03797
03798
03799
03800
03801
03802
03803
03804
03805 INT db_get_key_info(HNDLE hDB, HNDLE hKey, char *name, INT name_size,
03806 INT * type, INT * num_values, INT * item_size)
03807 {
03808 if (rpc_is_remote())
03809 return rpc_call(RPC_DB_GET_KEY_INFO, hDB, hKey, name, name_size, type,
03810 num_values, item_size);
03811
03812 #ifdef LOCAL_ROUTINES
03813 {
03814 DATABASE_HEADER *pheader;
03815 KEY *pkey;
03816 KEYLIST *pkeylist;
03817
03818 if (hDB > _database_entries || hDB <= 0) {
03819 cm_msg(MERROR, "db_get_key_info", "invalid database handle");
03820 return DB_INVALID_HANDLE;
03821 }
03822
03823 if (!_database[hDB - 1].attached) {
03824 cm_msg(MERROR, "db_get_key_info", "invalid database handle");
03825 return DB_INVALID_HANDLE;
03826 }
03827
03828 if (hKey < sizeof(DATABASE_HEADER)) {
03829 cm_msg(MERROR, "db_get_key_info", "invalid key handle");
03830 return DB_INVALID_HANDLE;
03831 }
03832
03833 db_lock_database(hDB);
03834
03835 pheader = _database[hDB - 1].database_header;
03836 pkey = (KEY *) ((char *) pheader + hKey);
03837
03838
03839 if (!db_validate_hkey(pheader, hKey)) {
03840 db_unlock_database(hDB);
03841 return DB_INVALID_HANDLE;
03842 }
03843
03844 if ((INT) strlen(pkey->name) + 1 > name_size) {
03845
03846 memcpy(name, pkey->name, name_size - 1);
03847 name[name_size] = 0;
03848 } else
03849 strcpy(name, pkey->name);
03850
03851
03852 if (strcmp(name, "root") == 0)
03853 strcpy(name, "/");
03854
03855 *type = pkey->type;
03856 *num_values = pkey->num_values;
03857 *item_size = pkey->item_size;
03858
03859 if (pkey->type == TID_KEY) {
03860 pkeylist = (KEYLIST *) ((char *) pheader + pkey->data);
03861 *num_values = pkeylist->num_keys;
03862 }
03863
03864 db_unlock_database(hDB);
03865 }
03866 #endif
03867
03868 return DB_SUCCESS;
03869 }
03870
03871
03872 #ifndef DOXYGEN_SHOULD_SKIP_THIS
03873
03874
03875
03876 INT db_rename_key(HNDLE hDB, HNDLE hKey, char *name)
03877
03878
03879
03880
03881
03882
03883
03884
03885
03886
03887
03888
03889
03890
03891
03892
03893
03894
03895
03896 {
03897 if (rpc_is_remote())
03898 return rpc_call(RPC_DB_RENAME_KEY, hDB, hKey, name);
03899
03900 #ifdef LOCAL_ROUTINES
03901 {
03902 DATABASE_HEADER *pheader;
03903 KEY *pkey;
03904
03905 if (hDB > _database_entries || hDB <= 0) {
03906 cm_msg(MERROR, "db_rename_key", "invalid database handle");
03907 return DB_INVALID_HANDLE;
03908 }
03909
03910 if (!_database[hDB - 1].attached) {
03911 cm_msg(MERROR, "db_rename_key", "invalid database handle");
03912 return DB_INVALID_HANDLE;
03913 }
03914
03915 if (hKey < sizeof(DATABASE_HEADER)) {
03916 cm_msg(MERROR, "db_rename_key", "invalid key handle");
03917 return DB_INVALID_HANDLE;
03918 }
03919
03920 db_lock_database(hDB);
03921
03922 pheader = _database[hDB - 1].database_header;
03923 pkey = (KEY *) ((char *) pheader + hKey);
03924
03925
03926 if (!db_validate_hkey(pheader, hKey)) {
03927 db_unlock_database(hDB);
03928 return DB_INVALID_HANDLE;
03929 }
03930
03931 if (!pkey->type) {
03932 db_unlock_database(hDB);
03933 cm_msg(MERROR, "db_rename_key", "invalid key");
03934 return DB_INVALID_HANDLE;
03935 }
03936
03937 name[NAME_LENGTH] = 0;
03938 strcpy(pkey->name, name);
03939
03940 db_unlock_database(hDB);
03941
03942 }
03943 #endif
03944
03945 return DB_SUCCESS;
03946 }
03947
03948
03949 INT db_reorder_key(HNDLE hDB, HNDLE hKey, INT index)
03950
03951
03952
03953
03954
03955
03956
03957
03958
03959
03960
03961
03962
03963
03964
03965
03966
03967
03968
03969
03970
03971
03972 {
03973 if (rpc_is_remote())
03974 return rpc_call(RPC_DB_REORDER_KEY, hDB, hKey, index);
03975
03976 #ifdef LOCAL_ROUTINES
03977 {
03978 DATABASE_HEADER *pheader;
03979 KEY *pkey, *pprev_key, *pnext_key, *pkey_tmp;
03980 KEYLIST *pkeylist;
03981 INT i;
03982
03983 if (hDB > _database_entries || hDB <= 0) {
03984 cm_msg(MERROR, "db_rename_key", "invalid database handle");
03985 return DB_INVALID_HANDLE;
03986 }
03987
03988 if (!_database[hDB - 1].attached) {
03989 cm_msg(MERROR, "db_rename_key", "invalid database handle");
03990 return DB_INVALID_HANDLE;
03991 }
03992
03993 if (hKey < sizeof(DATABASE_HEADER)) {
03994 cm_msg(MERROR, "db_rename_key", "invalid key handle");
03995 return DB_INVALID_HANDLE;
03996 }
03997
03998 db_lock_database(hDB);
03999
04000 pheader = _database[hDB - 1].database_header;
04001 pkey = (KEY *) ((char *) pheader + hKey);
04002
04003
04004 if (!db_validate_hkey(pheader, hKey)) {
04005 db_unlock_database(hDB);
04006 return DB_INVALID_HANDLE;
04007 }
04008
04009 if (!pkey->type) {
04010 db_unlock_database(hDB);
04011 cm_msg(MERROR, "db_reorder_key", "invalid key");
04012 return DB_INVALID_HANDLE;
04013 }
04014
04015 if (!(pkey->access_mode & MODE_WRITE)) {
04016 db_unlock_database(hDB);
04017 return DB_NO_ACCESS;
04018 }
04019
04020
04021 do {
04022 if (pkey->notify_count) {
04023 db_unlock_database(hDB);
04024 return DB_OPEN_RECORD;
04025 }
04026
04027 if (pkey->parent_keylist == 0)
04028 break;
04029
04030 pkeylist = (KEYLIST *) ((char *) pheader + pkey->parent_keylist);
04031 pkey = (KEY *) ((char *) pheader + pkeylist->parent);
04032 } while (TRUE);
04033
04034 pkey = (KEY *) ((char *) pheader + hKey);
04035 pkeylist = (KEYLIST *) ((char *) pheader + pkey->parent_keylist);
04036
04037
04038 pnext_key = (KEY *) (PTYPE) pkey->next_key;
04039
04040 if ((KEY *) ((char *) pheader + pkeylist->first_key) == pkey) {
04041
04042 pkeylist->first_key = (PTYPE) pnext_key;
04043 } else {
04044
04045 pkey_tmp = (KEY *) ((char *) pheader + pkeylist->first_key);
04046 while ((KEY *) ((char *) pheader + pkey_tmp->next_key) != pkey)
04047 pkey_tmp = (KEY *) ((char *) pheader + pkey_tmp->next_key);
04048 pkey_tmp->next_key = (PTYPE) pnext_key;
04049 }
04050
04051
04052 pkey_tmp = (KEY *) ((char *) pheader + pkeylist->first_key);
04053 if (index < 0 || index >= pkeylist->num_keys - 1) {
04054
04055
04056
04057 for (i = 0; i < pkeylist->num_keys - 2; i++) {
04058 pprev_key = pkey_tmp;
04059 pkey_tmp = (KEY *) ((char *) pheader + pkey_tmp->next_key);
04060 }
04061
04062 pkey_tmp->next_key = (PTYPE) pkey - (PTYPE) pheader;
04063 pkey->next_key = 0;
04064 } else {
04065 if (index == 0) {
04066
04067 pkey->next_key = pkeylist->first_key;
04068 pkeylist->first_key = (PTYPE) pkey - (PTYPE) pheader;
04069 } else {
04070
04071 for (i = 0; i < index - 1; i++)
04072 pkey_tmp = (KEY *) ((char *) pheader + pkey_tmp->next_key);
04073
04074 pkey->next_key = pkey_tmp->next_key;
04075 pkey_tmp->next_key = (PTYPE) pkey - (PTYPE) pheader;
04076 }
04077 }
04078
04079 db_unlock_database(hDB);
04080
04081 }
04082 #endif
04083
04084 return DB_SUCCESS;
04085 }
04086
04087
04088 #endif
04089
04090
04091
04092
04093
04094
04095
04096
04097
04098
04099
04100
04101
04102
04103
04104
04105
04106
04107
04108
04109
04110
04111
04112
04113
04114
04115 INT db_get_data(HNDLE hDB, HNDLE hKey, void *data, INT * buf_size,
04116 DWORD type)
04117 {
04118 if (rpc_is_remote())
04119 return rpc_call(RPC_DB_GET_DATA, hDB, hKey, data, buf_size, type);
04120
04121 #ifdef LOCAL_ROUTINES
04122 {
04123 DATABASE_HEADER *pheader;
04124 KEY *pkey;
04125
04126 if (hDB > _database_entries || hDB <= 0) {
04127 cm_msg(MERROR, "db_get_data", "Invalid database handle");
04128 return DB_INVALID_HANDLE;
04129 }
04130
04131 if (!_database[hDB - 1].attached) {
04132 cm_msg(MERROR, "db_get_data", "invalid database handle");
04133 return DB_INVALID_HANDLE;
04134 }
04135
04136 if (hKey < sizeof(DATABASE_HEADER)) {
04137 cm_msg(MERROR, "db_get_data", "invalid key handle");
04138 return DB_INVALID_HANDLE;
04139 }
04140
04141 db_lock_database(hDB);
04142
04143 pheader = _database[hDB - 1].database_header;
04144 pkey = (KEY *) ((char *) pheader + hKey);
04145
04146
04147 if (!db_validate_hkey(pheader, hKey)) {
04148 db_unlock_database(hDB);
04149 return DB_INVALID_HANDLE;
04150 }
04151
04152
04153 if (!(pkey->access_mode & MODE_READ)) {
04154 db_unlock_database(hDB);
04155 return DB_NO_ACCESS;
04156 }
04157
04158 if (!pkey->type) {
04159 db_unlock_database(hDB);
04160 cm_msg(MERROR, "db_get_data", "invalid key");
04161 return DB_INVALID_HANDLE;
04162 }
04163
04164 if (pkey->type != type) {
04165 db_unlock_database(hDB);
04166 cm_msg(MERROR, "db_get_data", "\"%s\" is of type %s, not %s",
04167 pkey->name, rpc_tid_name(pkey->type), rpc_tid_name(type));
04168 return DB_TYPE_MISMATCH;
04169 }
04170
04171
04172 if (pkey->type == TID_KEY) {
04173 db_unlock_database(hDB);
04174 cm_msg(MERROR, "db_get_data", "Key cannot contain data");
04175 return DB_TYPE_MISMATCH;
04176 }
04177
04178
04179 if (pkey->data == 0) {
04180 memset(data, 0, *buf_size);
04181 *buf_size = 0;
04182 db_unlock_database(hDB);
04183 return DB_SUCCESS;
04184 }
04185
04186
04187 if (pkey->num_values * pkey->item_size > *buf_size) {
04188 memcpy(data, (char *) pheader + pkey->data, *buf_size);
04189 db_unlock_database(hDB);
04190 cm_msg(MERROR, "db_get_data", "data for key \"%s\" truncated",
04191 pkey->name);
04192 return DB_TRUNCATED;
04193 }
04194
04195
04196 memcpy(data, (char *) pheader + pkey->data,
04197 pkey->num_values * pkey->item_size);
04198 *buf_size = pkey->num_values * pkey->item_size;
04199
04200 db_unlock_database(hDB);
04201
04202 }
04203 #endif
04204
04205 return DB_SUCCESS;
04206 }
04207
04208
04209 #ifndef DOXYGEN_SHOULD_SKIP_THIS
04210
04211
04212 INT db_get_data1(HNDLE hDB, HNDLE hKey, void *data, INT * buf_size,
04213 DWORD type, INT * num_values)
04214
04215
04216
04217
04218
04219
04220
04221
04222
04223
04224
04225
04226
04227
04228
04229
04230
04231
04232
04233
04234
04235
04236
04237
04238 {
04239 if (rpc_is_remote())
04240 return rpc_call(RPC_DB_GET_DATA, hDB, hKey, data, buf_size, type);
04241
04242 #ifdef LOCAL_ROUTINES
04243 {
04244 DATABASE_HEADER *pheader;
04245 KEY *pkey;
04246
04247 if (hDB > _database_entries || hDB <= 0) {
04248 cm_msg(MERROR, "db_get_data", "Invalid database handle");
04249 return DB_INVALID_HANDLE;
04250 }
04251
04252 if (!_database[hDB - 1].attached) {
04253 cm_msg(MERROR, "db_get_data", "invalid database handle");
04254 return DB_INVALID_HANDLE;
04255 }
04256
04257 if (hKey < sizeof(DATABASE_HEADER)) {
04258 cm_msg(MERROR, "db_get_data", "invalid key handle");
04259 return DB_INVALID_HANDLE;
04260 }
04261
04262 db_lock_database(hDB);
04263
04264 pheader = _database[hDB - 1].database_header;
04265 pkey = (KEY *) ((char *) pheader + hKey);
04266
04267
04268 if (!db_validate_hkey(pheader, hKey)) {
04269 db_unlock_database(hDB);
04270 return DB_INVALID_HANDLE;
04271 }
04272
04273
04274 if (!(pkey->access_mode & MODE_READ)) {
04275 db_unlock_database(hDB);
04276 return DB_NO_ACCESS;
04277 }
04278
04279 if (!pkey->type) {
04280 db_unlock_database(hDB);
04281 cm_msg(MERROR, "db_get_data", "invalid key");
04282 return DB_INVALID_HANDLE;
04283 }
04284
04285 if (pkey->type != type) {
04286 db_unlock_database(hDB);
04287 cm_msg(MERROR, "db_get_data", "\"%s\" is of type %s, not %s",
04288 pkey->name, rpc_tid_name(pkey->type), rpc_tid_name(type));
04289 return DB_TYPE_MISMATCH;
04290 }
04291
04292
04293 if (pkey->type == TID_KEY) {
04294 db_unlock_database(hDB);
04295 cm_msg(MERROR, "db_get_data", "Key cannot contain data");
04296 return DB_TYPE_MISMATCH;
04297 }
04298
04299
04300 if (pkey->data == 0) {
04301 memset(data, 0, *buf_size);
04302 *buf_size = 0;
04303 db_unlock_database(hDB);
04304 return DB_SUCCESS;
04305 }
04306
04307
04308 if (pkey->num_values * pkey->item_size > *buf_size) {
04309 memcpy(data, (char *) pheader + pkey->data, *buf_size);
04310 db_unlock_database(hDB);
04311 cm_msg(MERROR, "db_get_data", "data for key \"%s\" truncated",
04312 pkey->name);
04313 return DB_TRUNCATED;
04314 }
04315
04316
04317 memcpy(data, (char *) pheader + pkey->data,
04318 pkey->num_values * pkey->item_size);
04319 *buf_size = pkey->num_values * pkey->item_size;
04320 *num_values = pkey->num_values;
04321
04322 db_unlock_database(hDB);
04323
04324 }
04325 #endif
04326
04327 return DB_SUCCESS;
04328 }
04329
04330
04331 #endif
04332
04333
04334
04335
04336
04337
04338
04339
04340
04341
04342
04343
04344
04345
04346 INT db_get_data_index(HNDLE hDB, HNDLE hKey,
04347 void *data, INT * buf_size, INT index, DWORD type)
04348 {
04349 if (rpc_is_remote())
04350 return rpc_call(RPC_DB_GET_DATA_INDEX, hDB, hKey, data, buf_size,
04351 index, type);
04352
04353 #ifdef LOCAL_ROUTINES
04354 {
04355 DATABASE_HEADER *pheader;
04356 KEY *pkey;
04357 char str[256];
04358
04359 if (hDB > _database_entries || hDB <= 0) {
04360 cm_msg(MERROR, "db_get_data", "Invalid database handle");
04361 return DB_INVALID_HANDLE;
04362 }
04363
04364 if (!_database[hDB - 1].attached) {
04365 cm_msg(MERROR, "db_get_data", "invalid database handle");
04366 return DB_INVALID_HANDLE;
04367 }
04368
04369 if (hKey < sizeof(DATABASE_HEADER)) {
04370 cm_msg(MERROR, "db_get_data", "invalid key handle");
04371 return DB_INVALID_HANDLE;
04372 }
04373
04374 db_lock_database(hDB);
04375
04376 pheader = _database[hDB - 1].database_header;
04377 pkey = (KEY *) ((char *) pheader + hKey);
04378
04379
04380 if (!db_validate_hkey(pheader, hKey)) {
04381 db_unlock_database(hDB);
04382 return DB_INVALID_HANDLE;
04383 }
04384
04385
04386 if (!(pkey->access_mode & MODE_READ)) {
04387 db_unlock_database(hDB);
04388 return DB_NO_ACCESS;
04389 }
04390
04391 if (!pkey->type) {
04392 db_unlock_database(hDB);
04393 cm_msg(MERROR, "db_get_data_index", "invalid key");
04394 return DB_INVALID_HANDLE;
04395 }
04396
04397 if (pkey->type != type) {
04398 db_unlock_database(hDB);
04399 cm_msg(MERROR, "db_get_data_index", "\"%s\" is of type %s, not %s",
04400 pkey->name, rpc_tid_name(pkey->type), rpc_tid_name(type));
04401 return DB_TYPE_MISMATCH;
04402 }
04403
04404
04405 if (pkey->type == TID_KEY) {
04406 db_unlock_database(hDB);
04407 cm_msg(MERROR, "db_get_data_index", "Key cannot contain data");
04408 return DB_TYPE_MISMATCH;
04409 }
04410
04411
04412 if (pkey->data == 0) {
04413 memset(data, 0, *buf_size);
04414 *buf_size = 0;
04415 db_unlock_database(hDB);
04416 return DB_SUCCESS;
04417 }
04418
04419
04420 if (index < 0 || index >= pkey->num_values) {
04421 memset(data, 0, *buf_size);
04422 db_unlock_database(hDB);
04423
04424 db_get_path(hDB, hKey, str, sizeof(str));
04425 cm_msg(MERROR, "db_get_data_index",
04426 "index (%d) exceeds array length (%d) for key \"%s\"", index,
04427 pkey->num_values, str);
04428 return DB_OUT_OF_RANGE;
04429 }
04430
04431
04432 if (pkey->item_size > *buf_size) {
04433
04434 memcpy(data, (char *) pheader + pkey->data + index * pkey->item_size,
04435 *buf_size);
04436 db_unlock_database(hDB);
04437 cm_msg(MERROR, "db_get_data_index", "data for key \"%s\" truncated",
04438 pkey->name);
04439 return DB_TRUNCATED;
04440 }
04441
04442
04443 memcpy(data, (char *) pheader + pkey->data + index * pkey->item_size,
04444 pkey->item_size);
04445 *buf_size = pkey->item_size;
04446
04447 db_unlock_database(hDB);
04448
04449 }
04450 #endif
04451
04452 return DB_SUCCESS;
04453 }
04454
04455
04456
04457
04458
04459
04460
04461
04462
04463
04464
04465
04466
04467
04468
04469
04470
04471
04472
04473
04474
04475 INT db_set_data(HNDLE hDB, HNDLE hKey,
04476 void *data, INT buf_size, INT num_values, DWORD type)
04477 {
04478 if (rpc_is_remote())
04479 return rpc_call(RPC_DB_SET_DATA, hDB, hKey,
04480 data, buf_size, num_values, type);
04481
04482 #ifdef LOCAL_ROUTINES
04483 {
04484 DATABASE_HEADER *pheader;
04485 KEY *pkey;
04486
04487 if (hDB > _database_entries || hDB <= 0) {
04488 cm_msg(MERROR, "db_set_data", "invalid database handle");
04489 return DB_INVALID_HANDLE;
04490 }
04491
04492 if (!_database[hDB - 1].attached) {
04493 cm_msg(MERROR, "db_set_data", "invalid database handle");
04494 return DB_INVALID_HANDLE;
04495 }
04496
04497 if (hKey < sizeof(DATABASE_HEADER)) {
04498 cm_msg(MERROR, "db_set_data", "invalid key handle");
04499 return DB_INVALID_HANDLE;
04500 }
04501
04502 if (num_values == 0)
04503 return DB_INVALID_PARAM;
04504
04505 db_lock_database(hDB);
04506
04507 pheader = _database[hDB - 1].database_header;
04508 pkey = (KEY *) ((char *) pheader + hKey);
04509
04510
04511 if (!db_validate_hkey(pheader, hKey)) {
04512 db_unlock_database(hDB);
04513 return DB_INVALID_HANDLE;
04514 }
04515
04516
04517 if (!(pkey->access_mode & MODE_WRITE) ||
04518 (pkey->access_mode & MODE_EXCLUSIVE)) {
04519 db_unlock_database(hDB);
04520 return DB_NO_ACCESS;
04521 }
04522
04523 if (pkey->type != type) {
04524 db_unlock_database(hDB);
04525 cm_msg(MERROR, "db_set_data", "\"%s\" is of type %s, not %s",
04526 pkey->name, rpc_tid_name(pkey->type), rpc_tid_name(type));
04527 return DB_TYPE_MISMATCH;
04528 }
04529
04530
04531 if (pkey->type == TID_KEY) {
04532 db_unlock_database(hDB);
04533 cm_msg(MERROR, "db_set_data", "Key cannot contain data");
04534 return DB_TYPE_MISMATCH;
04535 }
04536
04537
04538 if (buf_size == 0)
04539 buf_size = pkey->item_size * num_values;
04540
04541
04542 if (pkey->total_size != buf_size) {
04543 pkey->data =
04544 (PTYPE) realloc_data(pheader, (char *) pheader + pkey->data,
04545 pkey->total_size, buf_size);
04546
04547 if (pkey->data == 0) {
04548 db_unlock_database(hDB);
04549 cm_msg(MERROR, "db_set_data", "online database full");
04550 return DB_FULL;
04551 }
04552
04553 pkey->data -= (PTYPE) pheader;
04554 pkey->total_size = buf_size;
04555 }
04556
04557
04558 pkey->num_values = num_values;
04559 if (num_values)
04560 pkey->item_size = buf_size / num_values;
04561
04562
04563 memcpy((char *) pheader + pkey->data, data, buf_size);
04564
04565
04566 pkey->last_written = ss_time();
04567
04568 db_notify_clients(hDB, hKey, TRUE);
04569 db_unlock_database(hDB);
04570
04571 }
04572 #endif
04573
04574 return DB_SUCCESS;
04575 }
04576
04577
04578 #ifndef DOXYGEN_SHOULD_SKIP_THIS
04579
04580
04581 INT db_set_num_values(HNDLE hDB, HNDLE hKey, INT num_values)
04582
04583
04584
04585
04586
04587
04588
04589
04590
04591
04592
04593
04594
04595
04596
04597
04598
04599
04600
04601 {
04602 if (rpc_is_remote())
04603 return rpc_call(RPC_DB_SET_NUM_VALUES, hDB, hKey, num_values);
04604
04605 #ifdef LOCAL_ROUTINES
04606 {
04607 DATABASE_HEADER *pheader;
04608 KEY *pkey;
04609 INT new_size;
04610
04611 if (hDB > _database_entries || hDB <= 0) {
04612 cm_msg(MERROR, "db_set_data", "invalid database handle");
04613 return DB_INVALID_HANDLE;
04614 }
04615
04616 if (!_database[hDB - 1].attached) {
04617 cm_msg(MERROR, "db_set_data", "invalid database handle");
04618 return DB_INVALID_HANDLE;
04619 }
04620
04621 if (hKey < sizeof(DATABASE_HEADER)) {
04622 cm_msg(MERROR, "db_set_data", "invalid key handle");
04623 return DB_INVALID_HANDLE;
04624 }
04625
04626 if (num_values == 0)
04627 return DB_INVALID_PARAM;
04628
04629 db_lock_database(hDB);
04630
04631 pheader = _database[hDB - 1].database_header;
04632 pkey = (KEY *) ((char *) pheader + hKey);
04633
04634
04635 if (!db_validate_hkey(pheader, hKey)) {
04636 db_unlock_database(hDB);
04637 return DB_INVALID_HANDLE;
04638 }
04639
04640
04641 if (!(pkey->access_mode & MODE_WRITE) ||
04642 (pkey->access_mode & MODE_EXCLUSIVE)) {
04643 db_unlock_database(hDB);
04644 return DB_NO_ACCESS;
04645 }
04646
04647
04648 if (pkey->type == TID_KEY) {
04649 db_unlock_database(hDB);
04650 cm_msg(MERROR, "db_set_data", "Key cannot contain data");
04651 return DB_TYPE_MISMATCH;
04652 }
04653
04654
04655 if (pkey->num_values != num_values) {
04656 new_size = pkey->item_size * num_values;
04657 pkey->data =
04658 (PTYPE) realloc_data(pheader, (char *) pheader + pkey->data,
04659 pkey->total_size, new_size);
04660
04661 if (pkey->data == 0) {
04662 db_unlock_database(hDB);
04663 cm_msg(MERROR, "db_set_data", "online database full");
04664 return DB_FULL;
04665 }
04666
04667 pkey->data -= (PTYPE) pheader;
04668 pkey->total_size = new_size;
04669 pkey->num_values = num_values;
04670 }
04671
04672
04673 pkey->last_written = ss_time();
04674
04675 db_notify_clients(hDB, hKey, TRUE);
04676 db_unlock_database(hDB);
04677
04678 }
04679 #endif
04680
04681 return DB_SUCCESS;
04682 }
04683
04684
04685 #endif
04686
04687
04688
04689
04690
04691
04692
04693
04694
04695
04696
04697
04698
04699
04700
04701
04702 INT db_set_data_index(HNDLE hDB, HNDLE hKey,
04703 void *data, INT data_size, INT index, DWORD type)
04704 {
04705 if (rpc_is_remote())
04706 return rpc_call(RPC_DB_SET_DATA_INDEX, hDB, hKey,
04707 data, data_size, index, type);
04708
04709 #ifdef LOCAL_ROUTINES
04710 {
04711 DATABASE_HEADER *pheader;
04712 KEY *pkey;
04713
04714 if (hDB > _database_entries || hDB <= 0) {
04715 cm_msg(MERROR, "db_set_data_index", "invalid database handle");
04716 return DB_INVALID_HANDLE;
04717 }
04718
04719 if (!_database[hDB - 1].attached) {
04720 cm_msg(MERROR, "db_set_data_index", "invalid database handle");
04721 return DB_INVALID_HANDLE;
04722 }
04723
04724 if (hKey < sizeof(DATABASE_HEADER)) {
04725 cm_msg(MERROR, "db_set_data_index", "invalid key handle");
04726 return DB_INVALID_HANDLE;
04727 }
04728
04729 db_lock_database(hDB);
04730
04731 pheader = _database[hDB - 1].database_header;
04732 pkey = (KEY *) ((char *) pheader + hKey);
04733
04734
04735 if (!db_validate_hkey(pheader, hKey)) {
04736 db_unlock_database(hDB);
04737 return DB_INVALID_HANDLE;
04738 }
04739
04740
04741 if (!(pkey->access_mode & MODE_WRITE) ||
04742 (pkey->access_mode & MODE_EXCLUSIVE)) {
04743 db_unlock_database(hDB);
04744 return DB_NO_ACCESS;
04745 }
04746
04747 if (pkey->type != type) {
04748 db_unlock_database(hDB);
04749 cm_msg(MERROR, "db_set_data_index", "\"%s\" is of type %s, not %s",
04750 pkey->name, rpc_tid_name(pkey->type), rpc_tid_name(type));
04751 return DB_TYPE_MISMATCH;
04752 }
04753
04754
04755 if (pkey->type == TID_KEY) {
04756 db_unlock_database(hDB);
04757 cm_msg(MERROR, "db_set_data_index", "key cannot contain data");
04758 return DB_TYPE_MISMATCH;
04759 }
04760
04761
04762 if (index < 0) {
04763 db_unlock_database(hDB);
04764 cm_msg(MERROR, "db_set_data_index", "invalid index");
04765 return DB_FULL;
04766 }
04767
04768
04769 if (index >= pkey->num_values || pkey->item_size == 0) {
04770 pkey->data =
04771 (PTYPE) realloc_data(pheader, (char *) pheader + pkey->data,
04772 pkey->total_size, data_size * (index + 1));
04773
04774 if (pkey->data == 0) {
04775 db_unlock_database(hDB);
04776 cm_msg(MERROR, "db_set_data_index", "online database full");
04777 return DB_FULL;
04778 }
04779
04780 pkey->data -= (PTYPE) pheader;
04781 if (!pkey->item_size)
04782 pkey->item_size = data_size;
04783 pkey->total_size = data_size * (index + 1);
04784 pkey->num_values = index + 1;
04785 }
04786
04787
04788 if ((type == TID_STRING || type == TID_LINK) &&
04789 (int) strlen((char *) data) + 1 > pkey->item_size)
04790 *((char *) data + pkey->item_size - 1) = 0;
04791
04792
04793 memcpy((char *) pheader + pkey->data + index * pkey->item_size,
04794 data, pkey->item_size);
04795
04796
04797 pkey->last_written = ss_time();
04798
04799 db_notify_clients(hDB, hKey, TRUE);
04800 db_unlock_database(hDB);
04801
04802 }
04803 #endif
04804
04805 return DB_SUCCESS;
04806 }
04807
04808
04809 #ifndef DOXYGEN_SHOULD_SKIP_THIS
04810
04811
04812 INT db_set_data_index2(HNDLE hDB, HNDLE hKey, void *data,
04813 INT data_size, INT index, DWORD type, BOOL bNotify)
04814
04815
04816
04817
04818
04819
04820
04821
04822
04823
04824
04825
04826
04827
04828
04829
04830
04831
04832
04833
04834
04835
04836
04837
04838
04839
04840 {
04841 if (rpc_is_remote())
04842 return rpc_call(RPC_DB_SET_DATA_INDEX2, hDB, hKey,
04843 data, data_size, index, type, bNotify);
04844
04845 #ifdef LOCAL_ROUTINES
04846 {
04847 DATABASE_HEADER *pheader;
04848 KEY *pkey;
04849
04850 if (hDB > _database_entries || hDB <= 0) {
04851 cm_msg(MERROR, "db_set_data_index2", "invalid database handle");
04852 return DB_INVALID_HANDLE;
04853 }
04854
04855 if (!_database[hDB - 1].attached) {
04856 cm_msg(MERROR, "db_set_data_index2", "invalid database handle");
04857 return DB_INVALID_HANDLE;
04858 }
04859
04860 if (hKey < sizeof(DATABASE_HEADER)) {
04861 cm_msg(MERROR, "db_set_data_index2", "invalid key handle");
04862 return DB_INVALID_HANDLE;
04863 }
04864
04865 db_lock_database(hDB);
04866
04867 pheader = _database[hDB - 1].database_header;
04868 pkey = (KEY *) ((char *) pheader + hKey);
04869
04870
04871 if (!db_validate_hkey(pheader, hKey)) {
04872 db_unlock_database(hDB);
04873 return DB_INVALID_HANDLE;
04874 }
04875
04876
04877 if (!(pkey->access_mode & MODE_WRITE) ||
04878 (pkey->access_mode & MODE_EXCLUSIVE)) {
04879 db_unlock_database(hDB);
04880 return DB_NO_ACCESS;
04881 }
04882
04883 if (pkey->type != type) {
04884 db_unlock_database(hDB);
04885 cm_msg(MERROR, "db_set_data_index2", "\"%s\" is of type %s, not %s",
04886 pkey->name, rpc_tid_name(pkey->type), rpc_tid_name(type));
04887 return DB_TYPE_MISMATCH;
04888 }
04889
04890
04891 if (pkey->type == TID_KEY) {
04892 db_unlock_database(hDB);
04893 cm_msg(MERROR, "db_set_data_index2", "key cannot contain data");
04894 return DB_TYPE_MISMATCH;
04895 }
04896
04897
04898 if (index < 0) {
04899 db_unlock_database(hDB);
04900 cm_msg(MERROR, "db_set_data_index2", "invalid index");
04901 return DB_FULL;
04902 }
04903
04904
04905 if (index >= pkey->num_values) {
04906 pkey->data =
04907 (PTYPE) realloc_data(pheader, (char *) pheader + pkey->data,
04908 pkey->total_size, data_size * (index + 1));
04909
04910 if (pkey->data == 0) {
04911 db_unlock_database(hDB);
04912 cm_msg(MERROR, "db_set_data_index2", "online database full");
04913 return DB_FULL;
04914 }
04915
04916 pkey->data -= (PTYPE) pheader;
04917 if (!pkey->item_size)
04918 pkey->item_size = data_size;
04919 pkey->total_size = data_size * (index + 1);
04920 pkey->num_values = index + 1;
04921 }
04922
04923
04924 if ((type == TID_STRING || type == TID_LINK) &&
04925 (int) strlen((char *) data) + 1 > pkey->item_size)
04926 *((char *) data + pkey->item_size - 1) = 0;
04927
04928
04929 memcpy((char *) pheader + pkey->data + index * pkey->item_size,
04930 data, pkey->item_size);
04931
04932
04933 pkey->last_written = ss_time();
04934
04935 if (bNotify)
04936 db_notify_clients(hDB, hKey, TRUE);
04937
04938 db_unlock_database(hDB);
04939 }
04940 #endif
04941
04942 return DB_SUCCESS;
04943 }
04944
04945
04946
04947 INT db_merge_data(HNDLE hDB, HNDLE hKeyRoot, char *name, void *data,
04948 INT data_size, INT num_values, INT type)
04949
04950
04951
04952
04953
04954
04955
04956
04957
04958
04959
04960
04961
04962
04963
04964
04965
04966
04967
04968
04969
04970
04971
04972
04973 {
04974 HNDLE hKey;
04975 INT status, old_size;
04976
04977 if (num_values == 0)
04978 return DB_INVALID_PARAM;
04979
04980 status = db_find_key(hDB, hKeyRoot, name, &hKey);
04981 if (status != DB_SUCCESS) {
04982 db_create_key(hDB, hKeyRoot, name, type);
04983 db_find_key(hDB, hKeyRoot, name, &hKey);
04984 status = db_set_data(hDB, hKey, data, data_size, num_values, type);
04985 } else {
04986 old_size = data_size;
04987 db_get_data(hDB, hKey, data, &old_size, type);
04988 status = db_set_data(hDB, hKey, data, data_size, num_values, type);
04989 }
04990
04991 return status;
04992 }
04993
04994
04995 INT db_set_mode(HNDLE hDB, HNDLE hKey, WORD mode, BOOL recurse)
04996
04997
04998
04999
05000
05001
05002
05003
05004
05005
05006
05007
05008
05009
05010
05011
05012
05013
05014
05015
05016
05017
05018
05019 {
05020 if (rpc_is_remote())
05021 return rpc_call(RPC_DB_SET_MODE, hDB, hKey, mode, recurse);
05022
05023 #ifdef LOCAL_ROUTINES
05024 {
05025 DATABASE_HEADER *pheader;
05026 KEYLIST *pkeylist;
05027 KEY *pkey, *pnext_key;
05028 HNDLE hKeyLink;
05029
05030 if (hDB > _database_entries || hDB <= 0) {
05031 cm_msg(MERROR, "db_set_mode", "invalid database handle");
05032 return DB_INVALID_HANDLE;
05033 }
05034
05035 if (!_database[hDB - 1].attached) {
05036 cm_msg(MERROR, "db_set_mode", "invalid database handle");
05037 return DB_INVALID_HANDLE;
05038 }
05039
05040 if (recurse < 2)
05041 db_lock_database(hDB);
05042
05043 pheader = _database[hDB - 1].database_header;
05044 if (!hKey)
05045 hKey = pheader->root_key;
05046 pkey = (KEY *) ((char *) pheader + hKey);
05047
05048
05049 if (!db_validate_hkey(pheader, hKey)) {
05050 db_unlock_database(hDB);
05051 return DB_INVALID_HANDLE;
05052 }
05053
05054 pkeylist = (KEYLIST *) ((char *) pheader + pkey->data);
05055
05056 if (pkey->type == TID_KEY && pkeylist->first_key && recurse) {
05057
05058 pkey = (KEY *) ((char *) pheader + pkeylist->first_key);
05059
05060 do {
05061 pnext_key = (KEY *) (PTYPE) pkey->next_key;
05062
05063 db_set_mode(hDB, (PTYPE) pkey - (PTYPE) pheader,
05064 mode, recurse + 1);
05065
05066 if (pnext_key)
05067 pkey = (KEY *) ((char *) pheader + (PTYPE) pnext_key);
05068 } while (pnext_key);
05069 }
05070
05071 pkey = (KEY *) ((char *) pheader + hKey);
05072
05073
05074 if (pkey->type == TID_LINK) {
05075 db_unlock_database(hDB);
05076 if (*((char *) pheader + pkey->data) == '/')
05077 db_find_key(hDB, 0, (char *) pheader + pkey->data, &hKeyLink);
05078 else
05079 db_find_key(hDB, hKey, (char *) pheader + pkey->data, &hKeyLink);
05080 if (hKeyLink)
05081 db_set_mode(hDB, hKeyLink, mode, recurse > 0);
05082 db_lock_database(hDB);
05083 pheader = _database[hDB - 1].database_header;
05084 pkey = (KEY *) ((char *) pheader + hKey);
05085 }
05086
05087
05088 pkey->access_mode = mode;
05089
05090 if (recurse < 2)
05091 db_unlock_database(hDB);
05092 }
05093 #endif
05094
05095 return DB_SUCCESS;
05096 }
05097
05098
05099 #endif
05100
05101
05102
05103
05104
05105
05106
05107
05108
05109
05110
05111
05112
05113
05114
05115 INT db_load(HNDLE hDB, HNDLE hKeyRoot, char *filename, BOOL bRemote)
05116 {
05117 struct stat stat_buf;
05118 INT hfile, size, n, i, status;
05119 char *buffer;
05120
05121 if (rpc_is_remote() && bRemote)
05122 return rpc_call(RPC_DB_LOAD, hDB, hKeyRoot, filename);
05123
05124
05125 hfile = open(filename, O_RDONLY | O_TEXT, 0644);
05126 if (hfile == -1) {
05127 cm_msg(MERROR, "db_load", "file \"%s\" not found", filename);
05128 return DB_FILE_ERROR;
05129 }
05130
05131
05132 fstat(hfile, &stat_buf);
05133 size = stat_buf.st_size;
05134 buffer = (char *) malloc(size + 1);
05135
05136 if (buffer == NULL) {
05137 cm_msg(MERROR, "db_load", "cannot allocate ODB load buffer");
05138 close(hfile);
05139 return DB_NO_MEMORY;
05140 }
05141
05142 n = 0;
05143
05144 do {
05145 i = read(hfile, buffer + n, size);
05146 if (i <= 0)
05147 break;
05148 n += i;
05149 } while (TRUE);
05150
05151 buffer[n] = 0;
05152
05153 status = db_paste(hDB, hKeyRoot, buffer);
05154
05155 close(hfile);
05156 free(buffer);
05157
05158 return status;
05159 }
05160
05161
05162
05163
05164
05165
05166
05167
05168
05169
05170
05171
05172
05173
05174
05175
05176
05177
05178
05179
05180
05181
05182
05183
05184
05185
05186
05187
05188
05189
05190
05191
05192
05193
05194
05195 INT db_copy(HNDLE hDB, HNDLE hKey, char *buffer, INT * buffer_size,
05196 char *path)
05197 {
05198 INT i, j, size, status;
05199 KEY key;
05200 HNDLE hSubkey;
05201 char full_path[MAX_ODB_PATH], str[MAX_STRING_LENGTH * 2];
05202 char *data, line[MAX_STRING_LENGTH * 2];
05203 BOOL bWritten;
05204
05205 strcpy(full_path, path);
05206
05207 bWritten = FALSE;
05208
05209
05210 for (i = 0;; i++) {
05211 db_enum_link(hDB, hKey, i, &hSubkey);
05212
05213 if (i == 0 && !hSubkey) {
05214
05215 db_get_key(hDB, hKey, &key);
05216 size = key.total_size;
05217 data = (char *) malloc(size);
05218 if (data == NULL) {
05219 cm_msg(MERROR, "db_copy", "cannot allocate data buffer");
05220 return DB_NO_MEMORY;
05221 }
05222 line[0] = 0;
05223
05224 if (key.type != TID_KEY) {
05225 db_get_data(hDB, hKey, data, &size, key.type);
05226 if (key.num_values == 1) {
05227 sprintf(line, "%s = %s : ", key.name, tid_name[key.type]);
05228
05229 if (key.type == TID_STRING && strchr(data, '\n') != NULL) {
05230
05231 sprintf(line + strlen(line), "[====#$@$#====]\n");
05232
05233
05234 if ((INT) (strlen(line) + 1) > *buffer_size) {
05235 free(data);
05236 return DB_TRUNCATED;
05237 }
05238
05239 strcpy(buffer, line);
05240 buffer += strlen(line);
05241 *buffer_size -= strlen(line);
05242
05243
05244 if (key.item_size > *buffer_size) {
05245 free(data);
05246 return DB_TRUNCATED;
05247 }
05248
05249 strcpy(buffer, data);
05250 buffer += strlen(data);
05251 *buffer_size -= strlen(data);
05252
05253 strcpy(line, "\n====#$@$#====\n");
05254 } else {
05255 db_sprintf(str, data, key.item_size, 0, key.type);
05256
05257 if (key.type == TID_STRING || key.type == TID_LINK)
05258 sprintf(line + strlen(line), "[%d] ", key.item_size);
05259
05260 sprintf(line + strlen(line), "%s\n", str);
05261 }
05262 } else {
05263 sprintf(line, "%s = %s[%d] :\n", key.name, tid_name[key.type],
05264 key.num_values);
05265
05266 for (j = 0; j < key.num_values; j++) {
05267 if (key.type == TID_STRING || key.type == TID_LINK)
05268 sprintf(line + strlen(line), "[%d] ", key.item_size);
05269 else
05270 sprintf(line + strlen(line), "[%d] ", j);
05271
05272 db_sprintf(str, data, key.item_size, j, key.type);
05273 sprintf(line + strlen(line), "%s\n", str);
05274
05275
05276 if ((INT) (strlen(line) + 1) > *buffer_size) {
05277 free(data);
05278 return DB_TRUNCATED;
05279 }
05280
05281 strcpy(buffer, line);
05282 buffer += strlen(line);
05283 *buffer_size -= strlen(line);
05284 line[0] = 0;
05285 }
05286 }
05287 }
05288
05289
05290 if ((INT) (strlen(line) + 1) > *buffer_size) {
05291 free(data);
05292 return DB_TRUNCATED;
05293 }
05294
05295 strcpy(buffer, line);
05296 buffer += strlen(line);
05297 *buffer_size -= strlen(line);
05298
05299 free(data);
05300 }
05301
05302 if (!hSubkey)
05303 break;
05304
05305 db_get_key(hDB, hSubkey, &key);
05306 size = key.total_size;
05307 data = (char *) malloc(size);
05308 if (data == NULL) {
05309 cm_msg(MERROR, "db_copy", "cannot allocate data buffer");
05310 return DB_NO_MEMORY;
05311 }
05312
05313 line[0] = 0;
05314
05315 if (key.type == TID_KEY) {
05316
05317 if (bWritten) {
05318 if (*buffer_size < 2) {
05319 free(data);
05320 return DB_TRUNCATED;
05321 }
05322
05323 strcpy(buffer, "\n");
05324 buffer += 1;
05325 *buffer_size -= 1;
05326 }
05327
05328 strcpy(str, full_path);
05329 if (str[0] && str[strlen(str) - 1] != '/')
05330 strcat(str, "/");
05331 strcat(str, key.name);
05332
05333
05334 status = db_copy(hDB, hSubkey, buffer, buffer_size, str);
05335 if (status != DB_SUCCESS) {
05336 free(data);
05337 return status;
05338 }
05339
05340 buffer += strlen(buffer);
05341 bWritten = FALSE;
05342 } else {
05343 db_get_data(hDB, hSubkey, data, &size, key.type);
05344 if (!bWritten) {
05345 if (path[0] == 0)
05346 sprintf(line, "[.]\n");
05347 else
05348 sprintf(line, "[%s]\n", path);
05349 bWritten = TRUE;
05350 }
05351
05352 if (key.num_values == 1) {
05353 sprintf(line + strlen(line), "%s = %s : ", key.name,
05354 tid_name[key.type]);
05355
05356 if (key.type == TID_STRING && strchr(data, '\n') != NULL) {
05357
05358 sprintf(line + strlen(line), "[====#$@$#====]\n");
05359
05360
05361 data[size - 1] = 0;
05362
05363
05364 if ((INT) (strlen(line) + 1) > *buffer_size) {
05365 free(data);
05366 return DB_TRUNCATED;
05367 }
05368
05369 strcpy(buffer, line);
05370 buffer += strlen(line);
05371 *buffer_size -= strlen(line);
05372
05373
05374 if (key.item_size > *buffer_size) {
05375 free(data);
05376 return DB_TRUNCATED;
05377 }
05378
05379 strcpy(buffer, data);
05380 buffer += strlen(data);
05381 *buffer_size -= strlen(data);
05382
05383 strcpy(line, "\n====#$@$#====\n");
05384 } else {
05385 db_sprintf(str, data, key.item_size, 0, key.type);
05386
05387 if (key.type == TID_STRING || key.type == TID_LINK)
05388 sprintf(line + strlen(line), "[%d] ", key.item_size);
05389
05390 sprintf(line + strlen(line), "%s\n", str);
05391 }
05392 } else {
05393 sprintf(line + strlen(line), "%s = %s[%d] :\n", key.name,
05394 tid_name[key.type], key.num_values);
05395
05396 for (j = 0; j < key.num_values; j++) {
05397 if (key.type == TID_STRING || key.type == TID_LINK)
05398 sprintf(line + strlen(line), "[%d] ", key.item_size);
05399 else
05400 sprintf(line + strlen(line), "[%d] ", j);
05401
05402 db_sprintf(str, data, key.item_size, j, key.type);
05403 sprintf(line + strlen(line), "%s\n", str);
05404
05405
05406 if ((INT) (strlen(line) + 1) > *buffer_size) {
05407 free(data);
05408 return DB_TRUNCATED;
05409 }
05410
05411 strcpy(buffer, line);
05412 buffer += strlen(line);
05413 *buffer_size -= strlen(line);
05414 line[0] = 0;
05415 }
05416 }
05417
05418
05419 if ((INT) (strlen(line) + 1) > *buffer_size) {
05420 free(data);
05421 return DB_TRUNCATED;
05422 }
05423
05424 strcpy(buffer, line);
05425 buffer += strlen(line);
05426 *buffer_size -= strlen(line);
05427 }
05428
05429 free(data);
05430 }
05431
05432 if (bWritten) {
05433 if (*buffer_size < 2)
05434 return DB_TRUNCATED;
05435
05436 strcpy(buffer, "\n");
05437 buffer += 1;
05438 *buffer_size -= 1;
05439 }
05440
05441 return DB_SUCCESS;
05442 }
05443
05444
05445
05446
05447
05448
05449
05450
05451
05452 INT db_paste(HNDLE hDB, HNDLE hKeyRoot, char *buffer)
05453 {
05454 char line[MAX_STRING_LENGTH];
05455 char title[MAX_STRING_LENGTH];
05456 char key_name[MAX_STRING_LENGTH];
05457 char data_str[MAX_STRING_LENGTH + 50];
05458 char test_str[MAX_STRING_LENGTH];
05459 char *pc, *pold, *data;
05460 INT data_size;
05461 INT tid, i, j, n_data, string_length, status, size;
05462 HNDLE hKey;
05463 KEY root_key;
05464 BOOL multi_line;
05465
05466 title[0] = 0;
05467 multi_line = FALSE;
05468
05469 if (hKeyRoot == 0)
05470 db_find_key(hDB, hKeyRoot, "", &hKeyRoot);
05471
05472 db_get_key(hDB, hKeyRoot, &root_key);
05473
05474
05475 data_size = 1000;
05476 data = (char *) malloc(data_size);
05477 if (data == NULL) {
05478 cm_msg(MERROR, "db_paste", "cannot allocate data buffer");
05479 return DB_NO_MEMORY;
05480 }
05481
05482 do {
05483 if (*buffer == 0)
05484 break;
05485
05486 for (i = 0; *buffer != '\n' && *buffer && i < MAX_STRING_LENGTH; i++)
05487 line[i] = *buffer++;
05488
05489 if (i == MAX_STRING_LENGTH) {
05490 cm_msg(MERROR, "db_paste", "line too long");
05491 free(data);
05492 return DB_TRUNCATED;
05493 }
05494
05495 line[i] = 0;
05496 if (*buffer == '\n')
05497 buffer++;
05498
05499
05500 if (line[0] == '[') {
05501
05502 strcpy(title, line + 1);
05503 if (strchr(title, ']'))
05504 *strchr(title, ']') = 0;
05505 if (title[0] && title[strlen(title) - 1] != '/')
05506 strcat(title, "/");
05507 } else {
05508
05509 if (strchr(line, '=') && line[0] != ';') {
05510
05511 pc = strchr(line, '=') + 1;
05512 while (*pc == ' ')
05513 pc++;
05514 strcpy(data_str, pc);
05515
05516
05517 *strchr(line, '=') = 0;
05518
05519 pc = &line[strlen(line) - 1];
05520 while (*pc == ' ')
05521 *pc-- = 0;
05522
05523 key_name[0] = 0;
05524 if (title[0] != '.')
05525 strcpy(key_name, title);
05526
05527 strcat(key_name, line);
05528
05529
05530 strcpy(line, data_str);
05531 if (strchr(line, ' '))
05532 *strchr(line, ' ') = 0;
05533
05534 n_data = 1;
05535 if (strchr(line, '[')) {
05536 n_data = atol(strchr(line, '[') + 1);
05537 *strchr(line, '[') = 0;
05538 }
05539
05540 for (tid = 0; tid < TID_LAST; tid++)
05541 if (strcmp(tid_name[tid], line) == 0)
05542 break;
05543
05544 string_length = 0;
05545
05546 if (tid == TID_LAST)
05547 cm_msg(MERROR, "db_paste",
05548 "found unknown data type \"%s\" in ODB file", line);
05549 else {
05550
05551 pc = data_str;
05552 while (*pc != ' ' && *pc)
05553 pc++;
05554 while ((*pc == ' ' || *pc == ':') && *pc)
05555 pc++;
05556 strcpy(data_str, pc);
05557
05558 if (n_data > 1) {
05559 data_str[0] = 0;
05560 if (!*buffer)
05561 break;
05562
05563 for (j = 0; *buffer != '\n' && *buffer; j++)
05564 data_str[j] = *buffer++;
05565 data_str[j] = 0;
05566 if (*buffer == '\n')
05567 buffer++;
05568 }
05569
05570 for (i = 0; i < n_data; i++) {
05571
05572 pc = &data_str[strlen(data_str) - 1];
05573 while (*pc == '\n' || *pc == '\r')
05574 *pc-- = 0;
05575
05576 if (tid == TID_STRING || tid == TID_LINK) {
05577 if (!string_length) {
05578 if (data_str[1] == '=')
05579 string_length = -1;
05580 else
05581 string_length = atoi(data_str + 1);
05582 if (string_length > MAX_STRING_LENGTH) {
05583 string_length = MAX_STRING_LENGTH;
05584 cm_msg(MERROR, "db_paste",
05585 "found string exceeding MAX_STRING_LENGTH");
05586 }
05587 }
05588
05589 if (string_length == -1) {
05590
05591 if (strstr(buffer, "\n====#$@$#====\n") != NULL) {
05592 string_length =
05593 (PTYPE) strstr(buffer,
05594 "\n====#$@$#====\n") -
05595 (PTYPE) buffer + 1;
05596
05597 if (string_length >= data_size) {
05598 data_size += string_length + 100;
05599 data = (char *) realloc(data, data_size);
05600 if (data == NULL) {
05601 cm_msg(MERROR, "db_paste",
05602 "cannot allocate data buffer");
05603 return DB_NO_MEMORY;
05604 }
05605 }
05606
05607 memset(data, 0, data_size);
05608 strncpy(data, buffer, string_length);
05609 data[string_length - 1] = 0;
05610 buffer =
05611 strstr(buffer,
05612 "\n====#$@$#====\n") +
05613 strlen("\n====#$@$#====\n");
05614 } else
05615 cm_msg(MERROR, "db_paste",
05616 "found multi-line string without termination sequence");
05617 } else {
05618 pc = data_str + 2;
05619 while (*pc && *pc != ' ')
05620 pc++;
05621 while (*pc && *pc == ' ')
05622 pc++;
05623
05624
05625 *(pc + string_length - 1) = 0;
05626
05627
05628 if (string_length * (i + 1) >= data_size) {
05629 data_size += 1000;
05630 data = (char *) realloc(data, data_size);
05631 if (data == NULL) {
05632 cm_msg(MERROR, "db_paste",
05633 "cannot allocate data buffer");
05634 return DB_NO_MEMORY;
05635 }
05636 }
05637
05638 strcpy(data + string_length * i, pc);
05639 }
05640 } else {
05641 pc = data_str;
05642
05643 if (n_data > 1 && data_str[0] == '[') {
05644 pc = strchr(data_str, ']') + 1;
05645 while (*pc && *pc == ' ')
05646 pc++;
05647 }
05648
05649 db_sscanf(pc, data, &size, i, tid);
05650
05651
05652 if (size * (i + 1) >= data_size) {
05653 data_size += 1000;
05654 data = (char *) realloc(data, data_size);
05655 if (data == NULL) {
05656 cm_msg(MERROR, "db_paste",
05657 "cannot allocate data buffer");
05658 return DB_NO_MEMORY;
05659 }
05660 }
05661
05662 }
05663
05664 if (i < n_data - 1) {
05665 data_str[0] = 0;
05666 if (!*buffer)
05667 break;
05668
05669 pold = buffer;
05670
05671 for (j = 0; *buffer != '\n' && *buffer; j++)
05672 data_str[j] = *buffer++;
05673 data_str[j] = 0;
05674 if (*buffer == '\n')
05675 buffer++;
05676
05677
05678 if (tid != TID_STRING && tid != TID_LINK) {
05679 if (data_str[0] == 0 ||
05680 (strchr(data_str, '=') && strchr(data_str, ':')))
05681 buffer = pold;
05682 }
05683 }
05684 }
05685
05686
05687 strcpy(test_str, key_name);
05688 test_str[15] = 0;
05689
05690 if (!equal_ustring(test_str, "/System/Clients")) {
05691 if (root_key.type != TID_KEY) {
05692
05693 hKey = hKeyRoot;
05694 } else {
05695
05696 if (key_name[0] == '/') {
05697 status = db_find_link(hDB, 0, key_name, &hKey);
05698 if (status == DB_NO_KEY) {
05699 db_create_key(hDB, 0, key_name, tid);
05700 status = db_find_link(hDB, 0, key_name, &hKey);
05701 }
05702 } else {
05703 status = db_find_link(hDB, hKeyRoot, key_name, &hKey);
05704 if (status == DB_NO_KEY) {
05705 db_create_key(hDB, hKeyRoot, key_name, tid);
05706 status = db_find_link(hDB, hKeyRoot, key_name, &hKey);
05707 }
05708 }
05709 }
05710
05711
05712 if (hKey) {
05713 if (tid == TID_STRING || tid == TID_LINK)
05714 db_set_data(hDB, hKey, data, string_length * n_data,
05715 n_data, tid);
05716 else
05717 db_set_data(hDB, hKey, data, rpc_tid_size(tid) * n_data,
05718 n_data, tid);
05719 }
05720 }
05721 }
05722 }
05723 }
05724 } while (TRUE);
05725
05726 free(data);
05727 return DB_SUCCESS;
05728 }
05729
05730
05731 #ifndef DOXYGEN_SHOULD_SKIP_THIS
05732
05733
05734 void name2c(char *str)
05735
05736
05737
05738
05739
05740
05741
05742 {
05743 if (*str >= '0' && *str <= '9')
05744 *str = '_';
05745
05746 while (*str) {
05747 if (!(*str >= 'a' && *str <= 'z') &&
05748 !(*str >= 'A' && *str <= 'Z') && !(*str >= '0' && *str <= '9'))
05749 *str = '_';
05750 *str = (char) tolower(*str);
05751 str++;
05752 }
05753 }
05754
05755
05756 static void db_save_tree_struct(HNDLE hDB, HNDLE hKey, int hfile,
05757 INT level)
05758
05759
05760
05761
05762
05763
05764
05765
05766 {
05767 INT i, index;
05768 KEY key;
05769 HNDLE hSubkey;
05770 char line[MAX_ODB_PATH], str[MAX_STRING_LENGTH];
05771
05772
05773 for (index = 0;; index++) {
05774 db_enum_key(hDB, hKey, index, &hSubkey);
05775
05776 if (!hSubkey)
05777 break;
05778
05779 db_get_key(hDB, hSubkey, &key);
05780
05781 if (key.type != TID_KEY) {
05782 for (i = 0; i <= level; i++)
05783 write(hfile, " ", 2);
05784
05785 switch (key.type) {
05786 case TID_SBYTE:
05787 case TID_CHAR:
05788 strcpy(line, "char");
05789 break;
05790 case TID_SHORT:
05791 strcpy(line, "short");
05792 break;
05793 case TID_FLOAT:
05794 strcpy(line, "float");
05795 break;
05796 case TID_DOUBLE:
05797 strcpy(line, "double");
05798 break;
05799 case TID_BITFIELD:
05800 strcpy(line, "unsigned char");
05801 break;
05802 case TID_STRING:
05803 strcpy(line, "char");
05804 break;
05805 case TID_LINK:
05806 strcpy(line, "char");
05807 break;
05808 default:
05809 strcpy(line, tid_name[key.type]);
05810 break;
05811 }
05812
05813 strcat(line, " ");
05814 strcpy(str, key.name);
05815 name2c(str);
05816
05817 if (key.num_values > 1)
05818 sprintf(str + strlen(str), "[%d]", key.num_values);
05819 if (key.type == TID_STRING || key.type == TID_LINK)
05820 sprintf(str + strlen(str), "[%d]", key.item_size);
05821
05822 strcpy(line + 10, str);
05823 strcat(line, ";\n");
05824
05825 write(hfile, line, strlen(line));
05826 } else {
05827
05828 for (i = 0; i <= level; i++)
05829 write(hfile, " ", 2);
05830
05831 sprintf(line, "struct {\n");
05832 write(hfile, line, strlen(line));
05833 db_save_tree_struct(hDB, hSubkey, hfile, level + 1);
05834
05835 for (i = 0; i <= level; i++)
05836 write(hfile, " ", 2);
05837
05838 strcpy(str, key.name);
05839 name2c(str);
05840
05841 sprintf(line, "} %s;\n", str);
05842 write(hfile, line, strlen(line));
05843 }
05844 }
05845 }
05846
05847
05848 #endif
05849
05850
05851
05852
05853
05854
05855
05856
05857
05858
05859
05860
05861
05862
05863 INT db_save(HNDLE hDB, HNDLE hKey, char *filename, BOOL bRemote)
05864 {
05865 if (rpc_is_remote() && bRemote)
05866 return rpc_call(RPC_DB_SAVE, hDB, hKey, filename, bRemote);
05867
05868 #ifdef LOCAL_ROUTINES
05869 {
05870 INT hfile, size, buffer_size, n, status;
05871 char *buffer, path[256];
05872
05873
05874 hfile = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT, 0644);
05875 if (hfile == -1) {
05876 cm_msg(MERROR, "db_save", "Cannot open file \"%s\"", filename);
05877 return DB_FILE_ERROR;
05878 }
05879
05880 db_get_path(hDB, hKey, path, sizeof(path));
05881
05882 buffer_size = 10000;
05883 do {
05884 buffer = (char *) malloc(buffer_size);
05885 if (buffer == NULL) {
05886 cm_msg(MERROR, "db_save", "cannot allocate ODB dump buffer");
05887 break;
05888 }
05889
05890 size = buffer_size;
05891 status = db_copy(hDB, hKey, buffer, &size, path);
05892 if (status != DB_TRUNCATED) {
05893 n = write(hfile, buffer, buffer_size - size);
05894 free(buffer);
05895
05896 if (n != buffer_size - size) {
05897 cm_msg(MERROR, "db_save", "cannot save .ODB file");
05898 close(hfile);
05899 return DB_FILE_ERROR;
05900 }
05901 break;
05902 }
05903
05904
05905 free(buffer);
05906 buffer_size *= 2;
05907 } while (1);
05908
05909 close(hfile);
05910
05911 }
05912 #endif
05913
05914 return DB_SUCCESS;
05915 }
05916
05917
05918
05919
05920
05921
05922
05923
05924
05925
05926
05927
05928 INT db_save_struct(HNDLE hDB, HNDLE hKey, char *file_name,
05929 char *struct_name, BOOL append)
05930 {
05931 KEY key;
05932 char str[100], line[100];
05933 INT status, i, fh;
05934
05935
05936 fh = open(file_name, O_WRONLY | O_CREAT | (append ? O_APPEND : O_TRUNC),
05937 0644);
05938
05939 if (fh == -1) {
05940 cm_msg(MERROR, "db_save_struct", "Cannot open file\"%s\"", file_name);
05941 return DB_FILE_ERROR;
05942 }
05943
05944 status = db_get_key(hDB, hKey, &key);
05945 if (status != DB_SUCCESS) {
05946 cm_msg(MERROR, "db_save_struct", "cannot find key");
05947 return DB_INVALID_HANDLE;
05948 }
05949
05950 sprintf(line, "typedef struct {\n");
05951 write(fh, line, strlen(line));
05952 db_save_tree_struct(hDB, hKey, fh, 0);
05953
05954 if (struct_name && struct_name[0])
05955 strcpy(str, struct_name);
05956 else
05957 strcpy(str, key.name);
05958
05959 name2c(str);
05960 for (i = 0; i < (int) strlen(str); i++)
05961 str[i] = (char) toupper(str[i]);
05962
05963 sprintf(line, "} %s;\n\n", str);
05964 write(fh, line, strlen(line));
05965
05966 close(fh);
05967
05968 return DB_SUCCESS;
05969 }
05970
05971
05972 #ifndef DOXYGEN_SHOULD_SKIP_THIS
05973
05974
05975 INT db_save_string(HNDLE hDB, HNDLE hKey, char *file_name,
05976 char *string_name, BOOL append)
05977
05978
05979
05980
05981
05982
05983
05984
05985
05986
05987
05988
05989
05990
05991
05992
05993
05994
05995
05996
05997
05998
05999 {
06000 KEY key;
06001 char str[256], line[256];
06002 INT status, i, size, fh, buffer_size;
06003 char *buffer, *pc;
06004
06005
06006
06007 fh = open(file_name, O_WRONLY | O_CREAT | (append ? O_APPEND : O_TRUNC),
06008 0644);
06009
06010 if (fh == -1) {
06011 cm_msg(MERROR, "db_save_string", "Cannot open file\"%s\"", file_name);
06012 return DB_FILE_ERROR;
06013 }
06014
06015 status = db_get_key(hDB, hKey, &key);
06016 if (status != DB_SUCCESS) {
06017 cm_msg(MERROR, "db_save_string", "cannot find key");
06018 return DB_INVALID_HANDLE;
06019 }
06020
06021 if (string_name && string_name[0])
06022 strcpy(str, string_name);
06023 else
06024 strcpy(str, key.name);
06025
06026 name2c(str);
06027 for (i = 0; i < (int) strlen(str); i++)
06028 str[i] = (char) toupper(str[i]);
06029
06030 sprintf(line, "#define %s(_name) char *_name[] = {\\\n", str);
06031 write(fh, line, strlen(line));
06032
06033 buffer_size = 10000;
06034 do {
06035 buffer = (char *) malloc(buffer_size);
06036 if (buffer == NULL) {
06037 cm_msg(MERROR, "db_save", "cannot allocate ODB dump buffer");
06038 break;
06039 }
06040
06041 size = buffer_size;
06042 status = db_copy(hDB, hKey, buffer, &size, "");
06043 if (status != DB_TRUNCATED)
06044 break;
06045
06046
06047 free(buffer);
06048 buffer_size *= 2;
06049 } while (1);
06050
06051
06052 pc = buffer;
06053
06054 do {
06055 i = 0;
06056 line[i++] = '"';
06057 while (*pc != '\n' && *pc != 0)
06058 line[i++] = *pc++;
06059 strcpy(&line[i], "\",\\\n");
06060 if (i > 0)
06061 write(fh, line, strlen(line));
06062
06063 if (*pc == '\n')
06064 pc++;
06065
06066 } while (*pc);
06067
06068 sprintf(line, "NULL }\n\n");
06069 write(fh, line, strlen(line));
06070
06071 close(fh);
06072 free(buffer);
06073
06074 return DB_SUCCESS;
06075 }
06076
06077
06078 #endif
06079
06080
06081
06082
06083
06084
06085
06086
06087
06088
06089
06090
06091
06092
06093
06094
06095
06096
06097
06098
06099
06100
06101
06102
06103 INT db_sprintf(char *string, void *data, INT data_size, INT index,
06104 DWORD type)
06105 {
06106 if (data_size == 0)
06107 sprintf(string, "<NULL>");
06108 else
06109 switch (type) {
06110 case TID_BYTE:
06111 sprintf(string, "%d", *(((BYTE *) data) + index));
06112 break;
06113 case TID_SBYTE:
06114 sprintf(string, "%d", *(((char *) data) + index));
06115 break;
06116 case TID_CHAR:
06117 sprintf(string, "%c", *(((char *) data) + index));
06118 break;
06119 case TID_WORD:
06120 sprintf(string, "%u", *(((WORD *) data) + index));
06121 break;
06122 case TID_SHORT:
06123 sprintf(string, "%d", *(((short *) data) + index));
06124 break;
06125 case TID_DWORD:
06126 sprintf(string, "%lu", *(((DWORD *) data) + index));
06127 break;
06128 case TID_INT:
06129 sprintf(string, "%d", *(((INT *) data) + index));
06130 break;
06131 case TID_BOOL:
06132 sprintf(string, "%c", *(((BOOL *) data) + index) ? 'y' : 'n');
06133 break;
06134 case TID_FLOAT:
06135 sprintf(string, "%g", *(((float *) data) + index));
06136 break;
06137 case TID_DOUBLE:
06138 sprintf(string, "%lg", *(((double *) data) + index));
06139 break;
06140 case TID_BITFIELD:
06141
06142 break;
06143 case TID_STRING:
06144 case TID_LINK:
06145 sprintf(string, "%s", ((char *) data) + data_size * index);
06146 break;
06147 default:
06148 sprintf(string, "<unknown>");
06149 break;
06150 }
06151
06152 return DB_SUCCESS;
06153 }
06154
06155
06156 #ifndef DOXYGEN_SHOULD_SKIP_THIS
06157
06158
06159 INT db_sprintfh(char *string, void *data, INT data_size, INT index,
06160 DWORD type)
06161
06162
06163
06164
06165
06166
06167
06168
06169
06170
06171
06172
06173
06174
06175
06176
06177
06178
06179
06180
06181 {
06182 if (data_size == 0)
06183 sprintf(string, "<NULL>");
06184 else
06185 switch (type) {
06186 case TID_BYTE:
06187 sprintf(string, "0x%X", *(((BYTE *) data) + index));
06188 break;
06189 case TID_SBYTE:
06190 sprintf(string, "0x%X", *(((char *) data) + index));
06191 break;
06192 case TID_CHAR:
06193 sprintf(string, "%c", *(((char *) data) + index));
06194 break;
06195 case TID_WORD:
06196 sprintf(string, "0x%X", *(((WORD *) data) + index));
06197 break;
06198 case TID_SHORT:
06199 sprintf(string, "0x%hX", *(((short *) data) + index));
06200 break;
06201 case TID_DWORD:
06202 sprintf(string, "0x%lX", *(((DWORD *) data) + index));
06203 break;
06204 case TID_INT:
06205 sprintf(string, "0x%X", *(((INT *) data) + index));
06206 break;
06207 case TID_BOOL:
06208 sprintf(string, "%c", *(((BOOL *) data) + index) ? 'y' : 'n');
06209 break;
06210 case TID_FLOAT:
06211 sprintf(string, "%g", *(((float *) data) + index));
06212 break;
06213 case TID_DOUBLE:
06214 sprintf(string, "%lg", *(((double *) data) + index));
06215 break;
06216 case TID_BITFIELD:
06217
06218 break;
06219 case TID_STRING:
06220 case TID_LINK:
06221 sprintf(string, "%s", ((char *) data) + data_size * index);
06222 break;
06223 default:
06224 sprintf(string, "<unknown>");
06225 break;
06226 }
06227
06228 return DB_SUCCESS;
06229 }
06230
06231
06232 INT db_sscanf(char *data_str, void *data, INT * data_size, INT i,
06233 DWORD tid)
06234
06235
06236
06237
06238
06239
06240
06241
06242
06243
06244
06245
06246
06247
06248
06249
06250
06251
06252
06253 {
06254 DWORD value;
06255 BOOL hex = FALSE;
06256
06257 if (data_str == NULL)
06258 return 0;
06259
06260 *data_size = rpc_tid_size(tid);
06261 if (strncmp(data_str, "0x", 2) == 0) {
06262 hex = TRUE;
06263 sscanf(data_str + 2, "%lx", &value);
06264 }
06265
06266 switch (tid) {
06267 case TID_BYTE:
06268 case TID_SBYTE:
06269 if (hex)
06270 *((char *) data + i) = (char) value;
06271 else
06272 *((char *) data + i) = (char) atoi(data_str);
06273 break;
06274 case TID_CHAR:
06275 *((char *) data + i) = data_str[0];
06276 break;
06277 case TID_WORD:
06278 if (hex)
06279 *((WORD *) data + i) = (WORD) value;
06280 else
06281 *((WORD *) data + i) = (WORD) atoi(data_str);
06282 break;
06283 case TID_SHORT:
06284 if (hex)
06285 *((short int *) data + i) = (short int) value;
06286 else
06287 *((short int *) data + i) = (short int) atoi(data_str);
06288 break;
06289 case TID_DWORD:
06290 if (!hex)
06291 sscanf(data_str, "%lu", &value);
06292
06293 *((DWORD *) data + i) = value;
06294 break;
06295 case TID_INT:
06296 if (hex)
06297 *((INT *) data + i) = value;
06298 else
06299 *((INT *) data + i) = atol(data_str);
06300 break;
06301 case TID_BOOL:
06302 if (data_str[0] == 'y' || data_str[0] == 'Y' || atoi(data_str) > 0)
06303 *((BOOL *) data + i) = 1;
06304 else
06305 *((BOOL *) data + i) = 0;
06306 break;
06307 case TID_FLOAT:
06308 *((float *) data + i) = (float) atof(data_str);
06309 break;
06310 case TID_DOUBLE:
06311 *((double *) data + i) = atof(data_str);
06312 break;
06313 case TID_BITFIELD:
06314
06315 break;
06316 case TID_STRING:
06317 case TID_LINK:
06318 strcpy((char *) data, data_str);
06319 *data_size = strlen(data_str) + 1;
06320 break;
06321 }
06322
06323 return DB_SUCCESS;
06324 }
06325
06326
06327
06328 #ifdef LOCAL_ROUTINES
06329
06330 static void db_recurse_record_tree(HNDLE hDB, HNDLE hKey, void **data,
06331 INT * total_size, INT base_align,
06332 INT * max_align, BOOL bSet,
06333 INT convert_flags)
06334
06335
06336
06337
06338
06339
06340
06341
06342 {
06343 DATABASE_HEADER *pheader;
06344 KEYLIST *pkeylist;
06345 KEY *pkey;
06346 INT size, align, corr, total_size_tmp;
06347
06348
06349 pheader = _database[hDB - 1].database_header;
06350 pkey = (KEY *) ((char *) pheader + hKey);
06351
06352 pkeylist = (KEYLIST *) ((char *) pheader + pkey->data);
06353 if (!pkeylist->first_key)
06354 return;
06355 pkey = (KEY *) ((char *) pheader + pkeylist->first_key);
06356
06357
06358 do {
06359 if (pkey->type != TID_KEY) {
06360
06361 align = 1;
06362
06363 if (rpc_tid_size(pkey->type))
06364 align = rpc_tid_size(pkey->type) < base_align ?
06365 rpc_tid_size(pkey->type) : base_align;
06366
06367 if (max_align && align > *max_align)
06368 *max_align = align;
06369
06370 corr = VALIGN(*total_size, align) - *total_size;
06371 *total_size += corr;
06372 if (data)
06373 *data = (void *) ((char *) (*data) + corr);
06374
06375
06376 size = pkey->item_size * pkey->num_values;
06377
06378 if (data) {
06379 if (bSet) {
06380
06381 if (pkey->access_mode & MODE_WRITE) {
06382 memcpy((char *) pheader + pkey->data, *data,
06383 pkey->item_size * pkey->num_values);
06384
06385
06386 if (convert_flags) {
06387 if (pkey->num_values > 1)
06388 rpc_convert_data((char *) pheader + pkey->data,
06389 pkey->type, RPC_FIXARRAY,
06390 pkey->item_size * pkey->num_values,
06391 convert_flags);
06392 else
06393 rpc_convert_single((char *) pheader + pkey->data,
06394 pkey->type, 0, convert_flags);
06395 }
06396
06397
06398 pkey->last_written = ss_time();
06399
06400
06401 if (pkey->notify_count)
06402 db_notify_clients(hDB, (PTYPE) pkey - (PTYPE) pheader,
06403 FALSE);
06404 }
06405 } else {
06406
06407 if (pkey->access_mode & MODE_READ) {
06408 memcpy(*data, (char *) pheader + pkey->data, pkey->total_size);
06409
06410
06411 if (convert_flags) {
06412 if (pkey->num_values > 1)
06413 rpc_convert_data(*data, pkey->type,
06414 RPC_FIXARRAY | RPC_OUTGOING,
06415 pkey->item_size * pkey->num_values,
06416 convert_flags);
06417 else
06418 rpc_convert_single(*data, pkey->type, RPC_OUTGOING,
06419 convert_flags);
06420 }
06421 }
06422 }
06423
06424 *data = (char *) (*data) + size;
06425 }
06426
06427 *total_size += size;
06428 } else {
06429
06430
06431 align = 1;
06432
06433 total_size_tmp = *total_size;
06434 db_recurse_record_tree(hDB, (PTYPE) pkey - (PTYPE) pheader,
06435 NULL, &total_size_tmp,
06436 base_align, &align, bSet, convert_flags);
06437
06438 if (max_align && align > *max_align)
06439 *max_align = align;
06440
06441 corr = VALIGN(*total_size, align) - *total_size;
06442 *total_size += corr;
06443 if (data)
06444 *data = (void *) ((char *) (*data) + corr);
06445
06446
06447 db_recurse_record_tree(hDB, (PTYPE) pkey - (PTYPE) pheader,
06448 data, total_size,
06449 base_align, NULL, bSet, convert_flags);
06450
06451 corr = VALIGN(*total_size, align) - *total_size;
06452 *total_size += corr;
06453 if (data)
06454 *data = (void *) ((char *) (*data) + corr);
06455
06456 if (bSet && pkey->notify_count)
06457 db_notify_clients(hDB, (PTYPE) pkey - (PTYPE) pheader, FALSE);
06458 }
06459
06460 if (!pkey->next_key)
06461 break;
06462
06463 pkey = (KEY *) ((char *) pheader + pkey->next_key);
06464 } while (TRUE);
06465 }
06466
06467 #endif
06468
06469
06470 #endif
06471
06472
06473
06474
06475
06476
06477
06478
06479
06480
06481
06482
06483
06484
06485 INT db_get_record_size(HNDLE hDB, HNDLE hKey, INT align, INT * buf_size)
06486 {
06487 if (rpc_is_remote()) {
06488 align = ss_get_struct_align();
06489 return rpc_call(RPC_DB_GET_RECORD_SIZE, hDB, hKey, align, buf_size);
06490 }
06491 #ifdef LOCAL_ROUTINES
06492 {
06493 KEY key;
06494 INT status, max_align;
06495
06496 if (!align)
06497 align = ss_get_struct_align();
06498
06499
06500 status = db_get_key(hDB, hKey, &key);
06501 if (status != DB_SUCCESS)
06502 return status;
06503
06504 if (key.type != TID_KEY) {
06505
06506 *buf_size = key.item_size * key.num_values;
06507 return DB_SUCCESS;
06508 }
06509
06510 db_lock_database(hDB);
06511
06512
06513 *buf_size = max_align = 0;
06514 db_recurse_record_tree(hDB, hKey, NULL, buf_size, align, &max_align, 0,
06515 0);
06516
06517
06518 *buf_size = VALIGN(*buf_size, max_align);
06519
06520 db_unlock_database(hDB);
06521 }
06522 #endif
06523
06524 return DB_SUCCESS;
06525 }
06526
06527
06528
06529
06530
06531
06532
06533
06534
06535
06536
06537
06538
06539
06540
06541
06542
06543
06544
06545
06546
06547
06548
06549
06550
06551
06552
06553
06554
06555
06556
06557
06558
06559
06560
06561
06562
06563
06564
06565
06566
06567
06568
06569
06570
06571
06572 INT db_get_record(HNDLE hDB, HNDLE hKey, void *data, INT * buf_size,
06573 INT align)
06574 {
06575 if (rpc_is_remote()) {
06576 align = ss_get_struct_align();
06577 return rpc_call(RPC_DB_GET_RECORD, hDB, hKey, data, buf_size, align);
06578 }
06579 #ifdef LOCAL_ROUTINES
06580 {
06581 KEY key;
06582 INT convert_flags, status;
06583 INT total_size;
06584 void *pdata;
06585 char str[256];
06586
06587 convert_flags = 0;
06588
06589 if (!align)
06590 align = ss_get_struct_align();
06591 else
06592
06593 if (rpc_get_server_option(RPC_OSERVER_TYPE) != ST_REMOTE)
06594 convert_flags = rpc_get_server_option(RPC_CONVERT_FLAGS);
06595
06596
06597 status = db_get_key(hDB, hKey, &key);
06598 if (status != DB_SUCCESS)
06599 return status;
06600
06601 if (key.type != TID_KEY) {
06602
06603 if (key.item_size * key.num_values != *buf_size) {
06604 cm_msg(MERROR, "db_get_record", "struct size mismatch for \"%s\"",
06605 key.name);
06606 return DB_STRUCT_SIZE_MISMATCH;
06607 }
06608
06609 db_get_data(hDB, hKey, data, buf_size, key.type);
06610
06611 if (convert_flags) {
06612 if (key.num_values > 1)
06613 rpc_convert_data(data, key.type, RPC_OUTGOING | RPC_FIXARRAY,
06614 key.item_size * key.num_values, convert_flags);
06615 else
06616 rpc_convert_single(data, key.type, RPC_OUTGOING, convert_flags);
06617 }
06618
06619 return DB_SUCCESS;
06620 }
06621
06622
06623 db_get_record_size(hDB, hKey, 0, &total_size);
06624 if (total_size != *buf_size) {
06625 db_get_path(hDB, hKey, str, sizeof(str));
06626 cm_msg(MERROR, "db_get_record",
06627 "struct size mismatch for \"%s\" (%d instead of %d)", str,
06628 *buf_size, total_size);
06629 return DB_STRUCT_SIZE_MISMATCH;
06630 }
06631
06632
06633 pdata = data;
06634 total_size = 0;
06635
06636 db_lock_database(hDB);
06637 db_recurse_record_tree(hDB, hKey, &pdata, &total_size, align,
06638 NULL, FALSE, convert_flags);
06639 db_unlock_database(hDB);
06640
06641 }
06642 #endif
06643
06644 return DB_SUCCESS;
06645 }
06646
06647
06648
06649
06650
06651
06652
06653
06654
06655
06656
06657
06658
06659
06660
06661
06662
06663
06664
06665
06666
06667
06668
06669
06670
06671
06672
06673
06674
06675
06676
06677 INT db_set_record(HNDLE hDB, HNDLE hKey, void *data, INT buf_size,
06678 INT align)
06679 {
06680 if (rpc_is_remote()) {
06681 align = ss_get_struct_align();
06682 return rpc_call(RPC_DB_SET_RECORD, hDB, hKey, data, buf_size, align);
06683 }
06684 #ifdef LOCAL_ROUTINES
06685 {
06686 KEY key;
06687 INT convert_flags;
06688 INT total_size;
06689 void *pdata;
06690
06691 convert_flags = 0;
06692
06693 if (!align)
06694 align = ss_get_struct_align();
06695 else
06696
06697 if (rpc_get_server_option(RPC_OSERVER_TYPE) != ST_REMOTE)
06698 convert_flags = rpc_get_server_option(RPC_CONVERT_FLAGS);
06699
06700
06701 db_get_key(hDB, hKey, &key);
06702 if (key.type != TID_KEY) {
06703
06704 if (key.item_size * key.num_values != buf_size) {
06705 cm_msg(MERROR, "db_set_record", "struct size mismatch for \"%s\"",
06706 key.name);
06707 return DB_STRUCT_SIZE_MISMATCH;
06708 }
06709
06710 if (convert_flags) {
06711 if (key.num_values > 1)
06712 rpc_convert_data(data, key.type, RPC_FIXARRAY,
06713 key.item_size * key.num_values, convert_flags);
06714 else
06715 rpc_convert_single(data, key.type, 0, convert_flags);
06716 }
06717
06718 db_set_data(hDB, hKey, data, key.total_size, key.num_values,
06719 key.type);
06720 return DB_SUCCESS;
06721 }
06722
06723
06724 db_get_record_size(hDB, hKey, 0, &total_size);
06725 if (total_size != buf_size) {
06726 cm_msg(MERROR, "db_set_record", "struct size mismatch for \"%s\"",
06727 key.name);
06728 return DB_STRUCT_SIZE_MISMATCH;
06729 }
06730
06731
06732 pdata = data;
06733 total_size = 0;
06734
06735 db_lock_database(hDB);
06736 db_recurse_record_tree(hDB, hKey, &pdata, &total_size, align,
06737 NULL, TRUE, convert_flags);
06738 db_notify_clients(hDB, hKey, TRUE);
06739 db_unlock_database(hDB);
06740 }
06741 #endif
06742
06743 return DB_SUCCESS;
06744 }
06745
06746
06747 #ifndef DOXYGEN_SHOULD_SKIP_THIS
06748
06749
06750 INT db_add_open_record(HNDLE hDB, HNDLE hKey, WORD access_mode)
06751
06752
06753
06754
06755
06756
06757
06758 {
06759 if (rpc_is_remote())
06760 return rpc_call(RPC_DB_ADD_OPEN_RECORD, hDB, hKey, access_mode);
06761
06762 #ifdef LOCAL_ROUTINES
06763 {
06764 DATABASE_HEADER *pheader;
06765 DATABASE_CLIENT *pclient;
06766 KEY *pkey;
06767 INT i;
06768
06769
06770 db_lock_database(hDB);
06771
06772 pheader = _database[hDB - 1].database_header;
06773 pclient = &pheader->client[_database[hDB - 1].client_index];
06774
06775
06776 for (i = 0; i < pclient->max_index; i++)
06777 if (pclient->open_record[i].handle == hKey)
06778 break;
06779
06780 if (i < pclient->max_index) {
06781 db_unlock_database(hDB);
06782 return DB_SUCCESS;
06783 }
06784
06785
06786 for (i = 0; i < pclient->max_index; i++)
06787 if (pclient->open_record[i].handle == 0)
06788 break;
06789
06790
06791 if (i == MAX_OPEN_RECORDS) {
06792 db_unlock_database(hDB);
06793 return DB_NO_MEMORY;
06794 }
06795
06796 if (i == pclient->max_index)
06797 pclient->max_index++;
06798
06799 pclient->open_record[i].handle = hKey;
06800 pclient->open_record[i].access_mode = access_mode;
06801
06802
06803 pkey = (KEY *) ((char *) pheader + hKey);
06804
06805
06806 if (!db_validate_hkey(pheader, hKey)) {
06807 db_unlock_database(hDB);
06808 return DB_INVALID_HANDLE;
06809 }
06810
06811 pkey->notify_count++;
06812
06813 pclient->num_open_records++;
06814
06815
06816 if (access_mode & MODE_WRITE)
06817 db_set_mode(hDB, hKey, (WORD) (pkey->access_mode | MODE_EXCLUSIVE),
06818 2);
06819
06820 db_unlock_database(hDB);
06821 }
06822 #endif
06823
06824 return DB_SUCCESS;
06825 }
06826
06827
06828 INT db_remove_open_record(HNDLE hDB, HNDLE hKey, BOOL lock)
06829
06830
06831
06832
06833
06834
06835
06836 {
06837 if (rpc_is_remote())
06838 return rpc_call(RPC_DB_REMOVE_OPEN_RECORD, hDB, hKey);
06839
06840 #ifdef LOCAL_ROUTINES
06841 {
06842 DATABASE_HEADER *pheader;
06843 DATABASE_CLIENT *pclient;
06844 KEY *pkey;
06845 INT i, index;
06846
06847 if (lock)
06848 db_lock_database(hDB);
06849
06850 pheader = _database[hDB - 1].database_header;
06851 pclient = &pheader->client[_database[hDB - 1].client_index];
06852
06853
06854 for (index = 0; index < pclient->max_index; index++)
06855 if (pclient->open_record[index].handle == hKey)
06856 break;
06857
06858 if (index == pclient->max_index) {
06859 if (lock)
06860 db_unlock_database(hDB);
06861
06862 return DB_INVALID_HANDLE;
06863 }
06864
06865
06866 pkey = (KEY *) ((char *) pheader + hKey);
06867
06868 if (pkey->notify_count > 0)
06869 pkey->notify_count--;
06870
06871 pclient->num_open_records--;
06872
06873
06874 if (pclient->open_record[index].access_mode & MODE_WRITE)
06875 db_set_mode(hDB, hKey, (WORD) (pkey->access_mode & ~MODE_EXCLUSIVE),
06876 2);
06877
06878 memset(&pclient->open_record[index], 0, sizeof(OPEN_RECORD));
06879
06880
06881 for (i = pclient->max_index - 1; i >= 0; i--)
06882 if (pclient->open_record[i].handle != 0)
06883 break;
06884 pclient->max_index = i + 1;
06885
06886 if (lock)
06887 db_unlock_database(hDB);
06888 }
06889 #endif
06890
06891 return DB_SUCCESS;
06892 }
06893
06894
06895
06896 #ifdef LOCAL_ROUTINES
06897
06898 INT db_notify_clients(HNDLE hDB, HNDLE hKey, BOOL bWalk)
06899
06900
06901
06902
06903
06904
06905
06906 {
06907 DATABASE_HEADER *pheader;
06908 DATABASE_CLIENT *pclient;
06909 KEY *pkey;
06910 KEYLIST *pkeylist;
06911 INT i, j;
06912 char str[80];
06913
06914 pheader = _database[hDB - 1].database_header;
06915
06916
06917 pkey = (KEY *) ((char *) pheader + hKey);
06918
06919 do {
06920
06921
06922 if (pkey->notify_count)
06923 for (i = 0; i < pheader->max_client_index; i++) {
06924 pclient = &pheader->client[i];
06925 for (j = 0; j < pclient->max_index; j++)
06926 if (pclient->open_record[j].handle == hKey) {
06927
06928 sprintf(str, "O %d %d", hDB, hKey);
06929 ss_resume(pclient->port, str);
06930 }
06931 }
06932
06933 if (pkey->parent_keylist == 0 || !bWalk)
06934 return DB_SUCCESS;
06935
06936 pkeylist = (KEYLIST *) ((char *) pheader + pkey->parent_keylist);
06937 pkey = (KEY *) ((char *) pheader + pkeylist->parent);
06938 hKey = (PTYPE) pkey - (PTYPE) pheader;
06939 } while (TRUE);
06940
06941 }
06942
06943 #endif
06944
06945
06946 void merge_records(HNDLE hDB, HNDLE hKey, KEY * pkey, INT level,
06947 void *info)
06948 {
06949 char full_name[256], buffer[10000];
06950 INT status, size;
06951 HNDLE hKeyInit;
06952 KEY initkey, key;
06953
06954
06955 db_get_path(hDB, hKey, full_name, 256);
06956 *strchr(full_name, 'O') = 'I';
06957
06958
06959 status = db_find_key(hDB, 0, full_name, &hKeyInit);
06960 if (status == DB_SUCCESS) {
06961 status = db_get_key(hDB, hKeyInit, &initkey);
06962 assert(status == DB_SUCCESS);
06963 status = db_get_key(hDB, hKey, &key);
06964 assert(status == DB_SUCCESS);
06965
06966 if (initkey.type != TID_KEY && initkey.type == key.type) {
06967
06968 size = sizeof(buffer);
06969 status = db_get_data(hDB, hKey, buffer, &size, initkey.type);
06970 assert(status == DB_SUCCESS);
06971 status =
06972 db_set_data(hDB, hKeyInit, buffer, initkey.total_size,
06973 initkey.num_values, initkey.type);
06974 assert(status == DB_SUCCESS);
06975 }
06976 } else if (status == DB_NO_KEY) {
06977
06978 } else {
06979 cm_msg(MERROR, "merge_records",
06980 "aborting on unexpected failure of db_find_key(%s), status %d",
06981 full_name, status);
06982 abort();
06983 }
06984 }
06985
06986 static int open_count;
06987
06988 void check_open_keys(HNDLE hDB, HNDLE hKey, KEY * pkey, INT level,
06989 void *info)
06990 {
06991 if (pkey->notify_count)
06992 open_count++;
06993 }
06994
06995
06996 #endif
06997
06998
06999
07000
07001
07002
07003
07004
07005
07006
07007
07008
07009
07010
07011
07012
07013
07014
07015
07016
07017
07018
07019
07020
07021
07022
07023
07024
07025
07026
07027
07028
07029
07030
07031
07032
07033
07034
07035
07036
07037
07038
07039
07040
07041
07042
07043
07044
07045
07046
07047
07048
07049
07050
07051
07052
07053
07054
07055 INT db_create_record(HNDLE hDB, HNDLE hKey, char *orig_key_name,
07056 char *init_str)
07057 {
07058 char str[256], key_name[256], *buffer;
07059 INT status, size, i, buffer_size;
07060 HNDLE hKeyTmp, hKeyTmpO, hKeyOrig, hSubkey;
07061
07062 if (rpc_is_remote())
07063 return rpc_call(RPC_DB_CREATE_RECORD, hDB, hKey, orig_key_name,
07064 init_str);
07065
07066
07067 db_lock_database(hDB);
07068
07069
07070 strlcpy(key_name, orig_key_name, sizeof(key_name));
07071 if (strlen(key_name) > 1 && key_name[strlen(key_name) - 1] == '/')
07072 key_name[strlen(key_name) - 1] = 0;
07073
07074
07075 status = db_find_key(hDB, hKey, key_name, &hKeyOrig);
07076 if (status == DB_SUCCESS) {
07077 assert(hKeyOrig != 0);
07078
07079 open_count = 0;
07080 db_scan_tree_link(hDB, hKeyOrig, 0, check_open_keys, NULL);
07081 if (open_count) {
07082 db_unlock_database(hDB);
07083 return DB_OPEN_RECORD;
07084 }
07085
07086
07087 sprintf(str, "/System/Tmp/%1dI", ss_gettid());
07088 db_find_key(hDB, 0, str, &hKeyTmp);
07089 if (hKeyTmp)
07090 db_delete_key(hDB, hKeyTmp, FALSE);
07091 db_create_key(hDB, 0, str, TID_KEY);
07092 status = db_find_key(hDB, 0, str, &hKeyTmp);
07093 if (status != DB_SUCCESS) {
07094 db_unlock_database(hDB);
07095 return status;
07096 }
07097
07098 sprintf(str, "/System/Tmp/%1dO", ss_gettid());
07099 db_find_key(hDB, 0, str, &hKeyTmpO);
07100 if (hKeyTmpO)
07101 db_delete_key(hDB, hKeyTmpO, FALSE);
07102 db_create_key(hDB, 0, str, TID_KEY);
07103 status = db_find_key(hDB, 0, str, &hKeyTmpO);
07104 if (status != DB_SUCCESS) {
07105 db_unlock_database(hDB);
07106 return status;
07107 }
07108
07109 status = db_paste(hDB, hKeyTmp, init_str);
07110 if (status != DB_SUCCESS) {
07111 db_unlock_database(hDB);
07112 return status;
07113 }
07114
07115 buffer_size = 10000;
07116 buffer = (char *) malloc(buffer_size);
07117 do {
07118 size = buffer_size;
07119 status = db_copy(hDB, hKeyOrig, buffer, &size, "");
07120 if (status == DB_TRUNCATED) {
07121 buffer_size += 10000;
07122 buffer = (char *) realloc(buffer, buffer_size);
07123 continue;
07124 }
07125 if (status != DB_SUCCESS) {
07126 db_unlock_database(hDB);
07127 return status;
07128 }
07129
07130 } while (status != DB_SUCCESS);
07131
07132 status = db_paste(hDB, hKeyTmpO, buffer);
07133 if (status != DB_SUCCESS) {
07134 free(buffer);
07135 db_unlock_database(hDB);
07136 return status;
07137 }
07138
07139
07140 db_scan_tree_link(hDB, hKeyTmpO, 0, merge_records, NULL);
07141
07142
07143 for (i = 0;; i++) {
07144 db_enum_link(hDB, hKeyOrig, 0, &hSubkey);
07145 if (!hSubkey)
07146 break;
07147
07148 status = db_delete_key(hDB, hSubkey, FALSE);
07149 if (status != DB_SUCCESS) {
07150 free(buffer);
07151 db_unlock_database(hDB);
07152 return status;
07153 }
07154 }
07155
07156
07157 do {
07158 size = buffer_size;
07159 status = db_copy(hDB, hKeyTmp, buffer, &size, "");
07160 if (status == DB_TRUNCATED) {
07161 buffer_size += 10000;
07162 buffer = (char *) realloc(buffer, buffer_size);
07163 continue;
07164 }
07165 if (status != DB_SUCCESS) {
07166 free(buffer);
07167 db_unlock_database(hDB);
07168 return status;
07169 }
07170
07171 } while (status != DB_SUCCESS);
07172
07173 status = db_paste(hDB, hKeyOrig, buffer);
07174 if (status != DB_SUCCESS) {
07175 free(buffer);
07176 db_unlock_database(hDB);
07177 return status;
07178 }
07179
07180
07181 db_delete_key(hDB, hKeyTmp, FALSE);
07182 db_delete_key(hDB, hKeyTmpO, FALSE);
07183
07184 free(buffer);
07185 } else if (status == DB_NO_KEY) {
07186
07187 db_create_key(hDB, hKey, key_name, TID_KEY);
07188 status = db_find_key(hDB, hKey, key_name, &hKeyTmp);
07189 if (status != DB_SUCCESS) {
07190 db_unlock_database(hDB);
07191 return status;
07192 }
07193
07194 status = db_paste(hDB, hKeyTmp, init_str);
07195 if (status != DB_SUCCESS) {
07196 db_unlock_database(hDB);
07197 return status;
07198 }
07199 } else {
07200 cm_msg(MERROR, "db_create_record",
07201 "aborting on unexpected failure of db_find_key(%s), status %d",
07202 key_name, status);
07203 abort();
07204 }
07205
07206 db_unlock_database(hDB);
07207
07208 return DB_SUCCESS;
07209 }
07210
07211
07212
07213
07214
07215
07216
07217
07218
07219
07220
07221
07222
07223
07224
07225
07226
07227 INT db_check_record(HNDLE hDB, HNDLE hKey, char *keyname, char *rec_str,
07228 BOOL correct)
07229 {
07230 char line[MAX_STRING_LENGTH];
07231 char title[MAX_STRING_LENGTH];
07232 char key_name[MAX_STRING_LENGTH];
07233 char info_str[MAX_STRING_LENGTH + 50];
07234 char *pc, *pold, *rec_str_orig;
07235 DWORD tid;
07236 INT i, j, n_data, string_length, status;
07237 HNDLE hKeyRoot, hKeyTest;
07238 KEY key;
07239 BOOL multi_line;
07240
07241 if (rpc_is_remote())
07242 return rpc_call(RPC_DB_CHECK_RECORD, hDB, hKey, keyname, rec_str,
07243 correct);
07244
07245
07246 status = db_find_key(hDB, hKey, keyname, &hKeyRoot);
07247
07248
07249 if (status == DB_NO_KEY)
07250 return db_create_record(hDB, hKey, keyname, rec_str);
07251
07252 assert(hKeyRoot);
07253
07254 title[0] = 0;
07255 multi_line = FALSE;
07256 rec_str_orig = rec_str;
07257
07258 db_get_key(hDB, hKeyRoot, &key);
07259 if (key.type == TID_KEY)
07260
07261 db_get_next_link(hDB, hKeyRoot, &hKeyTest);
07262 else
07263
07264 hKeyTest = hKeyRoot;
07265
07266 if (hKeyTest == 0 && *rec_str != 0) {
07267 if (correct)
07268 return db_create_record(hDB, hKey, keyname, rec_str_orig);
07269
07270 return DB_STRUCT_MISMATCH;
07271 }
07272
07273 do {
07274 if (*rec_str == 0)
07275 break;
07276
07277 for (i = 0; *rec_str != '\n' && *rec_str && i < MAX_STRING_LENGTH; i++)
07278 line[i] = *rec_str++;
07279
07280 if (i == MAX_STRING_LENGTH) {
07281 cm_msg(MERROR, "db_check_record", "line too long");
07282 return DB_TRUNCATED;
07283 }
07284
07285 line[i] = 0;
07286 if (*rec_str == '\n')
07287 rec_str++;
07288
07289
07290 if (line[0] == '[') {
07291
07292 strcpy(title, line + 1);
07293 if (strchr(title, ']'))
07294 *strchr(title, ']') = 0;
07295 if (title[0] && title[strlen(title) - 1] != '/')
07296 strcat(title, "/");
07297 } else {
07298
07299 if (strchr(line, '=') && line[0] != ';') {
07300
07301 pc = strchr(line, '=') + 1;
07302 while (*pc == ' ')
07303 pc++;
07304 strcpy(info_str, pc);
07305
07306
07307 *strchr(line, '=') = 0;
07308
07309 pc = &line[strlen(line) - 1];
07310 while (*pc == ' ')
07311 *pc-- = 0;
07312
07313 key_name[0] = 0;
07314 if (title[0] != '.')
07315 strcpy(key_name, title);
07316
07317 strcat(key_name, line);
07318
07319
07320 strcpy(line, info_str);
07321 if (strchr(line, ' '))
07322 *strchr(line, ' ') = 0;
07323
07324 n_data = 1;
07325 if (strchr(line, '[')) {
07326 n_data = atol(strchr(line, '[') + 1);
07327 *strchr(line, '[') = 0;
07328 }
07329
07330 for (tid = 0; tid < TID_LAST; tid++)
07331 if (strcmp(tid_name[tid], line) == 0)
07332 break;
07333
07334 string_length = 0;
07335
07336 if (tid == TID_LAST)
07337 cm_msg(MERROR, "db_check_record",
07338 "found unknown data type \"%s\" in ODB file", line);
07339 else {
07340
07341 pc = info_str;
07342 while (*pc != ' ' && *pc)
07343 pc++;
07344 while ((*pc == ' ' || *pc == ':') && *pc)
07345 pc++;
07346
07347 if (n_data > 1) {
07348 info_str[0] = 0;
07349 if (!*rec_str)
07350 break;
07351
07352 for (j = 0; *rec_str != '\n' && *rec_str; j++)
07353 info_str[j] = *rec_str++;
07354 info_str[j] = 0;
07355 if (*rec_str == '\n')
07356 rec_str++;
07357 }
07358
07359 for (i = 0; i < n_data; i++) {
07360
07361 pc = &info_str[strlen(info_str) - 1];
07362 while (*pc == '\n' || *pc == '\r')
07363 *pc-- = 0;
07364
07365 if (tid == TID_STRING || tid == TID_LINK) {
07366 if (!string_length) {
07367 if (info_str[1] == '=')
07368 string_length = -1;
07369 else
07370 string_length = atoi(info_str + 1);
07371 if (string_length > MAX_STRING_LENGTH) {
07372 string_length = MAX_STRING_LENGTH;
07373 cm_msg(MERROR, "db_check_record",
07374 "found string exceeding MAX_STRING_LENGTH");
07375 }
07376 }
07377
07378 if (string_length == -1) {
07379
07380 if (strstr(rec_str, "\n====#$@$#====\n") != NULL) {
07381 string_length =
07382 (PTYPE) strstr(rec_str,
07383 "\n====#$@$#====\n") -
07384 (PTYPE) rec_str + 1;
07385
07386 rec_str =
07387 strstr(rec_str,
07388 "\n====#$@$#====\n") +
07389 strlen("\n====#$@$#====\n");
07390 } else
07391 cm_msg(MERROR, "db_check_record",
07392 "found multi-line string without termination sequence");
07393 } else {
07394 pc = info_str + 2;
07395 while (*pc && *pc != ' ')
07396 pc++;
07397 while (*pc && *pc == ' ')
07398 pc++;
07399
07400
07401 *(pc + string_length - 1) = 0;
07402 }
07403 } else {
07404 pc = info_str;
07405
07406 if (n_data > 1 && info_str[0] == '[') {
07407 pc = strchr(info_str, ']') + 1;
07408 while (*pc && *pc == ' ')
07409 pc++;
07410 }
07411 }
07412
07413 if (i < n_data - 1) {
07414 info_str[0] = 0;
07415 if (!*rec_str)
07416 break;
07417
07418 pold = rec_str;
07419
07420 for (j = 0; *rec_str != '\n' && *rec_str; j++)
07421 info_str[j] = *rec_str++;
07422 info_str[j] = 0;
07423 if (*rec_str == '\n')
07424 rec_str++;
07425
07426
07427 if (tid != TID_STRING && tid != TID_LINK) {
07428 if (info_str[0] == 0 ||
07429 (strchr(info_str, '=') && strchr(info_str, ':')))
07430 rec_str = pold;
07431 }
07432 }
07433 }
07434
07435
07436 if (!hKeyTest) {
07437 if (correct)
07438 return db_create_record(hDB, hKey, keyname, rec_str_orig);
07439
07440 return DB_STRUCT_MISMATCH;
07441 }
07442
07443 status = db_get_key(hDB, hKeyTest, &key);
07444 assert(status == DB_SUCCESS);
07445
07446
07447 if (!equal_ustring(key.name, key_name) ||
07448 key.type != tid || key.num_values != n_data) {
07449 if (correct)
07450 return db_create_record(hDB, hKey, keyname, rec_str_orig);
07451
07452 return DB_STRUCT_MISMATCH;
07453 }
07454
07455
07456 db_get_next_link(hDB, hKeyTest, &hKeyTest);
07457 }
07458 }
07459 }
07460 } while (TRUE);
07461
07462 return DB_SUCCESS;
07463 }
07464
07465
07466
07467
07468
07469
07470
07471
07472
07473
07474
07475
07476
07477
07478
07479
07480
07481
07482
07483
07484
07485
07486
07487
07488
07489
07490
07491
07492
07493
07494
07495
07496
07497
07498
07499
07500
07501
07502
07503
07504
07505
07506
07507
07508
07509
07510
07511
07512
07513
07514
07515
07516
07517
07518
07519
07520
07521
07522
07523
07524
07525
07526
07527
07528
07529
07530
07531
07532
07533
07534
07535
07536 INT db_open_record(HNDLE hDB, HNDLE hKey, void *ptr, INT rec_size,
07537 WORD access_mode, void (*dispatcher) (INT, INT, void *),
07538 void *info)
07539 {
07540 INT index, status, size;
07541 KEY key;
07542 void *data;
07543 char str[256];
07544
07545
07546 if (_record_list_entries == 0) {
07547 _record_list = (RECORD_LIST *) malloc(sizeof(RECORD_LIST));
07548 memset(_record_list, 0, sizeof(RECORD_LIST));
07549 if (_record_list == NULL) {
07550 cm_msg(MERROR, "db_open_record", "not enough memory");
07551 return DB_NO_MEMORY;
07552 }
07553
07554 _record_list_entries = 1;
07555 index = 0;
07556 } else {
07557
07558 for (index = 0; index < _record_list_entries; index++)
07559 if (!_record_list[index].handle)
07560 break;
07561
07562
07563 if (index == _record_list_entries) {
07564 _record_list = (RECORD_LIST *) realloc(_record_list,
07565 sizeof(RECORD_LIST) *
07566 (_record_list_entries + 1));
07567 if (_record_list == NULL) {
07568 cm_msg(MERROR, "db_open_record", "not enough memory");
07569 return DB_NO_MEMORY;
07570 }
07571
07572 memset(&_record_list[_record_list_entries], 0, sizeof(RECORD_LIST));
07573
07574 _record_list_entries++;
07575 }
07576 }
07577
07578 db_get_key(hDB, hKey, &key);
07579
07580
07581 status = db_get_record_size(hDB, hKey, 0, &size);
07582 if (status != DB_SUCCESS) {
07583 _record_list_entries--;
07584 cm_msg(MERROR, "db_open_record", "cannot get record size");
07585 return DB_NO_MEMORY;
07586 }
07587 if (size != rec_size && ptr != NULL) {
07588 _record_list_entries--;
07589 db_get_path(hDB, hKey, str, sizeof(str));
07590 cm_msg(MERROR, "db_open_record",
07591 "struct size mismatch for \"%s\" (%d instead of %d)", str,
07592 rec_size, size);
07593 return DB_STRUCT_SIZE_MISMATCH;
07594 }
07595
07596
07597 if (((key.access_mode & MODE_EXCLUSIVE) && (access_mode & MODE_WRITE)) ||
07598 (!(key.access_mode & MODE_WRITE) && (access_mode & MODE_WRITE)) ||
07599 (!(key.access_mode & MODE_READ) && (access_mode & MODE_READ))) {
07600 _record_list_entries--;
07601 return DB_NO_ACCESS;
07602 }
07603
07604 if (access_mode & MODE_ALLOC) {
07605 data = malloc(size);
07606 memset(data, 0, size);
07607
07608 if (data == NULL) {
07609 _record_list_entries--;
07610 cm_msg(MERROR, "db_open_record", "not enough memory");
07611 return DB_NO_MEMORY;
07612 }
07613
07614 *((void **) ptr) = data;
07615 } else
07616 data = ptr;
07617
07618
07619 if (access_mode & MODE_READ && data != NULL) {
07620 status = db_get_record(hDB, hKey, data, &size, 0);
07621 if (status != DB_SUCCESS) {
07622 _record_list_entries--;
07623 cm_msg(MERROR, "db_open_record", "cannot get record");
07624 return DB_NO_MEMORY;
07625 }
07626 }
07627
07628
07629 if (access_mode & MODE_WRITE) {
07630
07631 if ((access_mode & MODE_ALLOC) == 0) {
07632 status = db_set_record(hDB, hKey, data, size, 0);
07633 if (status != DB_SUCCESS) {
07634 _record_list_entries--;
07635 cm_msg(MERROR, "db_open_record", "cannot set record");
07636 return DB_NO_MEMORY;
07637 }
07638 }
07639
07640
07641 _record_list[index].copy = malloc(size);
07642 if (_record_list[index].copy == NULL) {
07643 cm_msg(MERROR, "db_open_record", "not enough memory");
07644 return DB_NO_MEMORY;
07645 }
07646
07647 memcpy(_record_list[index].copy, data, size);
07648 }
07649
07650
07651 _record_list[index].handle = hKey;
07652 _record_list[index].hDB = hDB;
07653 _record_list[index].access_mode = access_mode;
07654 _record_list[index].data = data;
07655 _record_list[index].buf_size = size;
07656 _record_list[index].dispatcher = dispatcher;
07657 _record_list[index].info = info;
07658
07659
07660 db_add_open_record(hDB, hKey, (WORD) (access_mode & ~MODE_ALLOC));
07661
07662 return DB_SUCCESS;
07663 }
07664
07665
07666
07667
07668
07669
07670
07671
07672 INT db_close_record(HNDLE hDB, HNDLE hKey)
07673 {
07674 #ifdef LOCAL_ROUTINES
07675 {
07676 INT i;
07677
07678 for (i = 0; i < _record_list_entries; i++)
07679 if (_record_list[i].handle == hKey && _record_list[i].hDB == hDB)
07680 break;
07681
07682 if (i == _record_list_entries)
07683 return DB_INVALID_HANDLE;
07684
07685
07686 db_remove_open_record(hDB, hKey, TRUE);
07687
07688
07689 if (_record_list[i].access_mode & MODE_ALLOC)
07690 free(_record_list[i].data);
07691
07692 if (_record_list[i].access_mode & MODE_WRITE)
07693 free(_record_list[i].copy);
07694
07695 memset(&_record_list[i], 0, sizeof(RECORD_LIST));
07696 }
07697 #endif
07698
07699 return DB_SUCCESS;
07700 }
07701
07702
07703
07704
07705
07706
07707
07708
07709 INT db_close_all_records()
07710 {
07711 INT i;
07712
07713 for (i = 0; i < _record_list_entries; i++) {
07714 if (_record_list[i].handle) {
07715 if (_record_list[i].access_mode & MODE_WRITE)
07716 free(_record_list[i].copy);
07717
07718 if (_record_list[i].access_mode & MODE_ALLOC)
07719 free(_record_list[i].data);
07720
07721 memset(&_record_list[i], 0, sizeof(RECORD_LIST));
07722 }
07723 }
07724
07725 if (_record_list_entries > 0) {
07726 _record_list_entries = 0;
07727 free(_record_list);
07728 }
07729
07730 return DB_SUCCESS;
07731 }
07732
07733
07734
07735
07736
07737
07738
07739
07740
07741
07742
07743
07744 INT db_update_record(INT hDB, INT hKey, int socket)
07745 {
07746 INT i, size, convert_flags, status;
07747 char buffer[32];
07748 NET_COMMAND *nc;
07749
07750
07751 if (socket) {
07752 convert_flags = rpc_get_server_option(RPC_CONVERT_FLAGS);
07753
07754 if (convert_flags & CF_ASCII) {
07755 sprintf(buffer, "MSG_ODB&%d&%d", hDB, hKey);
07756 send_tcp(socket, buffer, strlen(buffer) + 1, 0);
07757 } else {
07758 nc = (NET_COMMAND *) buffer;
07759
07760 nc->header.routine_id = MSG_ODB;
07761 nc->header.param_size = 2 * sizeof(INT);
07762 *((INT *) nc->param) = hDB;
07763 *((INT *) nc->param + 1) = hKey;
07764
07765 if (convert_flags) {
07766 rpc_convert_single(&nc->header.routine_id, TID_DWORD,
07767 RPC_OUTGOING, convert_flags);
07768 rpc_convert_single(&nc->header.param_size, TID_DWORD,
07769 RPC_OUTGOING, convert_flags);
07770 rpc_convert_single(&nc->param[0], TID_DWORD,
07771 RPC_OUTGOING, convert_flags);
07772 rpc_convert_single(&nc->param[4], TID_DWORD,
07773 RPC_OUTGOING, convert_flags);
07774 }
07775
07776
07777 send_tcp(socket, buffer,
07778 sizeof(NET_COMMAND_HEADER) + 2 * sizeof(INT), 0);
07779 }
07780
07781 return DB_SUCCESS;
07782 }
07783
07784 status = DB_INVALID_HANDLE;
07785
07786
07787 for (i = 0; i < _record_list_entries; i++)
07788 if (_record_list[i].handle == hKey) {
07789 status = DB_SUCCESS;
07790
07791
07792 if ((_record_list[i].access_mode & MODE_WRITE) == 0) {
07793 size = _record_list[i].buf_size;
07794 if (_record_list[i].data != NULL)
07795 db_get_record(hDB, hKey, _record_list[i].data, &size, 0);
07796
07797
07798 if (_record_list[i].dispatcher)
07799 _record_list[i].dispatcher(hDB, hKey, _record_list[i].info);
07800 }
07801 }
07802
07803 return DB_SUCCESS;
07804 }
07805
07806
07807
07808
07809
07810
07811
07812
07813
07814
07815
07816
07817
07818
07819
07820
07821
07822
07823
07824
07825
07826
07827
07828
07829
07830
07831
07832
07833
07834
07835
07836
07837
07838
07839
07840
07841
07842
07843
07844
07845
07846
07847
07848
07849
07850
07851
07852
07853
07854
07855
07856
07857
07858
07859
07860
07861
07862
07863
07864
07865
07866
07867
07868
07869
07870
07871
07872
07873
07874
07875
07876
07877
07878
07879
07880
07881
07882
07883
07884
07885
07886
07887
07888
07889
07890
07891
07892
07893
07894
07895
07896
07897
07898
07899
07900
07901
07902
07903
07904
07905
07906
07907
07908
07909
07910
07911
07912
07913
07914
07915
07916
07917
07918
07919
07920
07921
07922
07923
07924
07925
07926
07927
07928
07929
07930
07931
07932
07933
07934
07935
07936
07937
07938
07939
07940
07941
07942
07943
07944
07945
07946
07947
07948
07949
07950
07951
07952
07953
07954
07955 INT db_send_changed_records()
07956 {
07957 INT i;
07958
07959 for (i = 0; i < _record_list_entries; i++)
07960 if (_record_list[i].access_mode & MODE_WRITE) {
07961 if (memcmp
07962 (_record_list[i].copy, _record_list[i].data,
07963 _record_list[i].buf_size) != 0) {
07964
07965 if (rpc_is_remote())
07966 rpc_set_option(-1, RPC_OTRANSPORT, RPC_FTCP);
07967 db_set_record(_record_list[i].hDB,
07968 _record_list[i].handle,
07969 _record_list[i].data, _record_list[i].buf_size, 0);
07970 if (rpc_is_remote())
07971 rpc_set_option(-1, RPC_OTRANSPORT, RPC_TCP);
07972 memcpy(_record_list[i].copy, _record_list[i].data,
07973 _record_list[i].buf_size);
07974 }
07975 }
07976
07977 return DB_SUCCESS;
07978 }
07979
07980
07981
07982
07983
07984
07985
07986