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 #define TRACK_REFERENCES 0
28 
29 #include <kdb/extern.h>
30 #include "libkdb.vers.h"
31 #include "dbmgr-priv.h"
32 #include "wkdb-priv.h"
33 #include <kfs/impl.h>
34 
35 #include <vfs/manager.h>
36 #include <vfs/manager-priv.h> /* VFSManagerOpenDirectoryReadDecryptUnreliable */
37 #include <vfs/resolver.h>
38 #include <vfs/path.h>
39 #include <vfs/path-priv.h>
40 
41 #include <klib/symbol.h>
42 #include <klib/checksum.h>
43 #include <klib/rc.h>
44 
45 #include <sysalloc.h>
46 
47 #include <limits.h>
48 #include <string.h>
49 #include <stdlib.h>
50 #include <assert.h>
51 
52 
53 
54 /*--------------------------------------------------------------------------
55  * KDBManager
56  *  handle to library
57  */
58 
59 
60 /* MakeUpdate
61  *  create library handle
62  */
KDBManagerMakeUpdate(KDBManager ** mgrp,KDirectory * wd)63 LIB_EXPORT rc_t CC KDBManagerMakeUpdate ( KDBManager **mgrp, KDirectory *wd )
64 {
65     if ( wd == NULL || ! wd -> read_only )
66         return KDBManagerMake ( mgrp, wd, "make-update", NULL );
67 
68     if ( mgrp != NULL )
69         * mgrp = NULL;
70 
71     return RC ( rcDB, rcMgr, rcConstructing, rcDirectory, rcReadonly );
72 }
73 
KDBManagerMakeUpdateWithVFSManager(KDBManager ** mgrp,KDirectory * wd,struct VFSManager * vfs)74 LIB_EXPORT rc_t CC KDBManagerMakeUpdateWithVFSManager (
75     KDBManager ** mgrp, KDirectory * wd, struct VFSManager * vfs )
76 {
77     if ( wd == NULL || ! wd -> read_only )
78         return KDBManagerMake ( mgrp, wd, "make-update", vfs );
79 
80     if ( mgrp != NULL )
81         * mgrp = NULL;
82 
83     return RC ( rcDB, rcMgr, rcConstructing, rcDirectory, rcReadonly );
84 }
85 
86 
87 /* Writable
88  *  returns 0 if object is writable
89  *  or a reason why if not
90  *
91  *  "path" [ IN ] - NUL terminated path
92  *
93  * TBD: Better reasons for non local paths
94  */
95 static
KDBManagerWritableInt(const KDirectory * dir,const char * path)96 rc_t KDBManagerWritableInt ( const KDirectory * dir, const char * path )
97 {
98     rc_t rc;
99 
100     int type = KDBPathType ( /*NULL,*/ dir, NULL, path ) & ~ kptAlias;
101     switch ( type )
102     {
103     case kptDatabase:
104     case kptTable:
105     case kptPrereleaseTbl:
106     case kptColumn:
107         rc = KDBWritable ( dir, path );
108         break;
109 
110     case kptIndex:
111     case kptMetadata:
112         /* a wrong database type */
113         rc = RC ( rcDB, rcMgr, rcAccessing, rcPath, rcIncorrect );
114         break;
115 #if 0
116         /*TBD - eventually we need to check for an archive here */
117     case kptFile:
118         /* check if this is an archive .tar or .sra and return rcReadonly if it is */
119 #endif
120     case kptNotFound:
121         rc = RC ( rcDB, rcMgr, rcAccessing, rcPath, rcNotFound );
122         break;
123     case kptBadPath:
124         rc = RC ( rcDB, rcMgr, rcAccessing, rcPath, rcInvalid );
125         break;
126     default:
127         rc = RC ( rcDB, rcMgr, rcAccessing, rcPath, rcIncorrect );
128     }
129 
130     return rc;
131 }
132 
KDBManagerVWritable(const KDBManager * self,const char * path,va_list args)133 LIB_EXPORT rc_t CC KDBManagerVWritable ( const KDBManager *self, const char * path, va_list args )
134 {
135     rc_t rc;
136 
137     if ( self == NULL )
138         rc = RC ( rcDB, rcMgr, rcAccessing, rcSelf, rcNull );
139     else
140     {
141         char dbpath [ 4096 ];
142 
143         /* get full path to object */
144         rc = KDirectoryVResolvePath ( self -> wd, true, dbpath, sizeof dbpath, path, args );
145         if ( rc == 0 )
146             rc = KDBManagerWritableInt ( self -> wd, dbpath );
147     }
148     return rc;
149 }
150 
KDBManagerWritable(const KDBManager * self,const char * path,...)151 LIB_EXPORT rc_t CC KDBManagerWritable ( const KDBManager *self, const char * path, ... )
152 {
153     rc_t rc;
154 
155     va_list args;
156     va_start ( args, path );
157 
158     rc = KDBManagerVWritable ( self, path, args );
159 
160     va_end ( args );
161 
162     return rc;
163 }
164 
165 /* Lock
166  *  apply lock
167  *
168  *  if object is already locked, the operation is idempotent
169  *  and returns an rc state of rcLocked
170  *
171  *  "path" [ IN ] - NUL terminated path
172  */
KDBManagerVLock(KDBManager * self,const char * path,va_list args)173 LIB_EXPORT rc_t CC KDBManagerVLock ( KDBManager *self, const char *path, va_list args )
174 {
175     rc_t rc;
176     char full [ 4096 ];
177 
178     if ( self == NULL )
179         rc =  RC ( rcDB, rcMgr, rcLocking, rcSelf, rcNull );
180     else
181     {
182         /* TBD:
183            Add code to validate that this path is not in a container
184            object's control.  That is the last facet in the path
185            is the name of the object.  To be valid the facet before
186            must not be "col", "tbl", or "db" as in those cases
187            the KDBManager should not be called for this object but
188            its containing object
189         */
190 
191         /* get full path to object */
192         rc = KDirectoryVResolvePath ( self -> wd, true,
193             full, sizeof full, path, args );
194         if ( rc == 0 )
195         {
196             /* if the path is not writable because it is already locked
197              * the return from this will contain "rcLocked" and the
198              * caller will be forced to check for zero or RCState(rcLocked)
199              *
200              * a side effect is that if the call does not return 0 it will
201              * be a wrong type to lock with the DBManager
202              */
203             rc = KDBManagerWritableInt ( self -> wd, full );
204             if ( rc == 0 )
205             {
206                 rc = KDBManagerCheckOpen ( self, full );
207                 if ( rc == 0 )
208                     rc = KDBLockDir ( self -> wd, full );
209             }
210         }
211 
212         /* return dbmgr context */
213         if ( rc != 0 )
214             rc = ResetRCContext ( rc, rcDB, rcMgr, rcLocking );
215     }
216 
217     return rc;
218 }
219 
KDBManagerLock(KDBManager * self,const char * path,...)220 LIB_EXPORT rc_t CC KDBManagerLock ( KDBManager *self, const char *path, ... )
221 {
222     rc_t rc;
223 
224     va_list args;
225     va_start ( args, path );
226 
227     rc = KDBManagerVLock ( self, path, args );
228 
229     va_end ( args );
230 
231     return rc;
232 }
233 
234 /* Unlock
235  *  remove lock
236  *
237  *  if object is already unlocked, the operation is idempotent
238  *  and returns an rc state of rcUnlocked
239  *
240  *  "path" [ IN ] - NUL terminated path
241  */
KDBManagerVUnlock(KDBManager * self,const char * path,va_list args)242 LIB_EXPORT rc_t CC KDBManagerVUnlock ( KDBManager *self, const char *path, va_list args )
243 {
244     rc_t rc;
245     char full [ 4096 ];
246 
247     if ( self == NULL )
248         rc =  RC ( rcDB, rcMgr, rcUnlocking, rcSelf, rcNull );
249     else
250     {
251         /* get full path to object */
252         rc = KDirectoryVResolvePath ( self -> wd, true,
253             full, sizeof full, path, args );
254         if ( rc == 0 )
255         {
256             /* TBD:
257                Add code to validate that this path is not in a container
258                object's control.  That is the last facet in the path
259                is the name of the object.  To be valid the facet before
260                must not be "col", "tbl", or "db" as in those cases
261                the KDBManager should not be called for this object but
262                its containing object
263             */
264 
265             /* if the path is not writable because it is already locked
266              * we attempt to unlock it.
267              *
268              * if the return is 0 from Writable than it was already
269              * unlocked so we say so and thus again the
270              * the return from this will contain "rcLocked" and the
271              * caller will be forced to check for zero or RCState(rcUnlocked)
272              *
273              * a side effect is that if the call does not return 0 it will
274              * be a wrong type to lock with the DBManager
275              */
276             rc = KDBManagerWritableInt ( self -> wd, full );
277             if ( rc == 0 )
278                 rc = RC ( rcDB, rcMgr, rcUnlocking, rcLock, rcUnlocked );
279             else if ( GetRCState ( rc ) == rcLocked )
280             {
281                 rc = KDBManagerCheckOpen ( self, full );
282                 if ( rc == 0 )
283                     rc = KDBUnlockDir ( self -> wd, full );
284             }
285         }
286 
287         if ( rc != 0 )
288             rc = ResetRCContext ( rc, rcDB, rcMgr, rcUnlocking );
289     }
290     return rc;
291 }
292 
KDBManagerUnlock(KDBManager * self,const char * path,...)293 LIB_EXPORT rc_t CC KDBManagerUnlock ( KDBManager *self, const char *path, ... )
294 {
295     rc_t rc;
296 
297     va_list args;
298     va_start ( args, path );
299 
300     rc = KDBManagerVUnlock ( self, path, args );
301 
302     va_end ( args );
303 
304     return rc;
305 }
306 
KDBManagerVDrop(KDBManager * self,uint32_t obj_type,const char * path,va_list args)307 LIB_EXPORT rc_t CC KDBManagerVDrop ( KDBManager *self, uint32_t obj_type, const char *path, va_list args )
308 {
309     return KDBMgrVDrop ( self -> wd, self, obj_type, path, args );
310 }
311 
KDBManagerDrop(KDBManager * self,uint32_t obj_type,const char * path,...)312 LIB_EXPORT rc_t CC KDBManagerDrop ( KDBManager *self, uint32_t obj_type, const char *path, ... )
313 {
314     rc_t rc;
315     va_list args;
316 
317     va_start ( args, path );
318     rc = KDBManagerVDrop ( self, obj_type, path, args );
319     va_end ( args );
320 
321     return rc;
322 }
323 
324 
325 
326 /* RunPeriodicTasks
327  *  executes periodic tasks, such as cache flushing
328  */
KDBManagerRunPeriodicTasks(const KDBManager * self)329 LIB_EXPORT rc_t CC KDBManagerRunPeriodicTasks ( const KDBManager *self )
330 {
331     if ( self == NULL )
332         return RC ( rcDB, rcMgr, rcExecuting, rcSelf, rcNull );
333 
334     return 0;
335 }
336 
337 /* PathType
338  * check the path type of an object/directory path.
339  * this is an extension of the KDirectoryPathType and will return
340  * the KDirectory values if a path type is not specifically a
341  * kdb object
342  */
KDBManagerPathTypeVPImpl(const KDBManager * self,const VPath * path,bool reliable)343 static int CC KDBManagerPathTypeVPImpl( const KDBManager * self,
344     const VPath * path, bool reliable )
345 {
346     int path_type = kptBadPath;
347     if ( self != NULL && path != NULL )
348     {
349         /*
350          * resolve the possible relative path or accession into
351          * a final path we can open directly
352          */
353 		VPath * rpath;
354 		rc_t rc = VFSManagerResolvePath( self->vfsmgr, vfsmgr_rflag_kdb_acc, path, &rpath );
355         if ( rc == 0 )
356         {
357             const KDirectory * dir;
358 
359             /*
360              * Most KDBPathType values are based on 'directories'
361              * so try to open the resolved path as a directory
362              */
363             if ( reliable )
364                 rc = VFSManagerOpenDirectoryReadDecrypt          ( self->vfsmgr,
365                     &dir, rpath );
366             else
367                 rc = VFSManagerOpenDirectoryReadDecryptUnreliable( self->vfsmgr,
368                     &dir, rpath );
369             if ( rc == 0 )
370             {
371                 path_type = KDBPathTypeDir( dir, kptDir, NULL, "." );
372                 KDirectoryRelease( dir );
373             }
374             /*
375              * If we couldn't open the path as a directory we 'might'
376              * have a KDB idx but we will only try that for a limited
377              * set of uri schemes.
378              */
379             else
380             {
381                 if ( VPathIsFSCompatible( rpath ) )
382                 {
383                     char buffer [ 4096 ];
384                     rc = VPathReadPath( rpath, buffer, sizeof buffer, NULL );
385                     if ( rc == 0 )
386                         path_type = KDBPathType( self -> wd, false, buffer );
387                 }
388             }
389             VPathRelease( rpath );
390         }
391     }
392     return path_type;
393 }
394 
395 LIB_EXPORT
KDBManagerPathTypeVP(const KDBManager * self,const VPath * path)396 int CC KDBManagerPathTypeVP( const KDBManager * self, const VPath * path )
397 {
398     return KDBManagerPathTypeVPImpl ( self, path, true );
399 }
400 
KDBManagerVPathTypeImpl(const KDBManager * self,const char * path,va_list args,bool reliable)401 LIB_EXPORT int CC KDBManagerVPathTypeImpl ( const KDBManager * self,
402     const char *path, va_list args, bool reliable )
403 {
404     int path_type = kptBadPath;
405 
406     if ( self != NULL && path != NULL )
407     {
408         VPath * vp;
409         rc_t rc;
410 
411         rc = VFSManagerVMakePath( self -> vfsmgr, &vp, path, args );
412         if ( rc == 0 )
413         {
414             path_type = KDBManagerPathTypeVPImpl( self, vp, reliable );
415             VPathRelease( vp );
416         }
417     }
418     return path_type;
419 }
420 
KDBManagerVPathType(const KDBManager * self,const char * path,va_list args)421 LIB_EXPORT int CC KDBManagerVPathType ( const KDBManager * self,
422     const char *path, va_list args )
423 {
424     return KDBManagerVPathTypeImpl ( self, path, args, true );
425 }
KDBManagerVPathTypeUnreliable(const KDBManager * self,const char * path,va_list args)426 LIB_EXPORT int CC KDBManagerVPathTypeUnreliable ( const KDBManager * self,
427     const char *path, va_list args )
428 {
429     return KDBManagerVPathTypeImpl ( self, path, args, false );
430 }
431 
KDBManagerPathType(const KDBManager * self,const char * path,...)432 LIB_EXPORT int CC KDBManagerPathType ( const KDBManager * self, const char *path, ... )
433 {
434     rc_t rc;
435     va_list args;
436 
437     va_start ( args, path );
438 
439     rc = KDBManagerVPathType ( self, path, args );
440 
441     va_end (args);
442     return rc;
443 }
444 
445