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