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