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