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