1 /*==============================================================================
2 *
3 * PUBLIC DOMAIN NOTICE
4 * National Center for Biotechnology Information
5 *
6 * This software/database is a "United States Government Work" under the
7 * terms of the United States Copyright Act. It was written as part of
8 * the author's official duties as a United States Government employee and
9 * thus cannot be copyrighted. This software/database is freely available
10 * to the public for use. The National Library of Medicine and the U.S.
11 * Government have not placed any restriction on its use or reproduction.
12 *
13 * Although all reasonable efforts have been taken to ensure the accuracy
14 * and reliability of the software and data, the NLM and the U.S.
15 * Government do not and cannot warrant the performance or results that
16 * may be obtained by using this software or data. The NLM and the U.S.
17 * Government disclaim all warranties, express or implied, including
18 * warranties of performance, merchantability or fitness for any particular
19 * purpose.
20 *
21 * Please cite the author in any work or product based on this material.
22 *
23 * ===========================================================================
24 *
25 */
26
27 #include <vdb/extern.h>
28
29 #include <vdb/vdb-priv.h> /* VDBManagerGetKDBManagerRead */
30 #include <vdb/manager.h> /* VDBManagerRelease */
31 #include <vdb/cursor.h>
32 #include <vdb/table.h>
33 #include <vdb/database.h>
34 #include <vdb/dependencies.h>
35
36 #include <kdb/kdb-priv.h> /* KDBManagerGetVFSManager */
37 #include <kdb/manager.h>
38
39 #include <vfs/manager.h> /* VFSManager */
40 #include <vfs/path.h>
41 #include <vfs/path-priv.h> /* VPathSetAccOfParentDb */
42 #include <vfs/resolver.h> /* VResolver */
43
44 #include <kfg/config.h>
45
46 #include <klib/container.h>
47 #include <klib/debug.h> /* DBG_VDB */
48 #include <klib/log.h>
49 #include <klib/out.h>
50 #include <klib/printf.h> /* string_printf */
51 #include <klib/rc.h>
52 #include <klib/text.h>
53
54 #include <sysalloc.h>
55
56 #include "cursor-table.h"
57
58 /* missing macros/function from klib/rc.h
59 */
60 #define GetRCSTATE( rc ) \
61 ( ( rc ) & 0x00003FFF )
62 #define RC_STATE( obj, state) \
63 ( rc_t ) ( ( ( rc_t ) ( obj ) << 6 ) | \
64 ( ( rc_t ) ( state ) ) )
65
66 #include <assert.h>
67 #include <limits.h>
68 #include <stdlib.h>
69 #include <string.h>
70
71 #ifndef PATH_MAX
72 #define PATH_MAX 4096
73 #endif
74
75 #define RELEASE(type, obj) do { rc_t rc2 = type##Release(obj); \
76 if (rc2 && !rc) { rc = rc2; } obj = NULL; } while (false)
77
78 static bool OLD = true;
79
80 typedef struct {
81 /* deprecated way */
82 char ref[PATH_MAX + 1];
83
84 /* new way */
85 const String *cache;
86 const VPath *cacheP;
87 rc_t cacheRc;
88
89 const String *local;
90 const VPath *localP;
91
92 const String *remote;
93 const VPath *remoteP;
94 rc_t remoteRc;
95
96 uint32_t count;
97 rc_t rc;
98 } Resolved;
99
100 typedef struct {
101 BSTNode n;
102
103 bool circular;
104 char* name;
105 uint32_t readLen;
106 char* seqId;
107 bool local;
108
109 Resolved resolved;
110 } RefNode;
111
_ResolvedRelease(Resolved * self)112 static rc_t _ResolvedRelease(Resolved *self) {
113 rc_t rc = 0;
114
115 assert(self);
116
117 StringWhack(self->cache);
118 StringWhack(self->local);
119 StringWhack(self->remote);
120
121 RELEASE(VPath, self->cacheP);
122 RELEASE(VPath, self->localP);
123 RELEASE(VPath, self->remoteP);
124
125 memset(self, 0, sizeof *self);
126
127 return rc;
128 }
129
130
bstWhack(BSTNode * n,void * ignore)131 static void CC bstWhack( BSTNode* n, void* ignore )
132 {
133 RefNode* sn = (RefNode*) n;
134
135 assert( sn );
136
137 free( sn->name );
138
139 free( sn->seqId );
140
141 _ResolvedRelease( &sn->resolved );
142
143 memset( sn, 0, sizeof *sn );
144
145 free( sn );
146 }
147
148 static
bstCmpBySeqId(const void * item,const BSTNode * n)149 int64_t CC bstCmpBySeqId(const void* item, const BSTNode* n)
150 {
151 const char* s1 = item;
152 const RefNode* sn = (const RefNode*) n;
153
154 assert(s1 && sn);
155
156 return strcmp(s1, sn->seqId);
157 }
158
bstCmpByRemote(const void * item,const BSTNode * n)159 static int64_t CC bstCmpByRemote(const void* item, const BSTNode* n)
160 {
161 const String* s1 = item;
162 const RefNode* sn = (const RefNode*) n;
163
164 assert(sn);
165
166 if (s1 == NULL) {
167 return sn->resolved.remote != NULL;
168 }
169 else {
170 size_t min = s1->size < sn->resolved.remote->size
171 ? s1->size : sn->resolved.remote->size;
172 return strncmp(s1->addr, sn->resolved.remote->addr, min);
173 }
174 }
175
176 static
bstSortBySeqId(const BSTNode * item,const BSTNode * n)177 int64_t CC bstSortBySeqId(const BSTNode* item, const BSTNode* n)
178 {
179 const RefNode* sn = (const RefNode*) item;
180
181 return bstCmpBySeqId(sn->seqId, n);
182 }
183
184 static
bstSortByRemote(const BSTNode * item,const BSTNode * n)185 int64_t CC bstSortByRemote(const BSTNode* item, const BSTNode* n)
186 {
187 const RefNode* sn = (const RefNode*) item;
188
189 return bstCmpByRemote(sn->resolved.remote, n);
190 }
191
192 typedef struct Column {
193 uint32_t idx;
194 const char* name;
195 uint32_t expected;
196 uint32_t elem_bits;
197 } Column;
198
199 static
AddColumn(rc_t rc,const VCursor * curs,Column * col)200 rc_t AddColumn(rc_t rc, const VCursor* curs, Column* col)
201 {
202 if (rc == 0) {
203 assert(curs && col);
204
205 rc = VCursorAddColumn(curs, &col->idx, "%s", col->name);
206 if (rc != 0) {
207 DBGMSG(DBG_VDB, DBG_FLAG(DBG_VDB),
208 ("Cannot Add Column %s", col->name));
209 }
210 }
211
212 return rc;
213 }
214
215 /* Read a column data from a Cursor */
216 static
CursorRead(rc_t rc,const VCursor * curs,int64_t row_id,const Column * col,void * buffer,uint32_t blen,uint32_t * row_len)217 rc_t CursorRead(rc_t rc, const VCursor* curs, int64_t row_id,
218 const Column* col, void* buffer, uint32_t blen, uint32_t* row_len)
219 {
220 assert(curs);
221
222 if (rc == 0) {
223 uint32_t elem_bits = col->elem_bits;
224 uint32_t expected = col->expected;
225 assert(col);
226
227 if (blen == 0) {
228 assert(buffer == NULL);
229 ++blen;
230 }
231
232 rc = VCursorReadDirect
233 (curs, row_id, col->idx, elem_bits, buffer, blen - 1, row_len);
234
235 if (rc != 0) {
236 if (buffer == NULL &&
237 rc == RC(rcVDB, rcCursor, rcReading, rcBuffer, rcInsufficient))
238 {
239 rc = 0;
240 }
241 }
242 else {
243 if (expected > 0 && *row_len != expected) {
244 rc = RC(rcVDB, rcCursor, rcReading, rcData, rcUnexpected);
245 }
246 if (buffer != NULL && expected == 0)
247 { ((char*)buffer)[*row_len] = '\0'; }
248 }
249 }
250
251 return rc;
252 }
253
254 #define SIZE 4096
255
256 /* Ctx struct is used to find a file using KConfig "refseq" parameters */
257 typedef struct {
258 KDirectory* dir;
259
260 char servers[SIZE];
261 char volumes[SIZE];
262 char paths[SIZE];
263
264 VResolver* resolver;
265
266 const String * dbAcc; /* accession of the database */
267
268 const Resolved* last;
269 bool hasDuplicates;
270 } Ctx;
271
CtxInit(Ctx * self,const VDatabase * db)272 static rc_t CtxInit(Ctx* self, const VDatabase *db) {
273 rc_t rc = 0;
274 KConfig* cfg = NULL;
275
276 assert(self && db);
277
278 memset(self, 0, sizeof *self);
279
280 if (rc == 0) {
281 rc = KConfigMake(&cfg, NULL);
282 if (rc == 0) {
283 const KConfigNode *node = NULL;
284 rc = KConfigOpenNodeRead(cfg, &node, "repository");
285 if (rc == 0) {
286 OLD = false;
287 LOGMSG(klogInfo, "KConfig(repository) found: using VResolver");
288 }
289 else {
290 OLD = true;
291 LOGMSG(klogInfo,
292 "KConfig(repository) not found: not using VResolver");
293 }
294 RELEASE(KConfigNode, node);
295 }
296 }
297
298 {
299 VFSManager* vfsmgr = NULL;
300 const KDBManager* kmgr = NULL;
301 const VDBManager *mgr = NULL;
302
303 if (rc == 0) {
304 rc = VDatabaseOpenManagerRead(db, &mgr);
305 }
306
307 if (rc == 0) {
308 rc = VDBManagerGetKDBManagerRead(mgr, &kmgr);
309 }
310
311 if (rc == 0) {
312 rc = KDBManagerGetVFSManager(kmgr, &vfsmgr);
313 }
314
315 if (rc == 0) {
316 rc = VFSManagerGetResolver(vfsmgr, &self->resolver);
317 }
318
319 if (rc == 0)
320 rc = VDatabaseGetAccession(db, &self->dbAcc);
321
322 RELEASE(VFSManager, vfsmgr);
323 RELEASE(KDBManager, kmgr);
324 RELEASE(VDBManager, mgr);
325 }
326
327 RELEASE(KConfig, cfg);
328
329 return rc;
330 }
331
StringRelease(const String * self)332 static rc_t StringRelease(const String *self) {
333 StringWhack(self);
334 return 0;
335 }
336
CtxDestroy(Ctx * self)337 static rc_t CtxDestroy(Ctx* self) {
338 rc_t rc = 0;
339
340 assert(self);
341
342 RELEASE(KDirectory, self->dir);
343 RELEASE(VResolver, self->resolver);
344 RELEASE(String, self->dbAcc);
345
346 memset(self, 0, sizeof *self);
347
348 return rc;
349 }
350
351 typedef struct {
352 const char* file;
353 bool found;
354 } FindRefseq;
355
356 #define rcResolver rcTree
NotFoundByResolver(rc_t rc)357 static bool NotFoundByResolver(rc_t rc) {
358 if (GetRCModule(rc) == rcVFS) {
359 if (GetRCTarget(rc) == rcResolver) {
360 if (GetRCContext(rc) == rcResolving) {
361 if (GetRCState(rc) == rcNotFound) {
362 return true;
363 }
364 }
365 }
366 }
367 return false;
368 }
369
370 /* find remote reference using VResolver */
FindRef(Ctx * ctx,const char * seqId,Resolved * resolved,int cacheState,bool alwaysResolveRemote)371 static rc_t FindRef(Ctx* ctx, const char* seqId, Resolved* resolved,
372 int cacheState, bool alwaysResolveRemote)
373 {
374 rc_t rc = 0;
375
376 VPath* acc = NULL;
377 size_t num_writ = 0;
378 char ncbiAcc[512] = "";
379
380 assert(ctx && resolved);
381
382 if (cacheState != -1) {
383 VResolverCacheEnable(ctx->resolver, cacheState);
384 }
385
386 if (rc == 0) {
387 rc = string_printf(ncbiAcc, sizeof ncbiAcc, &num_writ,
388 "ncbi-acc:%s?vdb-ctx=refseq", seqId);
389 rc = string_printf(ncbiAcc, sizeof ncbiAcc, &num_writ,
390 "%s", seqId);
391 if (rc == 0 && num_writ > sizeof ncbiAcc) {
392 return RC(rcExe, rcFile, rcCopying, rcBuffer, rcInsufficient);
393 }
394 }
395
396 if (rc == 0)
397 {
398 VFSManager *mgr;
399 rc = VFSManagerMake ( & mgr );
400 if ( rc == 0 )
401 {
402 rc = VFSManagerMakePath ( mgr, &acc, "%s", ncbiAcc);
403 RELEASE(VFSManager, mgr);
404
405 if (rc == 0)
406 rc = VPathSetAccOfParentDb(acc, ctx->dbAcc);
407 }
408 }
409
410 if (rc == 0) {
411 rc = VResolverLocal(ctx->resolver, acc, &resolved->localP);
412 if (rc == 0)
413 rc = VPathMakeString(resolved->localP, &resolved->local);
414 else if (NotFoundByResolver(rc))
415 rc = 0;
416
417 if (resolved->localP == NULL || alwaysResolveRemote) {
418 if (rc == 0) {
419 resolved->remoteRc = VResolverRemote(
420 ctx->resolver, 0, acc, &resolved->remoteP);
421 if (resolved->remoteRc == 0) {
422 if (rc == 0)
423 rc = VPathSetAccOfParentDb((VPath*)resolved->remoteP,
424 ctx->dbAcc);
425 if (rc == 0)
426 rc = VPathMakeString(resolved->remoteP, &resolved->remote);
427 if (rc == 0) {
428 char *fragment = string_chr(resolved->remote->addr,
429 resolved->remote->size, '#');
430 if (fragment != NULL)
431 *fragment = '\0';
432 }
433 }
434 }
435
436 if (rc == 0 && resolved->remoteRc == 0) {
437 uint64_t file_size = 0;
438 resolved->cacheRc = VResolverCache(ctx->resolver,
439 resolved->remoteP, &resolved->cacheP, file_size);
440 if (resolved->cacheRc == 0)
441 rc = VPathMakeString(resolved->cacheP, &resolved->cache);
442 }
443
444 if (rc == 0) {
445 if (ctx->last == NULL)
446 ctx->last = resolved;
447 else {
448 const String *last = ctx->last->remote;
449 const String *crnt = resolved->remote;
450 if (last != NULL && crnt != NULL &&
451 last->addr != NULL && crnt->addr != NULL)
452 {
453 size_t min
454 = crnt->size < last->size ? crnt->size : last->size;
455 if (strncmp(last->addr, crnt->addr, min) == 0)
456 ctx->hasDuplicates = true;
457 }
458 }
459 }
460 }
461 }
462
463 RELEASE(VPath, acc);
464
465 if (cacheState != -1) {
466 VResolverCacheEnable(ctx->resolver, vrAlwaysDisable);
467 }
468
469 return rc;
470 }
471
472 typedef struct {
473 /* row values */
474 uint32_t readLen;
475 char circular[8];
476 char name[256];
477 char seqId[256];
478
479 /* we do not read CMP_READ value, just its row_len */
480 uint32_t row_lenCMP_READ;
481 } Row;
482
483 /* Add a REFERENCE table Row to BSTree */
AddRow(BSTree * tr,Row * data,Ctx * ctx,int cacheState,bool alwaysResolveRemote)484 static rc_t AddRow(BSTree* tr, Row* data,
485 Ctx* ctx, int cacheState, bool alwaysResolveRemote)
486 {
487 rc_t rc = 0;
488 bool newRemote = false;
489 RefNode* sn = NULL;
490
491 assert(tr && data && ctx);
492
493 sn = (RefNode*) BSTreeFind(tr, data->seqId, bstCmpBySeqId);
494 if (sn == NULL) {
495 sn = calloc(1, sizeof *sn);
496 if (sn == NULL) {
497 return RC
498 (rcVDB, rcStorage, rcAllocating, rcMemory, rcExhausted);
499 }
500 sn->seqId = string_dup_measure(data->seqId, NULL);
501 if (sn->seqId == NULL) {
502 bstWhack((BSTNode*) sn, NULL);
503 sn = NULL;
504 return RC
505 (rcVDB, rcStorage, rcAllocating, rcMemory, rcExhausted);
506 }
507
508 sn->name = string_dup_measure(data->name, NULL);
509 if (sn->name == NULL) {
510 bstWhack((BSTNode*) sn, NULL);
511 sn = NULL;
512 return RC
513 (rcVDB, rcStorage, rcAllocating, rcMemory, rcExhausted);
514 }
515
516 sn->circular = data->circular[0];
517 sn->readLen = data->readLen;
518 sn->local = (data->row_lenCMP_READ != 0);
519 newRemote = ! sn->local;
520
521 BSTreeInsert(tr, (BSTNode*)sn, bstSortBySeqId);
522 }
523 else {
524 if (data->row_lenCMP_READ != 0) {
525 sn->local = true;
526 }
527 if (strcmp(sn->name, data->name) || sn->circular != data->circular[0]) {
528 return RC(rcVDB, rcCursor, rcReading, rcData, rcInconsistent);
529 }
530 sn->readLen += data->readLen;
531 }
532
533 if (rc == 0 && newRemote)
534 rc = FindRef(
535 ctx, sn->seqId, &sn->resolved, cacheState, alwaysResolveRemote);
536
537 return rc;
538 }
539
540 struct VDBDependencies {
541 uint32_t count;
542 RefNode** dependencies;
543
544 BSTree* tr;
545
546 /* open references */
547 KRefcount refcount;
548 };
549
550 typedef struct Initializer {
551 bool all; /* IN: when false: process just missed */
552 bool fill; /* IN:
553 false: count(fill count); true: fill dep(use count) */
554 uint32_t count; /* IO: all/missed count */
555 VDBDependencies* dep;/* OUT: to be filled */
556 uint32_t i; /* PRIVATE: index in dep */
557 rc_t rc; /* OUT */
558 } Initializer;
559
560 /* Work function to process dependencies tree
561 * Input parameters are in Initializer:
562 * all (true: all dependencies, false: just missing)
563 * fill(false: count dependencies, true: fill dependencies array
564 */
bstProcess(BSTNode * n,void * data)565 static void CC bstProcess(BSTNode* n, void* data) {
566 RefNode* elm = (RefNode*) n;
567 Initializer* obj = (Initializer*) data;
568 bool go = false;
569
570 assert(elm && obj);
571
572 /* remore reference && refseq table not found */
573 if (obj->all) {
574 go = true;
575 }
576 else if (!elm->local) {
577 if (OLD) {
578 if (elm->resolved.ref[0] == '\0') {
579 go = true;
580 }
581 }
582 else {
583 if (elm->resolved.local == NULL) {
584 go = true;
585 }
586 }
587 }
588
589 if (!go) {
590 return;
591 }
592
593 if (!obj->fill) {
594 ++obj->count;
595 }
596 else {
597 if (obj->dep == NULL || obj->dep->dependencies == NULL) {
598 return;
599 }
600 if (obj->i < obj->count) {
601 *(obj->dep->dependencies + ((obj->i)++)) = elm;
602 }
603 else {
604 obj->rc = RC(rcVDB, rcDatabase, rcAccessing, rcSelf, rcCorrupt);
605 }
606 }
607 }
608
609 /* Read REFERENCE table; fill in BSTree */
610 static
VDatabaseDependencies(const VDatabase * self,BSTree * tr,bool * has_no_REFERENCE,bool * hasDuplicates,bool disableCaching,bool alwaysResolveRemote)611 rc_t CC VDatabaseDependencies(const VDatabase *self, BSTree* tr,
612 bool* has_no_REFERENCE, bool* hasDuplicates,
613 bool disableCaching, bool alwaysResolveRemote)
614 {
615 rc_t rc = 0;
616
617 int64_t i = 0;
618 int64_t firstId = 0;
619 int64_t lastId = 0;
620
621 Column CIRCULAR = { 0, "CIRCULAR", 1, 8 };
622 Column CMP_READ = { 0, "CMP_READ", 0, 8 };
623 Column NAME = { 0, "NAME" , 0, 8 };
624 Column READ_LEN = { 0, "READ_LEN", 1, 32 };
625 Column SEQ_ID = { 0, "SEQ_ID", 0, 8 };
626
627 const VTable* tbl = NULL;
628 const VCursor* curs = NULL;
629
630 int cacheState = -1;
631
632 Ctx ctx;
633
634 assert(self && tr && has_no_REFERENCE);
635
636 *has_no_REFERENCE = false;
637
638 if (rc == 0) {
639 rc = CtxInit(&ctx, self);
640 }
641
642 if (rc == 0 && disableCaching) {
643 cacheState = VResolverCacheEnable(ctx.resolver, vrAlwaysDisable);
644 }
645
646
647 if (rc == 0) {
648 rc = VDatabaseOpenTableRead(self, &tbl, "REFERENCE");
649 if (GetRCState(rc) == rcNotFound) {
650 *has_no_REFERENCE = true;
651 }
652 }
653 if (rc == 0) {
654 const VTableCursor * tcurs;
655 rc = VTableCreateCursorReadInternal(tbl, &tcurs);
656 curs = ( const VCursor * )tcurs;
657 }
658
659 rc = AddColumn(rc, curs, &CIRCULAR);
660 rc = AddColumn(rc, curs, &CMP_READ);
661 rc = AddColumn(rc, curs, &NAME );
662 rc = AddColumn(rc, curs, &READ_LEN);
663 rc = AddColumn(rc, curs, &SEQ_ID );
664
665 if (rc == 0) {
666 rc = VCursorOpen(curs);
667 }
668 if (rc == 0) {
669 uint64_t count = 0;
670 rc = VCursorIdRange(curs, 0, &firstId, &count);
671 lastId = firstId + count - 1;
672 }
673
674 for (i = firstId; i <= lastId && rc == 0; ++i) {
675 uint32_t row_len = 0;
676 Row data;
677 if (rc == 0) {
678 rc = CursorRead(rc, curs, i, &CIRCULAR,
679 data.circular, sizeof data.circular, &row_len);
680 if (rc != 0) {
681 PLOGERR(klogErr, (klogErr, rc,
682 "failed to read cursor(col='CIRCULAR', spot='$(id)')",
683 "id=%ld", i));
684 }
685 }
686 if (rc == 0) {
687 rc = CursorRead(rc, curs, i, &CMP_READ,
688 NULL, 0, &data.row_lenCMP_READ);
689 if (rc != 0) {
690 PLOGERR(klogErr, (klogErr, rc,
691 "failed to read cursor(col='CMP_READ', spot='$(id)')",
692 "id=%ld", i));
693 }
694 }
695 if (rc == 0) {
696 rc = CursorRead(rc, curs, i, &NAME,
697 data.name, sizeof data.name, &row_len);
698 if (rc != 0) {
699 PLOGERR(klogErr, (klogErr, rc,
700 "failed to read cursor(col='NAME', spot='$(id)')",
701 "id=%ld", i));
702 }
703 }
704 if (rc == 0) {
705 rc = CursorRead(rc, curs, i, &READ_LEN,
706 &data.readLen, sizeof data.readLen, &row_len);
707 if (rc != 0) {
708 PLOGERR(klogErr, (klogErr, rc,
709 "failed to read cursor(col='READ_LEN', spot='$(id)')",
710 "id=%ld", i));
711 }
712 }
713 if (rc == 0) {
714 rc = CursorRead(rc, curs, i, &SEQ_ID,
715 data.seqId, sizeof data.seqId, &row_len);
716 if (rc != 0) {
717 PLOGERR(klogErr, (klogErr, rc,
718 "failed to read cursor(col='SEQ_ID', spot='$(id)')",
719 "id=%ld", i));
720 }
721 }
722 if (rc == 0)
723 rc = AddRow(tr, &data, &ctx, cacheState, alwaysResolveRemote);
724 }
725
726 if (rc == 0 && hasDuplicates != NULL)
727 *hasDuplicates = ctx.hasDuplicates;
728
729 if (*has_no_REFERENCE)
730 rc = 0;
731
732 if (cacheState != -1)
733 VResolverCacheEnable(ctx.resolver, cacheState);
734
735 {
736 rc_t rc2 = CtxDestroy(&ctx);
737 if (rc == 0 && rc2 != 0)
738 rc = rc2;
739 }
740
741 RELEASE(VCursor, curs);
742 RELEASE(VTable, tbl);
743
744 return rc;
745 }
746
747 /* Get dependency number "idx" */
748 static
VDBDependenciesGet(const VDBDependencies * self,RefNode ** dep,uint32_t idx)749 rc_t VDBDependenciesGet(const VDBDependencies* self,
750 RefNode** dep, uint32_t idx)
751 {
752 rc_t rc = 0;
753
754 assert(dep);
755
756 if (self == NULL) {
757 return RC(rcVDB, rcDatabase, rcAccessing, rcSelf, rcNull);
758 }
759
760 if (idx >= self->count) {
761 return RC(rcVDB, rcDatabase, rcAccessing, rcParam, rcExcessive);
762 }
763
764 *dep = *(self->dependencies + idx);
765 if (*dep == NULL) {
766 return RC(rcVDB, rcDatabase, rcAccessing, rcSelf, rcCorrupt);
767 }
768
769 return rc;
770 }
771
772 /* Count
773 * retrieve the number of dependencies
774 *
775 * "count" [ OUT ] - return parameter for dependencies count
776 */
VDBDependenciesCount(const VDBDependencies * self,uint32_t * count)777 LIB_EXPORT rc_t CC VDBDependenciesCount(const VDBDependencies* self,
778 uint32_t* count)
779 {
780 if (self == NULL) {
781 return RC(rcVDB, rcDatabase, rcAccessing, rcSelf, rcNull);
782 }
783
784 if (count == NULL) {
785 return RC(rcVDB, rcDatabase, rcAccessing, rcParam, rcNull);
786 }
787
788 *count = self->count;
789
790 return 0;
791 }
792
793 /* Circular */
VDBDependenciesCircular(const VDBDependencies * self,bool * circular,uint32_t idx)794 LIB_EXPORT rc_t CC VDBDependenciesCircular(const VDBDependencies* self,
795 bool* circular, uint32_t idx)
796 {
797 rc_t rc = 0;
798 RefNode* dep = NULL;
799
800 if (circular == NULL) {
801 return RC(rcVDB, rcDatabase, rcAccessing, rcParam, rcNull);
802 }
803
804 rc = VDBDependenciesGet(self, &dep, idx);
805
806 if (rc == 0) {
807 *circular = dep->circular;
808 }
809
810 return rc;
811 }
812
813 /* Local
814 * retrieve local property
815 *
816 * "local" [ OUT ] - true if object is stored internally
817 *
818 * "idx" [ IN ] - zero-based index of dependency
819 */
VDBDependenciesLocal(const VDBDependencies * self,bool * local,uint32_t idx)820 LIB_EXPORT rc_t CC VDBDependenciesLocal(const VDBDependencies* self,
821 bool* local, uint32_t idx)
822 {
823 rc_t rc = 0;
824 RefNode* dep = NULL;
825
826 if (local == NULL) {
827 return RC(rcVDB, rcDatabase, rcAccessing, rcParam, rcNull);
828 }
829
830 rc = VDBDependenciesGet(self, &dep, idx);
831
832 if (rc == 0) {
833 *local = dep->local;
834 }
835
836 return rc;
837 }
838
839 /* Name
840 *
841 * "name" [ OUT ] - returned pointed should not be released.
842 * it becomes invalid after VDBDependenciesRelease
843 */
VDBDependenciesName(const VDBDependencies * self,const char ** name,uint32_t idx)844 LIB_EXPORT rc_t CC VDBDependenciesName(const VDBDependencies* self,
845 const char** name, uint32_t idx)
846 {
847 rc_t rc = 0;
848 RefNode* dep = NULL;
849
850 if (name == NULL) {
851 return RC(rcVDB, rcDatabase, rcAccessing, rcParam, rcNull);
852 }
853
854 rc = VDBDependenciesGet(self, &dep, idx);
855
856 if (rc == 0) {
857 *name = dep->name;
858 }
859
860 return rc;
861 }
862
VDBDependencyGetPath(const String * from,const char ** to,const VPath * fromP,const VPath ** toP)863 static rc_t VDBDependencyGetPath(const String* from, const char** to,
864 const VPath* fromP, const VPath** toP)
865 {
866 assert(to);
867
868 *to = NULL;
869
870 if (OLD) {
871 return 0;
872 }
873
874 if (from == NULL) {
875 return 0;
876 }
877
878 if (from->addr != NULL && from->size > 0 &&
879 from->addr[from->size - 1] != '\0' &&
880 from->addr[from->size] != '\0')
881 {
882 return RC(rcVDB, rcString, rcValidating, rcChar, rcInvalid);
883 }
884
885 *to = from->addr;
886 return 0;
887 }
888
VDBDependenciesPathImpl(const VDBDependencies * self,const char ** path,const VPath ** vpath,uint32_t idx)889 static rc_t VDBDependenciesPathImpl(const VDBDependencies* self,
890 const char** path, const VPath** vpath, uint32_t idx)
891 {
892 rc_t rc = 0;
893 RefNode* dep = NULL;
894
895 if (path == NULL) {
896 return RC(rcVDB, rcDatabase, rcAccessing, rcParam, rcNull);
897 }
898
899 rc = VDBDependenciesGet(self, &dep, idx);
900
901 if (rc == 0) {
902 if (dep->local) {
903 *path = NULL;
904 }
905 else {
906 if (OLD) {
907 *path = dep->resolved.ref;
908 }
909 else {
910 rc = VDBDependencyGetPath(dep->resolved.local, path,
911 dep->resolved.localP, vpath);
912 }
913 }
914 }
915
916 return rc;
917 }
918
919 /* Path
920 * for remote dependencies: returns:
921 * path for resolved dependency,
922 * NULL for missing dependency.
923 * returns NULL for local dependencies
924 *
925 * "path" [ OUT ] - returned pointed should not be released.
926 * it becomes invalid after VDBDependenciesRelease
927 */
VDBDependenciesPath(const VDBDependencies * self,const char ** path,uint32_t idx)928 LIB_EXPORT rc_t CC VDBDependenciesPath(const VDBDependencies* self,
929 const char** path, uint32_t idx)
930 {
931 return VDBDependenciesPathImpl(self, path, NULL, idx);
932 }
933
934 /* VPath
935 * returns [Local] path for resolved dependency,
936 * returns NULL for local and missing dependency.
937 *
938 * "path" [ OUT ]
939 *
940 * "idx" [ IN ] - zero-based index of dependency
941 */
VDBDependenciesVPath(const VDBDependencies * self,const VPath ** path,uint32_t idx)942 LIB_EXPORT rc_t CC VDBDependenciesVPath(const VDBDependencies *self,
943 const VPath **path, uint32_t idx)
944 {
945 return VDBDependenciesPathImpl(self, NULL, path, idx);
946 }
947
VDBDependenciesPathRemote(const VDBDependencies * self,const char ** path,uint32_t idx)948 LIB_EXPORT rc_t CC VDBDependenciesPathRemote(const VDBDependencies* self,
949 const char** path, uint32_t idx)
950 {
951 rc_t rc = 0;
952 RefNode* dep = NULL;
953
954 if (path == NULL) {
955 return RC(rcVDB, rcDatabase, rcAccessing, rcParam, rcNull);
956 }
957
958 rc = VDBDependenciesGet(self, &dep, idx);
959
960 if (rc == 0) {
961 rc = VDBDependencyGetPath(dep->resolved.remote, path, NULL, NULL);
962 }
963
964 return rc;
965 }
966
VDBDependenciesPathCache(const VDBDependencies * self,const char ** path,uint32_t idx)967 LIB_EXPORT rc_t CC VDBDependenciesPathCache(const VDBDependencies* self,
968 const char** path, uint32_t idx)
969 {
970 rc_t rc = 0;
971 RefNode* dep = NULL;
972
973 if (path == NULL) {
974 return RC(rcVDB, rcDatabase, rcAccessing, rcParam, rcNull);
975 }
976
977 rc = VDBDependenciesGet(self, &dep, idx);
978
979 if (rc == 0) {
980 rc = VDBDependencyGetPath(dep->resolved.cache, path, NULL, NULL);
981 }
982
983 return rc;
984 }
985
986 /* RemoteAndCache
987 * returns Cache and remote path and rc_t for dependency.
988 *
989 * "idx" [ IN ] - zero-based index of dependency
990 */
VDBDependenciesRemoteAndCache(const VDBDependencies * self,uint32_t idx,rc_t * remoteRc,const VPath ** remote,rc_t * cacheRc,const VPath ** cache)991 LIB_EXPORT rc_t CC VDBDependenciesRemoteAndCache(const VDBDependencies *self,
992 uint32_t idx,
993 rc_t *remoteRc, const VPath **remote, rc_t *cacheRc, const VPath **cache)
994 {
995 rc_t rc = 0;
996 RefNode* dep = NULL;
997
998 if (remoteRc == NULL || cacheRc == NULL || cache == NULL || remote == NULL)
999 return RC(rcVDB, rcDatabase, rcAccessing, rcParam, rcNull);
1000
1001 rc = VDBDependenciesGet(self, &dep, idx);
1002
1003 if (rc == 0) {
1004 *remoteRc = dep->resolved.remoteRc;
1005 if (*remoteRc == 0) {
1006 rc = VPathAddRef(dep->resolved.remoteP);
1007 if (rc == 0)
1008 * remote = dep->resolved.remoteP;
1009 }
1010 }
1011
1012 if (rc == 0) {
1013 *cacheRc = dep->resolved.cacheRc;
1014 if (*cacheRc == 0) {
1015 rc = VPathAddRef(dep->resolved.cacheP);
1016 if (rc == 0)
1017 * cache = dep->resolved.cacheP;
1018 }
1019 }
1020
1021 return rc;
1022 }
1023
1024
1025 /* SeqId
1026 *
1027 * "seq_id" [ OUT ] - returned pointed should not be released.
1028 * it becomes invalid after VDBDependenciesRelease
1029 */
VDBDependenciesSeqId(const VDBDependencies * self,const char ** seq_id,uint32_t idx)1030 LIB_EXPORT rc_t CC VDBDependenciesSeqId(const VDBDependencies* self,
1031 const char** seq_id, uint32_t idx)
1032 {
1033 rc_t rc = 0;
1034 RefNode* dep = NULL;
1035
1036 if (seq_id == NULL) {
1037 return RC(rcVDB, rcDatabase, rcAccessing, rcParam, rcNull);
1038 }
1039
1040 rc = VDBDependenciesGet(self, &dep, idx);
1041
1042 if (rc == 0) {
1043 *seq_id = dep->seqId;
1044 }
1045
1046 return rc;
1047 }
1048
1049 /* Type
1050 *
1051 * "type" [ OUT ] - a KDBPathType from kdb/manager.h
1052 */
VDBDependenciesType(const VDBDependencies * self,uint32_t * type,uint32_t idx)1053 LIB_EXPORT rc_t CC VDBDependenciesType(const VDBDependencies* self,
1054 uint32_t* type, uint32_t idx)
1055 {
1056 rc_t rc = 0;
1057 RefNode* dep = NULL;
1058
1059 if (type == NULL) {
1060 return RC(rcVDB, rcDatabase, rcAccessing, rcParam, rcNull);
1061 }
1062
1063 rc = VDBDependenciesGet(self, &dep, idx);
1064
1065 if (rc == 0) {
1066 *type = kptTable;
1067 }
1068
1069 return rc;
1070 }
1071
1072 #define CLSNAME "VDBDependencies"
1073
VDBDependenciesAddRef(const VDBDependencies * self)1074 VDB_EXTERN rc_t CC VDBDependenciesAddRef(const VDBDependencies* self ) {
1075 if (self != NULL) {
1076 switch (KRefcountAdd(&self->refcount, CLSNAME)) {
1077 case krefLimit:
1078 return RC(rcVDB, rcDatabase, rcAttaching, rcRange, rcExcessive);
1079 }
1080 }
1081
1082 return 0;
1083 }
1084
VDBDependenciesWhack(VDBDependencies * self)1085 static rc_t VDBDependenciesWhack(VDBDependencies* self) {
1086 if (self == NULL) {
1087 return 0;
1088 }
1089
1090 KRefcountWhack(&self->refcount, CLSNAME);
1091
1092 BSTreeWhack(self->tr, bstWhack, NULL);
1093 free(self->tr);
1094
1095 free(self->dependencies);
1096
1097 memset(self, 0, sizeof *self);
1098
1099 free(self);
1100
1101 return 0;
1102 }
1103
1104 /* Release
1105 * (objects ARE NOT reference counted)
1106 * ignores NULL references
1107 */
VDBDependenciesRelease(const VDBDependencies * self)1108 LIB_EXPORT rc_t CC VDBDependenciesRelease(const VDBDependencies* self) {
1109 if (self != NULL) {
1110 switch (KRefcountDrop(&self->refcount, CLSNAME)) {
1111 case krefWhack:
1112 return VDBDependenciesWhack((VDBDependencies*)self);
1113 case krefNegative:
1114 return RC(rcVDB, rcDatabase, rcReleasing, rcRange, rcExcessive);
1115 }
1116 }
1117
1118 return 0;
1119 }
1120
1121 typedef struct {
1122 BSTree* tr;
1123 int count;
1124 bool all;
1125 } SBstCopy;
1126
bstCopy(BSTNode * n,void * data)1127 static void CC bstCopy(BSTNode* n, void* data) {
1128 RefNode* sn = NULL;
1129 RefNode* elm = (RefNode*) n;
1130 SBstCopy* x = (SBstCopy*)data;
1131 BSTree* tr = x->tr;
1132 bool go = false;
1133 assert(elm && tr);
1134
1135 if (x->all) {
1136 go = true;
1137 } else if (!elm->local) {
1138 assert(!OLD);
1139 if (elm->resolved.local == NULL) {
1140 go = true;
1141 }
1142 }
1143
1144 if (!go) {
1145 return;
1146 }
1147
1148 sn = (RefNode*) BSTreeFind(tr, elm->resolved.remote, bstCmpByRemote);
1149 if (sn == NULL) {
1150 sn = calloc(1, sizeof *sn);
1151 if (sn == NULL) {
1152 /* TODO: generate error message */
1153 return;
1154 }
1155
1156 sn->seqId = string_dup_measure(elm->seqId, NULL);
1157 if (sn->seqId == NULL) {
1158 bstWhack((BSTNode*) sn, NULL);
1159 return;
1160 }
1161
1162 sn->name = string_dup_measure(elm->name, NULL);
1163 if (sn->name == NULL) {
1164 bstWhack((BSTNode*) sn, NULL);
1165 return;
1166 }
1167
1168 sn->circular = elm->circular;
1169 sn->readLen = elm->readLen;
1170 sn->local = elm->local;
1171
1172 sn->resolved.count = 1;
1173
1174 sn->resolved.local = elm->resolved.local;
1175 elm->resolved.local = NULL;
1176
1177 sn->resolved.localP = elm->resolved.localP;
1178 elm->resolved.localP = NULL;
1179
1180 sn->resolved.remote = elm->resolved.remote;
1181 elm->resolved.remote = NULL;
1182
1183 sn->resolved.remoteP = elm->resolved.remoteP;
1184 elm->resolved.remoteP = NULL;
1185
1186 sn->resolved.cache = elm->resolved.cache;
1187 elm->resolved.cache = NULL;
1188
1189 sn->resolved.cacheP = elm->resolved.cacheP;
1190 elm->resolved.cacheP = NULL;
1191
1192 BSTreeInsert(tr, (BSTNode*)sn, bstSortByRemote);
1193 ++x->count;
1194 }
1195 else {
1196 bool archived = false;
1197 if (sn->resolved.rc != 0) {
1198 return;
1199 }
1200 else if (sn->circular != elm->circular) {
1201 sn->resolved.rc
1202 = RC(rcVDB, rcNumeral, rcComparing, rcData, rcInvalid);
1203 }
1204 else if ((sn->name == NULL && elm->name != NULL)
1205 || (sn->name != NULL && elm->name == NULL))
1206 {
1207 sn->resolved.rc
1208 = RC(rcVDB, rcString, rcComparing, rcData, rcInvalid);
1209 }
1210 else if (strcmp(sn->name, elm->name) != 0) {
1211 if (strncmp(sn->name, elm->name, 6) == 0) {
1212 archived = true;
1213 }
1214 else {
1215 sn->resolved.rc
1216 = RC(rcVDB, rcString, rcComparing, rcData, rcInvalid);
1217 }
1218 }
1219
1220 if (sn->resolved.rc != 0) {
1221 }
1222 else if (sn->readLen != elm->readLen && !archived) {
1223 sn->resolved.rc
1224 = RC(rcVDB, rcNumeral, rcComparing, rcData, rcInvalid);
1225 }
1226 else if (sn->seqId == NULL || elm->seqId == NULL) {
1227 sn->resolved.rc
1228 = RC(rcVDB, rcString, rcComparing, rcData, rcInvalid);
1229 }
1230 else if (sn->local != elm->local) {
1231 sn->resolved.rc
1232 = RC(rcVDB, rcNumeral, rcComparing, rcData, rcInvalid);
1233 }
1234 else if (sn->resolved.ref[0] != '\0' || elm->resolved.ref[0] != '\0') {
1235 sn->resolved.rc
1236 = RC(rcVDB, rcString, rcComparing, rcData, rcInvalid);
1237 }
1238 else if (sn->resolved.local != NULL || elm->resolved.local != NULL) {
1239 sn->resolved.rc
1240 = RC(rcVDB, rcString, rcComparing, rcData, rcInvalid);
1241 }
1242 else if (StringCompare(sn->resolved.remote, elm->resolved.remote) != 0)
1243 {
1244 size_t min = sn->resolved.remote->size < elm->resolved.remote->size
1245 ? sn->resolved.remote->size : elm->resolved.remote->size;
1246 if (!archived || strncmp(sn->resolved.remote->addr,
1247 elm->resolved.remote->addr, min) != 0)
1248 {
1249 sn->resolved.rc
1250 = RC(rcVDB, rcString, rcComparing, rcData, rcInvalid);
1251 }
1252 }
1253
1254 if (sn->resolved.rc != 0) {
1255 }
1256 else if (StringCompare(sn->resolved.cache, elm->resolved.cache) != 0)
1257 {
1258 sn->resolved.rc
1259 = RC(rcVDB, rcString, rcComparing, rcData, rcInvalid);
1260 }
1261 else {
1262 if (archived) {
1263 int i = 0;
1264 bool tail = false;
1265 for (;;++i) {
1266 char* c1 = &sn->seqId[i];
1267 const char c2 = elm->seqId[i];
1268 if (*c1 == '\0') {
1269 break;
1270 }
1271 if (!tail && (c2 == '\0' || *c1 != c2)) {
1272 tail = true;
1273 }
1274 if (tail) {
1275 /* incorrect:
1276 we keep at least one seqid for archived refseqs to be able to resolve them
1277 *c1 = '.'; */
1278 }
1279 }
1280 }
1281 ++sn->resolved.count;
1282 }
1283 }
1284 }
1285
1286 /* ListDependencies
1287 * create a dependencies object: list all dependencies
1288 *
1289 * "dep" [ OUT ] - return for VDBDependencies object
1290 *
1291 * "missing" [ IN ] - if true, list only missing dependencies
1292 * otherwise, list all dependencies
1293 *
1294 * N.B. If missing == true then
1295 * just one refseq dependency will be returned for 'container' Refseq files.
1296 */
VDatabaseListDependenciesImpl(const VDatabase * self,const VDBDependencies ** dep,bool missing,bool disableCaching,bool alwaysResolveRemote)1297 static rc_t VDatabaseListDependenciesImpl(const VDatabase* self,
1298 const VDBDependencies** dep,
1299 bool missing, bool disableCaching, bool alwaysResolveRemote)
1300 {
1301 rc_t rc = 0;
1302 VDBDependencies* obj = NULL;
1303 bool all = ! missing;
1304 bool has_no_REFERENCE = false;
1305 bool hasDuplicates = false;
1306
1307 if (self == NULL) {
1308 return RC(rcVDB, rcDatabase, rcAccessing, rcSelf, rcNull);
1309 }
1310 if (dep == NULL) {
1311 return RC(rcVDB, rcDatabase, rcAccessing, rcParam, rcNull);
1312 }
1313
1314 obj = calloc(1, sizeof *obj);
1315 if (obj == NULL) {
1316 return RC(rcVDB, rcStorage, rcAllocating, rcMemory, rcExhausted);
1317 }
1318
1319 obj->tr = malloc(sizeof *obj->tr);
1320 if (obj->tr == NULL) {
1321 free(obj);
1322 return RC(rcVDB, rcStorage, rcAllocating, rcMemory, rcExhausted);
1323 }
1324 BSTreeInit(obj->tr);
1325
1326 /* initialize dependencie tree */
1327 rc = VDatabaseDependencies(self, obj->tr,
1328 &has_no_REFERENCE, &hasDuplicates, disableCaching, alwaysResolveRemote);
1329 if (rc == 0 && has_no_REFERENCE) {
1330 KRefcountInit(&obj->refcount, 1, CLSNAME, "make", "nodep");
1331 *dep = obj;
1332 return rc;
1333 }
1334
1335 if (rc == 0) {
1336 Initializer init;
1337 memset(&init, 0, sizeof init);
1338
1339 /* count all/missing dependencies */
1340 init.all = all;
1341 init.fill = false;
1342 BSTreeForEach(obj->tr, false, bstProcess, &init);
1343 /* now init.count = number of (all == true ? 'all' : 'missed') references*/
1344
1345 rc = init.rc;
1346 if (rc == 0) {
1347 obj->count = init.count;
1348 }
1349
1350 if (rc == 0 && missing && hasDuplicates) {
1351 /* references have duplicates. e.g. AAAB01... */
1352 SBstCopy x;
1353 BSTree* tr = malloc(sizeof *tr);
1354 if (tr == NULL) {
1355 rc = RC(rcVDB, rcStorage, rcAllocating, rcMemory, rcExhausted);
1356 return rc;
1357 }
1358 BSTreeInit(tr);
1359 x.count = 0;
1360 x.tr = tr;
1361 x.all = all;
1362
1363 /* compact obj->tr into tr, skip duplicates
1364 x.count is the number of all references from obj.tr */
1365 BSTreeForEach(obj->tr, false, bstCopy, &x);
1366 BSTreeWhack(obj->tr, bstWhack, NULL);
1367 free(obj->tr);
1368 obj->tr = tr;
1369 obj->count = init.count = x.count;
1370 }
1371
1372 if (rc == 0) {
1373 /* initialize dependencies array with pointers to tree values */
1374 if (obj->count > 0) {
1375 obj->dependencies
1376 = calloc(obj->count, sizeof obj->dependencies);
1377 if (obj->dependencies == NULL) {
1378 free(obj);
1379 return RC
1380 (rcVDB, rcStorage, rcAllocating, rcMemory, rcExhausted);
1381 }
1382 init.fill = true;
1383 init.dep = obj;
1384 BSTreeForEach(obj->tr, false, bstProcess, &init);
1385 rc = init.rc;
1386 if (rc == 0 && init.i != init.count) {
1387 rc = RC(rcVDB, rcDatabase, rcAccessing, rcSelf, rcCorrupt);
1388 }
1389 }
1390 }
1391 }
1392
1393 if (rc == 0) {
1394 KRefcountInit(&obj->refcount, 1, CLSNAME, "make", "dep");
1395 *dep = obj;
1396 }
1397 else {
1398 VDBDependenciesRelease(obj);
1399 }
1400
1401 return rc;
1402 }
1403
1404
1405 /* ListDependencies
1406 * create a dependencies object: list all dependencies
1407 *
1408 * "dep" [ OUT ] - return for VDBDependencies object
1409 *
1410 * "missing" [ IN ] - if true, list only missing dependencies
1411 * otherwise, list all dependencies
1412 *
1413 * N.B. If missing == true then
1414 * just one refseq dependency will be returned for 'container' Refseq files.
1415 */
VDatabaseListDependencies(const VDatabase * self,const VDBDependencies ** dep,bool missing)1416 LIB_EXPORT rc_t CC VDatabaseListDependencies(const VDatabase* self,
1417 const VDBDependencies** dep, bool missing)
1418 {
1419 return VDatabaseListDependenciesImpl(self, dep, missing, false, true);
1420 }
1421
1422
1423 /* ListDependenciesWithCaching
1424 * create dependencies object: list dependencies
1425 *
1426 * Call VResolverCacheEnable(cacheState) before reading VDatabase.
1427 * It allows to control cache update inside the function.
1428 *
1429 * "dep" [ OUT ] - return for VDBDependencies object
1430 *
1431 * "missing" [ IN ] - if true, list only missing dependencies
1432 * otherwise, list all dependencies
1433 *
1434 * "disableCaching" [ IN ] - if true, disable caching inside of the function
1435 * otherwise, do not change the caching state
1436 */
VDatabaseListDependenciesWithCaching(struct VDatabase const * self,const VDBDependencies ** dep,bool missing,bool disableCaching)1437 LIB_EXPORT rc_t CC VDatabaseListDependenciesWithCaching (
1438 struct VDatabase const *self,
1439 const VDBDependencies **dep, bool missing,
1440 bool disableCaching )
1441 {
1442 return VDatabaseListDependenciesImpl(
1443 self, dep, missing, disableCaching, true);
1444 }
1445
1446 /* FindDependencies
1447 * create dependencies object: list dependencies
1448 *
1449 * Don't resolve remote location if dependency was found locally.
1450 *
1451 * "dep" [ OUT ] - return for VDBDependencies object
1452 */
VDatabaseFindDependencies(struct VDatabase const * self,const VDBDependencies ** dep)1453 LIB_EXPORT rc_t CC VDatabaseFindDependencies(struct VDatabase const *self,
1454 const VDBDependencies **dep)
1455 {
1456 return VDatabaseListDependenciesImpl(self, dep, false, false, false);
1457 }
1458
1459
DependenciesError(rc_t rc)1460 static bool DependenciesError(rc_t rc) {
1461 return GetRCModule(rc) == rcAlign && GetRCObject(rc) == (enum RCObject)rcTable
1462 && GetRCState(rc) == rcNotFound;
1463 }
1464
1465 typedef enum ErrType {
1466 eUnknown,
1467 eNoEncInKfg,
1468 ePwdFileNotFound,
1469 eBadPwdFile,
1470 eBadEncKey
1471 } ErrType;
1472
DependenciesType(rc_t rc)1473 static ErrType DependenciesType(rc_t rc) {
1474 if (GetRCTarget(rc) == rcEncryptionKey)
1475 {
1476 switch (GetRCSTATE(rc))
1477 {
1478 /* no configuration or environment */
1479 case RC_STATE(rcFile, rcUnknown):
1480 return eNoEncInKfg;
1481
1482 /* no file where told to look */
1483 case RC_STATE(rcFile, rcNotFound):
1484 return ePwdFileNotFound;
1485
1486 /* after decryption the file wasn't a database object */
1487 case RC_STATE(rcEncryption, rcIncorrect):
1488 return eBadEncKey;
1489
1490 default:
1491 break;
1492 }
1493 }
1494 else if (GetRCTarget(rc) == rcMgr)
1495 {
1496 switch (GetRCSTATE(rc))
1497 {
1498 case RC_STATE(rcEncryptionKey, rcTooShort): /* too short */
1499 case RC_STATE(rcEncryptionKey, rcTooLong): /* too long */
1500 return eBadPwdFile;
1501
1502 default:
1503 break;
1504 }
1505 }
1506 return eUnknown;
1507 }
1508
UIError(rc_t rc,const VDatabase * db,const VTable * table)1509 LIB_EXPORT bool CC UIError( rc_t rc,
1510 const VDatabase* db, const VTable* table)
1511 {
1512 bool retval = false;
1513 if( db != NULL || table != NULL ) {
1514 if( DependenciesError(rc) ) {
1515 if( db != NULL ) {
1516 VDatabaseAddRef(db);
1517 } else if( VTableOpenParentRead(table, &db) != 0 ) {
1518 db = NULL;
1519 }
1520 if( db != NULL ) {
1521 const VTable* ref;
1522 if( VDatabaseOpenTableRead(db, &ref, "REFERENCE") == 0 ) {
1523 const VCursor* c;
1524 if( VTableCreateCachedCursorRead(ref, &c, 0) == 0 ) {
1525 uint32_t i;
1526 retval = VCursorAddColumn(c, &i, "CIRCULAR") == 0
1527 && VCursorOpen(c) == 0;
1528 VCursorRelease(c);
1529 }
1530 VTableRelease(ref);
1531 }
1532 VDatabaseRelease(db);
1533 }
1534 }
1535 }
1536 else if (db == NULL && table == NULL) {
1537 ErrType type = DependenciesType(rc);
1538 if (type != eUnknown) {
1539 retval = true;
1540 }
1541 }
1542 return retval;
1543 }
1544
1545 static
VDBDependenciesLOGMissing(rc_t rc,const VDatabase * db,bool log_list)1546 void CC VDBDependenciesLOGMissing( rc_t rc,
1547 const VDatabase* db, bool log_list )
1548 {
1549 static bool once = false;
1550 if( !once ) {
1551 KWrtHandler handler;
1552
1553 once = true;
1554
1555 handler.writer = KOutWriterGet();
1556 handler.data = KOutDataGet();
1557 KOutHandlerSetStdErr();
1558
1559 if (DependenciesError(rc)) {
1560 OUTMSG(("This operation requires access to external"
1561 " reference sequence(s) that could not be located\n"));
1562 if (db && log_list) {
1563 const VDBDependencies* dep = NULL;
1564 uint32_t i, count = 0;
1565 if( VDatabaseListDependencies(db, &dep, true) == 0 &&
1566 VDBDependenciesCount(dep, &count) == 0 ) {
1567 for(i = 0; i < count; i++) {
1568 const char* name = NULL, *seqId = NULL;
1569 if (VDBDependenciesName(dep, &name, i) == 0
1570 && VDBDependenciesSeqId(dep, &seqId, i) == 0)
1571 {
1572 OUTMSG(("Reference sequence %s %s was not found\n",
1573 seqId, name));
1574 }
1575 }
1576 VDBDependenciesRelease(dep);
1577 }
1578 }
1579 OUTMSG((
1580 "Please run \"perl configuration-assistant.perl\" and try again\n"
1581 ));
1582 }
1583 else {
1584 switch (DependenciesType(rc)) {
1585 case eNoEncInKfg:
1586 OUTMSG((
1587 "The file you are trying to open is encrypted,\n"
1588 "but no decryption password could be located.\n"
1589 "To set up a password,\n"
1590 "run the 'configuration-assistant.perl' script provided with the toolkit.\n"));
1591 break;
1592 case ePwdFileNotFound:
1593 OUTMSG((
1594 "The file you are trying to open is encrypted,\n"
1595 "but no decryption password could be obtained\n"
1596 "from the path given in configuration.\n"
1597 "To set up or change a password,\n"
1598 "run the 'configuration-assistant.perl' script provided with the toolkit.\n"));
1599 break;
1600 case eBadEncKey:
1601 OUTMSG((
1602 "The file you are trying to open is encrypted, but could not be opened.\n"
1603 "Either your password is incorrect or the downloaded file is corrupt.\n"
1604 "To set up or change a password,\n"
1605 "run the 'configuration-assistant.perl' script provided with the toolkit.\n"
1606 "To test the file for corruption,\n"
1607 "run the 'nencvalid' tool provided with the toolkit.\n"));
1608 break;
1609 case eBadPwdFile:
1610 OUTMSG((
1611 "The file you are trying to open is encrypted, but could not be opened.\n"
1612 "The password in the password file in unusable either from being 0 bytes\n"
1613 "or more than 4096 bytes long. The password starts at the beginning of\n"
1614 "the file and ends with the first CR (\\r) pr LF (\\n) or at the end of\n"
1615 "the file.\n"
1616 "To set up or change a password,\n"
1617 "run the 'configuration-assistant.perl' script provided with the toolkit.\n"));
1618 break;
1619 default:
1620 assert(0);
1621 }
1622 }
1623
1624 OUTMSG(("\n"));
1625 KOutHandlerSet(handler.writer, handler.data);
1626 }
1627 }
1628
UIDatabaseGetErrorString(rc_t rc)1629 LIB_EXPORT const char* CC UIDatabaseGetErrorString(rc_t rc)
1630 {
1631 if (DependenciesError(rc)) {
1632 return "This operation requires access to external"
1633 " reference sequence(s) that could not be located";
1634 }
1635 else {
1636 switch (DependenciesType(rc)) {
1637 case eNoEncInKfg:
1638 return "The file is encrypted, "
1639 "but no decryption password could be located";
1640 case ePwdFileNotFound:
1641 return "The file is encrypted, "
1642 "but no decryption password could be obtained "
1643 "from the path given in configuration";
1644 case eBadEncKey:
1645 return "The file is encrypted, but could not be opened. "
1646 "Either the password is incorrect or the file is corrupt";
1647 case eBadPwdFile:
1648 return "The file is encrypted, but could not be opened. "
1649 "The password in the password file in unusable";
1650 default:
1651 assert(0);
1652 return "Unexpected Dependency Type";
1653 }
1654 }
1655 }
1656
UIDatabaseLOGError(rc_t rc,const VDatabase * db,bool log_list)1657 LIB_EXPORT void CC UIDatabaseLOGError( rc_t rc,
1658 const VDatabase* db, bool log_list )
1659 {
1660 VDBDependenciesLOGMissing(rc, db, log_list);
1661 }
1662
UITableLOGError(rc_t rc,const VTable * table,bool log_list)1663 LIB_EXPORT void CC UITableLOGError( rc_t rc,
1664 const VTable* table, bool log_list )
1665 {
1666 const VDatabase* db;
1667 if( table == NULL ) {
1668 VDBDependenciesLOGMissing(rc, NULL, log_list);
1669 }
1670 else if( VTableOpenParentRead(table, &db) == 0 && db != NULL ) {
1671 VDBDependenciesLOGMissing(rc, db, log_list);
1672 VDatabaseRelease(db);
1673 }
1674 }
1675