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 #define KONST const
30 #include "database-priv.h"
31 #include "dbmgr-priv.h"
32 #undef KONST
33
34 #include "schema-priv.h"
35 #include "linker-priv.h"
36
37 #include <vdb/manager.h>
38 #include <vdb/database.h>
39 #include <kdb/kdb-priv.h>
40 #include <kdb/manager.h>
41 #include <kdb/database.h>
42 #include <kdb/meta.h>
43 #include <kdb/namelist.h>
44 #include <vfs/manager.h>
45 #include <vfs/resolver.h>
46 #include <vfs/path.h>
47
48 #include <klib/debug.h> /* DBGMSG */
49 #include <klib/log.h>
50 #include <klib/namelist.h>
51 #include <klib/printf.h>
52 #include <klib/strings.h> /* ENV_MAGIC_REMOTE_VDBCACHE */
53 #include <klib/rc.h>
54
55 #include <sysalloc.h>
56
57 #include "../vfs/path-priv.h" /* VPath */
58 #include "../vfs/resolver-priv.h" /* rcResolver */
59
60 #include <stdlib.h>
61 #include <string.h>
62 #include <assert.h>
63
64
65 /*--------------------------------------------------------------------------
66 * VDatabase
67 * opaque connection to a database within file system
68 */
69
70
71 /* Whack
72 */
VDatabaseWhack(VDatabase * self)73 rc_t CC VDatabaseWhack ( VDatabase *self )
74 {
75 rc_t rc = 0;
76
77 KRefcountWhack ( & self -> refcount, "VDatabase" );
78
79 /* release user data */
80 if ( self -> user != NULL && self -> user_whack != NULL )
81 {
82 ( * self -> user_whack ) ( self -> user );
83 self -> user = NULL;
84 self -> user_whack = NULL;
85 }
86
87 /* release dad */
88 if ( self -> dad != NULL )
89 {
90 rc = VDatabaseSever ( self -> dad );
91 if ( rc == 0 )
92 self -> dad = NULL;
93 }
94 /* release cache_db */
95 if ( self -> cache_db != NULL)
96 {
97 rc = VDatabaseRelease ( self -> cache_db );
98 if ( rc == 0 )
99 self -> cache_db = NULL;
100 }
101
102 /* remove from mgr */
103 if ( rc == 0 )
104 rc = VDBManagerSever ( self -> mgr );
105
106 if ( rc == 0 )
107 {
108 /* complete */
109 KMetadataRelease ( self -> meta );
110 KDatabaseRelease ( self -> kdb );
111 VSchemaRelease ( self -> schema );
112
113 free ( self );
114 return 0;
115 }
116
117 KRefcountInit ( & self -> refcount, 1, "VDatabase", "whack", "vdb" );
118 return rc;
119 }
120
121 /* AddRef
122 * Release
123 * all objects are reference counted
124 * NULL references are ignored
125 */
VDatabaseAddRef(const VDatabase * self)126 LIB_EXPORT rc_t CC VDatabaseAddRef ( const VDatabase *self )
127 {
128 if ( self != NULL )
129 {
130 switch ( KRefcountAdd ( & self -> refcount, "VDatabase" ) )
131 {
132 case krefLimit:
133 return RC ( rcVDB, rcDatabase, rcAttaching, rcRange, rcExcessive );
134 }
135 }
136 return 0;
137 }
138
VDatabaseRelease(const VDatabase * self)139 LIB_EXPORT rc_t CC VDatabaseRelease ( const VDatabase *self )
140 {
141 if ( self != NULL )
142 {
143 switch ( KRefcountDrop ( & self -> refcount, "VDatabase" ) )
144 {
145 case krefWhack:
146 return VDatabaseWhack ( ( VDatabase* ) self );
147 case krefNegative:
148 return RC ( rcVDB, rcDatabase, rcReleasing, rcRange, rcExcessive );
149 }
150 }
151 return 0;
152 }
153
154 /* Attach
155 * Sever
156 * internal reference management
157 */
VDatabaseAttach(const VDatabase * self)158 VDatabase *VDatabaseAttach ( const VDatabase *self )
159 {
160 if ( self != NULL )
161 {
162 switch ( KRefcountAddDep ( & self -> refcount, "VDatabase" ) )
163 {
164 case krefLimit:
165 return NULL;
166 }
167 }
168 return ( VDatabase* ) self;
169 }
170
VDatabaseSever(const VDatabase * self)171 rc_t VDatabaseSever ( const VDatabase *self )
172 {
173 if ( self != NULL )
174 {
175 switch ( KRefcountDropDep ( & self -> refcount, "VDatabase" ) )
176 {
177 case krefWhack:
178 return VDatabaseWhack ( ( VDatabase* ) self );
179 case krefNegative:
180 return RC ( rcVDB, rcDatabase, rcReleasing, rcRange, rcExcessive );
181 }
182 }
183 return 0;
184 }
185
186
187 /* Make - PRIVATE
188 * creates an initialized database object
189 * expects a mgr and optionally a parent db,
190 * enforces schema validity according to some rules,
191 */
VDatabaseMake(VDatabase ** dbp,const VDBManager * mgr,const VDatabase * dad,const VSchema * schema)192 rc_t VDatabaseMake ( VDatabase **dbp,
193 const VDBManager *mgr, const VDatabase *dad, const VSchema *schema )
194 {
195 rc_t rc;
196
197 /* create a structure */
198 VDatabase *db = calloc ( 1, sizeof * db );
199 if ( db == NULL )
200 rc = RC ( rcVDB, rcDatabase, rcConstructing, rcMemory, rcExhausted );
201 else
202 {
203 /* create a modifiable schema */
204 rc = VSchemaMake ( ( VSchema** ) & db -> schema, schema );
205 if ( rc == 0 )
206 {
207 db -> mgr = VDBManagerAttach ( mgr );
208 db -> dad = VDatabaseAttach ( dad );
209 KRefcountInit ( & db -> refcount, 1, "VDatabase", "make", "vdb" );
210
211 * dbp = db;
212 return 0;
213 }
214
215 VDatabaseWhack ( db );
216 }
217
218 * dbp = NULL;
219
220 return rc;
221 }
222
223
224 /* OpenRead
225 * finish opening a db for read
226 */
227 static
VDatabaseOpenRead(VDatabase * self)228 rc_t CC VDatabaseOpenRead ( VDatabase *self )
229 {
230 /* open metadata */
231 rc_t rc = KDatabaseOpenMetadataRead ( self -> kdb, & self -> meta );
232 if ( rc == 0 )
233 {
234 /* fetch stored schema */
235 rc = VDatabaseLoadSchema ( self );
236 if ( rc == 0 && self -> sdb == NULL )
237 rc = RC ( rcVDB, rcDatabase, rcOpening, rcSchema, rcNotFound );
238 }
239
240 DBGMSG(DBG_VDB, DBG_FLAG(DBG_VDB_VDB), ("VDatabaseOpenRead = %d\n", rc));
241
242 return rc;
243 }
244
245
246 /* OpenDBRead
247 * VOpenDBRead
248 * open a database for read
249 *
250 * "db" [ OUT ] - return parameter for newly opened database
251 *
252 * "schema" [ IN, NULL OKAY ] - schema object containg database
253 * declaration to be used in creating db.
254 *
255 * "path" [ IN ] - NUL terminated string in
256 * wd-native character set giving path to database
257 */
258 static
VDBManagerVPathOpenLocalDBRead(const VDBManager * self,const VDatabase ** dbp,const VSchema * schema,const VPath * path)259 rc_t VDBManagerVPathOpenLocalDBRead ( const VDBManager *self,
260 const VDatabase **dbp, const VSchema *schema, const VPath * path )
261 {
262 rc_t rc;
263 VDatabase * db;
264
265 if ( schema == NULL )
266 schema = self -> schema;
267
268 rc = VDatabaseMake ( & db, self, NULL, schema );
269 if ( rc == 0 )
270 {
271 db -> read_only = true;
272
273 rc = KDBManagerVPathOpenLocalDBRead ( self -> kmgr, & db -> kdb, path );
274 if ( rc == 0 )
275 {
276 rc = VDatabaseOpenRead ( db );
277 if ( rc == 0 )
278 {
279 * dbp = db;
280 return 0;
281 }
282 }
283
284 VDatabaseWhack ( db );
285 }
286
287 return rc;
288 }
289
290 static
VDBManagerVPathOpenRemoteDBRead(const VDBManager * self,const VDatabase ** dbp,const VSchema * schema,const VPath * remote,const VPath * cache)291 rc_t VDBManagerVPathOpenRemoteDBRead ( const VDBManager *self,
292 const VDatabase **dbp, const VSchema *schema, const VPath * remote, const VPath * cache )
293 {
294 rc_t rc;
295 VDatabase * db;
296
297 if ( schema == NULL )
298 schema = self -> schema;
299
300 rc = VDatabaseMake ( & db, self, NULL, schema );
301 if ( rc == 0 )
302 {
303 db -> read_only = true;
304
305 rc = KDBManagerVPathOpenRemoteDBRead ( self -> kmgr, & db -> kdb, remote, cache );
306 if ( rc == 0 )
307 {
308 rc = VDatabaseOpenRead ( db );
309 if ( rc == 0 )
310 {
311 * dbp = db;
312 return 0;
313 }
314 }
315
316 VDatabaseWhack ( db );
317 }
318
319 return rc;
320 }
321
322 typedef enum {
323 eCheckExistFalse,
324 eCheckExistTrue,
325 } ECheckExist;
326
327 typedef enum {
328 eCheckFilePathFalse,
329 eCheckFilePathTrue,
330 } ECheckFilePath;
331
332 typedef enum {
333 eCheckUrlFalse,
334 eCheckUrlTrue,
335 } ECheckUrl;
336
337 /* Returned rc != 0: env-var was set but somehow invalid
338 or it is eet to empty string == query returns not found
339 * rc == 0:
340 * * path != NULL: env-var was set and valid: use it!
341 * * path == NULL: was not set, keep going the old way
342 */
VFSManagerMagicResolve(const VFSManager * self,VPath ** path,const char * name,ECheckExist checkExist,ECheckFilePath checkPath,ECheckUrl checkUrl,bool * envVarWasSet)343 static rc_t VFSManagerMagicResolve(const VFSManager *self,
344 VPath ** path, const char * name,
345 ECheckExist checkExist,
346 ECheckFilePath checkPath,
347 ECheckUrl checkUrl,
348 bool * envVarWasSet)
349 {
350 rc_t rc = 0;
351
352 const char * magic = getenv(name);
353
354 assert(path);
355 *path = NULL;
356
357 if (magic == NULL) {
358 DBGMSG(DBG_VFS, DBG_FLAG(DBG_VFS_PATH), ("'%s' magic not set\n", name));
359 return 0;
360 }
361
362 assert(envVarWasSet);
363 *envVarWasSet = true;
364
365 /* variable set to empty: VResolverQuery returns not found */
366 if (magic[0] == '\0') {
367 DBGMSG(DBG_VFS, DBG_FLAG(DBG_VFS_PATH), ("'%s' magic empty\n", name));
368 return RC(rcVDB, rcResolver, rcResolving, rcName, rcNotFound);
369 }
370
371 rc = VFSManagerMakePath(self, path, "%s", magic);
372
373 if (rc == 0) {
374 bool high_reliability = true;
375
376 assert(path);
377
378 if (checkUrl == eCheckUrlTrue) {
379 if (!(*path)->from_uri)
380 {
381 DBGMSG(DBG_VFS, DBG_FLAG(DBG_VFS_PATH), (
382 "'%s' magic '%s' is not URL\n", name, magic));
383 rc = RC(rcVDB, rcResolver, rcResolving, rcName, rcInvalid);
384 }
385 else if ((*path)->scheme_type != vpuri_http
386 && (*path)->scheme_type != vpuri_https)
387 {
388 DBGMSG(DBG_VFS, DBG_FLAG(DBG_VFS_PATH), (
389 "'%s' magic '%s' is not HTTP[S] URL\n", name, magic));
390 rc = RC(rcVDB, rcResolver, rcResolving, rcName, rcInvalid);
391 }
392 }
393
394 if (rc == 0) {
395 const char * e = getenv("NCBI_VDB_RELIABLE");
396 if (e != NULL && e[0] == '\0')
397 high_reliability = false;
398 if (high_reliability)
399 rc = VPathMarkHighReliability((VPath*)*path, true);
400 }
401
402 if (rc != 0) {
403 VPathRelease(*path);
404 *path = NULL;
405 return rc;
406 }
407 else
408 if (high_reliability)
409 DBGMSG(DBG_VFS, DBG_FLAG(DBG_VFS_PATH), (
410 "'%s' reliable magic '%s' found\n", name, magic));
411 else
412 DBGMSG(DBG_VFS, DBG_FLAG(DBG_VFS_PATH), (
413 "'%s' unreliable magic '%s' found\n", name, magic));
414 }
415
416 else
417 DBGMSG(DBG_VFS, DBG_FLAG(DBG_VFS_PATH), (
418 "'%s' magic '%s' cannot be converted to VPath: %R\n",
419 name, magic, rc));
420
421 return rc;
422 }
423
VFSManagerCacheMagicResolve(const VFSManager * self,VPath ** path,bool * envVarWasSet)424 static rc_t VFSManagerCacheMagicResolve(
425 const VFSManager * self, VPath ** path, bool * envVarWasSet)
426 {
427 return VFSManagerMagicResolve(self, path,
428 ENV_MAGIC_CACHE_VDBCACHE,
429 eCheckExistFalse, eCheckFilePathTrue, eCheckUrlFalse, envVarWasSet);
430 }
431
VFSManagerLocalMagicResolve(const VFSManager * self,VPath ** path,bool * envVarWasSet)432 static rc_t VFSManagerLocalMagicResolve(
433 const VFSManager * self, VPath ** path, bool * envVarWasSet)
434 {
435 return VFSManagerMagicResolve(self, path,
436 ENV_MAGIC_LOCAL_VDBCACHE,
437 eCheckExistTrue, eCheckFilePathTrue, eCheckUrlFalse, envVarWasSet);
438 }
439
VFSManagerRemoteMagicResolve(const VFSManager * self,VPath ** path,bool * envVarWasSet)440 static rc_t VFSManagerRemoteMagicResolve(
441 const VFSManager * self, VPath ** path, bool * envVarWasSet)
442 {
443 return VFSManagerMagicResolve(self, path,
444 ENV_MAGIC_REMOTE_VDBCACHE,
445 eCheckExistFalse, eCheckFilePathFalse, eCheckUrlTrue, envVarWasSet);
446 }
447
DBManagerOpenVdbcache(const VDBManager * self,const VFSManager * vfs,const VDatabase * db,const VSchema * schema,const VPath * orig,bool is_accession,const VResolver * resolver,const VPath ** pcache,const VPath * plocal,const VPath ** premote)448 static rc_t DBManagerOpenVdbcache(const VDBManager *self,
449 const VFSManager * vfs, const VDatabase * db, const VSchema *schema,
450 const VPath * orig, bool is_accession, const VResolver * resolver,
451 const VPath ** pcache,
452 const VPath * plocal,
453 const VPath ** premote)
454 /* just one of plocal | premote is set */
455 {
456 rc_t rc2 = 0;
457
458 /* CSRA databases may have an associated "vdbcache" */
459 const VDatabase * vdbcache = NULL;
460
461 VPath * clocal = NULL; /* local VPath to vdbcache DB */
462 VPath * ccache = NULL; /* cache VPath to vdbcache DB - for remote */
463 VPath * cremote = NULL; /* remote VPath to vdbcache DB */
464
465 bool magicWasSet = false;
466
467 /* if principal was local */
468 if (plocal != NULL)
469 {
470 rc2 = VFSManagerLocalMagicResolve(vfs, &clocal, &magicWasSet);
471 if (rc2 == 0 && clocal == NULL)
472 /* make local path to vdbcache out of DB's path
473 just when magic variable is not set */
474 rc2 = VFSManagerMakePathWithExtension(
475 vfs, &clocal, plocal, ".vdbcache");
476 if (rc2 == 0)
477 {
478 rc2 = VDBManagerVPathOpenLocalDBRead( /* try to open local */
479 self, &vdbcache, schema, clocal); /* vdbcache DB */
480 if (rc2 != 0)
481 { /* local vdbcache db does not exist */
482 rc2 = 0;
483 if (!is_accession)
484 {
485 VPath * acc;
486 rc2 = VFSManagerExtractAccessionOrOID(vfs, &acc, orig);
487 if (rc2 == 0)
488 {
489 orig = acc;
490 }
491 }
492
493 /* was not found locally - try to get one remotely */
494 if (rc2 == 0
495 && !magicWasSet) /* check it remotely just when not */
496 { /* called by driver tool: it sets EnvVar */
497 /* We need suppress error message in the
498 * case if here any error happened
499 */
500 KLogLevel lvl = KLogLevelGet();
501 KLogLevelSet(klogFatal);
502 assert(*premote == NULL);
503 assert(pcache && *pcache == NULL);
504 /* YES,
505 DBG_VFS should be used here to be printed along with other VFS messages */
506 DBGMSG(DBG_VFS, DBG_FLAG(DBG_VFS_SERVICE),
507 (">>>>>>>>>>>>>> calling VResolverQuery to locate vdbcache..."
508 "\n"));
509 rc2 = VResolverQuery(
510 resolver, 0, orig, NULL, premote, pcache);
511 assert((rc2 == 0) ||
512 (rc2 != 0 && *premote == NULL));
513
514 /* Here we are restoring log level
515 */
516 KLogLevelSet(lvl);
517 VPathRelease(orig);
518 }
519 }
520 }
521 }
522
523 /* if principal was remote, or attempting remote vdbcache */
524 if (*premote != NULL)
525 {
526 rc2 = VFSManagerRemoteMagicResolve(vfs, &cremote, &magicWasSet);
527 if (rc2 == 0 && cremote == NULL) {
528 /* check if names service returned vdbcache */
529 bool vdbcacheChecked = false;
530
531 /* check remote path to vdbcache
532 just when magic variable is not set */
533 rc2 = VPathGetVdbcache(*premote,
534 (const VPath **)& cremote, &vdbcacheChecked);
535
536 /* try to manually build remote vdbcache path
537 just when names service was not able to return vdbcache:
538 should never happen these days */
539 if (rc2 != 0 || vdbcacheChecked == false)
540 rc2 = VFSManagerMakePathWithExtension(
541 vfs, (VPath**)& cremote, *premote, ".vdbcache");
542 }
543
544 if (rc2 == 0) {
545 rc2 = VFSManagerCacheMagicResolve(vfs, &ccache, &magicWasSet);
546 if (rc2 == 0 && ccache == NULL) {
547 /* manually build cache path to vdbcache
548 just when magic variable is not set */
549 if (*pcache != NULL)
550 rc2 = VFSManagerMakePathWithExtension(
551 vfs, &ccache, *pcache, ".vdbcache");
552 }
553 }
554
555 if (rc2 == 0)
556 rc2 = VDBManagerVPathOpenRemoteDBRead(
557 self, &vdbcache, schema, cremote, ccache);
558 }
559
560 VPathRelease(clocal);
561 VPathRelease(cremote);
562 VPathRelease(ccache);
563
564 /* if "vdbcache" is anything but NULL, we got the cache */
565 ((VDatabase*)db)->cache_db = vdbcache;
566
567 return rc2;
568 }
569
VDBManagerOpenDBReadVPathImpl(const VDBManager * self,const VDatabase ** dbp,const VSchema * schema,const VPath * path,bool openVdbcache)570 static rc_t VDBManagerOpenDBReadVPathImpl ( const VDBManager *self,
571 const VDatabase ** dbp, const VSchema *schema,
572 const VPath * path, bool openVdbcache )
573 {
574 rc_t rc = 0;
575
576 if ( dbp == NULL )
577 rc = RC ( rcVDB, rcMgr, rcOpening, rcParam, rcNull );
578 else
579 {
580 if ( self == NULL )
581 rc = RC ( rcVDB, rcMgr, rcOpening, rcSelf, rcNull );
582 else
583 {
584 /* need VFS manager to make a path */
585 VFSManager * vfs;
586 rc = KDBManagerGetVFSManager ( self -> kmgr, & vfs );
587 if ( rc == 0 )
588 {
589 /* get a reference to its pre-built resolver */
590 VResolver * resolver;
591 rc = VFSManagerGetResolver ( vfs, & resolver );
592 if ( rc == 0 )
593 {
594 /* turn spec in "path_fmt" + "args" into VPath "orig" */
595 const VPath * aOrig = path;
596 if ( rc == 0 )
597 {
598 /* the original VPath may get resolved into other paths */
599 const VPath * plocal = NULL, * premote = NULL, * pcache = NULL;
600
601 const VPath * orig = aOrig;
602 bool is_accession;
603
604 VFSManagerCheckEnvAndAd(vfs, aOrig, &orig);
605
606 /* check whether we were given a path or accession */
607 is_accession = VPathIsAccessionOrOID ( orig );
608
609 /* if the original is not an accession */
610 if ( ! is_accession )
611 {
612 /* just create a new reference to original */
613 rc = VPathAddRef ( orig );
614 if ( rc == 0 )
615 plocal = orig;
616 }
617 else
618 {
619 /* otherwise, ask resolver to find a local path,
620 or get a remote path and optional place to cache data */
621 rc = VResolverQuery ( resolver, 0, orig, & plocal, & premote, & pcache );
622 if ( rc != 0 && GetRCState ( rc ) == rcNotFound )
623 {
624 rc = VPathAddRef ( orig );
625 if ( rc == 0 )
626 {
627 plocal = orig;
628 }
629
630 }
631 }
632 if ( rc == 0 )
633 {
634 /* now open the principal database */
635 if ( plocal != NULL )
636 rc = VDBManagerVPathOpenLocalDBRead ( self, dbp, schema, plocal );
637 else if ( premote != NULL )
638 rc = VDBManagerVPathOpenRemoteDBRead ( self, dbp, schema, premote, pcache );
639 else
640 {
641 /* resolver was unable to resolve this, so perhaps it was
642 not an accession or OID, but a simple file name */
643 rc = VPathAddRef ( orig );
644 if ( rc == 0 )
645 {
646 plocal = orig;
647 #define VDB_3531_FIX 1
648 #if VDB_3531_FIX
649 if ( pcache != NULL )
650 {
651 VPathRelease(pcache);
652 pcache = NULL;
653 }
654 #endif
655 rc = VDBManagerVPathOpenLocalDBRead ( self, dbp, schema, plocal );
656 }
657 }
658 if ( rc == 0 )
659 {
660 const VDatabase * db = * dbp;
661 if ( VDatabaseIsCSRA ( db ) )
662 {
663 if ( openVdbcache ) {
664 DBGMSG(DBG_VFS,
665 DBG_FLAG(DBG_VFS_SERVICE),
666 ("VDatabase is CSRA: "
667 "searching vdbcache...\n"));
668 DBManagerOpenVdbcache(self, vfs, db,
669 schema, orig, is_accession,
670 resolver,
671 &pcache, plocal, &premote);
672 }
673 else {
674 DBGMSG(DBG_VFS,
675 DBG_FLAG(DBG_VFS_SERVICE),
676 ("VDatabase is CSRA: "
677 "skip searching vdbcache\n"));
678 }
679 }
680 else
681 DBGMSG(DBG_VFS, DBG_FLAG(DBG_VFS_SERVICE),
682 ("VDatabase is not CSRA: "
683 "don't use vdbcache\n"));
684 }
685
686 VPathRelease ( plocal );
687 VPathRelease ( premote );
688 VPathRelease ( pcache );
689 }
690 }
691
692 VResolverRelease ( resolver );
693 }
694
695 VFSManagerRelease ( vfs );
696 }
697 }
698
699 if ( rc != 0 )
700 * dbp = NULL;
701 }
702
703 return rc;
704 }
705
706
VDBManagerOpenDBReadVPath(const VDBManager * self,const VDatabase ** dbp,const VSchema * schema,const VPath * path)707 LIB_EXPORT rc_t CC VDBManagerOpenDBReadVPath ( const VDBManager *self,
708 const VDatabase ** dbp, const VSchema *schema,
709 const VPath * path )
710 {
711 return VDBManagerOpenDBReadVPathImpl ( self, dbp, schema, path, true );
712 }
713
VDBManagerOpenDBReadVPathLight(const VDBManager * self,const VDatabase ** dbp,const VSchema * schema,const VPath * path)714 LIB_EXPORT rc_t CC VDBManagerOpenDBReadVPathLight ( const VDBManager *self,
715 const VDatabase ** dbp, const VSchema *schema,
716 const VPath * path )
717 {
718 return VDBManagerOpenDBReadVPathImpl ( self, dbp, schema, path, false );
719 }
720
VDBManagerVOpenDBRead(const VDBManager * self,const VDatabase ** dbp,const VSchema * schema,const char * path_fmt,va_list args)721 LIB_EXPORT rc_t CC VDBManagerVOpenDBRead ( const VDBManager *self,
722 const VDatabase ** dbp, const VSchema *schema,
723 const char * path_fmt, va_list args )
724 {
725 rc_t rc;
726
727 if ( dbp == NULL )
728 rc = RC ( rcVDB, rcMgr, rcOpening, rcParam, rcNull );
729 else
730 {
731 if ( self == NULL )
732 rc = RC ( rcVDB, rcMgr, rcOpening, rcSelf, rcNull );
733 else
734 {
735 /* need VFS manager to make a path */
736 VFSManager * vfs;
737 rc = KDBManagerGetVFSManager ( self -> kmgr, & vfs );
738 if ( rc == 0 )
739 {
740 /* get a reference to its pre-built resolver *
741 VResolver * resolver;
742 rc = VFSManagerGetResolver ( vfs, & resolver );*/
743 if ( rc == 0 )
744 {
745 /* turn spec in "path_fmt" + "args" into VPath "orig" */
746 VPath * aOrig = NULL;
747 rc = VFSManagerVMakePath ( vfs, &aOrig, path_fmt, args );
748 if ( rc == 0 )
749 rc = VDBManagerOpenDBReadVPath ( self, dbp, schema, aOrig );
750 VPathRelease ( aOrig );
751
752 #if 0
753 {
754 /* the original VPath may get resolved into other paths */
755 const VPath * plocal = NULL, * premote = NULL, * pcache = NULL;
756
757 const VPath * orig = aOrig;
758 ad(self->kmgr, aOrig, &orig);
759
760 /* check whether we were given a path or accession */
761 bool is_accession = VPathIsAccessionOrOID ( orig );
762
763 /* if the original is not an accession */
764 if ( ! is_accession )
765 {
766 /* just create a new reference to original */
767 rc = VPathAddRef ( orig );
768 if ( rc == 0 )
769 plocal = orig;
770 }
771 else
772 {
773 /* otherwise, ask resolver to find a local path,
774 or get a remote path and optional place to cache data */
775 rc = VResolverQuery ( resolver, 0, orig, & plocal, & premote, & pcache );
776 if ( rc != 0 && GetRCState ( rc ) == rcNotFound )
777 {
778 rc = VPathAddRef ( orig );
779 if ( rc == 0 )
780 {
781 plocal = orig;
782 }
783
784 }
785 }
786 if ( rc == 0 )
787 {
788 /* now open the principal database */
789 if ( plocal != NULL )
790 rc = VDBManagerVPathOpenLocalDBRead ( self, dbp, schema, plocal );
791 else if ( premote != NULL )
792 rc = VDBManagerVPathOpenRemoteDBRead ( self, dbp, schema, premote, pcache );
793 else
794 {
795 /* resolver was unable to resolve this, so perhaps it was
796 not an accession or OID, but a simple file name */
797 rc = VPathAddRef ( orig );
798 if ( rc == 0 )
799 {
800 plocal = orig;
801 #define VDB_3531_FIX 1
802 #if VDB_3531_FIX
803 if ( pcache != NULL )
804 {
805 VPathRelease(pcache);
806 pcache = NULL;
807 }
808 #endif
809 rc = VDBManagerVPathOpenLocalDBRead ( self, dbp, schema, plocal );
810 }
811 }
812 if ( rc == 0 )
813 {
814 const VDatabase * db = * dbp;
815 if ( VDatabaseIsCSRA ( db ) )
816 {
817 DBManagerOpenVdbcache(self, vfs, db,
818 schema, orig, is_accession, resolver,
819 &pcache, plocal, premote);
820 #if 0
821 /* CSRA databases may have an associated "vdbcache" */
822 const VDatabase * vdbcache = NULL;
823 VPath * clocal = NULL, * ccache = NULL;
824 const VPath * cremote = NULL;
825 /* if principal was local */
826 if ( plocal != NULL )
827 {
828 rc2 = VFSManagerMakePathWithExtension ( vfs, & clocal, plocal, ".vdbcache" );
829 if ( rc2 == 0 )
830 {
831 rc2 = VDBManagerVPathOpenLocalDBRead ( self, & vdbcache, schema, clocal );
832 if ( rc2 != 0 )
833 {
834 rc2 = 0;
835 if ( ! is_accession )
836 {
837 VPath * acc;
838 rc2 = VFSManagerExtractAccessionOrOID ( vfs, & acc, orig );
839 if ( rc2 == 0 )
840 {
841 VPathRelease ( orig );
842 orig = acc;
843 }
844 }
845
846 /* was not found locally - try to get one remotely */
847 if ( rc2 == 0 )
848 {
849 /* We need suppress error message in the
850 * case if here any error happened
851 */
852 KLogLevel lvl = KLogLevelGet ();
853 KLogLevelSet ( klogFatal );
854 assert ( premote == NULL );
855 assert ( pcache == NULL );
856 rc2 = VResolverQuery ( resolver, 0, orig, NULL, & premote, & pcache );
857 assert ( ( rc2 == 0 ) ||
858 ( rc2 != 0 && premote == NULL ) );
859
860 /* Here we are restoring log level
861 */
862 KLogLevelSet ( lvl );
863 }
864 }
865 }
866 }
867
868 /* if principal was remote, or attempting remote vdbcache */
869 if ( premote != NULL )
870 {
871 /* check
872 if names service returned vdbache */
873 bool vdbcacheChecked = false;
874 rc2 = VPathGetVdbcache ( premote,
875 & cremote, & vdbcacheChecked );
876
877 /* try to manually build remote vdbcache path
878 just when names service was not able to return vdbcache: shold never happen these days */
879 if ( rc2 != 0 || vdbcacheChecked == false )
880 rc2 = VFSManagerMakePathWithExtension ( vfs, (VPath**) & cremote, premote, ".vdbcache" );
881
882 if ( rc2 == 0 && pcache != NULL )
883 rc2 = VFSManagerMakePathWithExtension ( vfs, & ccache, pcache, ".vdbcache" );
884 if ( rc2 == 0 )
885 rc2 = VDBManagerVPathOpenRemoteDBRead ( self, & vdbcache, schema, cremote, ccache );
886 }
887
888 VPathRelease ( clocal );
889 VPathRelease ( cremote );
890 VPathRelease ( ccache );
891
892 /* if "vdbcache" is anything but NULL, we got the cache */
893 ( ( VDatabase* ) db ) -> cache_db = vdbcache;
894 #endif
895 }
896 }
897
898 VPathRelease ( plocal );
899 VPathRelease ( premote );
900 VPathRelease ( pcache );
901 }
902
903 if (aOrig != orig)
904 VPathRelease(aOrig);
905
906 VPathRelease ( orig );
907 }
908
909 VResolverRelease ( resolver );
910 #endif
911 }
912
913 VFSManagerRelease ( vfs );
914 }
915 }
916
917 if ( rc != 0 )
918 * dbp = NULL;
919 }
920
921 return rc;
922 }
923
VDBManagerOpenDBRead(const VDBManager * self,const VDatabase ** db,const VSchema * schema,const char * path,...)924 LIB_EXPORT rc_t CC VDBManagerOpenDBRead ( const VDBManager *self,
925 const VDatabase **db, const VSchema *schema,
926 const char *path, ... )
927 {
928 rc_t rc;
929 va_list args;
930
931 va_start ( args, path );
932 rc = VDBManagerVOpenDBRead ( self, db, schema, path, args );
933 va_end ( args );
934
935 return rc;
936 }
937
VDatabaseVOpenDBRead(const VDatabase * self,const VDatabase ** dbp,const char * name,va_list args)938 LIB_EXPORT rc_t CC VDatabaseVOpenDBRead ( const VDatabase *self,
939 const VDatabase **dbp, const char *name, va_list args )
940 {
941 rc_t rc;
942
943 if ( dbp == NULL )
944 rc = RC ( rcVDB, rcDatabase, rcOpening, rcParam, rcNull );
945 else
946 {
947 if ( self == NULL )
948 rc = RC ( rcVDB, rcDatabase, rcOpening, rcSelf, rcNull );
949 else
950 {
951 VDatabase *db;
952 rc = VDatabaseMake ( & db, self -> mgr, self, self -> schema );
953 if ( rc == 0 )
954 {
955 db -> read_only = true;
956
957 rc = KDatabaseVOpenDBRead ( self -> kdb, & db -> kdb, name, args );
958 if ( rc == 0 )
959 {
960 rc = VDatabaseOpenRead ( db );
961 if ( rc == 0 )
962 {
963 * dbp = db;
964 return 0;
965 }
966 }
967
968 VDatabaseWhack ( db );
969 }
970 }
971
972 * dbp = NULL;
973 }
974 return rc;
975 }
976
VDatabaseOpenDBRead(const VDatabase * self,const VDatabase ** db,const char * name,...)977 LIB_EXPORT rc_t CC VDatabaseOpenDBRead ( const VDatabase *self,
978 const VDatabase **db, const char *name, ... )
979 {
980 rc_t rc;
981 va_list args;
982
983 va_start ( args, name );
984 rc = VDatabaseVOpenDBRead ( self, db, name, args );
985 va_end ( args );
986
987 return rc;
988 }
989
990
991 /* Locked
992 * returns true if locked
993 */
VDatabaseLocked(const VDatabase * self)994 LIB_EXPORT bool CC VDatabaseLocked ( const VDatabase *self )
995 {
996 /* TBD - no concept of virtual database locking
997 other than physical database locking */
998 if ( self != NULL )
999 return KDatabaseLocked ( self -> kdb );
1000 return false;
1001 }
1002
1003
1004 /* IsAlias
1005 * returns true if object name is an alias
1006 * returns path to fundamental name if it was aliased
1007 *
1008 * "type" [ IN ] - a KDBPathType
1009 * valid values are kptDatabase, kptTable and kptIndex
1010 *
1011 * "resolved" [ OUT ] and "rsize" [ IN ] - optional output buffer
1012 * for fundamenta object name if "alias" is not a fundamental name,
1013 *
1014 * "name" [ IN ] - NUL terminated object name
1015 */
VDatabaseIsAlias(const VDatabase * self,uint32_t type,char * resolved,size_t rsize,const char * name)1016 LIB_EXPORT bool CC VDatabaseIsAlias ( const VDatabase *self, uint32_t type,
1017 char *resolved, size_t rsize, const char *name )
1018 {
1019 if ( self != NULL )
1020 return KDatabaseIsAlias ( self -> kdb, type, resolved, rsize, name );
1021
1022 if ( resolved != NULL && rsize != 0 )
1023 * resolved = 0;
1024
1025 return false;
1026 }
1027
1028
1029 /* Writable
1030 * returns 0 if object is writable
1031 * or a reason why if not
1032 *
1033 * "type" [ IN ] - a KDBPathType
1034 * valid values are kptDatabase, kptTable and kptIndex
1035 *
1036 * "path" [ IN ] - NUL terminated path
1037 */
VDatabaseVWritable(const VDatabase * self,uint32_t type,const char * name,va_list args)1038 LIB_EXPORT rc_t CC VDatabaseVWritable ( const VDatabase *self, uint32_t type,
1039 const char *name, va_list args )
1040 {
1041 rc_t rc;
1042
1043 if ( self == NULL )
1044 rc = RC ( rcVDB, rcDatabase, rcAccessing, rcSelf, rcNull );
1045 else
1046 rc = KDatabaseVWritable ( self -> kdb, type, name, args );
1047
1048 return rc;
1049 }
1050
VDatabaseWritable(const VDatabase * self,uint32_t type,const char * name,...)1051 LIB_EXPORT rc_t CC VDatabaseWritable ( const VDatabase *self, uint32_t type, const char *name, ... )
1052 {
1053 rc_t rc;
1054
1055 va_list args;
1056 va_start ( args, name );
1057
1058 rc = VDatabaseVWritable ( self, type, name, args );
1059
1060 va_end ( args );
1061
1062 return rc;
1063 }
1064
1065 /* OpenMetadataRead
1066 * opens metadata for read
1067 *
1068 * "meta" [ OUT ] - return parameter for metadata
1069 */
VDatabaseOpenMetadataRead(const VDatabase * self,const KMetadata ** meta)1070 LIB_EXPORT rc_t CC VDatabaseOpenMetadataRead ( const VDatabase *self, const KMetadata **meta )
1071 {
1072 rc_t rc;
1073 if ( meta == NULL )
1074 rc = RC ( rcVDB, rcDatabase, rcAccessing, rcParam, rcNull );
1075 else
1076 {
1077 * meta = NULL;
1078
1079 if ( self == NULL )
1080 rc = RC ( rcVDB, rcDatabase, rcAccessing, rcSelf, rcNull );
1081 else
1082 {
1083 /* we operate under the notion of
1084 single-threaded operation, so hand out
1085 read or update capable object */
1086 rc = KMetadataAddRef ( self -> meta );
1087 if ( rc == 0 )
1088 * meta = self -> meta;
1089 }
1090 }
1091
1092 return rc;
1093 }
1094
1095
1096 /* OpenManager
1097 * duplicate reference to manager
1098 * NB - returned reference must be released
1099 */
VDatabaseOpenManagerRead(const VDatabase * self,const VDBManager ** mgr)1100 LIB_EXPORT rc_t CC VDatabaseOpenManagerRead ( const VDatabase *self, const VDBManager **mgr )
1101 {
1102 rc_t rc;
1103
1104 if ( mgr == NULL )
1105 rc = RC ( rcVDB, rcDatabase, rcAccessing, rcParam, rcNull );
1106 else
1107 {
1108 if ( self == NULL )
1109 rc = RC ( rcVDB, rcDatabase, rcAccessing, rcSelf, rcNull );
1110 else
1111 {
1112 rc = VDBManagerAddRef ( self -> mgr );
1113 if ( rc == 0 )
1114 {
1115 * mgr = self -> mgr;
1116 return 0;
1117 }
1118 }
1119
1120 * mgr = NULL;
1121 }
1122
1123 return rc;
1124 }
1125
1126
1127 /* OpenParent
1128 * duplicate reference to parent database
1129 * NB - returned reference must be released
1130 */
VDatabaseOpenParentRead(const VDatabase * self,const VDatabase ** par)1131 LIB_EXPORT rc_t CC VDatabaseOpenParentRead ( const VDatabase *self, const VDatabase **par )
1132 {
1133 rc_t rc;
1134
1135 if ( par == NULL )
1136 rc = RC ( rcVDB, rcDatabase, rcAccessing, rcParam, rcNull );
1137 else
1138 {
1139 if ( self == NULL )
1140 rc = RC ( rcVDB, rcDatabase, rcAccessing, rcSelf, rcNull );
1141 else
1142 {
1143 rc = VDatabaseAddRef ( self -> dad );
1144 if ( rc == 0 )
1145 {
1146 * par = self -> dad;
1147 return 0;
1148 }
1149 }
1150
1151 * par = NULL;
1152 }
1153
1154 return rc;
1155 }
1156
1157
1158 /* OpenSchema
1159 * duplicate reference to table schema
1160 * NB - returned reference must be released
1161 */
VDatabaseOpenSchema(const VDatabase * self,const VSchema ** schema)1162 LIB_EXPORT rc_t CC VDatabaseOpenSchema ( const VDatabase *self, const VSchema **schema )
1163 {
1164 rc_t rc;
1165
1166 if ( schema == NULL )
1167 rc = RC ( rcVDB, rcDatabase, rcAccessing, rcParam, rcNull );
1168 else
1169 {
1170 if ( self == NULL )
1171 rc = RC ( rcVDB, rcDatabase, rcAccessing, rcSelf, rcNull );
1172 else
1173 {
1174 rc = VSchemaAddRef ( self -> schema );
1175 if ( rc == 0 )
1176 {
1177 * schema = self -> schema;
1178 return 0;
1179 }
1180 }
1181
1182 * schema = NULL;
1183 }
1184
1185 return rc;
1186 }
1187
1188
1189 /* lists the tables of the database
1190 *
1191 * "names" [ OUT ] - return parameter for tables
1192 */
VDatabaseListTbl(const VDatabase * self,KNamelist ** names)1193 LIB_EXPORT rc_t CC VDatabaseListTbl ( const VDatabase *self, KNamelist **names )
1194 {
1195 rc_t rc;
1196
1197 if ( names == NULL )
1198 rc = RC ( rcVDB, rcDatabase, rcListing, rcParam, rcNull );
1199 else
1200 {
1201 if ( self == NULL )
1202 rc = RC ( rcVDB, rcDatabase, rcListing, rcSelf, rcNull );
1203 else
1204 {
1205 if ( self->kdb == NULL )
1206 rc = RC ( rcVDB, rcDatabase, rcListing, rcParam, rcNull );
1207 else
1208 {
1209 return KDatabaseListTbl ( self->kdb, names );
1210 }
1211 }
1212 *names = NULL;
1213 }
1214 return rc;
1215 }
1216
1217 /* lists the sub-databases of the database
1218 *
1219 * "names" [ OUT ] - return parameter for databases
1220 */
VDatabaseListDB(const VDatabase * self,KNamelist ** names)1221 LIB_EXPORT rc_t CC VDatabaseListDB ( const VDatabase *self, KNamelist **names )
1222 {
1223 rc_t rc;
1224
1225 if ( names == NULL )
1226 rc = RC ( rcVDB, rcDatabase, rcListing, rcParam, rcNull );
1227 else
1228 {
1229 if ( self == NULL )
1230 rc = RC ( rcVDB, rcDatabase, rcListing, rcSelf, rcNull );
1231 else
1232 {
1233 if ( self->kdb == NULL )
1234 rc = RC ( rcVDB, rcDatabase, rcListing, rcParam, rcNull );
1235 else
1236 {
1237 return KDatabaseListDB ( self->kdb, names );
1238 }
1239 }
1240 *names = NULL;
1241 }
1242 return rc;
1243 }
1244
1245 /* GetUserData
1246 * SetUserData
1247 * store/retrieve an opaque pointer to user data
1248 */
VDatabaseGetUserData(const VDatabase * self,void ** data)1249 LIB_EXPORT rc_t CC VDatabaseGetUserData ( const VDatabase *self, void **data )
1250 {
1251 rc_t rc;
1252
1253 if ( data == NULL )
1254 rc = RC ( rcVDB, rcDatabase, rcAccessing, rcParam, rcNull );
1255 else
1256 {
1257 if ( self == NULL )
1258 rc = RC ( rcVDB, rcDatabase, rcAccessing, rcSelf, rcNull );
1259 else
1260 {
1261 * data = self -> user;
1262 return 0;
1263 }
1264
1265 * data = NULL;
1266 }
1267
1268 return rc;
1269 }
1270
VDatabaseSetUserData(const VDatabase * cself,void * data,void (CC * destroy)(void * data))1271 LIB_EXPORT rc_t CC VDatabaseSetUserData ( const VDatabase *cself,
1272 void *data, void ( CC * destroy ) ( void *data ) )
1273 {
1274 VDatabase *self = ( VDatabase* ) cself;
1275 if ( cself == NULL )
1276 return RC ( rcVDB, rcDatabase, rcUpdating, rcSelf, rcNull );
1277
1278 self -> user = data;
1279 self -> user_whack = destroy;
1280
1281 return 0;
1282 }
1283
1284
1285 /* OpenKDatabase
1286 * returns a new reference to underlying KDatabase
1287 */
VDatabaseOpenKDatabaseRead(const VDatabase * self,const KDatabase ** kdb)1288 LIB_EXPORT rc_t CC VDatabaseOpenKDatabaseRead ( const VDatabase *self, const KDatabase **kdb )
1289 {
1290 rc_t rc;
1291
1292 if ( kdb == NULL )
1293 rc = RC ( rcVDB, rcDatabase, rcAccessing, rcParam, rcNull );
1294 else
1295 {
1296 if ( self == NULL )
1297 rc = RC ( rcVDB, rcDatabase, rcAccessing, rcSelf, rcNull );
1298 else
1299 {
1300 rc = KDatabaseAddRef ( self -> kdb );
1301 if ( rc == 0 )
1302 {
1303 * kdb = self -> kdb;
1304 return 0;
1305 }
1306 }
1307
1308 * kdb = NULL;
1309 }
1310
1311 return rc;
1312 }
1313
1314
1315
1316 /* Typespec
1317 * retrieve db typespec
1318 *
1319 * AVAILABILITY: version 2.2
1320 *
1321 * "ts_buff" [ IN ] and "ts_size" [ IN ] - buffer for return of NUL-terminated
1322 * db typespec, e.g. 'NCBI:db:abc#1.1'
1323 */
VDatabaseTypespec(const VDatabase * self,char * ts_buff,size_t ts_size)1324 LIB_EXPORT rc_t CC VDatabaseTypespec ( const VDatabase *self, char *ts_buff, size_t ts_size )
1325 {
1326 rc_t rc;
1327
1328 if ( ts_size == 0 )
1329 rc = RC ( rcVDB, rcDatabase, rcAccessing, rcBuffer, rcInsufficient );
1330 else if ( ts_buff == NULL )
1331 rc = RC ( rcVDB, rcDatabase, rcAccessing, rcBuffer, rcNull );
1332 else
1333 {
1334 if ( self == NULL )
1335 rc = RC ( rcVDB, rcDatabase, rcAccessing, rcSelf, rcNull );
1336 else
1337 {
1338 rc_t rc2;
1339 rc2 = string_printf ( ts_buff, ts_size, NULL, "%N#%V", self -> sdb -> name, self -> sdb -> version );
1340 if ( rc2 == 0 )
1341 return 0;
1342 rc = rc2;
1343 }
1344
1345 ts_buff [ 0 ] = 0;
1346 }
1347
1348 return rc;
1349 }
1350
1351
1352 /* IsCSRA
1353 * ask an open database if it conforms to cSRA schema
1354 */
VDatabaseIsCSRA(const VDatabase * self)1355 LIB_EXPORT bool CC VDatabaseIsCSRA ( const VDatabase *self )
1356 {
1357 if ( self != NULL )
1358 {
1359 if ( KDatabaseExists ( self -> kdb, kptTable, "PRIMARY_ALIGNMENT" ) )
1360 {
1361 return KDatabaseExists ( self -> kdb, kptTable, "SEQUENCE" );
1362 }
1363 }
1364
1365 return false;
1366 }
1367
validName(const String * acc,const String * file)1368 static bool validName(const String * acc, const String * file) {
1369 assert(acc && file);
1370 const char ext[] = ".sra";
1371 const char next[] = ".noqual.sra";
1372 if (file->size == acc->size + 4) {
1373 if (string_cmp(file->addr, file->size,
1374 acc->addr, acc->size, acc->len) == 0)
1375 {
1376 if (string_cmp(file->addr + acc->size, file->size - acc->size,
1377 ext, sizeof ext - 1, sizeof ext - 1) == 0)
1378 {
1379 return true;
1380 }
1381 }
1382 return false;
1383 }
1384 else if (file->size == acc->size + 4 + 7) {
1385 if (string_cmp(file->addr, file->size,
1386 acc->addr, acc->size, acc->len) == 0)
1387 {
1388 if (string_cmp(file->addr + acc->size, file->size - acc->size,
1389 next, sizeof next - 1, sizeof next - 1) == 0)
1390 {
1391 return true;
1392 }
1393 }
1394 return false;
1395 }
1396 else {
1397 if (string_cmp(file->addr, file->size,
1398 acc->addr, acc->size, acc->len) == 0)
1399 {
1400 const char sfx[] = "_dbGaP-";
1401 if (string_cmp(file->addr + acc->size, sizeof sfx - 1,
1402 sfx, sizeof sfx - 1, sizeof sfx - 1) == 0)
1403 {
1404 size_t i = 0;
1405 for (i = acc->size + sizeof sfx - 1;
1406 i < file->size; ++i)
1407 {
1408 char c = file->addr[i];
1409 if (c < '0' || c > '9') {
1410 if (c == '.')
1411 break;
1412 else
1413 return false;
1414 }
1415 }
1416 if (string_cmp(file->addr + i, file->size - acc->size,
1417 ext, sizeof ext - 1, sizeof ext - 1) == 0)
1418 {
1419 return true;
1420 }
1421 if (string_cmp(file->addr + i, file->size - acc->size,
1422 next, sizeof next - 1, sizeof next - 1) == 0)
1423 {
1424 return true;
1425 }
1426 }
1427 }
1428 return false;
1429 }
1430 }
1431
1432 #define RELEASE(type, obj) do { rc_t rc2 = type##Release(obj); \
1433 if (rc2 && !rc) { rc = rc2; } obj = NULL; } while (false)
1434
1435 LIB_EXPORT
VDatabaseGetAccession(const VDatabase * self,const String ** aAcc)1436 rc_t CC VDatabaseGetAccession(const VDatabase * self, const String ** aAcc)
1437 {
1438 rc_t rc = 0;
1439
1440 const VDBManager *mgr = NULL;
1441 const KDBManager* kmgr = NULL;
1442 VFSManager* vfsmgr = NULL;
1443 const KDatabase * kdb = NULL;
1444
1445 const char * path = NULL;
1446
1447 if (rc == 0)
1448 rc = VDatabaseOpenManagerRead(self, &mgr);
1449 if (rc == 0)
1450 rc = VDBManagerGetKDBManagerRead(mgr, &kmgr);
1451 if (rc == 0)
1452 rc = KDBManagerGetVFSManager(kmgr, &vfsmgr);
1453 if (rc == 0)
1454 rc = VDatabaseOpenKDatabaseRead(self, &kdb);
1455 if (rc == 0)
1456 rc = KDatabaseGetPath(kdb, &path);
1457
1458 if (rc == 0) {
1459 /* path = "/S/S.sra";
1460 or path = "/S/S_dbGaP-NNN.sra" */
1461 uint32_t pathLen = string_measure(path, NULL);
1462
1463 /* find the last '/' */
1464 const char * last = string_rchr(path, pathLen, '/');
1465 if (last != NULL) {
1466 uint32_t fileLen = pathLen - (last - path) - 1;
1467 uint32_t l = pathLen - fileLen - 1;
1468 const char * start = NULL;
1469 uint32_t accLen = 0;
1470 String acc, file;
1471
1472 start = string_rchr(path, l, '/'); /* find the second last '/' */
1473 if (start == NULL)
1474 start = path;
1475 else
1476 ++start;
1477
1478 accLen = last - start;
1479 StringInit(&acc, start, accLen, accLen);
1480 StringInit(&file, last + 1, fileLen, fileLen);
1481
1482 if (validName(&acc, &file))
1483 rc = StringCopy(aAcc, &acc);
1484 }
1485 }
1486
1487 RELEASE(VDBManager, mgr);
1488 RELEASE(KDBManager, kmgr);
1489 RELEASE(VFSManager, vfsmgr);
1490 RELEASE(KDatabase, kdb);
1491
1492 return rc;
1493 }
1494
1495
1496 /* GetQualityCapability
1497 * can the database deliver full quality? synthetic quallity?
1498 */
VDatabaseGetQualityCapability(const VDatabase * self,bool * fullQuality,bool * synthQuality)1499 LIB_EXPORT rc_t CC VDatabaseGetQualityCapability ( const VDatabase *self,
1500 bool *fullQuality, bool *synthQuality )
1501 { /* function stub */
1502 if ( self == NULL )
1503 return RC ( rcVDB, rcDatabase, rcListing, rcSelf, rcNull );
1504 if ( fullQuality != NULL )
1505 *fullQuality = true;
1506 if ( synthQuality != NULL )
1507 *synthQuality = false;
1508 return 0;
1509 }
1510
1511 /* SetFullQualityType
1512 * switch database to deliver full quality
1513 */
VDatabaseSetFullQualityType(VDatabase * self)1514 LIB_EXPORT rc_t CC VDatabaseSetFullQualityType ( VDatabase *self )
1515 { /* function stub */
1516 if ( self == NULL )
1517 return RC ( rcVDB, rcDatabase, rcResetting, rcSelf, rcNull );
1518 return 0;
1519 }
1520
1521 /* SetSynthQualityType
1522 * switch database to deliver synthetic quality
1523 */
VDatabaseSetSynthQualityType(VDatabase * self)1524 LIB_EXPORT rc_t CC VDatabaseSetSynthQualityType ( VDatabase *self )
1525 { /* function stub */
1526 if (self == NULL)
1527 return RC ( rcVDB, rcDatabase, rcResetting, rcSelf, rcNull );
1528 return RC ( rcVDB, rcDatabase, rcResetting, rcMode, rcNotAvailable );
1529 }
1530