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 <kdb/extern.h>
28
29 #include "kdb-priv.h"
30 #include "kdbfmt-priv.h"
31 #include "dbmgr-priv.h"
32
33 #include <krypto/key.h>
34 #include <krypto/encfile.h>
35 #include <krypto/wgaencrypt.h>
36
37 #include <vfs/manager.h>
38 #include <vfs/path.h>
39 #include <vfs/resolver.h>
40 #include <vfs/manager-priv.h>
41 #include <sra/srapath.h>
42
43 #include <kfs/kfs-priv.h>
44 #include <kfs/directory.h>
45 #include <kfs/file.h>
46 #include <kfs/arc.h>
47 #include <kfs/tar.h>
48 #include <kfs/sra.h>
49 #include <kfs/kfs-priv.h>
50 #include <klib/container.h>
51 #include <klib/text.h>
52 #include <klib/rc.h>
53 #include <sysalloc.h>
54
55 #include <va_copy.h>
56
57 #include <limits.h>
58 #include <stdlib.h>
59 #include <stdio.h>
60 #include <stdarg.h>
61 #include <stdio.h>
62 #include <string.h>
63 #include <ctype.h>
64 #include <os-native.h>
65 #include <assert.h>
66 #include <errno.h>
67
68 #ifndef SUPPORT_VFS_URI
69 #define SUPPORT_VFS_URI 0
70 #endif
71
72 #ifndef SUPPORT_KDB_TAR
73 #define SUPPORT_KDB_TAR 0
74 #endif
75
76 /*--------------------------------------------------------------------------
77 * KDB utility
78 */
79
80 /* KDBHdrValidate
81 * validates that a header sports a supported byte order
82 * and that the version is within range
83 */
84 /* this is included to make kdb.c vs. wkdb.c file comparisons easier in [x]emacs.*/
85 #if NOT_USED_IN_READ_ONLY_SIDE
KDBHdrValidate(const KDBHdr * hdr,size_t size,uint32_t min_vers,uint32_t max_vers)86 rc_t KDBHdrValidate ( const KDBHdr *hdr, size_t size,
87 uint32_t min_vers, uint32_t max_vers )
88 {
89 assert ( hdr != NULL );
90
91 if ( size < sizeof * hdr )
92 return RC ( rcDB, rcHeader, rcValidating, rcData, rcCorrupt );
93
94 if ( hdr -> endian != eByteOrderTag )
95 {
96 if ( hdr -> endian == eByteOrderReverse )
97 return RC ( rcDB, rcHeader, rcValidating, rcByteOrder, rcIncorrect );
98 return RC ( rcDB, rcHeader, rcValidating, rcData, rcCorrupt );
99 }
100
101 if ( hdr -> version < min_vers || hdr -> version > max_vers )
102 return RC ( rcDB, rcHeader, rcValidating, rcHeader, rcBadVersion );
103
104 return 0;
105 }
106 #endif
107
108 /* KDBPathType
109 * checks type of path
110 */
111 enum ScanBits
112 {
113 scan_db = ( 1 << 0 ),
114 scan_tbl = ( 1 << 1 ),
115 scan_idx = ( 1 << 2 ),
116 scan_col = ( 1 << 3 ),
117 scan_idxN = ( 1 << 4 ),
118 scan_data = ( 1 << 5 ),
119 scan_dataN = ( 1 << 6 ),
120 scan_md = ( 1 << 7 ),
121 scan_cur = ( 1 << 8 ),
122 scan_rNNN = ( 1 << 9 ),
123 scan_lock = ( 1 << 10 ),
124 scan_odir = ( 1 << 11 ),
125 scan_ofile = ( 1 << 12 ),
126 scan_meta = ( 1 << 13 ),
127 scan_skey = ( 1 << 14 ),
128 scan_sealed = ( 1 << 15 ),
129 scan_zombie = ( 1 << 16 )
130 };
131
132 static
scan_dbdir(const KDirectory * dir,uint32_t type,const char * name,void * data)133 rc_t CC scan_dbdir ( const KDirectory *dir, uint32_t type, const char *name, void *data )
134 {
135 uint32_t *bits = data;
136
137 type &= kptAlias - 1;
138
139 if ( type == kptDir )
140 {
141 switch ( name [ 0 ] )
142 {
143 case 'c':
144 if ( strcmp ( name, "col" ) == 0 )
145 { * bits |= scan_col; return 0; }
146 break;
147 case 'm':
148 if ( strcmp ( name, "md" ) == 0 )
149 { * bits |= scan_md; return 0; }
150 break;
151 case 't':
152 if ( strcmp ( name, "tbl" ) == 0 )
153 { * bits |= scan_tbl; return 0; }
154 break;
155 case 'i':
156 if ( strcmp ( name, "idx" ) == 0 )
157 { * bits |= scan_idx; return 0; }
158 break;
159 case 'd':
160 if ( strcmp ( name, "db" ) == 0 )
161 { * bits |= scan_db; return 0; }
162 break;
163 }
164
165 * bits |= scan_odir;
166 }
167 else if ( type == kptFile )
168 {
169 switch ( name [ 0 ] )
170 {
171 case 'l':
172 if ( strcmp ( name, "lock" ) == 0 )
173 { * bits |= scan_lock; return 0; }
174 break;
175 case 'i':
176 if ( memcmp ( name, "idx", 3 ) == 0 )
177 {
178 if ( isdigit ( name [ 3 ] ) )
179 { * bits |= scan_idxN; return 0; }
180 }
181 break;
182 case 'd':
183 if ( memcmp ( name, "data", 4 ) == 0 )
184 {
185 if ( name [ 4 ] == 0 )
186 { * bits |= scan_data; return 0; }
187 if ( isdigit ( name [ 4 ] ) )
188 { * bits |= scan_dataN; return 0; }
189 }
190 case 'c':
191 if ( strcmp ( name, "cur" ) == 0 )
192 { * bits |= scan_cur; return 0; }
193 break;
194 case 'r':
195 if ( isdigit ( name [ 1 ] ) && isdigit ( name [ 2 ] ) &&
196 isdigit ( name [ 3 ] ) && name [ 4 ] == 0 )
197 { * bits |= scan_rNNN; return 0; }
198 break;
199 case 'm':
200 if ( strcmp ( name, "meta" ) == 0 )
201 { * bits |= scan_meta; return 0; }
202 break;
203 case 's':
204 if ( strcmp ( name, "skey" ) == 0 )
205 { * bits |= scan_skey; return 0; }
206 if ( strcmp ( name, "sealed" ) == 0 )
207 { * bits |= scan_sealed; return 0; }
208 break;
209 }
210
211 * bits |= scan_ofile;
212 }
213 else if (type == kptZombieFile )
214 {
215 * bits |= scan_zombie;
216 }
217
218 return 0;
219 }
220
221
KDBPathTypeDir(const KDirectory * dir,int type,bool * pHasZombies,const char * path)222 int KDBPathTypeDir (const KDirectory * dir, int type, bool * pHasZombies, const char * path)
223 {
224 const char * leaf, * parent;
225 uint32_t bits;
226 rc_t rc;
227
228 bits = 0;
229
230 assert ((type == kptDir) || (type == (kptDir|kptAlias)));
231
232 rc = KDirectoryVisit ( dir, false, scan_dbdir, & bits, "%s", path );
233 if ( rc == 0 ) do
234 {
235 if ( ( bits & scan_zombie ) != 0 ) {
236 bits &= ~scan_zombie;
237 if (pHasZombies)
238 *pHasZombies = true;
239 }
240 /* look for a column */
241 if ( ( bits & scan_idxN ) != 0 &&
242 ( bits & ( scan_data | scan_dataN ) ) != 0 )
243 {
244 if ( ( bits & ( scan_db | scan_tbl | scan_idx | scan_col ) ) == 0 )
245 type += kptColumn - kptDir;
246 break;
247 }
248
249 /* look for a table */
250 if ( ( bits & scan_col ) != 0 )
251 {
252 /* can't have sub-tables or a db */
253 if ( ( bits & ( scan_db | scan_tbl ) ) == 0 )
254 {
255 /* look for an old-structure table */
256 if ( ( bits & ( scan_meta | scan_md ) ) == scan_meta ||
257 ( bits & ( scan_skey | scan_idx ) ) == scan_skey )
258 type += kptPrereleaseTbl - kptDir;
259 else
260 type += kptTable - kptDir;
261 }
262 break;
263 }
264
265 /* look for metadata */
266 if ( ( bits & ( scan_cur | scan_rNNN ) ) != 0 )
267 {
268 if ( ( bits & ( scan_db | scan_tbl | scan_idx | scan_col ) ) == 0 )
269 type += kptMetadata - kptDir;
270 break;
271 }
272
273 /* look for a database */
274 if ( ( bits & scan_tbl ) != 0 )
275 {
276 if ( ( bits & scan_col ) == 0 )
277 type += kptDatabase - kptDir;
278 break;
279 }
280
281 /* look for a structured column */
282 if ( ( bits & scan_odir ) != 0 )
283 {
284 leaf = strrchr ( path, '/' );
285 if ( leaf != NULL )
286 {
287 parent = string_rchr ( path, leaf - path, '/' );
288 if ( parent ++ == NULL )
289 parent = path;
290 if ( memcmp ( parent, "col/", 4 ) != 0 )
291 break;
292
293 bits = 0;
294 if ( KDirectoryVisit ( dir, 1, scan_dbdir, & bits, "%s", path ) == 0 )
295 {
296 if ( ( bits & scan_idxN ) != 0 &&
297 ( bits & ( scan_data | scan_dataN ) ) != 0 )
298 {
299 if ( ( bits & ( scan_db | scan_tbl | scan_idx | scan_col ) ) == 0 )
300 type += kptColumn - kptDir;
301 break;
302 }
303 }
304 }
305 }
306 } while (0);
307
308 return type;
309 }
310
311
KDBPathType(const KDirectory * dir,bool * pHasZombies,const char * path)312 int KDBPathType ( const KDirectory *dir, bool *pHasZombies, const char *path )
313 {
314 const char *leaf, *parent;
315
316
317 rc_t rc;
318 int type = KDirectoryPathType ( dir, "%s", path );
319
320 if (pHasZombies)
321 *pHasZombies = false;
322
323 switch ( type )
324 {
325 case kptDir:
326 case kptDir | kptAlias:
327 type = KDBPathTypeDir (dir, type, pHasZombies, path);
328 break;
329
330 case kptFile:
331 case kptFile | kptAlias:
332 {
333 /* if we hit a file first try it as an archive */
334 const KDirectory * ldir;
335
336 rc = KDirectoryOpenSraArchiveRead_silent ( dir, &ldir, false, "%s", path );
337 #if SUPPORT_KDB_TAR
338 if ( rc != 0 )
339 rc = KDirectoryOpenTarArchiveRead_silent ( dir, &ldir, false, "%s", path );
340 #endif
341 /* it was an archive so recur */
342 if ( rc == 0 )
343 {
344 /* recheck this newly opened directory for KDB/KFS type */
345 int type2;
346
347 type2 = KDBPathType ( ldir, NULL, "." );
348 if ((type2 != kptDir) || (type != (kptDir|kptAlias)))
349 type = type2;
350
351 KDirectoryRelease (ldir);
352 }
353 /* it was not an archive so see if it it's an idx file */
354 else
355 {
356 leaf = strrchr ( path, '/' );
357 if ( leaf != NULL )
358 {
359 parent = string_rchr ( path, leaf - path, '/' );
360 if ( parent ++ == NULL )
361 parent = path;
362 if ( memcmp ( parent, "idx/", 4 ) == 0 )
363 type += kptIndex - kptFile;
364 }
365 }
366 break;
367 }
368 }
369 return type;
370 }
371
372
373
374 #if SUPPORT_VFS_URI
375 #else
376 /* return configured password as ASCIZ
377 * opertates on vfs/kfs/kfg objects, not kdb objects */
378 static
KDBOpenFileGetPassword(char * pw,size_t pwz)379 rc_t KDBOpenFileGetPassword (char * pw, size_t pwz)
380 {
381 VFSManager * mgr;
382 rc_t rc;
383
384 assert (pw);
385 assert (pwz);
386
387 pw[0] = '\0';
388
389 rc = VFSManagerMake (&mgr);
390 if (rc)
391 ; /* failure to make VFS manager: pass along rc */
392 else
393 {
394 size_t pwfz;
395 char pwf [4096 + 1];
396
397 rc = VFSManagerGetConfigPWFile (mgr, pwf, sizeof (pwf) - 1, &pwfz);
398 if (rc)
399 /* failure to get password file path: tweak rc */
400 rc = RC (rcDB, rcMgr, rcOpening, rcEncryptionKey, rcNotFound);
401
402 else
403 {
404 VPath * pwp;
405
406 pwf [pwfz] = '\0'; /* force to ASCIZ */
407
408 #if 0
409 rc = VPathMakeSysPath (&pwp, pwf);
410 #else
411 rc = VFSManagerMakePath (mgr, &pwp, "%s", pwf);
412 #endif
413
414 if (rc)
415 ; /* failure to construct a path from the string */
416
417 else
418 {
419 const KFile * pwf;
420
421 rc = VFSManagerOpenFileRead (mgr, &pwf, pwp);
422 if (rc)
423 /* failure to open password file */
424 rc = RC (rcDB, rcMgr, rcOpening, rcEncryptionKey, rcNotOpen);
425
426 else
427 {
428 size_t z;
429 char pwb [4098]; /* arbitrarily using 4096 as maximum
430 allowed length */
431
432 /* at this point we are only getting the password from a
433 * file but in the future if we can get it from a pipe of
434 * some sort we can't count on the ReadAll to really know
435 * if we hit end of file and not just a pause in the
436 * streaming. VFS/KFS 2 will have to fix this somehow
437 */
438
439 rc = KFileReadAll (pwf, 0, pwb, sizeof pwb, &z);
440 if (rc)
441 ; /* failure to read password file: pass along rc */
442 else
443 {
444 /* trim off EOL if present */
445 char * pc;
446
447 pwb[z] = '\0'; /* force ASCIZ */
448
449 pc = string_chr (pwb, z, '\r');
450 if (pc)
451 {
452 *pc = '\0';
453 z = 1 + pc - pwb;
454 }
455 pc = string_chr (pwb, z, '\n');
456 if (pc)
457 {
458 *pc = '\0';
459 z = 1 + pc - pwb;
460 }
461 if (z == 0)
462 rc = RC (rcDB, rcMgr, rcOpening, rcEncryptionKey, rcTooShort);
463
464 else if (pwz < z) /* pwz came in as 4096 */
465 rc = RC (rcDB, rcMgr, rcOpening, rcEncryptionKey, rcTooLong);
466
467 else
468 {
469 memmove (pw, pwb, z+1);
470 }
471 }
472 KFileRelease (pwf);
473 }
474 VPathRelease (pwp);
475 }
476 }
477 VFSManagerRelease (mgr);
478 }
479 return rc;
480 }
481
482
483 /* not KDB specific - just uses vfs/krypto/kfs objects */
484 static
KDBOpenFileAsDirectory(const KDirectory * dir,const char * path,const KDirectory ** pdir,uint32_t rcobj)485 rc_t KDBOpenFileAsDirectory (const KDirectory * dir,
486 const char * path,
487 const KDirectory ** pdir,
488 uint32_t rcobj)
489 {
490 const KFile * file;
491 const KFile * f;
492 const KDirectory * ldir;
493 bool encrypted = false;
494
495 rc_t rc;
496
497 *pdir = NULL;
498
499 rc = KDirectoryOpenFileRead (dir, &file, "%s", path);
500 if (rc == 0)
501 {
502 rc = KFileRandomAccess(file);
503 if (rc)
504 rc = RC (rcDB, rcMgr, rcOpening, rcobj, rcUnsupported);
505 else
506 {
507 size_t tz;
508 char tbuff [4096];
509 char pbuff [4096 + 1];
510
511 rc = KFileReadAll (file, 0, tbuff, sizeof tbuff, &tz);
512 if (rc == 0)
513 {
514 if (KFileIsEnc (tbuff, tz) == 0)
515 {
516 encrypted = true;
517
518 rc = KDBOpenFileGetPassword (pbuff, sizeof (pbuff) - 1);
519 if (rc == 0)
520 {
521 KKey key;
522
523 rc = KKeyInitRead (&key, kkeyAES128, pbuff, string_size (pbuff));
524 if (rc == 0)
525 {
526 rc = KEncFileMakeRead (&f, file, &key);
527 if (rc == 0)
528 {
529 /* KEncFileMakeRead adds a reference */
530 KFileRelease (file);
531 file = f;
532 rc = KFileReadAll (file, 0, tbuff, sizeof tbuff, &tz);
533 }
534 }
535 }
536 }
537 else if (KFileIsWGAEnc (tbuff, tz) == 0)
538 {
539 encrypted = true;
540
541 rc = KDBOpenFileGetPassword (pbuff, sizeof (pbuff) - 1);
542 if (rc == 0)
543 {
544 rc = KFileMakeWGAEncRead (&f, file, pbuff, string_size (pbuff));
545 if (rc == 0)
546 {
547 /* KFileMakeWGAEncRead adds a reference */
548 KFileRelease (file);
549 file = f;
550 rc = KFileReadAll (file, 0, tbuff, sizeof tbuff, &tz);
551 }
552 }
553 }
554 /* else not a handled encryption or unencrypted: we can't distinguish too much */
555
556 if (rc == 0)
557 {
558 if (KFileIsSRA (tbuff, tz) == 0)
559 {
560 rc = KDirectoryOpenSraArchiveReadUnbounded_silent_preopened (dir,
561 &ldir,
562 false,
563 file,
564 "%s",
565 path);
566 }
567 else
568 {
569 #if SUPPORT_KDB_TAR
570 rc = KDirectoryOpenTarArchiveRead_silent_preopened (dir, &ldir, false,
571 file, "%s", path);
572 #else
573 /* will be reset immediately below */
574 rc = -1;
575 #endif
576 }
577
578 /* not an archive type we handle or a bad archive */
579 if ( rc != 0 )
580 {
581 if (encrypted)
582 rc = RC ( rcDB, rcMgr, rcOpening, rcEncryptionKey, rcIncorrect );
583 else
584 rc = RC ( rcDB, rcMgr, rcOpening, rcPath, rcIncorrect );
585 }
586 else
587 {
588 /*
589 * release our ownership of the KFile that but archive will
590 * keep theirs
591 */
592 KFileRelease (file);
593 *pdir = ldir;
594 return 0;
595 }
596 }
597 }
598 }
599 KFileRelease (file);
600 }
601 return rc;
602 }
603 #endif
604
605
KDBOpenPathTypeReadInt(const KDBManager * mgr,const KDirectory * dir,const char * path,const KDirectory ** pdir,int * type,int pathtype,uint32_t rcobj,bool try_srapath,const VPath * aVpath)606 static rc_t KDBOpenPathTypeReadInt ( const KDBManager * mgr, const KDirectory * dir, const char * path,
607 const KDirectory ** pdir, int * type,
608 int pathtype, uint32_t rcobj, bool try_srapath,
609 const VPath * aVpath )
610 {
611 VFSManager * vmgr = mgr->vfsmgr;
612 const KDirectory * ldir = NULL;
613 rc_t rc = 0;
614
615 /* object relative opens can be done using KFS - we hacked in VFS after all */
616 if (! try_srapath)
617 {
618 rc = KDirectoryOpenDirUpdate ((KDirectory*)dir, (KDirectory**)pdir, false, "%s", path);
619 if ((rc) && (GetRCState(rc) != rcNotFound))
620 rc = KDirectoryOpenDirRead (dir, pdir, false, "%s", path);
621 }
622 else
623 {
624 VPath * vpath = ( VPath * ) aVpath;
625
626 /*
627 * We've got to decide if the path coming in is a full or relative
628 * path and if relative make it relative to dir or possibly its a srapath
629 * accession
630 *
631 */
632 rc = VFSManagerMakeDirectoryRelativeVPath (vmgr,
633 &vpath, dir, path, vpath );
634 if ( rc == 0 )
635 {
636 rc = VFSManagerOpenDirectoryReadDirectoryRelativeDecrypt ( vmgr, dir, &ldir, vpath );
637
638 if ( rc == 0 )
639 {
640 *type = (~kptAlias) & KDBPathType ( ldir, NULL, "." );
641
642 /* just a directory, not a kdb type */
643 if ( *type == kptDir )
644 rc = RC (rcDB, rcMgr, rcOpening, rcPath, rcIncorrect);
645
646 else if ( *type != pathtype )
647 {
648 KDirectoryRelease( ldir );
649 rc = RC ( rcDB, rcMgr, rcOpening, rcobj, rcIncorrect );
650 }
651 else
652 {
653 if ( pdir != NULL )
654 *pdir = ldir;
655 else
656 KDirectoryRelease( ldir );
657 }
658 }
659 if ( aVpath == NULL )
660 VPathRelease ( vpath );
661 }
662 }
663 return rc;
664 }
665
KDBOpenPathTypeRead(const KDBManager * mgr,const KDirectory * dir,const char * path,const KDirectory ** pdir,int pathtype,int * ppathtype,bool try_srapath,const VPath * vpath)666 rc_t KDBOpenPathTypeRead ( const KDBManager * mgr, const KDirectory * dir, const char * path,
667 const KDirectory ** pdir, int pathtype, int * ppathtype, bool try_srapath,
668 const VPath * vpath )
669 {
670 const KDirectory *ldir;
671 rc_t rc = 0;
672 uint32_t rcobj;
673 int type = kptNotFound; /* bogus? */
674
675 /* KOutMsg ("%s: %s\n", __func__, path); */
676
677 if ( pdir != NULL )
678 *pdir = NULL;
679 if ( ppathtype != NULL )
680 *ppathtype = type;
681
682 switch (pathtype & ~ kptAlias) /* tune the error message based on path type */
683 {
684 /* we'll hit this if we don't track defines in kdb/manager.h */
685 default:
686 rc = RC (rcDB, rcMgr, rcOpening, rcType, rcInvalid);
687 return rc;
688
689 case kptTable:
690 case kptPrereleaseTbl:
691 rcobj = rcTable;
692 break;
693
694 case kptColumn:
695 rcobj = rcColumn;
696 break;
697
698 case kptDatabase:
699 case kptDatabase | kptAlias:
700 rcobj = rcDatabase;
701 break;
702 }
703
704 rc = KDBOpenPathTypeReadInt( mgr, dir, path, &ldir, &type, pathtype, rcobj,
705 try_srapath, vpath );
706
707 if (rc == 0)
708 {
709 if ( ppathtype != NULL )
710 *ppathtype = type;
711
712 if (pdir != NULL)
713 *pdir = ldir;
714 else
715 KDirectoryRelease (ldir);
716 }
717
718 return rc;
719 }
720
721
722 /* Writable
723 * examines a directory structure for any "lock" files
724 */
KDBWritable(const KDirectory * dir,const char * path)725 rc_t KDBWritable ( const KDirectory *dir, const char *path )
726 {
727 uint32_t access;
728 rc_t rc;
729
730 /* protect us from bad parameters */
731 if (dir == NULL)
732 return RC (rcDB, rcPath, rcAccessing, rcDirectory, rcNull);
733 if (path == NULL)
734 return RC (rcDB, rcPath, rcAccessing, rcPath, rcNull);
735
736 /* we have to be able to check the access if it is to be writable */
737 rc = KDirectoryAccess ( dir, & access, "%s", path );
738 if ( rc == 0 )
739 {
740 /* if there is a lock (or deprecated sealed) file in this directory */
741 switch ( KDirectoryPathType ( dir, "%s/lock", path ) )
742 {
743 case kptFile:
744 case kptFile | kptAlias:
745 rc = RC ( rcDB, rcPath, rcAccessing, rcLock, rcLocked );
746 break;
747 case kptNotFound:
748 /* much simpler handling for the sealed file */
749 switch ( KDirectoryPathType ( dir, "%s/sealed", path ) )
750 {
751 case kptFile:
752 case kptFile | kptAlias:
753 rc = RC ( rcDB, rcPath, rcAccessing, rcLock, rcLocked );
754 break;
755 case kptNotFound:
756 /* check if there are no write permissions */
757 if ( ( access & 0222 ) == 0 )
758 rc = RC ( rcDB, rcPath, rcAccessing, rcPath, rcReadonly );
759 /* else rc is still 0 from VAccess */
760 }
761 break;
762 case kptBadPath:
763 /* likely to be a non-driectory or something */
764 rc = RC ( rcDB, rcPath, rcAccessing, rcPath, rcInvalid);
765 break;
766 default:
767 /* an illegal type of object named "lock" is in this directory
768 * which will block the ability to lock it
769 */
770 rc = RC ( rcDB, rcPath, rcAccessing, rcPath, rcIncorrect );
771 }
772 }
773 return rc;
774 }
775
776
KDBIsLocked(const KDirectory * dir,const char * path)777 bool KDBIsLocked ( const KDirectory *dir, const char *path )
778 {
779 return ( KDBWritable (dir, path) != 0 );
780 }
781
782
783 /* GetObjModDate
784 * extract mod date from a path
785 */
KDBGetObjModDate(const KDirectory * dir,KTime_t * mtime)786 rc_t KDBGetObjModDate ( const KDirectory *dir, KTime_t *mtime )
787 {
788 /* HACK ALERT - there needs to be a proper way to record modification times */
789
790 /* this only tells the last time the table was locked,
791 which may be close to the last time it was modified */
792 rc_t rc = KDirectoryDate ( dir, mtime, "lock" );
793 if ( rc == 0 )
794 return 0;
795
796 if ( GetRCState ( rc ) == rcNotFound )
797 {
798 rc = KDirectoryDate ( dir, mtime, "sealed" );
799 if ( rc == 0 )
800 return 0;
801 }
802
803 /* get directory timestamp */
804 rc = KDirectoryDate ( dir, mtime, "." );
805 if ( rc == 0 )
806 return 0;
807
808 * mtime = 0;
809 return rc;
810 }
811
812 /* GetPathModDate
813 * extract mod date from a path
814 */
KDBVGetPathModDate(const KDirectory * dir,KTime_t * mtime,const char * path,va_list args)815 rc_t KDBVGetPathModDate ( const KDirectory *dir,
816 KTime_t *mtime, const char *path, va_list args )
817 {
818 rc_t rc;
819 uint32_t ptype;
820 const KDirectory *obj_dir;
821
822 va_list cpy;
823 va_copy ( cpy, args );
824 ptype = KDirectoryVPathType ( dir, path, cpy );
825 va_end ( cpy );
826
827 switch ( ptype )
828 {
829 case kptDir:
830 case kptDir | kptAlias:
831 break;
832
833 default:
834 return KDirectoryVDate ( dir, mtime, path, args );
835 }
836
837 * mtime = 0;
838 rc = KDirectoryVOpenDirRead ( dir, & obj_dir, true, path, args );
839 if ( rc == 0 )
840 {
841 rc = KDBGetObjModDate ( obj_dir, mtime );
842 KDirectoryRelease ( obj_dir );
843 }
844
845 return rc;
846 }
847
848
849 /* KDBVMakeSubPath
850 * adds a namespace to path spec
851 */
KDBVMakeSubPath(struct KDirectory const * dir,char * subpath,size_t subpath_max,const char * ns,uint32_t ns_size,const char * path,va_list args)852 rc_t KDBVMakeSubPath ( struct KDirectory const *dir,
853 char *subpath, size_t subpath_max, const char *ns,
854 uint32_t ns_size, const char *path, va_list args )
855 {
856 rc_t rc;
857
858 if ( ns_size > 0 )
859 {
860 subpath += ns_size + 1;
861 subpath_max -= ns_size + 1;
862 }
863
864 #if CRUFTY_USE_OF_RESOLVE_PATH
865 /* because this call only builds a path instead of resolving anything
866 * is is okay that we are using the wrong directory */
867 rc = KDirectoryVResolvePath ( dir, false,
868 subpath, subpath_max, path, args );
869 #else
870 {
871 int sz = vsnprintf ( subpath, subpath_max, path, args );
872 if ( sz < 0 || ( size_t ) sz >= subpath_max )
873 rc = RC ( rcDB, rcDirectory, rcResolving, rcBuffer, rcInsufficient );
874 else if ( sz == 0 )
875 rc = RC ( rcDB, rcDirectory, rcResolving, rcPath, rcEmpty );
876 else
877 {
878 rc = 0;
879 }
880 }
881 #endif
882 switch ( GetRCState ( rc ) )
883 {
884 case 0:
885 assert ( subpath [ 0 ] != 0 );
886 if ( subpath [ 0 ] == '.' || subpath [ 1 ] == '/' )
887 return RC ( rcDB, rcDirectory, rcResolving, rcPath, rcInvalid );
888 break;
889 case rcInsufficient:
890 return RC ( rcDB, rcDirectory, rcResolving, rcPath, rcExcessive );
891 default:
892 return rc;
893 }
894
895 if ( ns_size != 0 )
896 {
897 subpath -= ns_size + 1;
898 memmove ( subpath, ns, ns_size );
899 subpath [ ns_size ] = '/';
900 }
901 return rc;
902 }
903
904 /* KDBMakeSubPath
905 * adds a namespace to path spec
906 */
KDBMakeSubPath(struct KDirectory const * dir,char * subpath,size_t subpath_max,const char * ns,uint32_t ns_size,const char * path,...)907 rc_t KDBMakeSubPath ( struct KDirectory const *dir,
908 char *subpath, size_t subpath_max, const char *ns,
909 uint32_t ns_size, const char *path, ... )
910 {
911 rc_t rc = 0;
912 va_list args;
913 va_start(args, path);
914 rc = KDBVMakeSubPath(dir, subpath, subpath_max, ns, ns_size, path, args);
915 va_end(args);
916 return rc;
917 }
918
919 /* this is included to make kdb.c vs. wkdb.c file comparisons easier in [x]emacs.*/
920 #if NOT_USED_IN_READ_ONLY_SIDE
921 /* VDrop
922 */
923 static
KDBDropInt(KDirectory * dir,const KDBManager * mgr,const char * path)924 rc_t KDBDropInt ( KDirectory * dir, const KDBManager * mgr,
925 const char * path )
926 {
927 }
928
KDBMgrVDrop(KDirectory * dir,const KDBManager * mgr,uint32_t obj_type,const char * path,va_list args)929 rc_t KDBMgrVDrop ( KDirectory * dir, const KDBManager * mgr, uint32_t obj_type,
930 const char * path, va_list args )
931 {
932 }
933 #endif
934
935 /* KDBIsPathUri
936 * A hack to get some of VFS into KDB that is too tightly bound to KFS
937 */
938
KDBIsPathUri(const char * path)939 bool KDBIsPathUri (const char * path)
940 {
941 const char * pc;
942 size_t z;
943
944 z = string_size (path);
945
946 if (NULL != (pc = string_chr (path, z, ':')))
947 return true;
948
949 if (NULL != (pc = string_chr (path, z, '?')))
950 return true;
951
952 if (NULL != (pc = string_chr (path, z, '#')))
953 return true;
954
955 return false;
956 }
957