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 <vfs/extern.h>
28 
29 #include <sra/srapath.h>
30 
31 #include <vfs/manager.h>
32 #include <vfs/manager-priv.h>
33 #include <vfs/path.h>
34 #include <vfs/path-priv.h>
35 #include <vfs/resolver-priv.h> /* VResolverGetKNSManager */
36 #include <vfs/services-priv.h> /* KServiceMakeWithMgr */
37 
38 #include <krypto/key.h>
39 #include <krypto/encfile.h>
40 #include <krypto/wgaencrypt.h>
41 #include <krypto/ciphermgr.h>
42 
43 #include <kfg/config.h>
44 #include <kfg/repository.h>
45 #include <kfg/properties.h>
46 #include <kfg/keystore.h>
47 #include <kfg/keystore-priv.h>
48 #include <kfg/kfg-priv.h>
49 
50 #include <kfs/directory.h>
51 #include <kfs/file.h>
52 #include <kfs/sra.h>
53 #include <kfs/tar.h>
54 #include <kfs/dyload.h>
55 #include <kfs/kfs-priv.h>
56 #include <kfs/nullfile.h>
57 #include <kfs/buffile.h>
58 #include <kfs/quickmount.h>
59 #include <kfs/cacheteefile.h>
60 #include <kfs/cachetee2file.h>
61 #include <kfs/cachetee3file.h>
62 #include <kfs/rrcachedfile.h>
63 #include <kfs/recorder.h>
64 #include <kfs/lockfile.h>
65 #include <kfs/logfile.h>
66 #include <kfs/defs.h>
67 
68 #include <kns/http.h>
69 #include <kns/http-priv.h>
70 #include <kns/kns-mgr-priv.h>
71 #include <kns/manager.h>
72 
73 #include <kxml/xml.h>
74 
75 #include <klib/debug.h>
76 #include <klib/log.h>
77 #include <klib/namelist.h>
78 #include <klib/out.h>
79 #include <klib/printf.h>
80 #include <klib/rc.h>
81 #include <klib/refcount.h>
82 #include <klib/strings.h> /* ENV_VDB_REMOTE_NEED_CE */
83 #include <klib/time.h>
84 #include <klib/vector.h>
85 
86 #include <vdb/vdb-priv.h> /* VDBManagerGetQuality */
87 
88 #include "path-priv.h"
89 #include "resolver-priv.h"
90 
91 #include "../kfg/ngc-priv.h" /* KNgcObjMakeFromCmdLine */
92 
93 #include <strtol.h>
94 
95 #include <sysalloc.h>
96 #include <stdlib.h>
97 #include <string.h>
98 #include <ctype.h>
99 #include <os-native.h>
100 #include <assert.h>
101 
102 #include <limits.h> /* PATH_MAX */
103 #ifndef PATH_MAX
104 #define PATH_MAX 4096
105 #endif
106 
107 
108 #if _DEBUGGING
109 #define MGR_DEBUG(msg) DBGMSG(DBG_VFS,DBG_FLAG(DBG_VFS_MGR), msg)
110 #else
111 #define MGR_DEBUG(msg)
112 #endif
113 
114 #define VFS_KRYPTO_PASSWORD_MAX_SIZE 4096
115 
116 /*--------------------------------------------------------------------------
117  * VFSManager
118  */
119 
120 /* currently expected to be a singleton and not use a vtable but
121  * be fully fleshed out here */
122 struct VFSManager
123 {
124     /* the current directory in the eyes of the O/S when created */
125     KDirectory * cwd;
126 
127     /* configuration manager */
128     KConfig * cfg;
129 
130     /* krypto's cipher manager */
131     KCipherManager * cipher;
132 
133     /* SRAPath will be replaced with a VResolver */
134     struct VResolver * resolver;
135 
136     /* network manager */
137     KNSManager * kns;
138 
139     /* path to a global password file */
140     char *pw_env;
141 
142     /* encryption key storage */
143     struct KKeyStore* keystore;
144 
145     KRefcount refcount;
146 
147     VRemoteProtocols protocols;
148 };
149 
150 static const char kfsmanager_classname [] = "VFSManager";
151 
152 static
153 VFSManager * singleton = NULL;
154 
155 
156 /* Destroy
157  *  destroy file
158  */
VFSManagerDestroy(VFSManager * self)159 static rc_t VFSManagerDestroy ( VFSManager *self )
160 {
161     if ( self == NULL )
162         return RC ( rcVFS, rcFile, rcDestroying, rcSelf, rcNull );
163 
164     KKeyStoreRelease( self -> keystore );
165     free ( self -> pw_env );
166     VResolverRelease ( self -> resolver );
167     KNSManagerRelease ( self -> kns );
168     KCipherManagerRelease ( self -> cipher );
169     KConfigRelease ( self -> cfg );
170     KDirectoryRelease ( self -> cwd );
171     KRefcountWhack (&self->refcount, kfsmanager_classname);
172 
173     free (self);
174     singleton = NULL;
175 
176     return 0;
177 }
178 
179 /* AddRef
180  *  creates a new reference
181  *  ignores NULL references
182  */
VFSManagerAddRef(const VFSManager * self)183 LIB_EXPORT rc_t CC VFSManagerAddRef ( const VFSManager *self )
184 {
185     if (self != NULL)
186     {
187         switch (KRefcountAdd (&self->refcount, kfsmanager_classname))
188         {
189         case krefOkay:
190             break;
191         case krefZero:
192             return RC (rcVFS, rcMgr, rcAttaching, rcRefcount, rcIncorrect);
193         case krefLimit:
194             return RC (rcVFS, rcMgr, rcAttaching, rcRefcount, rcExhausted);
195         case krefNegative:
196             return RC (rcVFS, rcMgr, rcAttaching, rcRefcount, rcInvalid);
197         default:
198             return RC (rcVFS, rcMgr, rcAttaching, rcRefcount, rcUnknown);
199         }
200     }
201     return 0;
202 }
203 
204 /* Release
205  *  discard reference to file
206  *  ignores NULL references
207  */
VFSManagerRelease(const VFSManager * self)208 LIB_EXPORT rc_t CC VFSManagerRelease ( const VFSManager *self )
209 {
210     rc_t rc = 0;
211     if (self != NULL)
212     {
213         switch (KRefcountDrop (&self->refcount, kfsmanager_classname))
214         {
215         case krefOkay:
216         case krefZero:
217             break;
218         case krefWhack:
219             rc = VFSManagerDestroy ((VFSManager*)self);
220             break;
221         case krefNegative:
222             return RC (rcVFS, rcMgr, rcAttaching, rcRefcount, rcInvalid);
223         default:
224             rc = RC (rcVFS, rcMgr, rcAttaching, rcRefcount, rcUnknown);
225             break;
226         }
227     }
228     return rc;
229 }
230 
231 enum cache_version
232 { cachetee = 0, cachetee_2 = 1, cachetee_3 = 2, rrcache = 3, logging = 4 };
233 
234 typedef struct caching_params
235 {
236     enum cache_version version;
237     size_t cache_page_size;
238     uint32_t cache_page_count;
239     uint32_t cluster_factor_bits; /* for cachetee_v3 dflt = 5,  1 << 5  = 32 */
240     uint32_t page_size_bits;      /* for cachetee_v3 dflt = 15, 1 << 15 = 64k */
241     uint32_t cache_amount_mb;     /* for cachetee_v3 dlft = 32 MB */
242 
243     char temp_cache[ 4096 ];
244 
245     bool use_file_cache;    /* is caching turned on */
246     bool use_cwd;       /* use the current working directory if not cach-location is given */
247     bool append;        /* append to existing recording 0...no - 1...yes */
248     bool timed;         /* record timing 0...no - 1...yes */
249     bool record_inner;  /* record the request made before the cache */
250     bool record_outer;  /* record the request made after the cache */
251     bool is_refseq;     /* when used for external reference sequences, decrease cache size */
252     bool promote;       /* do we want a promoting cache-tee-file ? */
253     bool debug;         /* print cache-debug-messages */
254 } caching_params;
255 
256 #define DEFAULT_CACHETEE_VERSION cachetee_3
257 #define DEFAULT_CACHE_PAGE_SIZE ( 32 * 1024 )
258 #define DEFAULT_CACHE_PAGE_COUNT ( 10 * 1024 )
259 #define DEFAULT_CLUSTER_FACTOR_BITS 5
260 #define DEFAULT_PAGE_SIZE_BITS 15
261 #define DEFAULT_CACHE_AMOUNT_MB 256
262 
get_caching_params(caching_params * params,uint32_t dflt_block_size,bool is_refseq,bool promote)263 static void get_caching_params( caching_params * params,
264                 uint32_t dflt_block_size,
265                 bool is_refseq,
266                 bool promote )
267 {
268     KConfig * cfg;
269     rc_t rc = KConfigMake ( &cfg, NULL );
270 
271     /* set some default values... */
272     params -> version = DEFAULT_CACHETEE_VERSION;
273     params -> cache_page_size = dflt_block_size;
274     params -> cache_page_count = DEFAULT_CACHE_PAGE_COUNT;
275     params -> cluster_factor_bits = DEFAULT_CLUSTER_FACTOR_BITS;
276     params -> page_size_bits = DEFAULT_PAGE_SIZE_BITS;
277     params -> cache_amount_mb = DEFAULT_CACHE_AMOUNT_MB;
278     params -> temp_cache[ 0 ] = 0;
279     params -> use_file_cache = false;
280     params -> use_cwd = false;
281     params -> append = false;
282     params -> timed = false;
283     params -> record_inner = false;
284     params -> record_outer = false;
285     params -> is_refseq = is_refseq;
286     params -> promote = promote;
287     params -> debug = false;
288 
289     if ( rc == 0 )
290     {
291         size_t written;
292 
293         /* functions in libs/kfg/properties.c */
294         rc = KConfig_Get_CacheTeeVersion( cfg, &( params -> version ), DEFAULT_CACHETEE_VERSION );
295         if ( rc != 0 )
296             params -> version = DEFAULT_CACHETEE_VERSION;
297 
298         rc = KConfig_Get_CacheBlockSize( cfg, &( params -> cache_page_size ), dflt_block_size );
299         if ( rc != 0 )
300             params -> cache_page_size = dflt_block_size;
301 
302         rc = KConfig_Get_CachePageCount( cfg, &( params -> cache_page_count ), DEFAULT_CACHE_PAGE_COUNT );
303         if ( rc != 0 )
304             params -> cache_page_count = DEFAULT_CACHE_PAGE_COUNT;
305 
306         rc = KConfig_Get_CacheClusterFactorBits( cfg, &( params -> cluster_factor_bits ), DEFAULT_CLUSTER_FACTOR_BITS );
307         if ( rc != 0 )
308             params -> cluster_factor_bits = DEFAULT_CLUSTER_FACTOR_BITS;
309 
310         rc = KConfig_Get_CachePageSizeBits( cfg, &( params -> page_size_bits ), DEFAULT_PAGE_SIZE_BITS );
311         if ( rc != 0 )
312             params -> page_size_bits = DEFAULT_PAGE_SIZE_BITS;
313 
314         rc = KConfig_Get_Cache_Amount( cfg, &( params -> cache_amount_mb ) );
315         if ( rc == 0 )
316         {
317             if ( params -> cache_amount_mb == 0 || params -> cache_amount_mb < DEFAULT_CACHE_AMOUNT_MB )
318                 params -> cache_amount_mb = DEFAULT_CACHE_AMOUNT_MB;
319         }
320         else
321             params -> cache_amount_mb = DEFAULT_CACHE_AMOUNT_MB;
322 
323         rc = KConfig_Get_Temp_Cache( cfg, params -> temp_cache, sizeof( params -> temp_cache ), &written );
324         if ( rc != 0 )
325             params -> temp_cache[ 0 ] = 0;
326 
327         rc = KConfig_Get_User_Public_Cached( cfg, &( params -> use_file_cache ) );
328         if ( rc != 0 )
329             params -> use_file_cache = false;
330 
331         rc = KConfig_Get_CacheLogUseCWD( cfg, &( params -> use_cwd ), false );
332         if ( rc != 0 )
333             params -> use_cwd = false;
334 
335         rc = KConfig_Get_CacheLogAppend( cfg, &( params -> append ), false );
336         if ( rc != 0 )
337             params -> append = false;
338 
339         rc = KConfig_Get_CacheLogTimed ( cfg, &( params -> timed ), false );
340         if ( rc != 0 )
341             params -> timed = 0;
342 
343         rc = KConfig_Get_CacheLogOuter( cfg, &( params -> record_outer ), false );
344         if ( rc != 0 )
345             params -> record_outer = false;
346 
347         rc = KConfig_Get_CacheLogInner( cfg, &( params -> record_inner ), false );
348         if ( rc != 0 )
349             params -> record_inner = false;
350 
351         rc = KConfig_Get_CacheDebug( cfg, &( params -> debug ), false );
352         if ( rc != 0 )
353             params -> debug = false;
354 
355         KConfigRelease ( cfg );
356     }
357 }
358 
extract_acc_from_url(const char * url)359 static const char * extract_acc_from_url( const char * url )
360 {
361     char * res = string_rchr ( url, string_size( url ), '/' );
362     if ( res != NULL )
363         return ++res;
364     return url;
365 }
366 
wrap_in_logfile(KDirectory * dir,const KFile ** cfp,const char * loc,const char * fmt,const caching_params * cps)367 static rc_t wrap_in_logfile( KDirectory * dir,
368                              const KFile **cfp,
369                              const char * loc,
370                              const char * fmt,
371                              const caching_params * cps )
372 {
373     const KFile * temp_file;
374     const char * rec_loc = cps -> use_cwd ? extract_acc_from_url( loc ) : loc;
375     rc_t rc = MakeLogFile ( dir,
376                             &temp_file,
377                             ( KFile * )*cfp,
378                             cps -> append > 0,
379                             cps -> timed > 0,
380                             fmt,
381                             rec_loc );
382     if ( rc == 0 )
383     {
384         KFileRelease ( * cfp );
385         * cfp = temp_file;
386     }
387     return rc;
388 }
389 
wrap_in_cachetee(KDirectory * dir,const KFile ** cfp,const char * loc,const caching_params * cps)390 static rc_t wrap_in_cachetee( KDirectory * dir,
391                               const KFile **cfp,
392                               const char * loc,
393                               const caching_params * cps )
394 {
395     rc_t rc = 0;
396     if ( cps -> record_outer )
397         rc = wrap_in_logfile( dir, cfp, loc, "%s.outer.rec", cps );
398     if ( rc == 0 )
399     {
400         const KFile * temp_file;
401         if ( cps -> promote )
402         {
403             rc = KDirectoryMakeCacheTeePromote ( dir,
404                                                  &temp_file,
405                                                  *cfp,
406                                                  cps -> cache_page_size,
407                                                  "%s",
408                                                  loc );
409 
410         }
411         else
412         {
413             rc = KDirectoryMakeCacheTee ( dir,
414                                           &temp_file,
415                                           *cfp,
416                                           cps -> cache_page_size,
417                                           "%s",
418                                           loc );
419         }
420         if ( rc == 0 )
421         {
422             KFileRelease ( * cfp );
423             * cfp = temp_file;
424 
425             if ( cps -> record_inner )
426                 rc = wrap_in_logfile( dir, cfp, loc, "%s.inner.rec", cps );
427         }
428     }
429     return rc;
430 }
431 
wrap_in_cachetee2(KDirectory * dir,const KFile ** cfp,const char * loc,const caching_params * cps)432 static rc_t wrap_in_cachetee2( KDirectory * dir,
433                                const KFile **cfp,
434                                const char * loc,
435                                const caching_params * cps )
436 {
437     rc_t rc = 0;
438     if ( cps -> record_outer )
439         rc = wrap_in_logfile( dir, cfp, loc, "%s.outer.rec", cps );
440     if ( rc == 0 )
441     {
442         const KFile * temp_file;
443         rc_t rc = KDirectoryMakeCacheTee2 ( dir,
444                                             &temp_file,
445                                             *cfp,
446                                             cps -> cache_page_size,
447                                             "%s",
448                                             loc );
449         if ( rc == 0 )
450         {
451             KFileRelease ( * cfp );
452             * cfp = temp_file;
453 
454             if ( cps -> record_inner )
455                 rc = wrap_in_logfile( dir, cfp, loc, "%s.inner.rec", cps );
456         }
457     }
458     return rc;
459 }
460 
wrap_in_rr_cache(KDirectory * dir,const KFile ** cfp,const char * loc,const caching_params * cps)461 static rc_t wrap_in_rr_cache( KDirectory * dir,
462                               const KFile **cfp,
463                               const char * loc,
464                               const caching_params * cps )
465 {
466     rc_t rc = 0;
467     if ( cps -> record_outer )
468         rc = wrap_in_logfile( dir, cfp, loc, "%s.outer.rec", cps );
469     if ( rc == 0 )
470     {
471         const KFile * temp_file;
472         rc_t rc = MakeRRCached ( &temp_file, *cfp, cps -> cache_page_size, cps -> cache_page_count );
473         if ( rc == 0 )
474         {
475             KFileRelease ( * cfp );
476             * cfp = temp_file;
477 
478             if ( cps -> record_inner )
479                 rc = wrap_in_logfile( dir, cfp, loc, "%s.inner.rec", cps );
480         }
481     }
482     return rc;
483 }
484 
485 #if WINDOWS
486     static const char * fallback_cache_location = "c:\\temp";
487 #else
488 	static const char * fallback_cache_location = "/var/tmp";
489 #endif
490 
get_fallback_cache_location(void)491 const char * get_fallback_cache_location( void )
492 {
493     const char * c = getenv ( "TMPDIR" );
494     if ( c != NULL )
495         return c;
496     return fallback_cache_location;
497 }
498 
499 
make_id(const VPath * path)500 static const String * make_id( const VPath * path )
501 {
502     const String * res = NULL;
503 
504     /* first try to extract a id from the path */
505     String path_id = { 0, 0, 0 };
506     rc_t rc = VPathGetId ( path, &path_id );
507     if ( rc == 0 && path_id . len > 0 )
508     {
509         rc = StringCopy ( &res, &path_id );
510     }
511     /* if we have no id now, as a last resort use a timestamp */
512     if ( res == NULL )
513     {
514         size_t num_writ = 0;
515         char buffer [ 4096 ];
516         static atomic32_t counter;
517 #ifdef _WIN32
518         KTime_t t = KTimeStamp();
519         rc = string_printf ( buffer, sizeof buffer, &num_writ
520                              , "t_%lu.%u"
521                              , t
522                              , atomic32_read_and_add ( & counter, 1 )
523             );
524 #else
525         uint32_t sys_GetPID ( void );
526         uint32_t pid = sys_GetPID ();
527         int sys_GetHostName ( char * buffer, size_t buffer_size );
528         int status = sys_GetHostName ( buffer, sizeof buffer );
529         if ( status != 0 )
530         {
531             KTime_t t = KTimeStamp();
532             rc = string_printf ( buffer, sizeof buffer, &num_writ
533                                  , "t%u_%lu.%u"
534                                  , pid
535                                  , t
536                                  , atomic32_read_and_add ( & counter, 1 )
537                 );
538         }
539         else
540         {
541             num_writ = strlen ( buffer );
542             rc = string_printf ( & buffer [ num_writ ], sizeof buffer - num_writ, &num_writ
543                                  , "-%u.%u"
544                                  , pid
545                                  , atomic32_read_and_add ( & counter, 1 )
546                 );
547         }
548 #endif
549         if ( rc == 0 )
550         {
551             String S;
552             StringInitCString( &S, buffer );
553             rc = StringCopy ( &res, &S );
554         }
555     }
556     return res;
557 }
558 
wrap_in_cachetee3(KDirectory * dir,const KFile ** cfp,const char * cache_loc,const caching_params * cps,const VPath * path)559 static rc_t wrap_in_cachetee3( KDirectory * dir,
560                                const KFile **cfp,
561                                const char * cache_loc,
562                                const caching_params * cps,
563                                const VPath * path )
564 {
565     rc_t rc = 0;
566     const KFile * temp_file;
567     uint32_t cluster_factor = ( 1 << ( cps -> cluster_factor_bits - 1 ) );
568     size_t page_size = ( 1 << ( cps -> page_size_bits - 1 ));
569     size_t cache_amount = ( ( size_t )cps -> cache_amount_mb * 1024 * 1024 );
570     size_t ram_page_count = ( cache_amount + page_size - 1 ) / page_size;
571     bool ram_only = true;
572 
573     if ( cps -> debug )
574     {
575         const String * uri = NULL;
576         rc_t rc1 = VPathMakeUri ( path, &uri );
577 
578         KOutMsg( "{\n " );
579         KOutMsg( "cache.cluster-factor ... %d\n", cluster_factor );
580         KOutMsg( "cache.page_size ........ %d bytes\n", page_size );
581         KOutMsg( "cache.amount ........... %d MB\n", cps -> cache_amount_mb );
582         KOutMsg( "cache.page_count ....... %d\n", ram_page_count );
583         KOutMsg( "cache_loc (resolver) ... %s\n", cache_loc == NULL ? "NULL" : cache_loc );
584         if ( rc1 == 0 )
585         {
586             if ( uri != NULL )
587                 KOutMsg( "uri : %S\n", uri );
588             else
589                 KOutMsg( "uri : NULL\n" );
590 
591             StringWhack( uri );
592         }
593     }
594 
595     if ( cps -> use_file_cache )
596     {
597         char location[ 4096 ];
598         bool remove_on_close = false;
599         bool promote = cps -> promote;
600         location[ 0 ] = 0;
601 
602         if ( cps -> debug )
603             KOutMsg( "use file-cache\n" );
604 
605         /* if we have been given a location, we use it. CacheTeeV3 can deal with invalid/unreachable ones! */
606         if ( cache_loc != NULL )
607         {
608             rc = KDirectoryResolvePath ( dir, true, location, sizeof location,
609                                          "%s", cache_loc );
610         }
611 
612         /* if we have no given location or it does not exist or it is not read/writable for us */
613         if ( location[ 0 ] == 0 )
614         {
615             const String * id = make_id( path );
616             if ( id != NULL )
617             {
618                 remove_on_close = true;
619                 promote = false;
620 
621                 if ( cps -> temp_cache[ 0 ] != 0 )
622                 {
623                     /* we have user given temp cache - location ( do not try promotion, remove-on-close ) */
624                     rc = KDirectoryResolvePath ( dir, true, location, sizeof location,
625                                                  "%s/%s.sra", cps -> temp_cache, id -> addr );
626                 }
627                 else
628                 {
629                     /* fallback to hardcoded path location ( do not try promotion, remove-on-close */
630                     rc = KDirectoryResolvePath ( dir, true, location, sizeof location,
631                                                  "%s/%s.sra",
632                                                  get_fallback_cache_location(),
633                                                  id -> addr );
634                 }
635                 StringWhack ( id );
636             }
637             else
638                 rc = SILENT_RC( rcVFS, rcPath, rcReading, rcFormat, rcInvalid );
639         }
640 
641         if ( cps -> debug )
642         {
643             KOutMsg( "cache.remove-on-close ... %s\n", remove_on_close ? "Yes" : "No" );
644             KOutMsg( "cache.try-promote ....... %s\n", promote ? "Yes" : "No" );
645             KOutMsg( "cache location: '%s', rc = %R\n", location, rc );
646         }
647 
648         if ( rc == 0 )
649             /* check if location is writable... */
650             rc = KDirectoryMakeKCacheTeeFile_v3 ( dir,
651                                                   &temp_file,
652                                                   *cfp,
653                                                   page_size,
654                                                   cluster_factor,
655                                                   ram_page_count,
656                                                   promote,
657                                                   remove_on_close,
658                                                   "%s", location );
659         ram_only = ( rc != 0 );
660     }
661 
662     if ( ram_only )
663     {
664         if ( cps -> debug )
665             KOutMsg( "use no file-cache\n" );
666 
667         rc = KDirectoryMakeKCacheTeeFile_v3 ( dir,
668                                               &temp_file,
669                                               *cfp,
670                                               page_size,
671                                               cluster_factor,
672                                               ram_page_count,
673                                               false,
674                                               false,
675                                               "" );
676     }
677 
678     if ( cps -> debug )
679         KOutMsg( "}\n" );
680 
681     if ( rc == 0 )
682     {
683         KFileRelease ( * cfp );
684         * cfp = temp_file;
685     }
686     return rc;
687 }
688 
689 /*--------------------------------------------------------------------------
690  * VFSManagerMakeHTTPFile
691 
692  enum cache_version
693  { cachetee = 0, cachetee_2 = 1, cachetee_3 = 2, rrcache = 3, logging = 4 };
694 
695 
696  */
697 static
VFSManagerMakeHTTPFile(const VFSManager * self,const KFile ** cfp,const VPath * path,const char * cache_location,uint32_t blocksize,bool high_reliability,bool is_refseq,bool promote)698 rc_t VFSManagerMakeHTTPFile( const VFSManager * self,
699                              const KFile **cfp,
700                              const VPath * path,
701                              const char * cache_location,
702                              uint32_t blocksize,
703                              bool high_reliability,
704                              bool is_refseq,
705                              bool promote )
706 {
707     bool is_wgs = false;
708 
709     const String * uri = NULL;
710     rc_t rc = VPathMakeString ( path, &uri );
711 
712     if (rc == 0) {
713         String objectType;
714         String refseq;
715         CONST_STRING(&refseq, "refseq");
716         rc = VPathGetObjectType(path, &objectType);
717         if (rc == 0) {
718             if (!is_refseq)
719                 is_refseq = StringEqual(&objectType, &refseq);
720             if (!is_refseq) {
721                 assert(uri);
722                 is_refseq = strstr(uri->addr, refseq.addr) != NULL;
723             }
724             if (!is_refseq) {
725                 String wgs;
726                 CONST_STRING(&wgs, "wgs");
727                 is_refseq = is_wgs = StringEqual(&objectType, &wgs);
728             }
729         }
730     }
731 
732     if ( rc == 0 ) {
733         bool ceRequired = false;
734         bool payRequired = false;
735 
736         {
737             const char * name = path->sraClass == eSCvdbcache ?
738                 ENV_MAGIC_CACHE_NEED_CE : ENV_MAGIC_REMOTE_NEED_CE;
739             const char * magic = getenv(name);
740             bool hasMagic = magic != NULL;
741             if (is_refseq) {
742                 if (magic != NULL) {
743                     DBGMSG(DBG_VFS, DBG_FLAG(DBG_VFS_PATH), (
744                         "'%s' magic ignored for %s\n",
745                         name, is_wgs ? "WGS" : "refseq"));
746                     magic = NULL;
747                 }
748             }
749             if (magic != NULL) {
750                     DBGMSG(DBG_VFS, DBG_FLAG(DBG_VFS_PATH), (
751                         "'%s' magic found\n", name));
752                     ceRequired = true;
753             }
754             else {
755                     ceRequired = path->ceRequired;
756                     if (!hasMagic)
757                         DBGMSG(DBG_VFS, DBG_FLAG(DBG_VFS_PATH), (
758                             "'%s' magic not set\n", name));
759             }
760         }
761 
762         {
763             const char * name = path->sraClass == eSCvdbcache ?
764                 ENV_MAGIC_CACHE_NEED_PMT : ENV_MAGIC_REMOTE_NEED_PMT;
765             const char * magic = getenv(name);
766             bool hasMagic = magic != NULL;
767             if (is_refseq) {
768                 if (magic != NULL) {
769                     DBGMSG(DBG_VFS, DBG_FLAG(DBG_VFS_PATH), (
770                         "'%s' pmtReq magic ignored for %s\n",
771                         name, is_wgs ? "WGS" : "refseq"));
772                     magic = NULL;
773                 }
774             }
775             if (magic != NULL) {
776                 DBGMSG(DBG_VFS, DBG_FLAG(DBG_VFS_PATH), (
777                     "'%s' magic found\n", name));
778                 payRequired = true;
779             }
780             else {
781                 payRequired = path->payRequired;
782                 if (!hasMagic)
783                     DBGMSG(DBG_VFS, DBG_FLAG(DBG_VFS_PATH), (
784                         "'%s' magic not set\n", name));
785             }
786         }
787 
788         rc = KNSManagerMakeReliableHttpFile ( self -> kns,
789                                               cfp,
790                                               NULL,
791                                               0x01010000,
792                                               high_reliability,
793                                               ceRequired,
794                                               payRequired,
795                                               "%s", uri -> addr );
796 
797         /* in case we are not able to open the remote-file : return with error-code */
798         if ( rc == 0 )
799         {
800             /* let's try to get some details about how to do caching from the configuration */
801             caching_params cps;
802             get_caching_params( &cps, blocksize, is_refseq, promote );
803             if ( cps . version == cachetee_3 )
804             {
805                 rc = wrap_in_cachetee3( self -> cwd, cfp, cache_location, &cps, path );
806             }
807             else
808             {
809                 if ( cache_location == NULL )
810                 {
811                     const String * id = make_id( path );
812                     if ( id != NULL )
813                     {
814                         /* the user has turned off caching... ( we should not make a cache-tee )*/
815                         switch( cps . version )
816                         {
817                             case cachetee   : ;  /* fall-through into rr-cache !!! */
818                             case cachetee_2 : ;  /* fall-through into rr-cache !!! */
819                             case rrcache    : rc = wrap_in_rr_cache( self -> cwd, cfp, id -> addr, &cps ); break;
820                             case logging    : rc = wrap_in_logfile( self -> cwd, cfp, id -> addr, "%s.rec", &cps ); break;
821                             case cachetee_3 : break; /* in common path above */
822                         }
823                         StringWhack ( id );
824                     }
825                 }
826                 else
827                 {
828                     /* the user has turned on caching... */
829                     switch( cps . version )
830                     {
831                         case cachetee   : rc = wrap_in_cachetee( self -> cwd, cfp, cache_location, &cps ); break;
832                         case cachetee_2 : rc = wrap_in_cachetee2( self -> cwd, cfp, cache_location, &cps ); break;
833                         case rrcache    : rc = wrap_in_rr_cache( self -> cwd, cfp, cache_location, &cps ); break;
834                         case logging    : rc = wrap_in_logfile( self -> cwd, cfp, cache_location, "%s.rec", &cps ); break;
835                         case cachetee_3 : break; /* in common path above */
836                     }
837                 }
838             }
839         }
840         free( ( void * )uri );
841     }
842     return rc;
843 }
844 
VFSManagerGetConfigPWFile(const VFSManager * self,char * b,size_t bz,size_t * pz,bool * pwdItself)845 static rc_t CC VFSManagerGetConfigPWFile (const VFSManager * self,
846     char * b, size_t bz, size_t * pz, bool * pwdItself)
847 {
848     const char * env;
849     const KConfigNode * node;
850     size_t oopsy;
851     size_t z = 0;
852     rc_t rc;
853 
854     assert(self && b && pwdItself);
855     *pwdItself = false;
856 
857     if (pz)
858         *pz = 0;
859 
860     env = getenv (ENV_KRYPTO_PWFILE);
861     if (!env)
862         env = self->pw_env;
863     if (env)
864     {
865         z = string_copy (b, bz, env, string_size (env));
866 
867         /* force a NUL that string_copy might have omitted
868          * even if this truncates the path */
869         b[bz-1] = '\0';
870 
871         if (pz)
872             *pz = z;
873 
874         return 0;
875     }
876 
877     { /* If we are in a protected area, there may be an area-specific key file */
878         const KRepositoryMgr *repoMgr;
879         rc = KConfigMakeRepositoryMgrRead ( self->cfg, &repoMgr );
880         if (rc == 0)
881         {
882             const KRepository* prot;
883             rc = KRepositoryMgrCurrentProtectedRepository ( repoMgr, &prot );
884             if (rc == 0)
885             {
886                 rc = KRepositoryEncryptionKeyFile (prot, b, bz, pz);
887                 if (rc != 0 || b[0] == '\0') {
888                     rc = KRepositoryEncryptionKey (prot, b, bz, pz);
889                     if (rc == 0)
890                         *pwdItself = true;
891                 }
892 
893                 KRepositoryRelease(prot);
894             }
895             KRepositoryMgrRelease(repoMgr);
896         }
897         if (GetRCState(rc) == rcNotFound)
898             rc = RC (rcVFS, rcMgr, rcOpening, rcEncryptionKey, rcNotFound);
899     }
900 
901     if (rc != 0)
902     {   /* fall back on an old-style global password file*/
903         rc = KConfigOpenNodeRead (self->cfg, &node, "%s", KFG_KRYPTO_PWFILE);
904         if (rc)
905         {
906             /* if not found, change object from path to encryption key */
907             if (GetRCState(rc) == rcNotFound)
908                 rc = RC (rcVFS, rcMgr, rcOpening, rcEncryptionKey, rcNotFound);
909         }
910         else
911         {
912             rc = KConfigNodeRead (node, 0, b, bz-1, &z, &oopsy);
913             if (rc == 0)
914             {
915                 if (oopsy != 0)
916                     rc = RC (rcKrypto, rcMgr, rcReading, rcBuffer, rcInsufficient);
917                 else
918                 {
919                     b[z] = '\0';
920                     *pz = z;
921                 }
922             }
923             KConfigNodeRelease (node);
924         }
925     }
926 
927     return rc;
928 }
929 
930 static
GetEncryptionKey(const VFSManager * self,const VPath * vpath,char * obuff,size_t buf_size,size_t * pwd_size)931 rc_t GetEncryptionKey(const VFSManager * self, const VPath * vpath, char* obuff, size_t buf_size, size_t *pwd_size)
932 {
933     /* -----
934      * #if 0
935      * first check the insecure password on the command line hack
936      * #endif
937      *
938      * then check the option for pwfile in the VPath
939      * then check the option for pwfd
940      * then check the keystore. if necessary, keystore will
941      *          check the environment
942      *          check the configuration
943      */
944 
945 #if 0
946     /* obviously not used yet */
947     if (VPathOption (vpath, vpopt_temporary_pw_hack, obuff, buf_size, &z) == 0)
948     {
949         if (z < 1)
950             rc = RC (rcVFS, rcPath, rcConstructing, rcParam, rcInvalid);
951         else
952         {
953             size_t x = 0;
954             size_t y = 0;
955             int ch, h, l;
956 
957             while (x < z)
958             {
959                 h = tolower(obuff[x++]);
960                 l = tolower(obuff[x++]);
961 
962                 if (!isxdigit(h) || !isxdigit(l))
963                     rc = RC (rcVFS, rcPath, rcConstructing, rcParam, rcInvalid);
964 
965                 if (isdigit(h))
966                     ch = (h - '0') << 4;
967                 else
968                     ch = (h + 10 - 'a') << 4;
969                 if (isdigit(l))
970                     ch |= (l - '0');
971                 else
972                     ch |= (l + 10 - 'a');
973 
974                 /* added for compatibility with other passwords */
975                 if ((ch == '\r') || (ch == '\n'))
976                     break;
977                 obuff[y++] = (char)ch;
978             }
979             obuff[y] = '\0';
980             assert (z == x);
981             assert (z/2 == y);
982             z = y;
983             * pwd_size = z;
984         }
985     }
986 #endif
987 
988     rc_t rc = 0;
989     rc_t rc2;
990     size_t z;
991 
992     if (VPathOption (vpath, vpopt_pwpath, obuff, buf_size - 1, &z)
993         == 0)
994     {
995         const KFile * pwfile;
996         obuff [z] = '\0';
997         rc = KDirectoryOpenFileRead(self->cwd, &pwfile, "%s", obuff);
998         if (rc == 0)
999         {
1000             rc = KKeyStoreSetTemporaryKeyFromFile(self->keystore, pwfile);
1001             rc2 = KFileRelease(pwfile);
1002             if (rc == 0)
1003                 rc = rc2;
1004         }
1005     }
1006     else if (VPathOption (vpath, vpopt_pwfd, obuff, buf_size - 1, &z)
1007         == 0)
1008     {
1009         /* -----
1010          * pwfd is not fully a VPath at this point: we
1011          * should obsolete it
1012          */
1013         const KFile * pwfile;
1014         obuff [z] = '\0';
1015         rc = KFileMakeFDFileRead (&pwfile, atoi (obuff));
1016         if (rc == 0)
1017         {
1018             rc = KKeyStoreSetTemporaryKeyFromFile(self->keystore, pwfile);
1019             rc2 = KFileRelease(pwfile);
1020             if (rc == 0)
1021                 rc = rc2;
1022         }
1023     }
1024 
1025     if (rc == 0)
1026     {
1027         KEncryptionKey* enc_key = NULL;
1028 
1029         /* here, we are only interested in global keys - at least for now */
1030 
1031         /* Get Key for current protected repository ( or global ) */
1032         rc = KKeyStoreGetKey(self->keystore, NULL, &enc_key);
1033         if (rc != 0 && self->resolver != NULL) {
1034             bool has_project_id = false;
1035             uint32_t projectId = 0;
1036             rc_t r2 = VResolverGetProjectId(self->resolver, &projectId);
1037             has_project_id = projectId != 0;
1038 
1039   /* Get Key for protected repository that was used to create self's resolver */
1040             if (r2 == 0 && has_project_id) {
1041                 rc = KKeyStoreGetKeyByProjectId(
1042                     self->keystore, NULL, &enc_key,projectId);
1043             }
1044         }
1045 
1046         if (rc == 0)
1047         {
1048 /* VDB-3590: Encryption key is a sequence of bytes.
1049              It is not a string and can represent an invalid UNICODE sequence */
1050             memmove(obuff, enc_key->value.addr, enc_key->value.size);
1051             *pwd_size = enc_key->value.size;
1052 
1053             if (*pwd_size != enc_key->value.size)
1054                 rc = RC(rcVFS, rcPath, rcReading, rcBuffer, rcInsufficient);
1055             rc2 = KEncryptionKeyRelease(enc_key);
1056             if (rc == 0)
1057                 rc = rc2;
1058         }
1059     }
1060 
1061     if ( GetRCState ( rc ) == rcNoPerm && GetRCObject ( rc ) == ( enum RCObject ) rcEncryptionKey )
1062     {
1063         LOGMSG ( klogErr, "You do not have read permissions to decrypt data from this project." );
1064         LOGMSG ( klogErr, "Please contact your PI to request an NGC token with decrypt permissions." );
1065         LOGMSG ( klogErr, "Import the new NGC file before decrypting again." );
1066         LOGMSG ( klogErr, "If you continue to have problems, contact sra@ncbi.nlm.nih.gov for assistance." );
1067     }
1068 
1069     rc2 = KKeyStoreSetTemporaryKeyFromFile(self->keystore, NULL); /* forget the temp key if set */
1070     if (rc == 0)
1071         rc = rc2;
1072     return rc;
1073 }
1074 
1075 /*
1076  * This is still hack - must match VFSManagerResolvePathRelativeDir()
1077  */
VFSManagerWGAValidateHack(const VFSManager * self,const KFile * file,const char * path)1078 LIB_EXPORT rc_t CC VFSManagerWGAValidateHack (const VFSManager * self,
1079                                               const KFile * file,
1080                                               const char * path) /* we'll move this to a vpath */
1081 {
1082     VPath * vpath;
1083     rc_t rc = 0;
1084 
1085     rc = VPathMake (&vpath, path);
1086     if (rc == 0)
1087     {
1088         size_t z;
1089         char obuff [VFS_KRYPTO_PASSWORD_MAX_SIZE + 2]; /* 1 for over-read and 1 for NUL */
1090         rc = GetEncryptionKey(self, vpath, obuff, sizeof(obuff), &z);
1091 
1092         if (rc == 0)
1093         {
1094             rc = WGAEncValidate (file, obuff, z);
1095         }
1096     }
1097     return rc;
1098 }
1099 
1100 
1101 
1102 /* ResolvePath
1103  *
1104  * take a VPath and resolve to a final form apropriate for KDB
1105  *
1106  * that is take a relative path and resolve it against the CWD
1107  * or take an accession and resolve into the local or remote
1108  * VResolver file based on config. It is just a single resolution percall
1109  */
VFSManagerResolvePathResolver(const VFSManager * self,uint32_t flags,const VPath * in_path,VPath ** out_path)1110 static rc_t VFSManagerResolvePathResolver (const VFSManager * self,
1111                                            uint32_t flags,
1112                                            const VPath * in_path,
1113                                            VPath ** out_path)
1114 {
1115     rc_t rc = 0;
1116 
1117     assert(out_path);
1118     *out_path = NULL;
1119 
1120     /*
1121      * this RC perculates up for ncbi-acc: schemes but not for
1122      * no scheme uris
1123      */
1124     if ((flags & vfsmgr_rflag_no_acc) == vfsmgr_rflag_no_acc)
1125     {
1126         /* hack */
1127         if ( VPathGetUri_t ( in_path ) == vpuri_none )
1128             rc = SILENT_RC (rcVFS, rcMgr, rcResolving, rcSRA, rcNotAvailable);
1129         else
1130             rc = RC (rcVFS, rcMgr, rcResolving, rcSRA, rcNotAvailable);
1131     }
1132     else
1133     {
1134         bool not_done = true;
1135 
1136         /*
1137          * cast because we seem to have the restriction on the output from
1138          * VResolver that seems too restrictive
1139          */
1140         if ((flags & vfsmgr_rflag_no_acc_local) == 0)
1141         {
1142             rc = VResolverQuery(self->resolver, 0, in_path,
1143                 (const VPath **)out_path, NULL, NULL);
1144             if (rc == 0)
1145                 not_done = false;
1146         }
1147 
1148         if (not_done && ((flags & vfsmgr_rflag_no_acc_remote) == 0))
1149         {
1150             rc = VResolverRemote (self->resolver, self -> protocols,
1151                 in_path, (const VPath **)out_path);
1152         }
1153     }
1154     return rc;
1155 }
1156 
1157 
VFSManagerResolvePathInt(const VFSManager * self,uint32_t flags,const KDirectory * base_dir,const VPath * in_path,VPath ** out_path)1158 static rc_t VFSManagerResolvePathInt (const VFSManager * self,
1159                                       uint32_t flags,
1160                                       const KDirectory * base_dir,
1161                                       const VPath * in_path,
1162                                       VPath ** out_path)
1163 {
1164     rc_t rc;
1165     char * pc;
1166     VPUri_t uri_type;
1167 
1168     assert (self);
1169     assert (in_path);
1170     assert (out_path);
1171 
1172     uri_type = VPathGetUri_t ( in_path );
1173     switch ( uri_type )
1174     {
1175     default:
1176         rc = RC (rcVFS, rcMgr, rcResolving, rcPath, rcInvalid);
1177         break;
1178 
1179     case vpuri_not_supported:
1180     case vpuri_ncbi_legrefseq:
1181         rc = RC (rcVFS, rcMgr, rcResolving, rcPath, rcUnsupported);
1182         break;
1183 
1184     case vpuri_ncbi_acc:
1185         rc = VFSManagerResolvePathResolver (self, flags, in_path, out_path);
1186         break;
1187 
1188     case vpuri_none:
1189         /* for KDB purposes, no scheme might be an accession */
1190         if (flags & vfsmgr_rflag_kdb_acc)
1191         {
1192              /* no '/' is permitted in an accession */
1193             pc = string_chr (in_path->path.addr, in_path->path.size, '/');
1194             if (pc == NULL)
1195             {
1196                 rc = VFSManagerResolvePathResolver (self, flags, in_path, out_path);
1197                 if (rc == 0)
1198                     break;
1199             }
1200         }
1201         /* Fall through */
1202     case vpuri_ncbi_vfs:
1203     case vpuri_file:
1204         /* check for relative versus full path : assumes no 'auth' not starting with '/' */
1205         if (in_path->path.addr[0] == '/')
1206         {
1207             rc = VPathAddRef (in_path);
1208             if (rc == 0)
1209                 *out_path = (VPath *)in_path; /* oh these const ptr are annoying */
1210         }
1211         else
1212         {
1213             /* not 'properly' handling query, fragment etc. for relative path
1214              * assumes path within VPath is ASCIZ
1215              */
1216             size_t s;
1217             VPath * v;
1218             char u [32 * 1024];
1219 
1220             switch ( uri_type )
1221             {
1222             default:
1223                 rc = RC (rcVFS, rcMgr, rcResolving, rcFunction, rcInvalid);
1224                 break;
1225 
1226             case vpuri_ncbi_vfs:
1227                 string_printf ( u, sizeof u, & s, "%S:", & in_path -> scheme );
1228                 rc = KDirectoryResolvePath ( base_dir, true, & u [ s ], sizeof u - s,
1229                     "%.*s", ( int ) in_path -> path . size, in_path -> path . addr );
1230                 if ( rc == 0 )
1231                 {
1232                     s = string_size ( u );
1233                     rc = string_printf ( & u [ s ], sizeof u - s, NULL,
1234                         "%S%S", & in_path -> query, & in_path -> fragment );
1235                 }
1236                 if (rc == 0)
1237                     rc = VPathMake (&v, u);
1238                 break;
1239 
1240             case vpuri_none:
1241             case vpuri_file:
1242                 rc = KDirectoryResolvePath ( base_dir, true, u, sizeof u,
1243                     "%.*s", ( int ) in_path -> path . size, in_path -> path . addr );
1244                 rc = VPathMake (&v, u);
1245                 break;
1246             }
1247             if (rc == 0)
1248                 *out_path = v;
1249         }
1250         break;
1251 
1252         /* these are considered fully resolved already */
1253     case vpuri_http:
1254     case vpuri_https:
1255     case vpuri_ftp:
1256         rc = VPathAddRef (in_path);
1257         if (rc == 0)
1258             *out_path = (VPath*)in_path;
1259         break;
1260 
1261     }
1262     return rc;
1263 }
1264 
1265 
VFSManagerResolvePath(const VFSManager * self,uint32_t flags,const VPath * in_path,VPath ** out_path)1266 LIB_EXPORT rc_t CC VFSManagerResolvePath (const VFSManager * self,
1267                                           uint32_t flags,
1268                                           const VPath * in_path,
1269                                           VPath ** out_path)
1270 {
1271     if (out_path == NULL)
1272         return RC (rcVFS, rcMgr, rcResolving, rcParam, rcNull);
1273 
1274     *out_path = NULL;
1275 
1276     if (self == NULL)
1277         return RC (rcVFS, rcMgr, rcResolving, rcSelf, rcNull);
1278 
1279     if (in_path == NULL)
1280         return RC (rcVFS, rcMgr, rcResolving, rcParam, rcNull);
1281 
1282     return VFSManagerResolvePathInt (self, flags, self->cwd, in_path, out_path);
1283 }
1284 
VFSManagerResolvePathRelative(const VFSManager * self,uint32_t flags,const struct VPath * base_path,const struct VPath * in_path,struct VPath ** out_path)1285 LIB_EXPORT rc_t CC VFSManagerResolvePathRelative (const VFSManager * self,
1286                                                   uint32_t flags,
1287                                                   const struct  VPath * base_path,
1288                                                   const struct  VPath * in_path,
1289                                                   struct VPath ** out_path)
1290 {
1291     const KDirectory * dir;
1292     rc_t rc;
1293 
1294     if (out_path == NULL)
1295         rc = RC (rcVFS, rcMgr, rcResolving, rcParam, rcNull);
1296 
1297     *out_path = NULL;
1298 
1299     if (self == NULL)
1300         return RC (rcVFS, rcMgr, rcResolving, rcSelf, rcNull);
1301 
1302     if (in_path == NULL)
1303         return RC (rcVFS, rcMgr, rcResolving, rcParam, rcNull);
1304 
1305     rc = VFSManagerOpenDirectoryRead (self, &dir, base_path);
1306     if (rc == 0)
1307         rc = VFSManagerResolvePathInt (self, flags, dir, in_path, out_path);
1308 
1309     return rc;
1310 }
1311 
1312 /*
1313  * This is still hack - must match VFSManagerGetEncryptionKey()
1314  */
1315 
VFSManagerResolvePathRelativeDir(const VFSManager * self,uint32_t flags,const KDirectory * base_dir,const VPath * in_path,VPath ** out_path)1316 LIB_EXPORT rc_t CC VFSManagerResolvePathRelativeDir (const VFSManager * self,
1317                                                      uint32_t flags,
1318                                                      const KDirectory * base_dir,
1319                                                      const VPath * in_path,
1320                                                      VPath ** out_path)
1321 {
1322     if (out_path == NULL)
1323         return RC (rcVFS, rcMgr, rcResolving, rcParam, rcNull);
1324 
1325     *out_path = NULL;
1326 
1327     if (self == NULL)
1328         return RC (rcVFS, rcMgr, rcResolving, rcSelf, rcNull);
1329 
1330     if (in_path == NULL)
1331         return RC (rcVFS, rcMgr, rcResolving, rcParam, rcNull);
1332 
1333     return VFSManagerResolvePathInt (self, flags, base_dir, in_path, out_path);
1334 }
1335 
1336 
1337 /* OpenFileRead
1338  *  opens an existing file with read-only access
1339  *
1340  *  "f" [ OUT ] - return parameter for newly opened file
1341  *
1342  *  "path" [ IN ] - NUL terminated string in directory-native
1343  *  character set denoting target file
1344  */
1345 static
VFSManagerOpenFileReadDecryption(const VFSManager * self,const KDirectory * dir,const KFile ** f,const KFile * file,const VPath * path,bool force_decrypt,bool * was_encrypted)1346 rc_t VFSManagerOpenFileReadDecryption (const VFSManager *self,
1347                                        const KDirectory * dir,
1348                                        const KFile ** f,
1349                                        const KFile * file,
1350                                        const VPath * path,
1351                                        bool force_decrypt,
1352                                        bool * was_encrypted)
1353 {
1354     rc_t rc = 0;
1355     size_t z;
1356     char obuff [VFS_KRYPTO_PASSWORD_MAX_SIZE + 2]; /* 1 for over-read and 1 for NUL */
1357     bool has_enc_opt;
1358 
1359     if (was_encrypted)
1360         *was_encrypted = false;
1361 
1362     /* -----
1363      * at this point we have no fatal errors and we have the
1364      * file opened but we have not seen if we have to decrypt
1365      * or use other query options
1366      */
1367     has_enc_opt = (VPathOption (path, vpopt_encrypted, obuff,
1368                                 sizeof obuff, &z) == 0);
1369 
1370     if ((has_enc_opt == false) &&
1371         (force_decrypt == false))
1372     {
1373         /* if we are not told to decrypt, don't and we are done */
1374         KFileAddRef (file);
1375         *f = file;
1376     }
1377 
1378     else /* we are told to decrypt if possible */
1379     {
1380         /* -----
1381          * pre-read 4kb from the 'encrypted file'
1382          */
1383         rc = KFileRandomAccess (file);
1384         if (rc == 0)
1385             ;
1386         /* most common and easiest option is it has random
1387          * access - a no-op here
1388          */
1389         else if (GetRCState(rc) == rcUnsupported)
1390         {
1391             const KFile * buffile;
1392 
1393             rc = KBufFileMakeRead (&buffile, file, 32 * 2 * 1024);
1394             if (rc)
1395                 ;
1396             else
1397             {
1398                 /* there is an extra reference to file now, but
1399                  * it gets removed after this function returns
1400                  */
1401                 file = buffile;
1402             }
1403         }
1404 
1405         if (rc == 0)
1406         {
1407             size_t tz;
1408             char tbuff [4096];
1409 
1410             /* we now have a file from which we can pre-read the
1411              * possible encrypted format header */
1412             rc = KFileReadAll (file, 0, tbuff, sizeof tbuff, &tz);
1413             if (rc == 0)
1414             {
1415                 /*
1416                  * we've successfully read 4KB from the file,
1417                  * now decide if is actually an encrypted file
1418                  * format we support
1419                  */
1420                 const KFile * encfile;
1421 
1422                 /* is this the header of an ecnrypted file? */
1423                 if (KFileIsEnc (tbuff, tz) == 0)
1424                 {
1425                     if (was_encrypted)
1426                         *was_encrypted = true;
1427                     rc = GetEncryptionKey(self, path, obuff, sizeof(obuff), &z);
1428                     if (rc == 0)
1429                     {
1430                         KKey key;
1431 
1432                         /* create the AES Key */
1433                         rc = KKeyInitRead (&key, kkeyAES128, obuff, z);
1434                         if (rc)
1435                             ;
1436                         else
1437                         {
1438                             rc = KEncFileMakeRead (&encfile, file, &key);
1439                             if (rc)
1440                                 ;
1441                             else
1442                             {
1443                                 const KFile * buffile;
1444 
1445                                 /*
1446                                  * TODO: make the bsize a config item not a hard constant
1447                                  */
1448                                 rc = KBufFileMakeRead (&buffile, encfile,
1449                                                        256 * 1024 * 1024);
1450                                 if (rc == 0)
1451                                 {
1452                                     *f = buffile;
1453                                     /* *f keeps a reference to encfile, can release it here */
1454                                     KFileRelease (encfile);
1455                                     return 0;
1456                                 }
1457                                 KFileRelease (encfile);
1458                             }
1459                         }
1460                     }
1461                 }
1462                 else if (KFileIsWGAEnc (tbuff, tz) == 0)
1463                 {
1464                     if (was_encrypted)
1465                         *was_encrypted = true;
1466                     rc = GetEncryptionKey(self, path, obuff, sizeof(obuff), &z);
1467                     if (rc == 0)
1468                     {
1469                         rc = KFileMakeWGAEncRead (&encfile, file, obuff, z);
1470                         if (rc)
1471                             ;
1472                         else
1473                         {
1474                             /* we'll release anextra reference to file
1475                              * after this function returns
1476                              */
1477                             *f = encfile;
1478                             return 0;
1479                         }
1480                     }
1481                 }
1482                 else
1483                 {
1484                     /* -----
1485                      * not encrypted in a manner we can decrypt so
1486                      * give back the raw file (possibly buffered
1487                      *
1488                      * since file is released in the caller
1489                      * we need another reference
1490                      */
1491                     KFileAddRef (file);
1492                     *f = file;
1493                     return 0;
1494                 }
1495             }
1496         }
1497     }
1498     return rc;
1499 }
1500 
1501 
1502 /*
1503  * try to open the file as a regular file
1504  */
1505 static
VFSManagerOpenFileReadRegularFile(char * pbuff,size_t z,KFile const ** file,const KDirectory * dir)1506 rc_t VFSManagerOpenFileReadRegularFile (char * pbuff, size_t z,
1507                                         KFile const ** file,
1508                                         const KDirectory * dir)
1509 {
1510     rc_t rc;
1511     char rbuff [8192];
1512 
1513     assert ((pbuff) && (pbuff[0]));
1514     assert (*file == NULL);
1515 
1516     rc = KDirectoryResolvePath (dir, true, rbuff, sizeof rbuff,
1517                                 "%s", pbuff);
1518     if (rc)
1519         ; /* log? */
1520     else
1521     {
1522         /* validate that the file system agrees the path refers
1523          * to a regular file (even if through a link */
1524         uint32_t type;
1525 
1526         type = KDirectoryPathType (dir, "%s", rbuff);
1527         switch (type & ~kptAlias)
1528         {
1529         case kptNotFound:
1530             rc = RC (rcVFS, rcMgr, rcOpening, rcFile,
1531                      rcNotFound);
1532             break;
1533 
1534         case kptBadPath:
1535             rc = RC (rcVFS, rcMgr, rcOpening, rcFile,
1536                      rcInvalid);
1537             break;
1538 
1539         case kptDir:
1540         case kptCharDev:
1541         case kptBlockDev:
1542         case kptFIFO:
1543         case kptZombieFile:
1544             rc = RC (rcVFS, rcMgr, rcOpening, rcFile,
1545                      rcIncorrect);
1546             break;
1547 
1548         default:
1549             rc = RC (rcVFS, rcMgr, rcOpening, rcFile, rcUnknown);
1550             break;
1551 
1552         case kptFile:
1553             /*
1554              * this is the good/successful path: open the file
1555              * as a const KFile
1556              */
1557             rc = KDirectoryOpenFileRead (dir, file, "%s", rbuff);
1558             break;
1559         }
1560     }
1561 
1562     return rc;
1563 }
1564 
1565 /*
1566  * if successful set *file to a usable KFile * and return 0
1567  * if unsuccessful but without error, set *file to NULL and return 0
1568  * if an error encountered set *file to NULL and return non-zero.
1569  */
1570 static
VFSManagerOpenFileReadSpecial(char * pbuff,size_t z,KFile const ** file)1571 rc_t VFSManagerOpenFileReadSpecial (char * pbuff, size_t z, KFile const ** file)
1572 {
1573     rc_t rc = 0;
1574     static const char dev [] = "/dev/";
1575     static const char dev_stdin [] = "/dev/stdin";
1576     static const char dev_null [] = "/dev/null";
1577 
1578     assert (pbuff);
1579     assert (z);
1580     assert (file);
1581 
1582     *file = NULL;
1583 
1584     /*
1585      * Handle a few special case path names that are pre-opened
1586      * 'file descriptors'
1587      *
1588      * This probably needs to be system specific eventually
1589      *
1590      * First check for the path being in the 'dev' directory in
1591      * posix/unix terms
1592      */
1593     if (string_cmp (dev, sizeof dev - 1, pbuff, z, sizeof dev - 1) != 0)
1594         rc = 0; /* we're done */
1595 
1596     else
1597     {
1598         if (strcmp (dev_stdin, pbuff) == 0)
1599             rc = KFileMakeStdIn (file);
1600 
1601         else if (strcmp (dev_null, pbuff) == 0)
1602             rc = KFileMakeNullRead (file);
1603 
1604         else if (strncmp ("/dev/fd/", pbuff, sizeof "/dev/fd/" - 1) == 0)
1605         {
1606             char * pc;
1607             size_t ix;
1608 
1609             pc = pbuff + sizeof "/dev/fd/" - 1;
1610 
1611             for (ix = 0; isdigit (pc[ix]); ++ix)
1612                 assert (ix <= z);
1613 
1614             if ((ix > 0)&&(pc[ix] == '\0'))
1615             {
1616                 int fd;
1617 
1618                 fd = atoi (pc);
1619                 rc = KFileMakeFDFileRead (file, fd);
1620             }
1621         }
1622     }
1623 
1624     return rc;
1625 }
1626 
1627 static
VFSManagerOpenFileReadInt(const VFSManager * self,const KDirectory * dir,KFile const ** f,const VPath * path,bool force_decrypt,bool * was_encrypted)1628 rc_t VFSManagerOpenFileReadInt (const VFSManager *self,
1629                                 const KDirectory * dir,
1630                                 KFile const **f,
1631                                 const VPath * path,
1632                                 bool force_decrypt,
1633                                 bool * was_encrypted)
1634 {
1635     /* -----
1636      * this is a first pass that only opens files directory referenced from
1637      * the ced or have a sysdir root; that is it uses KSysDir and KSysFile
1638      * only.
1639      */
1640     const KFile * file = NULL;
1641     size_t num_read;
1642     char pbuff [4096];
1643     rc_t rc;
1644 
1645     rc = VPathReadPath (path, pbuff, sizeof pbuff, &num_read);
1646     if (rc)
1647         ; /* log? */
1648     else
1649     {
1650         /* -----
1651          * try to open path as a special file if requested
1652          *
1653          * *file will be set or a usable file or to NULL and rc will reflect
1654          * any error
1655          */
1656         rc = VFSManagerOpenFileReadSpecial (pbuff, num_read, &file);
1657 
1658         if (rc == 0)
1659         {
1660             /* -----
1661              * If we didn't open the file using the special
1662              * logic above for special paths open the file and have no error,
1663              * continue
1664              */
1665             if (file == NULL)
1666                 rc = VFSManagerOpenFileReadRegularFile (pbuff, num_read,
1667                                                         &file, dir);
1668             /*
1669              * we either have an rc to return with or we have an open KFile:
1670              * check for possible encryption that we are told to decrypt
1671              */
1672             if (rc == 0)
1673             {
1674                 rc = VFSManagerOpenFileReadDecryption (self, dir, f, file, path,
1675                                                        force_decrypt, was_encrypted);
1676             }
1677             /* release file if we are here and it is open */
1678             KFileRelease (file);
1679         }
1680     }
1681     return rc;
1682 }
1683 
1684 
1685 static
VFSManagerOpenFileReadDirectoryRelativeInt(const VFSManager * self,const KDirectory * dir,KFile const ** f,const VPath * path,bool force_decrypt,bool * was_encrypted)1686 rc_t VFSManagerOpenFileReadDirectoryRelativeInt (const VFSManager *self,
1687                                                  const KDirectory * dir,
1688                                                  KFile const **f,
1689                                                  const VPath * path,
1690                                                  bool force_decrypt,
1691                                                  bool * was_encrypted)
1692 {
1693     rc_t rc;
1694 
1695     if (f == NULL)
1696         rc = RC (rcVFS, rcMgr, rcOpening, rcParam, rcNull);
1697 
1698     else
1699     {
1700         *f = NULL;
1701 
1702         if ((f == NULL) || (path == NULL))
1703             rc = RC (rcVFS, rcMgr, rcOpening, rcParam, rcNull);
1704 
1705         else if (self == NULL)
1706             rc = RC (rcVFS, rcMgr, rcOpening, rcSelf, rcNull);
1707 
1708         else
1709         {
1710 
1711             rc = VFSManagerOpenFileReadInt (self, dir, f, path, force_decrypt, was_encrypted);
1712         }
1713     }
1714     return rc;
1715 }
1716 
1717 
1718 /* we will create a KFile from a http or ftp url... */
VFSManagerOpenCurlFile(const VFSManager * self,KFile const ** f,const VPath * path,uint32_t blocksize,bool promote)1719 static rc_t VFSManagerOpenCurlFile ( const VFSManager *self,
1720                                      KFile const **f,
1721                                      const VPath * path,
1722                                      uint32_t blocksize,
1723                                      bool promote )
1724 {
1725     rc_t rc;
1726     bool high_reliability, is_refseq;
1727 
1728     if ( f == NULL )
1729         return RC( rcVFS, rcMgr, rcOpening, rcParam, rcNull );
1730     *f = NULL;
1731     if ( self == NULL )
1732         return RC( rcVFS, rcMgr, rcOpening, rcSelf, rcNull );
1733     if ( path == NULL )
1734         return RC( rcVFS, rcMgr, rcOpening, rcParam, rcNull );
1735 
1736     high_reliability = VPathIsHighlyReliable ( path );
1737     is_refseq = VPathHasRefseqContext ( path );
1738     if ( self->resolver != NULL )
1739     {
1740         const VPath * local_cache;
1741 
1742         /* find cache - vresolver call */
1743         rc = VResolverCache ( self->resolver, path, &local_cache, 0 );
1744         if ( rc == 0 )
1745         {
1746             /* we did find a place for local cache --> use it! */
1747             rc = VFSManagerMakeHTTPFile( self,
1748                                          f,
1749                                          path,
1750                                          local_cache -> path.addr,
1751                                          blocksize,
1752                                          high_reliability,
1753                                          is_refseq,
1754                                          promote );
1755             {
1756                 rc_t rc2 = VPathRelease ( local_cache );
1757                 if ( rc == 0 )
1758                 {
1759                     rc = rc2;
1760                 }
1761             }
1762         }
1763         else
1764         {
1765             /* we did NOT find a place for local cache --> we are not caching! */
1766             rc = VFSManagerMakeHTTPFile( self,
1767                                          f,
1768                                          path,
1769                                          NULL,
1770                                          blocksize,
1771                                          high_reliability,
1772                                          is_refseq,
1773                                          promote );
1774         }
1775     }
1776     else
1777     {
1778         /* no resolver has been found ---> we cannot do caching! */
1779         rc = VFSManagerMakeHTTPFile( self,
1780                                      f,
1781                                      path,
1782                                      NULL,
1783                                      blocksize,
1784                                      high_reliability,
1785                                      is_refseq,
1786                                      promote );
1787     }
1788     return rc;
1789 }
1790 
1791 LIB_EXPORT
VFSManagerOpenFileReadDirectoryRelative(const VFSManager * self,const KDirectory * dir,KFile const ** f,const VPath * path)1792 rc_t CC VFSManagerOpenFileReadDirectoryRelative (const VFSManager *self,
1793                                                  const KDirectory * dir,
1794                                                  KFile const **f,
1795                                                  const VPath * path)
1796 {
1797     return VFSManagerOpenFileReadDirectoryRelativeInt (self, dir, f, path, false, NULL);
1798 }
1799 
1800 LIB_EXPORT
VFSManagerOpenFileReadDirectoryRelativeDecrypt(const VFSManager * self,const KDirectory * dir,KFile const ** f,const VPath * path)1801 rc_t CC VFSManagerOpenFileReadDirectoryRelativeDecrypt (const VFSManager *self,
1802                                                         const KDirectory * dir,
1803                                                         KFile const **f,
1804                                                         const VPath * path) /*,
1805                                                         bool force_decrypt) */
1806 {
1807     return VFSManagerOpenFileReadDirectoryRelativeInt (self, dir, f, path, true, NULL);
1808 }
1809 
1810 
ResolveVPathByVResolver(struct VResolver * resolver,const VPath ** path)1811 static rc_t ResolveVPathByVResolver( struct VResolver * resolver, const VPath ** path )
1812 {
1813     rc_t rc;
1814 
1815     if ( resolver == NULL )
1816         rc = RC ( rcVFS, rcFile, rcOpening, rcSRA, rcUnsupported );
1817     else
1818     {
1819         const VPath * tpath;
1820         rc = VResolverLocal ( resolver, *path, &tpath );
1821         if ( rc == 0 )
1822         {
1823             VPathRelease ( *path );
1824             *path = tpath;
1825         }
1826     }
1827     return rc;
1828 }
1829 
ResolveVPathBySRAPath(const VPath ** path)1830 static rc_t ResolveVPathBySRAPath( const VPath ** path )
1831 {
1832     * path = NULL;
1833     return RC ( rcVFS, rcFile, rcOpening, rcSRA, rcUnsupported );
1834 }
1835 
VFSManagerOpenFileReadWithBlocksize(const VFSManager * self,KFile const ** f,const VPath * path_,uint32_t blocksize,bool promote)1836 LIB_EXPORT rc_t CC VFSManagerOpenFileReadWithBlocksize ( const VFSManager *self,
1837                                             KFile const **f,
1838                                             const VPath * path_,
1839                                             uint32_t blocksize,
1840                                             bool promote )
1841 {
1842     rc_t rc;
1843 
1844     if ( f == NULL )
1845         rc = RC (rcVFS, rcMgr, rcOpen, rcParam, rcNull);
1846     else
1847     {
1848         *f = NULL;
1849 
1850         if  (self == NULL )
1851             rc = RC ( rcVFS, rcMgr, rcOpen, rcSelf, rcNull );
1852         else if ( f == NULL )
1853             rc = RC ( rcVFS, rcMgr, rcOpen, rcParam, rcNull );
1854         else
1855         {
1856             rc = VPathAddRef ( path_ );
1857             if ( rc == 0 )
1858             {
1859                 const VPath * path = path_;
1860                 VPUri_t uri_type = VPathGetUri_t ( path );
1861 
1862                 switch ( uri_type )
1863                 {
1864                 default:
1865                 case vpuri_invalid:
1866                     rc = RC (rcVFS, rcFile, rcOpening, rcPath, rcInvalid);
1867                     break;
1868 
1869                 case vpuri_not_supported:
1870                     rc = RC (rcVFS, rcFile, rcOpening, rcPath, rcUnsupported);
1871                     break;
1872 
1873                 case vpuri_ncbi_acc:
1874                     if ( self->resolver != NULL )
1875                         rc = ResolveVPathByVResolver( self->resolver, &path );
1876                     else
1877                         rc = ResolveVPathBySRAPath( &path );
1878 
1879                     if ( rc != 0 )
1880                         break;
1881 
1882                 /* !!! fall through !!! */
1883 
1884                 case vpuri_none:
1885                 case vpuri_ncbi_vfs:
1886                 case vpuri_file:
1887                     rc = VFSManagerOpenFileReadDirectoryRelativeInt ( self, self->cwd, f, path, false, NULL );
1888                     break;
1889 
1890                 case vpuri_ncbi_legrefseq:
1891                     rc = RC ( rcVFS, rcFile, rcOpening, rcPath, rcIncorrect );
1892                     break;
1893 
1894                 case vpuri_http:
1895                 case vpuri_https:
1896                 case vpuri_ftp:
1897                     rc = VFSManagerOpenCurlFile ( self, f, path, blocksize, promote );
1898                     break;
1899                 }
1900                 VPathRelease (path);
1901             }
1902         }
1903     }
1904     return rc;
1905 }
1906 
VFSManagerOpenFileRead(const VFSManager * self,KFile const ** f,const VPath * path)1907 LIB_EXPORT rc_t CC VFSManagerOpenFileRead ( const VFSManager *self,
1908                                             KFile const **f,
1909                                             const VPath * path )
1910 {
1911     return VFSManagerOpenFileReadWithBlocksize ( self, f, path, DEFAULT_CACHE_PAGE_SIZE, false );
1912 }
1913 
VFSManagerOpenFileReadPromote(const VFSManager * self,KFile const ** f,const VPath * path)1914 LIB_EXPORT rc_t CC VFSManagerOpenFileReadPromote ( const VFSManager *self,
1915                                             KFile const **f,
1916                                             const VPath * path )
1917 {
1918     return VFSManagerOpenFileReadWithBlocksize ( self, f, path, DEFAULT_CACHE_PAGE_SIZE, true );
1919 }
1920 
VFSManagerOpenFileReadDecrypt(const VFSManager * self,KFile const ** f,const VPath * path)1921 LIB_EXPORT rc_t CC VFSManagerOpenFileReadDecrypt (const VFSManager *self,
1922                                                   KFile const **f,
1923                                                   const VPath * path)
1924 {
1925     return VFSManagerOpenFileReadDirectoryRelativeInt ( self, self->cwd, f, path, true, NULL );
1926 }
1927 
1928 LIB_EXPORT
VFSManagerOpenDirectoryUpdateDirectoryRelative(const VFSManager * self,const KDirectory * dir,KDirectory ** d,const VPath * path)1929 rc_t CC VFSManagerOpenDirectoryUpdateDirectoryRelative (const VFSManager *self,
1930                                                         const KDirectory * dir,
1931                                                         KDirectory **d,
1932                                                         const VPath * path)
1933 {
1934     rc_t rc;
1935     VPUri_t uri_type;
1936 
1937     if ((d == NULL) || (path == NULL))
1938         return RC (rcVFS, rcMgr, rcOpening, rcParam, rcNull);
1939 
1940     *d = NULL;
1941 
1942     if (self == NULL)
1943         return RC (rcVFS, rcMgr, rcOpening, rcSelf, rcNull);
1944 
1945     uri_type = VPathGetUri_t ( path );
1946     switch ( uri_type )
1947     {
1948     case vpuri_http :
1949     case vpuri_https:
1950     case vpuri_ftp :
1951         return RC( rcVFS, rcMgr, rcOpening, rcParam, rcWrongType );
1952 
1953     default :
1954         {
1955             uint32_t type;
1956 
1957             /* WHY NOT JUST TRY TO OPEN THE DIRECTORY,
1958                AND LET KFS TELL US WHAT'S WRONG? */
1959 
1960             type = KDirectoryPathType (dir, "%.*s", ( int ) path -> path . size, path -> path . addr );
1961             switch (type & ~kptAlias)
1962             {
1963             case kptNotFound:
1964                 rc = RC (rcVFS, rcMgr, rcOpening, rcDirectory, rcNotFound);
1965                 break;
1966 
1967             case kptFile:
1968                 rc = RC (rcVFS, rcMgr, rcOpening, rcDirectory, rcReadonly);
1969                 break;
1970 
1971             case kptBadPath:
1972                 rc = RC (rcVFS, rcMgr, rcOpening, rcDirectory, rcInvalid);
1973                 break;
1974 
1975             case kptDir:
1976                 rc = KDirectoryOpenDirUpdate ((KDirectory*)dir, d, false, "%.*s", ( int ) path -> path . size, path -> path . addr);
1977                 return rc;
1978 
1979             case kptCharDev:
1980             case kptBlockDev:
1981             case kptFIFO:
1982             case kptZombieFile:
1983                 rc = RC (rcVFS, rcMgr, rcOpening, rcDirectory, rcIncorrect);
1984                 break;
1985 
1986             default:
1987                 rc = RC (rcVFS, rcMgr, rcOpening, rcDirectory, rcUnknown);
1988                 break;
1989             }
1990         }
1991     }
1992     return rc;
1993 }
1994 
1995 
VFSManagerOpenDirectoryUpdate(const VFSManager * self,KDirectory ** d,const VPath * path)1996 LIB_EXPORT rc_t CC VFSManagerOpenDirectoryUpdate (const VFSManager *self,
1997                                                   KDirectory **d,
1998                                                   const VPath * path)
1999 {
2000     return VFSManagerOpenDirectoryUpdateDirectoryRelative (self, self->cwd, d, path);
2001 }
2002 
2003 
2004 static
TransformFileToDirectory(const KDirectory * dir,const KFile * file,KDirectory const ** d,const char * path_str,bool was_encrypted)2005 rc_t TransformFileToDirectory(const KDirectory * dir,
2006                               const KFile * file,
2007                               KDirectory const **d,
2008                               const char *path_str,
2009                               bool was_encrypted)
2010 {
2011     rc_t rc;
2012 
2013     rc = KFileRandomAccess( file );
2014     if (rc)
2015         PLOGERR(klogErr,(klogErr, rc, "Can not use files without random access"
2016                          " as database archives '$(P)'", "P=%s", path_str));
2017     else
2018     {
2019         size_t tz;
2020         char tbuff [4096];
2021 
2022         rc = KFileReadAll (file, 0, tbuff, sizeof tbuff, &tz);
2023         if ( rc )
2024             LOGERR (klogErr, rc, "Error reading the head of an archive to use as a database object");
2025         else
2026         {
2027             /* we only use KAR/SRA or tar files as archives so try to identify
2028              * as our KAR/SRA file.
2029              IT IS NOT TRUE ANYMORE ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ */
2030             if ( KFileIsSRA( tbuff, tz ) == 0 )
2031                 /* if it was open it as a directory */
2032                 rc = KDirectoryOpenSraArchiveReadUnbounded_silent_preopened( dir, d, false, file, "%s", path_str );
2033 
2034             else
2035             {
2036                 rc = KDirectoryOpenTarArchiveRead_silent_preopened( dir, d, false, file, "%s", path_str );
2037 
2038                 /*
2039                  * if RC here we did not have an SRA and did not have
2040                  * a tar file we could use; assume the problem was:
2041                  * - decryption if the file was encrypted
2042                  * - or it is not an archive
2043                  */
2044                 if (rc != 0) {
2045                     if ( was_encrypted ) {
2046                      /* the following RC update is not correct anymore but:
2047                         TODO: check tools/libraries
2048                             that expect this returned code and fix them
2049                         rc = RC(rcVFS, rcEncryptionKey, rcOpening, rcEncryption,
2050                              rcIncorrect );
2051                         PLOGERR (klogErr, (klogErr, rc,
2052                             "could not use '$(P)' as an "
2053                             "archive it was encrypted so the password"
2054                             " was possibly wrong or it is not SRA or"
2055                             " TAR file", "P=%s", path_str)); */
2056                         MGR_DEBUG(("TransformFileToDirectory: could not use "
2057                             "'%s' as an archive - it was encrypted and "
2058                             "the password was possibly wrong "
2059                             "or it is not SRA or TAR file\n", path_str));
2060                     }
2061                     else {
2062                         PLOGERR (klogInfo, (klogInfo, rc,
2063                             "could not use '$(P)' as an "
2064                             "archive not identified as SRA or"
2065                             " TAR file", "P=%s", path_str));
2066                     }
2067                 }
2068             }
2069         }
2070     }
2071     return rc;
2072 }
2073 
2074 static
VFSManagerOpenDirectoryReadHttp(const VFSManager * self,const KDirectory * dir,KDirectory const ** d,const VPath * path,bool force_decrypt,bool reliable,bool promote)2075 rc_t VFSManagerOpenDirectoryReadHttp (const VFSManager *self,
2076                                       const KDirectory * dir,
2077                                       KDirectory const **d,
2078                                       const VPath * path,
2079                                       bool force_decrypt,
2080                                       bool reliable,
2081                                       bool promote )
2082 {
2083     const KFile * file = NULL;
2084     rc_t rc = VFSManagerOpenCurlFile ( self, &file, path, DEFAULT_CACHE_PAGE_SIZE, promote );
2085     if ( rc != 0 )
2086     {
2087         bool toLog = false;
2088         const char extension[] = ".vdbcache";
2089         const String * s = & path -> path;
2090         assert ( s );
2091         /* do not log error for .vdbcache http files : find a better solution */
2092         if ( s -> addr == NULL
2093             || s -> size < sizeof extension || s -> len < sizeof extension
2094             || string_cmp ( s -> addr + s -> size - sizeof extension + 1,
2095                 sizeof extension - 1,
2096                 extension, sizeof extension - 1, sizeof extension - 1 ) != 0 )
2097         {
2098             toLog = reliable;
2099         }
2100         if ( toLog ) {
2101           const String * p = NULL;
2102           rc_t rc2 = VPathMakeString ( path, & p );
2103           if ( rc2 == 0 ) {
2104                 PLOGERR ( klogErr, ( klogErr, rc, "error with https open '$(path)'",
2105                                        "path=%S", p ) );
2106                 free (  ( void * ) p );
2107           } else {
2108             PLOGERR ( klogErr, ( klogErr, rc, "error with https open '$(scheme):$(path)'",
2109                              "scheme=%S,path=%S", & path -> scheme, s ) );
2110           }
2111         }
2112     }
2113     else
2114     {
2115         const char mountpointpath[] = "/";
2116         const KDirectory * mountpoint;
2117 
2118         rc = KQuickMountDirMake (self->cwd, &mountpoint, file,
2119                                  mountpointpath, sizeof mountpointpath - 1,
2120                                  path->path.addr, path->path.size);
2121         if (rc)
2122         {
2123             PLOGERR (klogInt, (klogErr, rc, "error creating mount "
2124                                "'$(M)' for '$(F)", "M=%s,F=%S",
2125                                mountpointpath, &path->path));
2126         }
2127         else
2128         {
2129             const KFile * f;
2130             bool was_encrypted = false;
2131 
2132             rc = VFSManagerOpenFileReadDecryption (self, mountpoint, &f,
2133                                                    file, path,
2134                                                    force_decrypt,
2135                                                    &was_encrypted);
2136             if (rc == 0)
2137             {
2138 
2139                 rc = TransformFileToDirectory (mountpoint, f, d,
2140                                                path->path.addr,
2141                                                was_encrypted);
2142                 /* hacking in the fragment bit */
2143                 if ((rc == 0) && (path->fragment . size > 1 ) )
2144                 {
2145                     const KDirectory * tempd = * d;
2146                     const char * fragment = path -> fragment . addr + 1;
2147                     int frag_size = ( int ) path -> fragment . size - 1;
2148 
2149                     assert ( fragment [ -1 ] == '#' );
2150 
2151                     rc = KDirectoryOpenDirRead (tempd, d, false, "%.*s", frag_size, fragment );
2152 
2153                     KDirectoryRelease (tempd);
2154                 }
2155                 KFileRelease (f);
2156             }
2157             KDirectoryRelease (mountpoint);
2158         }
2159         KFileRelease (file);
2160     }
2161     return rc;
2162 }
2163 
2164 /* similar to VFSManagerOpenDirectoryReadHttp but already resolved */
2165 static
VFSManagerOpenDirectoryReadHttpResolved(const VFSManager * self,KDirectory const ** d,const VPath * path,const VPath * cache,bool force_decrypt,bool promote)2166 rc_t VFSManagerOpenDirectoryReadHttpResolved (const VFSManager *self,
2167                                               KDirectory const **d,
2168                                               const VPath * path,
2169                                               const VPath * cache,
2170                                               bool force_decrypt,
2171                                               bool promote)
2172 {
2173     const String * uri = NULL;
2174     rc_t rc = VPathMakeString ( path, &uri );
2175     if ( rc == 0 )
2176     {
2177         /* check how the path has been marked */
2178         bool high_reliability = VPathIsHighlyReliable ( path );
2179         bool is_refseq = VPathHasRefseqContext ( path );
2180 
2181         const KFile * file = NULL;
2182         rc = VFSManagerMakeHTTPFile( self,
2183                                      &file,
2184                                      path,
2185                                      cache == NULL ? NULL : cache -> path . addr,
2186                                      DEFAULT_CACHE_PAGE_SIZE,
2187                                      high_reliability,
2188                                      is_refseq,
2189                                      promote );
2190         if ( rc != 0 )
2191         {
2192             if ( high_reliability )
2193             {
2194                 PLOGERR ( klogErr, ( klogErr, rc, "error with https open '$(U)'",
2195                                      "U=%S", uri ) );
2196             }
2197         }
2198         else
2199         {
2200             const char mountpointpath[] = "/";
2201             const KDirectory * mountpoint;
2202 
2203             rc = KQuickMountDirMake (self->cwd, &mountpoint, file,
2204                                      mountpointpath, sizeof mountpointpath - 1,
2205                                      path->path.addr, path->path.size);
2206             if (rc)
2207             {
2208                 PLOGERR (klogInt, (klogErr, rc, "error creating mount "
2209                                    "'$(M)' for '$(F)", "M=%s,F=%S",
2210                                    mountpointpath, &path->path));
2211             }
2212             else
2213             {
2214                 const KFile * f;
2215                 bool was_encrypted = false;
2216 
2217                 rc = VFSManagerOpenFileReadDecryption (self, mountpoint, &f,
2218                                                        file, path,
2219                                                        force_decrypt,
2220                                                        &was_encrypted);
2221                 if ( rc == 0 )
2222                 {
2223 
2224                     rc = TransformFileToDirectory ( mountpoint, f, d,
2225                                                     path -> path . addr,
2226                                                     was_encrypted);
2227                     /* hacking in the fragment bit */
2228                     if ( ( rc == 0 ) && ( path -> fragment . size > 1 ) )
2229                     {
2230                         const KDirectory * tempd = * d;
2231                         const char * fragment = path -> fragment . addr + 1;
2232                         int frag_size = ( int ) path -> fragment . size - 1;
2233 
2234                         assert ( fragment [ -1 ] == '#' );
2235 
2236                         rc = KDirectoryOpenDirRead (tempd, d, false, "%.*s", frag_size, fragment );
2237 
2238                         KDirectoryRelease (tempd);
2239                     }
2240                     KFileRelease (f);
2241                 }
2242                 KDirectoryRelease (mountpoint);
2243             }
2244             KFileRelease (file);
2245         }
2246         free( ( void * )uri );
2247     }
2248     return rc;
2249 }
2250 
2251 
2252 static
VFSManagerOpenDirectoryReadKfs(const VFSManager * self,const KDirectory * dir,KDirectory const ** d,const VPath * path,bool force_decrypt)2253 rc_t VFSManagerOpenDirectoryReadKfs (const VFSManager *self,
2254                                      const KDirectory * dir,
2255                                      KDirectory const **d,
2256                                      const VPath * path,
2257                                      bool force_decrypt)
2258 {
2259     const KFile * file = NULL;
2260     char rbuff[ 4096 ]; /* resolved path buffer */
2261     rc_t rc;
2262 
2263     assert (self);
2264     assert (dir);
2265     assert (d);
2266     assert (path);
2267     assert ((force_decrypt == false) || (force_decrypt == true));
2268     assert (*d == NULL);
2269 
2270     file = NULL;
2271 
2272     rc = KDirectoryResolvePath( dir, true, rbuff, sizeof rbuff, "%.*s", ( int ) path -> path . size, path -> path . addr );
2273     if ( rc == 0 )
2274     {
2275         uint32_t type;
2276         bool was_encrypted;
2277 
2278         type = KDirectoryPathType( dir, "%s", rbuff );
2279         switch (type & ~kptAlias)
2280         {
2281         case kptNotFound:
2282             rc = RC( rcVFS, rcMgr, rcOpening, rcDirectory, rcNotFound );
2283             break;
2284 
2285         case kptFile:
2286             rc = VFSManagerOpenFileReadDirectoryRelativeInt (self, dir,
2287                                                              &file, path,
2288                                                              force_decrypt,
2289                                                              &was_encrypted);
2290             if (rc == 0)
2291                 rc = TransformFileToDirectory (dir, file, d, rbuff,
2292                                                was_encrypted);
2293             break;
2294 
2295         case kptBadPath:
2296             rc = RC( rcVFS, rcMgr, rcOpening, rcDirectory, rcInvalid );
2297             break;
2298 
2299         case kptDir:
2300             rc = KDirectoryOpenDirRead( dir, d, false, "%s", rbuff );
2301             return rc;
2302 
2303         case kptCharDev:
2304         case kptBlockDev:
2305         case kptFIFO:
2306         case kptZombieFile:
2307             rc = RC( rcVFS, rcMgr, rcOpening, rcDirectory, rcIncorrect );
2308             break;
2309 
2310         default:
2311             rc = RC( rcVFS, rcMgr, rcOpening, rcDirectory, rcUnknown );
2312             break;
2313         }
2314 
2315         /* hacking in the fragment bit */
2316         /* the C grammar specifies order of precedence... */
2317         if ((rc == 0) && (path->fragment.size > 1 ))
2318         {
2319             const KDirectory * tempd = * d;
2320             const char * fragment = path -> fragment . addr + 1;
2321             int frag_size = ( int ) path -> fragment . size - 1;
2322 
2323             assert ( fragment [ -1 ] == '#' );
2324 
2325             rc = KDirectoryOpenDirRead (tempd, d, false, "%.*s", frag_size, fragment );
2326 
2327             KDirectoryRelease (tempd);
2328         }
2329     }
2330 
2331     KFileRelease(file);
2332 
2333     return rc;
2334 }
2335 
2336 
2337 static
VFSManagerOpenDirectoryReadLegrefseq(const VFSManager * self,const KDirectory * dir,KDirectory const ** d,const VPath * path,bool force_decrypt)2338 rc_t VFSManagerOpenDirectoryReadLegrefseq (const VFSManager *self,
2339                                            const KDirectory * dir,
2340                                            KDirectory const **d,
2341                                            const VPath * path,
2342                                            bool force_decrypt)
2343 {
2344     const KFile * file;
2345     const KDirectory * dd;
2346     size_t num_read;
2347     char pbuff [4096]; /* path buffer */
2348     rc_t rc;
2349 
2350     assert (self);
2351     assert (dir);
2352     assert (d);
2353     assert (path);
2354     assert ((force_decrypt == false) || (force_decrypt == true));
2355     assert (*d == NULL);
2356 
2357     file = NULL;
2358     dd = NULL;
2359 
2360     /* hier part only */
2361     rc = VPathReadPath (path, pbuff, sizeof pbuff, &num_read);
2362     if ( rc == 0 )
2363     {
2364         char rbuff[ 4096 ]; /* resolved path buffer */
2365         rc = KDirectoryResolvePath( dir, true, rbuff, sizeof rbuff, "%s", pbuff );
2366         if ( rc == 0 )
2367         {
2368             uint32_t type;
2369             bool was_encrypted;
2370 
2371             type = KDirectoryPathType( dir, "%s", rbuff );
2372             switch (type & ~kptAlias)
2373             {
2374             case kptNotFound:
2375                 rc = RC( rcVFS, rcMgr, rcOpening, rcDirectory, rcNotFound );
2376                 break;
2377 
2378             case kptFile:
2379                 rc = VFSManagerOpenFileReadDirectoryRelativeInt (self, dir,
2380                                                                  &file, path,
2381                                                                  force_decrypt,
2382                                                                  &was_encrypted);
2383                 if (rc == 0)
2384                     rc = TransformFileToDirectory (dir, file, &dd, rbuff,
2385                                                    was_encrypted);
2386                 break;
2387 
2388             case kptBadPath:
2389                 rc = RC( rcVFS, rcMgr, rcOpening, rcDirectory, rcInvalid );
2390                 break;
2391 
2392             case kptDir:
2393                 rc = KDirectoryOpenDirRead( dir, &dd, false, "%s", rbuff );
2394                 break;
2395 
2396             case kptCharDev:
2397             case kptBlockDev:
2398             case kptFIFO:
2399             case kptZombieFile:
2400                 rc = RC( rcVFS, rcMgr, rcOpening, rcDirectory, rcIncorrect );
2401                 break;
2402 
2403             default:
2404                 rc = RC( rcVFS, rcMgr, rcOpening, rcDirectory, rcUnknown );
2405                 break;
2406             }
2407 
2408             if (rc == 0)
2409             {
2410                 if ( path -> fragment . size < 2 )
2411                     rc = RC( rcVFS, rcMgr, rcOpening, rcPath, rcIncorrect );
2412                 else
2413                 {
2414                     const char *fragment = path -> fragment . addr + 1;
2415                     int frag_size = ( int ) path -> fragment . size - 1;
2416                     assert ( fragment [ -1 ] == '#' );
2417 
2418                     rc = KDirectoryOpenDirRead (dd, d, false, "%.*s", frag_size, fragment );
2419 
2420                     KDirectoryRelease (dd);
2421                 }
2422             }
2423         }
2424     }
2425     return rc;
2426 }
2427 
2428 
2429 static
VFSManagerOpenDirectoryReadDirectoryRelativeInt(const VFSManager * self,const KDirectory * dir,KDirectory const ** d,const VPath * path_,bool force_decrypt,bool reliable,bool promote)2430 rc_t VFSManagerOpenDirectoryReadDirectoryRelativeInt (const VFSManager *self,
2431                                                       const KDirectory * dir,
2432                                                       KDirectory const **d,
2433                                                       const VPath * path_,
2434                                                       bool force_decrypt,
2435                                                       bool reliable,
2436                                                       bool promote)
2437 {
2438     rc_t rc;
2439     do
2440     {
2441         if (d == NULL)
2442         {
2443             rc =  RC (rcVFS, rcDirectory, rcOpening, rcParam, rcNull);
2444             break;
2445         }
2446 
2447         *d = NULL;
2448 
2449         if (self == NULL)
2450         {
2451             rc = RC (rcVFS, rcDirectory, rcOpening, rcSelf, rcNull);
2452             break;
2453         }
2454 
2455         if ((dir == NULL) || (path_ == NULL))
2456         {
2457             rc = RC (rcVFS, rcDirectory, rcOpening, rcParam, rcNull);
2458             break;
2459         }
2460 
2461 #if 0
2462         if ((force_decrypt != false) && (force_decrypt != true))
2463         {
2464             rc = RC (rcVFS, rcDirectory, rcOpening, rcParam, rcInvalid);
2465             break;
2466         }
2467 #endif
2468 
2469         rc = VPathAddRef (path_);
2470         if ( rc )
2471             break;
2472         else
2473         {
2474             const VPath *path = path_;
2475             VPUri_t uri_type = VPathGetUri_t ( path );
2476 
2477             switch ( uri_type )
2478             {
2479             default:
2480             case vpuri_invalid:
2481                 rc = RC (rcVFS, rcDirectory, rcOpening, rcPath, rcInvalid);
2482                 break;
2483 
2484 
2485             case vpuri_not_supported:
2486                 rc = RC (rcVFS, rcDirectory, rcOpening, rcPath, rcUnsupported);
2487                 break;
2488 
2489             case vpuri_ncbi_acc:
2490                 if ( self->resolver != NULL )
2491                     rc = ResolveVPathByVResolver( self->resolver, &path );
2492                 else
2493                     rc = ResolveVPathBySRAPath( &path );
2494                 if ( rc != 0 )
2495                     break;
2496 
2497             /* !!! fall through !!! */
2498 
2499             case vpuri_none:
2500             case vpuri_ncbi_vfs:
2501             case vpuri_file:
2502                 rc = VFSManagerOpenDirectoryReadKfs ( self, dir, d, path, force_decrypt );
2503                 break;
2504 
2505             case vpuri_ncbi_legrefseq:
2506                 rc = VFSManagerOpenDirectoryReadLegrefseq ( self, dir, d, path, force_decrypt );
2507                 break;
2508 
2509             case vpuri_http:
2510             case vpuri_https:
2511             case vpuri_ftp:
2512                 rc = VFSManagerOpenDirectoryReadHttp ( self, dir, d, path,
2513                                                       force_decrypt, reliable, promote );
2514                 break;
2515             }
2516             VPathRelease ( path ); /* same as path_ if not uri */
2517         }
2518     } while (0);
2519     return rc;
2520 }
2521 
2522 
2523 LIB_EXPORT
VFSManagerOpenDirectoryReadDirectoryRelative(const VFSManager * self,const KDirectory * dir,KDirectory const ** d,const VPath * path)2524 rc_t CC VFSManagerOpenDirectoryReadDirectoryRelative (const VFSManager *self,
2525                                                       const KDirectory * dir,
2526                                                       KDirectory const **d,
2527                                                       const VPath * path)
2528 {
2529     /* HACK - this function should not be exported.
2530        in order to not change the signature, we are synthesizing
2531        a "promote" parameter as "true" to mimic old behavior */
2532     return VFSManagerOpenDirectoryReadDirectoryRelativeInt (self, dir, d, path,
2533         false, true, true);
2534 }
2535 
2536 
2537 LIB_EXPORT
VFSManagerOpenDirectoryReadDirectoryRelativeDecrypt(const VFSManager * self,const KDirectory * dir,KDirectory const ** d,const VPath * path)2538 rc_t CC VFSManagerOpenDirectoryReadDirectoryRelativeDecrypt (const VFSManager *self,
2539                                                              const KDirectory * dir,
2540                                                              KDirectory const **d,
2541                                                              const VPath * path)
2542 {
2543     /* HACK - this function should not be exported.
2544        in order to not change the signature, we are synthesizing
2545        a "promote" parameter as "true" to mimic old behavior */
2546     return VFSManagerOpenDirectoryReadDirectoryRelativeInt (self, dir, d, path,
2547         true, true, true);
2548 }
2549 
2550 
VFSManagerOpenDirectoryReadDecrypt(const VFSManager * self,KDirectory const ** d,const VPath * path)2551 LIB_EXPORT rc_t CC VFSManagerOpenDirectoryReadDecrypt (const VFSManager *self,
2552                                                        KDirectory const **d,
2553                                                        const VPath * path)
2554 {
2555     /* HACK - this function should not be exported.
2556        in order to not change the signature, we are synthesizing
2557        a "promote" parameter as "true" to mimic old behavior */
2558     return VFSManagerOpenDirectoryReadDirectoryRelativeInt (self, self->cwd, d,
2559         path, true, true, true);
2560 }
2561 
VFSManagerOpenDirectoryReadDecryptUnreliable(const VFSManager * self,KDirectory const ** d,const VPath * path)2562 LIB_EXPORT rc_t CC VFSManagerOpenDirectoryReadDecryptUnreliable (
2563                                                        const VFSManager *self,
2564                                                        KDirectory const **d,
2565                                                        const VPath * path)
2566 {
2567     return VFSManagerOpenDirectoryReadDirectoryRelativeInt (self, self->cwd, d,
2568         path, true, false, true);
2569 }
2570 
2571 
VFSManagerOpenDirectoryRead(const VFSManager * self,KDirectory const ** d,const VPath * path)2572 LIB_EXPORT rc_t CC VFSManagerOpenDirectoryRead (const VFSManager *self,
2573                                                 KDirectory const **d,
2574                                                 const VPath * path)
2575 {
2576     if ( self == NULL )
2577         return RC (rcVFS, rcDirectory, rcOpening, rcSelf, rcNull);
2578     /* HACK - this function should not be exported.
2579        in order to not change the signature, we are synthesizing
2580        a "promote" parameter as "true" to mimic old behavior */
2581     return VFSManagerOpenDirectoryReadDirectoryRelativeInt (self, self->cwd, d,
2582         path, false, true, true);
2583 }
2584 
2585 LIB_EXPORT
VFSManagerOpenDirectoryReadDecryptRemote(const VFSManager * self,KDirectory const ** d,const VPath * path,const VPath * cache)2586 rc_t CC VFSManagerOpenDirectoryReadDecryptRemote (const VFSManager *self,
2587                                                   KDirectory const **d,
2588                                                   const VPath * path,
2589                                                   const VPath * cache)
2590 {
2591     rc_t rc;
2592     if ( self == NULL )
2593         return RC (rcVFS, rcDirectory, rcOpening, rcSelf, rcNull);
2594     if ( path == NULL )
2595         return RC (rcVFS, rcDirectory, rcOpening, rcParam, rcNull);
2596     /* cache == NULL is ok */
2597     if ( d == NULL )
2598         return RC (rcVFS, rcDirectory, rcOpening, rcParam, rcNull);
2599     *d = NULL;
2600 
2601     switch ( VPathGetUri_t ( path ) )
2602     {
2603     case vpuri_http:
2604     case vpuri_https:
2605     case vpuri_ftp:
2606         /* HACK - this function should not be exported.
2607            in order to not change the signature, we are synthesizing
2608            a "promote" parameter as "true" to mimic old behavior */
2609         rc = VFSManagerOpenDirectoryReadHttpResolved ( self, d, path, cache, true, true );
2610         break;
2611 
2612     default:
2613         rc = RC (rcVFS, rcDirectory, rcOpening, rcPath, rcInvalid);
2614         break;
2615     }
2616 
2617     return rc;
2618 }
2619 
2620 
2621 /* OpenFileWrite
2622  *  opens an existing file with write access
2623  *
2624  *  "f" [ OUT ] - return parameter for newly opened file
2625  *
2626  *  "update" [ IN ] - if true, open in read/write mode
2627  *  otherwise, open in write-only mode
2628  *
2629  *  "path" [ IN ] - NUL terminated string in directory-native
2630  *  character set denoting target file
2631  */
VFSManagerOpenFileWrite(const VFSManager * self,KFile ** f,bool update,const VPath * path)2632 LIB_EXPORT rc_t CC VFSManagerOpenFileWrite (const VFSManager *self,
2633                                             KFile **f, bool update,
2634                                             const VPath * path )
2635 {
2636     /* -----
2637      * this is a first pass that only opens files directory referenced from
2638      * the ced or have a sysdir root; that is it uses KSysDir and KSysFile
2639      * only.
2640      */
2641     KFile * file = NULL;
2642     size_t num_read;
2643     char pbuff [4096];
2644     rc_t rc;
2645 
2646     if ((f == NULL) || (path == NULL))
2647         return RC (rcVFS, rcMgr, rcOpening, rcParam, rcNull);
2648 
2649     *f = NULL;
2650 
2651     if (self == NULL)
2652         return RC (rcVFS, rcMgr, rcOpening, rcSelf, rcNull);
2653 
2654     rc = VPathReadPath (path, pbuff, sizeof pbuff, &num_read);
2655     if (rc == 0)
2656     {
2657         /* handle a few special case path names
2658          * This probably needs to be system specifica eventually
2659          */
2660         if (strncmp ("/dev/", pbuff, sizeof "/dev/" - 1) == 0)
2661         {
2662 
2663             if (strcmp ("/dev/stdout", pbuff) == 0)
2664                 rc = KFileMakeStdOut (&file);
2665             else if (strcmp ("/dev/stderr", pbuff) == 0)
2666                 rc = KFileMakeStdErr (&file);
2667             else if (strcmp ("/dev/null", pbuff) == 0)
2668                 rc = KFileMakeNullUpdate (&file);
2669             else if (strncmp ("/dev/fd/", pbuff, sizeof "/dev/fd/" - 1) == 0)
2670             {
2671                 char * pc;
2672                 size_t ix;
2673 
2674                 pc = pbuff + sizeof "/dev/fd/" - 1;
2675 
2676                 for (ix = 0; isdigit (pc[ix]); ++ix)
2677                     ;
2678 
2679                 if ((ix > 0)&&(pc[ix] == '\0'))
2680                 {
2681                     int fd = atoi (pc);
2682 
2683                     rc = KFileMakeFDFileWrite (&file, update, fd);
2684                 }
2685             }
2686         }
2687         if ((rc == 0)&&(file == NULL))
2688         {
2689             char rbuff [4096];
2690 
2691             rc = KDirectoryResolvePath (self->cwd, true, rbuff, sizeof rbuff, "%s", pbuff);
2692             if (rc == 0)
2693             {
2694                 uint32_t type;
2695 
2696                 type = KDirectoryPathType (self->cwd, "%s", rbuff);
2697                 switch (type & ~kptAlias)
2698                 {
2699                 case kptNotFound:
2700                     rc = RC (rcVFS, rcMgr, rcOpening, rcFile, rcNotFound);
2701                     break;
2702 
2703                 case kptFile:
2704                     rc = KDirectoryOpenFileWrite (self->cwd, &file, update, "%s", rbuff);
2705                     break;
2706 
2707                 case kptBadPath:
2708                     rc = RC (rcVFS, rcMgr, rcOpening, rcFile, rcInvalid);
2709                     break;
2710                 case kptDir:
2711                 case kptCharDev:
2712                 case kptBlockDev:
2713                 case kptFIFO:
2714                 case kptZombieFile:
2715                     rc = RC (rcVFS, rcMgr, rcOpening, rcFile, rcIncorrect);
2716                     break;
2717 
2718                 default:
2719                     rc = RC (rcVFS, rcMgr, rcOpening, rcFile, rcUnknown);
2720                     break;
2721                 }
2722             }
2723         }
2724     }
2725     if (rc == 0)
2726     {
2727         size_t z;
2728         char obuff [VFS_KRYPTO_PASSWORD_MAX_SIZE+2];
2729 
2730         if (VPathOption (path, vpopt_encrypted, obuff, sizeof obuff, &z) == 0)
2731         {
2732             rc = GetEncryptionKey(self, path, obuff, sizeof(obuff), &z);
2733             if (rc == 0)
2734             {
2735                 KKey key;
2736                 KFile * encfile;
2737 
2738                 rc = KKeyInitUpdate (&key, kkeyAES128, obuff, z);
2739                 if (rc == 0)
2740                 {
2741                     rc = KEncFileMakeWrite (&encfile, file, &key);
2742                     if (rc == 0)
2743                     {
2744                         KFileRelease (file); /* owned by encfile now */
2745                         *f = encfile;
2746                         return 0;
2747                     }
2748                 }
2749             }
2750             if (rc)
2751                 KFileRelease (file);
2752         }
2753         else
2754         {
2755             *f = file;
2756             return 0;
2757         }
2758     }
2759     return rc;
2760 }
2761 
2762 
2763 /* CreateFile
2764  *  opens a file with write access
2765  *
2766  *  "f" [ OUT ] - return parameter for newly opened file
2767  *
2768  *  "update" [ IN ] - if true, open in read/write mode
2769  *  otherwise, open in write-only mode
2770  *
2771  *  "access" [ IN ] - standard Unix access mode, e.g. 0664
2772  *
2773  *  "mode" [ IN ] - a creation mode ( see explanation above ).
2774  *
2775  *  "path" [ IN ] VPath representing the path, URL or URN of the desired file
2776  */
VFSManagerCreateFile(const VFSManager * self,KFile ** f,bool update,uint32_t access,KCreateMode mode,const VPath * path)2777 LIB_EXPORT rc_t CC VFSManagerCreateFile ( const VFSManager *self, KFile **f,
2778                                           bool update, uint32_t access, KCreateMode mode, const VPath * path )
2779 {
2780     /* -----
2781      * this is a first pass that only opens files directory referenced from
2782      * the ced or have a sysdir root; that is it uses KSysDir and KSysFile
2783      * only.
2784      */
2785     KFile * file = NULL;
2786     size_t num_read;
2787     rc_t rc;
2788     bool file_created = false;
2789     char pbuff [4096];
2790     char rbuff [4096];
2791 
2792     if ((f == NULL) || (path == NULL))
2793         return RC (rcVFS, rcMgr, rcOpening, rcParam, rcNull);
2794 
2795     *f = NULL;
2796 
2797     if (self == NULL)
2798         return RC (rcVFS, rcMgr, rcOpening, rcSelf, rcNull);
2799 
2800     rc = VPathReadPath (path, pbuff, sizeof pbuff, &num_read);
2801     if (rc == 0)
2802     {
2803 
2804         /* handle a few special case path names
2805          * This probably needs to be system specifica eventually
2806          */
2807         if (strncmp ("/dev/", pbuff, sizeof "/dev/" - 1) == 0)
2808         {
2809 
2810             if (strcmp ("/dev/stdout", pbuff) == 0)
2811                 rc = KFileMakeStdOut (&file);
2812             else if (strcmp ("/dev/stderr", pbuff) == 0)
2813                 rc = KFileMakeStdErr (&file);
2814             else if (strcmp ("/dev/null", pbuff) == 0)
2815                 rc = KFileMakeNullUpdate (&file);
2816             else if (strncmp ("/dev/fd/", pbuff, sizeof "/dev/fd/" - 1) == 0)
2817             {
2818                 char * pc;
2819                 size_t ix;
2820 
2821                 pc = pbuff + sizeof "/dev/fd/" - 1;
2822 
2823                 for (ix = 0; isdigit (pc[ix]); ++ix)
2824                     ;
2825 
2826                 if ((ix > 0)&&(pc[ix] == '\0'))
2827                 {
2828                     int fd = atoi (pc);
2829 
2830                     rc = KFileMakeFDFileWrite (&file, update, fd);
2831                 }
2832             }
2833         }
2834         if ((rc == 0)&&(file == NULL))
2835         {
2836             rc = KDirectoryResolvePath (self->cwd, true, rbuff, sizeof rbuff, "%s", pbuff);
2837             if (rc == 0)
2838             {
2839                 uint32_t type;
2840 
2841                 type = KDirectoryPathType (self->cwd, "%s", rbuff);
2842                 switch (type & ~kptAlias)
2843                 {
2844                 case kptNotFound:
2845                 case kptFile:
2846                     rc = KDirectoryCreateFile (self->cwd, &file, update, access, mode,
2847                                                "%s", rbuff);
2848                     if (rc == 0)
2849                         file_created = true;
2850                     break;
2851 
2852                 case kptBadPath:
2853                     rc = RC (rcVFS, rcMgr, rcOpening, rcFile, rcInvalid);
2854                     break;
2855                 case kptDir:
2856                 case kptCharDev:
2857                 case kptBlockDev:
2858                 case kptFIFO:
2859                 case kptZombieFile:
2860                     rc = RC (rcVFS, rcMgr, rcOpening, rcFile, rcIncorrect);
2861                     break;
2862 
2863                 default:
2864                     rc = RC (rcVFS, rcMgr, rcOpening, rcFile, rcUnknown);
2865                     break;
2866                 }
2867             }
2868         }
2869     }
2870     if (rc == 0)
2871     {
2872         size_t z;
2873         char obuff [VFS_KRYPTO_PASSWORD_MAX_SIZE+2];
2874 
2875         if (VPathOption (path, vpopt_encrypted, obuff, sizeof obuff, &z) == 0)
2876         {
2877             rc = GetEncryptionKey(self, path, obuff, sizeof(obuff), &z);
2878             if (rc == 0)
2879             {
2880                 KKey key;
2881                 KFile * encfile;
2882                 rc = KKeyInitUpdate (&key, kkeyAES128, obuff, z);
2883 
2884                 obuff[z] = '\0';
2885 
2886                 rc = KEncFileMakeWrite (&encfile, file, &key);
2887                 if (rc == 0)
2888                 {
2889                     KFileRelease (file); /* now owned by encfile */
2890                     *f = encfile;
2891                     return 0;
2892                 }
2893             }
2894             if (rc)
2895                 KFileRelease (file);
2896         }
2897         else
2898         {
2899             *f = file;
2900             return 0;
2901         }
2902     }
2903     if (rc && file_created)
2904         KDirectoryRemove (self->cwd, true, "%s", rbuff);
2905     return rc;
2906 }
2907 
2908 
2909 /* Remove
2910  *  remove an accessible object from its directory
2911  *
2912  *  "force" [ IN ] - if true and target is a directory,
2913  *  remove recursively
2914  *
2915  *  "path" [ IN ] - NUL terminated string in directory-native
2916  *  character set denoting target object
2917  */
VFSManagerRemove(const VFSManager * self,bool force,const VPath * path)2918 LIB_EXPORT rc_t CC VFSManagerRemove ( const VFSManager *self, bool force,
2919                                       const VPath * path )
2920 {
2921     /* -----
2922      * this is a first pass that only opens files directory referenced from
2923      * the ced or have a sysdir root; that is it uses KSysDir and KSysFile
2924      * only.
2925      */
2926     size_t num_read;
2927     char pbuff [4096];
2928     rc_t rc;
2929 
2930     if (path == NULL)
2931         return RC (rcVFS, rcMgr, rcOpening, rcParam, rcNull);
2932 
2933     if (self == NULL)
2934         return RC (rcVFS, rcMgr, rcOpening, rcSelf, rcNull);
2935 
2936     rc = VPathReadPath (path, pbuff, sizeof pbuff, &num_read);
2937     if (rc == 0)
2938     {
2939         char rbuff [4096];
2940 
2941         rc = KDirectoryResolvePath (self->cwd, true, rbuff, sizeof rbuff, "%s", pbuff);
2942         if (rc == 0)
2943         {
2944             uint32_t type;
2945 
2946             type = KDirectoryPathType (self->cwd, "%s", rbuff);
2947             switch (type & ~kptAlias)
2948             {
2949             case kptNotFound:
2950                 break;
2951 
2952             case kptFile:
2953             case kptDir:
2954             case kptCharDev:
2955             case kptBlockDev:
2956             case kptFIFO:
2957             case kptZombieFile:
2958                 rc = KDirectoryRemove (self->cwd, force, "%s", rbuff);
2959                 break;
2960 
2961             case kptBadPath:
2962                 rc = RC (rcVFS, rcMgr, rcOpening, rcFile, rcInvalid);
2963                 break;
2964 /*                 rc = RC (rcVFS, rcMgr, rcOpening, rcFile, rcIncorrect); */
2965 /*                 break; */
2966 
2967             default:
2968                 rc = RC (rcVFS, rcMgr, rcOpening, rcFile, rcUnknown);
2969                 break;
2970             }
2971         }
2972     }
2973     return rc;
2974 }
2975 
2976 /* RemoteProtocols
2977  */
VRemoteProtocolsParse(const String * protos)2978 LIB_EXPORT VRemoteProtocols CC  VRemoteProtocolsParse ( const String * protos )
2979 {
2980     VRemoteProtocols parsed_protos = 0;
2981 
2982     bool have_proto [ eProtocolMask + 1 ];
2983 
2984     size_t i, end;
2985     const char * start;
2986     String http, https, fasp;
2987 
2988     CONST_STRING ( & http,  "http"  );
2989     CONST_STRING ( & https, "https" );
2990     CONST_STRING ( & fasp,  "fasp"  );
2991 
2992     end = protos -> size;
2993     start = protos -> addr;
2994 
2995     memset ( have_proto, 0, sizeof have_proto );
2996 
2997     for ( i = end; i > 0; )
2998     {
2999         -- i;
3000         if ( i == 0 || start [ i ] == ',' )
3001         {
3002             VRemoteProtocols parsed_proto = 0;
3003 
3004             /* beginning of protocol string is either 0 or 1 past the comma */
3005             size_t begin = ( i == 0 ) ? 0 : i + 1;
3006 
3007             /* capture single protocol string */
3008             String proto;
3009             StringInit ( & proto, & start [ begin ], end - begin, string_len ( & start [ begin ], end - begin ) );
3010 
3011             /* trim white space */
3012             StringTrim ( & proto, & proto );
3013 
3014             /* compare against known protocols */
3015             if ( StringCaseEqual ( & http, & proto ) )
3016                 parsed_proto = eProtocolHttp;
3017             else if ( StringCaseEqual ( & https, & proto ) )
3018                 parsed_proto = eProtocolHttps;
3019             else if ( StringCaseEqual ( & fasp, & proto ) )
3020                 parsed_proto = eProtocolFasp;
3021 
3022             if ( parsed_proto != eProtocolNone && ! have_proto [ parsed_proto ] )
3023             {
3024                 parsed_protos <<= 3;
3025                 parsed_protos |= parsed_proto;
3026                 have_proto [ parsed_proto ] = true;
3027             }
3028 
3029             end = i;
3030         }
3031     }
3032 
3033     return parsed_protos;
3034 }
3035 
KConfigReadRemoteProtocols(const KConfig * self,VRemoteProtocols * remote_protos)3036 void KConfigReadRemoteProtocols ( const KConfig * self, VRemoteProtocols * remote_protos )
3037 {
3038     String * protos;
3039     rc_t rc = KConfigReadString ( self, "/name-resolver/remote-protocols", & protos );
3040     if ( rc == 0 )
3041     {
3042         VRemoteProtocols parsed_protos = VRemoteProtocolsParse ( protos );
3043         if ( parsed_protos != 0 )
3044             * remote_protos = parsed_protos;
3045 
3046         StringWhack ( protos );
3047     }
3048 }
3049 
VFSManagerLoadLogNamesServiceErrors(VFSManager * self)3050 static void VFSManagerLoadLogNamesServiceErrors(VFSManager * self) {
3051     rc_t rc = 0;
3052 
3053     bool enabled = true;
3054 
3055     assert(self);
3056 /* KConfigPrint(self->cfg,0); */
3057     rc = KConfigReadBool(self->cfg, "/name-resolver/log-names-service-errors",
3058         &enabled);
3059     if (rc == 0)
3060         LogNamesServiceErrorsInit(enabled);
3061 }
3062 
3063 /* Make
3064  */
VFSManagerMake(VFSManager ** pmanager)3065 LIB_EXPORT rc_t CC VFSManagerMake ( VFSManager ** pmanager )
3066 {
3067     return VFSManagerMakeFromKfg(pmanager, NULL);
3068 }
3069 
3070 /* Make
3071  */
VFSManagerMakeFromKfgImpl(struct VFSManager ** pmanager,struct KConfig * cfg,KNSManager * kmgr,bool local)3072 static rc_t CC VFSManagerMakeFromKfgImpl ( struct VFSManager ** pmanager,
3073     struct KConfig * cfg, KNSManager * kmgr, bool local )
3074 {
3075     rc_t rc;
3076 
3077     if (pmanager == NULL)
3078         return RC (rcVFS, rcMgr, rcConstructing, rcParam, rcNull);
3079 
3080     *pmanager = NULL;
3081     if (!local)
3082         *pmanager = singleton;
3083     if ( *pmanager != NULL )
3084     {
3085         rc = VFSManagerAddRef ( singleton );
3086         if ( rc != 0 )
3087             *pmanager = NULL;
3088     }
3089     else
3090     {
3091         VFSManager * obj;
3092 
3093         obj = calloc (1, sizeof (*obj));
3094         if (obj == NULL)
3095             rc = RC (rcVFS, rcMgr, rcConstructing, rcMemory, rcExhausted);
3096         else
3097         {
3098             KRefcountInit (& obj -> refcount, 1,
3099                 kfsmanager_classname, "init", "singleton" );
3100 
3101             /* hard-coded default */
3102             obj -> protocols = DEFAULT_PROTOCOLS;
3103 
3104             rc = KDirectoryNativeDir ( & obj -> cwd );
3105             if ( rc == 0 )
3106             {
3107                 if (cfg == NULL)
3108                     rc = KConfigMake ( & obj -> cfg, NULL );
3109                 else
3110                 {
3111                     rc = KConfigAddRef ( cfg );
3112                     if (rc == 0)
3113                         obj -> cfg = cfg;
3114                 }
3115                 if ( rc == 0 )
3116                 {
3117                     /* look for remote protocols in configuration */
3118                     KConfigReadRemoteProtocols ( obj -> cfg, & obj -> protocols );
3119 
3120                     rc = KCipherManagerMake ( & obj -> cipher );
3121                     if ( rc == 0 )
3122                     {
3123                         rc = KKeyStoreMake ( & obj -> keystore, obj -> cfg );
3124                         if ( rc == 0 )
3125                         {
3126                             if (kmgr != NULL) {
3127                                 rc = KNSManagerAddRef(kmgr);
3128                                 if (rc == 0)
3129                                     obj->kns = kmgr;
3130                             }
3131                             else if (local)
3132                                 rc = KNSManagerMakeLocal ( & obj -> kns, cfg );
3133                             else
3134                                 rc = KNSManagerMakeWithConfig
3135                                                          ( & obj -> kns, cfg );
3136                             if ( rc != 0 )
3137                             {
3138                                 LOGERR ( klogWarn, rc, "could not build network manager" );
3139                                 rc = 0;
3140                             }
3141 
3142                             rc = VFSManagerMakeResolver ( obj, & obj -> resolver, obj -> cfg );
3143                             if ( rc != 0 )
3144                             {
3145                                 LOGERR ( klogWarn, rc, "could not build vfs-resolver" );
3146                                 rc = 0;
3147                             }
3148 
3149                             VFSManagerLoadLogNamesServiceErrors(obj);
3150 
3151                             *pmanager = obj;
3152                             if (!local)
3153                                 singleton = obj;
3154                             DBGMSG(DBG_KNS, DBG_FLAG(DBG_KNS_MGR),  ("%s(%p)\n", __func__, cfg));
3155                             return 0;
3156                         }
3157                     }
3158                 }
3159             }
3160         }
3161 
3162         VFSManagerDestroy (obj);
3163     }
3164     return rc;
3165 }
3166 
VFSManagerMakeFromKfg(struct VFSManager ** pmanager,struct KConfig * cfg)3167 LIB_EXPORT rc_t CC VFSManagerMakeFromKfg ( struct VFSManager ** pmanager,
3168     struct KConfig * cfg)
3169 {
3170     return VFSManagerMakeFromKfgImpl(pmanager, cfg, NULL, false);
3171 }
3172 
VFSManagerMakeFromKns(struct VFSManager ** pmanager,struct KConfig * cfg,KNSManager * kns)3173 LIB_EXPORT rc_t CC VFSManagerMakeFromKns(struct VFSManager ** pmanager,
3174     struct KConfig * cfg, KNSManager * kns)
3175 {
3176     return VFSManagerMakeFromKfgImpl(pmanager, cfg, kns, false);
3177 }
3178 
VFSManagerMakeLocal(struct VFSManager ** pmanager,struct KConfig * cfg)3179 LIB_EXPORT rc_t CC VFSManagerMakeLocal ( struct VFSManager ** pmanager,
3180     struct KConfig * cfg)
3181 {
3182     return VFSManagerMakeFromKfgImpl(pmanager, cfg, NULL, true);
3183 }
3184 
VFSManagerGetCWD(const VFSManager * self,KDirectory ** cwd)3185 LIB_EXPORT rc_t CC VFSManagerGetCWD (const VFSManager * self, KDirectory ** cwd)
3186 {
3187     rc_t rc;
3188 
3189     if ( cwd == NULL )
3190         rc = RC (rcVFS, rcMgr, rcAccessing, rcParam, rcNull);
3191     else
3192     {
3193         if ( self == NULL )
3194             rc = RC (rcVFS, rcMgr, rcAccessing, rcSelf, rcNull);
3195         else
3196         {
3197             rc = KDirectoryAddRef ( self -> cwd );
3198             if ( rc == 0 )
3199             {
3200                 * cwd = self -> cwd;
3201                 return 0;
3202             }
3203         }
3204 
3205         * cwd = NULL;
3206     }
3207 
3208     return rc;
3209 }
3210 
3211 
VFSManagerGetResolver(const VFSManager * self,struct VResolver ** resolver)3212 LIB_EXPORT rc_t CC VFSManagerGetResolver ( const VFSManager * self, struct VResolver ** resolver )
3213 {
3214     rc_t rc;
3215 
3216     if ( resolver == NULL )
3217         rc = RC (rcVFS, rcMgr, rcAccessing, rcParam, rcNull);
3218     else
3219     {
3220         if ( self == NULL )
3221             rc = RC (rcVFS, rcMgr, rcAccessing, rcSelf, rcNull);
3222         else if ( self -> resolver == NULL )
3223             rc = RC ( rcVFS, rcMgr, rcAccessing, rcResolver, rcNull );
3224         else
3225         {
3226             rc = VResolverAddRef ( self -> resolver );
3227             if ( rc == 0 )
3228             {
3229                 * resolver = self -> resolver;
3230                 return 0;
3231             }
3232         }
3233 
3234         * resolver = NULL;
3235     }
3236 
3237     return rc;
3238 }
3239 
3240 
VFSManagerSetResolver(VFSManager * self,VResolver * resolver)3241 LIB_EXPORT rc_t CC VFSManagerSetResolver ( VFSManager * self, VResolver * resolver )
3242 {
3243     rc_t rc = 0;
3244 
3245     if ( self == NULL )
3246         rc = RC (rcVFS, rcMgr, rcUpdating, rcSelf, rcNull);
3247     else if ( resolver == NULL )
3248         rc = RC (rcVFS, rcMgr, rcUpdating, rcParam, rcNull);
3249     else if (self -> resolver != resolver ) {
3250         rc = VResolverAddRef ( resolver );
3251         if (rc == 0) {
3252             rc = VResolverRelease ( self -> resolver );
3253             if (rc == 0) {
3254                 self -> resolver = resolver;
3255                 return 0;
3256             }
3257         }
3258         VResolverRelease ( resolver );
3259     }
3260 
3261     return rc;
3262 }
3263 
3264 
VFSManagerGetKNSMgr(const VFSManager * self,struct KNSManager ** kns)3265 LIB_EXPORT rc_t CC VFSManagerGetKNSMgr ( const VFSManager * self, struct KNSManager ** kns )
3266 {
3267     rc_t rc;
3268 
3269     if ( kns == NULL )
3270         rc = RC (rcVFS, rcMgr, rcAccessing, rcParam, rcNull);
3271     else
3272     {
3273         if ( self == NULL )
3274             rc = RC (rcVFS, rcMgr, rcAccessing, rcSelf, rcNull);
3275         else
3276         {
3277             rc = KNSManagerAddRef ( self -> kns );
3278             if ( rc == 0 )
3279             {
3280                 * kns = self -> kns;
3281                 return 0;
3282             }
3283         }
3284 
3285         * kns = NULL;
3286     }
3287 
3288     return rc;
3289 }
3290 
3291 
VFSManagerGetKryptoPassword(const VFSManager * self,char * password,size_t max_size,size_t * size)3292 LIB_EXPORT rc_t CC VFSManagerGetKryptoPassword (const VFSManager * self,
3293                                                 char * password,
3294                                                 size_t max_size,
3295                                                 size_t * size)
3296 {
3297     rc_t rc;
3298 
3299     if (self == NULL)
3300         rc = RC (rcVFS, rcMgr, rcAccessing, rcSelf, rcNull);
3301 
3302     else if ((password == NULL) || (max_size == 0) || (size == NULL))
3303         rc = RC (rcVFS, rcMgr, rcAccessing, rcParam, rcNull);
3304 
3305     else
3306     {
3307         size_t z;
3308         char obuff [4096 + 16];
3309         bool pwdItself = false;
3310 
3311         rc = VFSManagerGetConfigPWFile(self, obuff, sizeof obuff, &z,
3312             &pwdItself);
3313         if (rc == 0)
3314         {
3315           if (pwdItself)
3316               *size = string_copy(password, max_size, obuff, z);
3317           else {
3318             VPath * vpath;
3319             rc_t rc2;
3320             rc = VPathMake (&vpath, obuff);
3321             if (rc == 0)
3322                 rc = GetEncryptionKey(self, vpath, password, max_size, size);
3323             rc2 = VPathRelease (vpath);
3324             if (rc == 0)
3325                 rc = rc2;
3326           }
3327         }
3328     }
3329     return rc;
3330 }
3331 
3332 /* N.B. This finction might fail if password is stored in configuration,
3333 	not file (pwdItself == true after ) VFSManagerGetConfigPWFile */
VFSManagerUpdateKryptoPassword(const VFSManager * self,const char * password,size_t size,char * pwd_dir,size_t pwd_dir_size)3334 LIB_EXPORT rc_t CC VFSManagerUpdateKryptoPassword (const VFSManager * self,
3335                                                    const char * password,
3336                                                    size_t size,
3337                                                    char * pwd_dir,
3338                                                    size_t pwd_dir_size)
3339 {
3340     static const char temp_extension [] = ".tmp";
3341     rc_t rc;
3342 
3343     if (self == NULL)
3344         rc = RC (rcVFS, rcEncryptionKey, rcUpdating, rcSelf, rcNull);
3345 
3346     else if ((password == NULL) || (size == 0))
3347         rc = RC (rcVFS, rcEncryptionKey, rcUpdating, rcParam, rcNull);
3348 
3349     else if (size > VFS_KRYPTO_PASSWORD_MAX_SIZE)
3350         rc = RC (rcVFS, rcEncryptionKey, rcUpdating, rcSize, rcExcessive);
3351 
3352     else if ((string_chr (password, size, '\n') != NULL) ||
3353              (string_chr (password, size, '\r') != NULL))
3354         rc = RC (rcVFS, rcEncryptionKey, rcUpdating, rcEncryptionKey, rcInvalid);
3355 
3356     else
3357     {
3358         size_t old_password_file_size;
3359         char old_password_file [8193];
3360         bool pwdItself = false;
3361 
3362         rc = VFSManagerGetConfigPWFile (self, old_password_file,
3363                                         sizeof old_password_file - 1,
3364                                         &old_password_file_size, &pwdItself);
3365         if (rc) {
3366             if (rc ==
3367                 SILENT_RC(rcKrypto, rcMgr, rcReading, rcBuffer, rcInsufficient))
3368             {
3369                 rc =
3370                     RC(rcVFS, rcEncryptionKey, rcUpdating, rcPath, rcExcessive);
3371             }
3372             LOGERR (klogErr, rc, "failed to obtain configured path for password file");
3373         }
3374 
3375         else if (old_password_file_size >= (sizeof old_password_file - 1))
3376         {
3377             rc = RC (rcVFS, rcEncryptionKey, rcUpdating, rcPath, rcExcessive);
3378             PLOGERR (klogErr,
3379                      (klogErr, rc, "configured path too long for function "
3380                       "'$(P)' '${F}'", "P=%s,F=%s",
3381                       old_password_file, __func__));
3382         }
3383         else
3384         {
3385             KPathType ftype;
3386             bool old_exists;
3387 
3388             old_password_file[old_password_file_size] = '\0';
3389             ftype = KDirectoryPathType (self->cwd, "%s", old_password_file);
3390 
3391             switch (ftype)
3392             {
3393             case kptNotFound:
3394                 old_exists = false;
3395                 break;
3396 
3397             case kptBadPath:
3398                 rc = RC (rcVFS, rcEncryptionKey, rcUpdating, rcPath, rcInvalid);
3399                 break;
3400 
3401             case kptFile:
3402                 old_exists = true;
3403                 break;
3404 
3405             case kptDir:
3406             case kptCharDev:
3407             case kptBlockDev:
3408             case kptFIFO:
3409             case kptZombieFile:
3410             case kptDataset:
3411             case kptDatatype:
3412                 rc = RC (rcVFS, rcEncryptionKey, rcUpdating, rcPath, rcIncorrect);
3413                 break;
3414 
3415             default:
3416                 rc = RC (rcVFS, rcEncryptionKey, rcUpdating, rcPath, rcCorrupt);
3417                 break;
3418             }
3419 
3420             if (rc)
3421                 PLOGERR (klogErr,
3422                          (klogErr, rc, "cannot use configured path for "
3423                           "password file '$(P)'", "P=%s", old_password_file));
3424 
3425             else
3426             {
3427                 VPath * vold;
3428                 /* size_t new_password_file_size; */
3429                 char new_password_file [sizeof old_password_file + sizeof temp_extension];
3430                 size_t password_dir_size;
3431                 char password_dir [sizeof old_password_file];
3432 /*                 bool save_old_password; */
3433                 char * pc;
3434 
3435                 memmove (password_dir, old_password_file, old_password_file_size);
3436                 memmove (new_password_file, old_password_file, old_password_file_size);
3437                 memmove (new_password_file + old_password_file_size, temp_extension, sizeof temp_extension);
3438                 /* new_password_file_size = old_password_file_size + sizeof temp_extension - 1; */
3439 
3440                 pc = string_rchr (password_dir, old_password_file_size, '/');
3441                 if (pc == NULL)
3442                 {
3443                     password_dir[0] = '.';
3444                     pc = password_dir+1;
3445                 }
3446                 *pc = '\0';
3447                 password_dir_size = pc - password_dir;
3448 
3449                 if (pwd_dir && pwd_dir_size) {
3450                     size_t n = string_copy(pwd_dir, pwd_dir_size,
3451                                            password_dir, password_dir_size + 1);
3452                     if (n >= pwd_dir_size) {
3453                         int i = 0;
3454                         size_t p = pwd_dir_size - 1;
3455                         pwd_dir[p] = '\0';
3456                         for (i = 0; i < 3; ++i) {
3457                             if (p == 0)
3458                             {   break; }
3459                             pwd_dir[--p] = '.';
3460                         }
3461                         if (p != 0)
3462                         {   pwd_dir[--p] = ' '; }
3463                     }
3464                 }
3465 
3466                 rc = VPathMake (&vold, old_password_file);
3467                 if (rc)
3468                     PLOGERR (klogErr,
3469                              (klogErr, rc, "could not create vpath for "
3470                               "password file '$(P)'", "P=%s",
3471                               old_password_file));
3472 
3473                 else
3474                 {
3475                     VPath * vnew;
3476 
3477                     rc = VPathMake (&vnew, new_password_file);
3478                     if (rc)
3479                         PLOGERR (klogErr,
3480                                  (klogErr, rc, "could not create vpath for "
3481                                   "password file '$(P)'", "P=%s",
3482                                   new_password_file));
3483 
3484                     else
3485                     {
3486                         const KFile * fold = NULL;
3487                         KFile * fnew = NULL;
3488 
3489                         if (old_exists)
3490                         {
3491                             rc = VFSManagerOpenFileRead ( self, &fold, vold );
3492 
3493                             if (rc)
3494                                 PLOGERR (klogErr,
3495                                          (klogErr, rc, "unable to open existing "
3496                                           "password file '$(P)'", "P=%s",
3497                                           old_password_file));
3498                         }
3499 
3500 
3501                         if (rc == 0)
3502                         {
3503                             rc = VFSManagerCreateFile (self, &fnew, false, 0600,
3504                                                        kcmInit|kcmParents,
3505                                                        vnew);
3506                             if (rc)
3507                                 PLOGERR (klogErr,
3508                                          (klogErr, rc, "unable to open temporary "
3509                                           "password file '$(P)'", "P=%s",
3510                                           new_password_file));
3511 
3512                             else
3513                             {
3514                                 uint64_t writ;
3515                                 size_t this_writ;
3516 
3517                                 rc = KFileWriteAll (fnew, 0, password, size, &this_writ);
3518                                 if (rc)
3519                                     PLOGERR (klogErr,
3520                                              (klogErr, rc, "unable to write "
3521                                               "password to temporary password "
3522                                               "file '$(P)'", "P=%s",
3523                                               new_password_file));
3524 
3525                                 else if (this_writ != size)
3526                                 {
3527                                     rc = RC (rcVFS, rcEncryptionKey, rcWriting,
3528                                              rcFile, rcInsufficient);
3529                                     PLOGERR (klogErr,
3530                                              (klogErr, rc, "unable to write complete "
3531                                               "password to temporary password "
3532                                               "file '$(P)'", "P=%s",
3533                                               new_password_file));
3534                                 }
3535 
3536                                 else
3537                                 {
3538                                     writ = this_writ;
3539 
3540                                     rc = KFileWriteAll (fnew, this_writ, "\n", 1, &this_writ);
3541                                     if (rc)
3542                                         PLOGERR (klogErr,
3543                                                  (klogErr, rc, "unable to write "
3544                                                   "password to temporary password "
3545                                                   "file '$(P)'", "P=%s",
3546                                                   new_password_file));
3547 
3548                                     else if (this_writ != 1)
3549                                     {
3550                                         rc = RC (rcVFS, rcEncryptionKey, rcWriting,
3551                                                  rcFile, rcInsufficient);
3552                                         PLOGERR (klogErr,
3553                                                  (klogErr, rc, "unable to write complete "
3554                                                   "password to temporary password "
3555                                                   "file '$(P)'", "P=%s",
3556                                                   new_password_file));
3557                                     }
3558 
3559                                     else
3560                                     {
3561                                         bool do_rename;
3562 
3563                                         do_rename = true;
3564                                         ++writ;
3565 
3566                                         if (old_exists)
3567                                         {
3568                                             size_t read;
3569                                             size_t this_read;
3570                                             char buffer [VFS_KRYPTO_PASSWORD_MAX_SIZE+4];
3571 
3572                                             rc = KFileReadAll (fold, 0, buffer,
3573                                                                sizeof buffer, &this_read);
3574                                             if (rc)
3575                                                 ;
3576 
3577                                             else
3578                                             {
3579                                                 read = this_read;
3580                                                 /* look for duplicated password */
3581                                                 if (read > size)
3582                                                 {
3583                                                     char cc;
3584 
3585                                                     cc = buffer[size];
3586                                                     if (((cc == '\n') || (cc == '\r')) &&
3587                                                         (memcmp (buffer, password, size) == 0))
3588                                                     {
3589                                                         do_rename = false;
3590                                                     }
3591                                                 }
3592                                                 if (read)
3593                                                     rc = KFileWriteAll (fnew, writ, buffer, read, &this_writ);
3594 
3595                                                 if (rc)
3596                                                     ;
3597                                                 else if (do_rename)
3598                                                 {
3599                                                     writ += this_writ;
3600 
3601                                                     do
3602                                                     {
3603                                                         rc = KFileReadAll (fold, read, buffer,
3604                                                                            sizeof buffer, &this_read);
3605                                                         if (rc)
3606                                                             ;
3607 
3608                                                         else if (this_read == 0)
3609                                                             break;
3610 
3611                                                         else
3612                                                         {
3613                                                             rc = KFileWriteAll (fnew, writ, buffer,
3614                                                                                 this_read, &this_writ);
3615                                                             if (rc)
3616                                                                 ;
3617 
3618                                                             else if (this_read != this_writ)
3619                                                             {
3620                                                                 rc = RC (rcVFS, rcEncryptionKey, rcWriting,
3621                                                                          rcFile, rcInsufficient);
3622                                                                 PLOGERR (klogErr,
3623                                                                          (klogErr, rc,
3624                                                                           "unable to write complete "
3625                                                                           "password to temporary password "
3626                                                                           "file '$(P)'", "P=%s",
3627                                                                           new_password_file));
3628                                                             }
3629 
3630                                                             else
3631                                                             {
3632                                                                 read += this_read;
3633                                                                 writ += this_writ;
3634                                                             }
3635                                                         }
3636                                                     } while (rc == 0);
3637                                                 }
3638                                             }
3639                                             KFileRelease (fold);
3640                                             fold = NULL;
3641                                         }
3642 
3643                                         KFileRelease (fnew);
3644                                         fnew = NULL;
3645 
3646                                         if (rc == 0)
3647                                         {
3648                                             if (do_rename)
3649                                             {
3650                                                 rc = KDirectoryRename (self->cwd, true,
3651                                                                        new_password_file,
3652                                                                        old_password_file);
3653                                             }
3654                                             else
3655                                             {
3656                                                 KDirectoryRemove (self->cwd, true, "%s", new_password_file);
3657                                             }
3658 
3659 #if !WINDOWS
3660                                             if (rc == 0)
3661                                             {
3662                                                 uint32_t access;
3663 
3664                                                 rc = KDirectoryAccess (self->cwd,
3665                                                                        &access, "%s", password_dir);
3666                                                 if (rc)
3667                                                     ;
3668 
3669                                                 else
3670                                                 {
3671                                                     if (access & 0027)
3672                                                         rc = RC (rcVFS, rcEncryptionKey, rcUpdating, rcDirectory, rcExcessive);
3673                                                 }
3674                                             }
3675 #endif
3676                                         }
3677                                     }
3678                                 }
3679                                 KFileRelease (fnew);
3680                             }
3681                             KFileRelease (fold);
3682                         }
3683                         VPathRelease (vold);
3684                     }
3685                     VPathRelease (vnew);
3686                 }
3687             }
3688         }
3689     }
3690     return rc;
3691 }
3692 
3693 /*--------------------------------------------------------------------------
3694  * KConfig
3695  *  placing some KConfig code that relies upon VFS here
3696  */
3697 
3698 
3699 /* ReadVPath
3700  *  read a VPath node value
3701  *
3702  * self [ IN ] - KConfig object
3703  * path [ IN ] - path to the node
3704  * result [ OUT ] - return value (rc != 0 if cannot be converted)
3705  *
3706  */
KConfigReadVPath(struct KConfig const * self,const char * path,struct VPath ** result)3707 LIB_EXPORT rc_t CC KConfigReadVPath ( struct KConfig const* self, const char* path, struct VPath** result )
3708 {
3709     rc_t rc;
3710 
3711     if ( result == NULL )
3712         rc = RC ( rcKFG, rcNode, rcReading, rcParam, rcNull );
3713     else
3714     {
3715         struct KConfigNode const *n;
3716         rc = KConfigOpenNodeRead ( self, & n, "%s", path );
3717         if ( rc == 0 )
3718         {
3719             rc = KConfigNodeReadVPath ( n, result );
3720             KConfigNodeRelease ( n );
3721             return rc;
3722         }
3723 
3724         * result = NULL;
3725     }
3726 
3727     return rc;
3728 }
3729 
3730 /* ReadVPath
3731  *  read a VPath node value
3732  *
3733  * self [ IN ] - KConfigNode object
3734  * result [ OUT ] - return value (rc != 0 if cannot be converted)
3735  *
3736  */
KConfigNodeReadVPath(struct KConfigNode const * self,struct VPath ** result)3737 LIB_EXPORT rc_t CC KConfigNodeReadVPath ( struct KConfigNode const *self, struct VPath** result )
3738 {
3739     rc_t rc;
3740 
3741     if ( result == NULL )
3742         rc = RC ( rcKFG, rcNode, rcReading, rcParam, rcNull );
3743     else
3744     {
3745         char buffer [ 4096 ];
3746         size_t num_read, to_read;
3747         rc = KConfigNodeRead ( self, 0, buffer, sizeof buffer, & num_read, & to_read );
3748         if ( rc == 0 )
3749         {
3750             char *p;
3751 
3752             if ( to_read == 0 && num_read < sizeof buffer )
3753             {
3754                 buffer [ num_read ] = 0;
3755                 return VPathMake ( result, buffer );
3756             }
3757 
3758             p = malloc ( num_read + to_read + 1 );
3759             if ( p == NULL )
3760                 rc = RC ( rcKFG, rcNode, rcReading, rcMemory, rcExhausted );
3761             else
3762             {
3763                 rc = KConfigNodeRead ( self, 0, p, num_read + to_read + 1, & num_read, & to_read );
3764                 if ( rc == 0 )
3765                 {
3766                     p [ num_read ] = 0;
3767                     rc = VPathMake ( result, p );
3768                 }
3769 
3770                 free ( p );
3771                 return rc;
3772             }
3773         }
3774 
3775         * result = NULL;
3776     }
3777 
3778     return rc;
3779 }
3780 
3781 
VFSManagerResolveAcc(const VFSManager * self,const struct VPath * source,struct VPath ** path_to_build,const struct KFile ** remote_file,const struct VPath ** local_cache)3782 static rc_t VFSManagerResolveAcc( const VFSManager * self,
3783                                   const struct VPath * source,
3784                                   struct VPath ** path_to_build,
3785                                   const struct KFile ** remote_file,
3786                                   const struct VPath ** local_cache )
3787 {
3788     rc_t rc;
3789     const VPath * local, * remote;
3790 
3791     assert (self);
3792     assert (source);
3793     assert (path_to_build);
3794     assert (remote_file);
3795     assert (local_cache);
3796 
3797 #if 1
3798     rc = VResolverQuery ( self -> resolver, self -> protocols, source, & local, & remote, local_cache );
3799     if ( rc == 0 )
3800     {
3801         assert ( local != NULL || remote != NULL );
3802         assert ( local == NULL || remote == NULL );
3803         * path_to_build = ( VPath* ) ( ( local != NULL ) ? local : remote );
3804     }
3805 #else
3806 
3807     /* first try to find it localy */
3808     rc = VResolverLocal ( self->resolver, source, (const VPath **)path_to_build );
3809     if ( GetRCState( rc ) == rcNotFound )
3810     {
3811         /* if not found localy, try to find it remotely */
3812         rc = VResolverRemote ( self->resolver, self -> protocols,
3813             source, (const VPath **)path_to_build, remote_file );
3814         if ( rc == 0 && remote_file != NULL && local_cache != NULL )
3815         {
3816             /* if found and the caller wants to know the location of a local cache file... */
3817             uint64_t size_of_remote_file = 0;
3818             if ( *remote_file != NULL )
3819                 rc = KFileSize ( *remote_file, &size_of_remote_file );
3820             if ( rc ==  0 )
3821                 rc = VResolverCache ( self->resolver, *path_to_build, local_cache, size_of_remote_file );
3822         }
3823     }
3824 
3825 #endif
3826     return rc;
3827 }
3828 
3829 
VFSManagerResolveLocal(const VFSManager * self,const char * local_path,struct VPath ** path_to_build)3830 static rc_t VFSManagerResolveLocal( const VFSManager * self,
3831                                     const char * local_path,
3832                                     struct VPath ** path_to_build )
3833 {
3834     assert ( self != NULL );
3835     assert ( local_path != NULL && local_path [ 0 ] != 0 );
3836     assert ( path_to_build != NULL );
3837 
3838     return VFSManagerMakePath ( self, path_to_build, "ncbi-file:%s", local_path );
3839 }
3840 
VFSManagerResolvePathOrAcc(const VFSManager * self,const struct VPath * source,struct VPath ** path_to_build,const struct KFile ** remote_file,const struct VPath ** local_cache,bool resolve_acc)3841 static rc_t VFSManagerResolvePathOrAcc( const VFSManager * self,
3842                                         const struct VPath * source,
3843                                         struct VPath ** path_to_build,
3844                                         const struct KFile ** remote_file,
3845                                         const struct VPath ** local_cache,
3846                                         bool resolve_acc )
3847 {
3848     char buffer[ 4096 ];
3849     size_t num_read;
3850     rc_t rc = VPathReadPath ( source, buffer, sizeof buffer, &num_read );
3851     if ( rc == 0 && num_read > 0 )
3852     {
3853         char * pos_of_slash = string_chr ( buffer, string_size( buffer ), '/' );
3854         if ( pos_of_slash != NULL )
3855         {
3856             /* we can now assume that the source is a filesystem-path :
3857                we build a new VPath and prepend with 'ncbi-file:' */
3858             rc = VFSManagerResolveLocal( self, buffer, path_to_build );
3859         }
3860         else if ( resolve_acc )
3861         {
3862             /* we assume the source is an accession! */
3863             rc = VFSManagerResolveAcc( self, source, path_to_build, remote_file, local_cache );
3864             if ( GetRCState( rc ) == rcNotFound )
3865             {
3866                 /* if we were not able to find the source as accession, we assume it is a local path */
3867                 rc = VFSManagerResolveLocal( self, buffer, path_to_build );
3868             }
3869         }
3870         else
3871         {
3872             rc = RC ( rcVFS, rcMgr, rcAccessing, rcParam, rcInvalid );
3873         }
3874     }
3875     return rc;
3876 }
3877 
3878 
VFSManagerResolveRemote(const VFSManager * self,struct VPath ** source,struct VPath ** path_to_build,const struct KFile ** remote_file,const struct VPath ** local_cache)3879 static rc_t VFSManagerResolveRemote( const VFSManager * self,
3880                                      struct VPath ** source,
3881                                      struct VPath ** path_to_build,
3882                                      const struct KFile ** remote_file,
3883                                      const struct VPath ** local_cache )
3884 {
3885     rc_t rc = 0;
3886     *path_to_build = *source;
3887     if ( local_cache != NULL && remote_file != NULL && self->resolver != NULL )
3888     {
3889 
3890 /*        VFS_EXTERN rc_t CC VPathMakeString ( const VPath * self, const String ** uri ); */
3891         char full_url[ 4096 ];
3892         size_t num_read;
3893         rc = VPathReadPath ( *source, full_url, sizeof full_url, &num_read );
3894         if ( rc == 0 && num_read > 0 )
3895         {
3896             rc = KNSManagerMakeHttpFile ( self -> kns, remote_file, NULL, 0x01010000, full_url );
3897             if ( rc == 0 )
3898             {
3899                 uint64_t size_of_remote_file = 0;
3900                 rc = KFileSize ( *remote_file, &size_of_remote_file );
3901                 if ( rc == 0 )
3902                     rc = VResolverCache ( self->resolver, *source, local_cache, size_of_remote_file );
3903             }
3904         }
3905     }
3906     *source = NULL;
3907     return rc;
3908 }
3909 
3910 /* DEPRECATED */
VFSManagerResolveSpec(const VFSManager * self,const char * spec,struct VPath ** path_to_build,const struct KFile ** remote_file,const struct VPath ** local_cache,bool resolve_acc)3911 LIB_EXPORT rc_t CC VFSManagerResolveSpec ( const VFSManager * self,
3912                                            const char * spec,
3913                                            struct VPath ** path_to_build,
3914                                            const struct KFile ** remote_file,
3915                                            const struct VPath ** local_cache,
3916                                            bool resolve_acc )
3917 {
3918     rc_t rc = 0;
3919     if ( self == NULL )
3920         rc = RC ( rcVFS, rcMgr, rcAccessing, rcSelf, rcNull );
3921     else if ( spec == NULL || path_to_build == NULL )
3922         rc = RC ( rcVFS, rcMgr, rcAccessing, rcParam, rcNull );
3923     else if ( spec[ 0 ] == 0 )
3924         rc = RC ( rcVFS, rcMgr, rcAccessing, rcParam, rcEmpty );
3925     else
3926     {
3927         VPath * temp;
3928         *path_to_build = NULL;
3929         if ( local_cache != NULL )
3930             *local_cache = NULL;
3931         if ( remote_file != NULL )
3932             *remote_file = NULL;
3933         rc = VPathMake ( &temp, spec );
3934         if ( rc == 0 )
3935         {
3936             VPUri_t uri_type;
3937             rc = VPathGetScheme_t( temp, &uri_type );
3938             if ( rc == 0 )
3939             {
3940                 switch ( uri_type )
3941                 {
3942                 default                  : /* !! fall through !! */
3943                 case vpuri_invalid       : rc = RC ( rcVFS, rcMgr, rcAccessing, rcParam, rcInvalid );
3944                                            break;
3945 
3946                 case vpuri_none          : /* !! fall through !! */
3947                 case vpuri_not_supported : rc = VFSManagerResolvePathOrAcc( self, temp, path_to_build, remote_file, local_cache, resolve_acc );
3948                                            break;
3949 
3950                 case vpuri_ncbi_vfs      : /* !! fall through !! */
3951                 case vpuri_file          : *path_to_build = temp;
3952                                            temp = NULL;
3953                                            break;
3954 
3955                 case vpuri_ncbi_acc      : if ( resolve_acc )
3956                                                 rc = VFSManagerResolveAcc( self, temp, path_to_build, remote_file, local_cache );
3957                                            else
3958                                                 rc = RC ( rcVFS, rcMgr, rcAccessing, rcParam, rcInvalid );
3959                                            break;
3960 
3961                 case vpuri_http          : /* !! fall through !! */
3962                 case vpuri_https:
3963                 case vpuri_ftp           : rc = VFSManagerResolveRemote( self, &temp, path_to_build, remote_file, local_cache );
3964                                            break;
3965 
3966                 case vpuri_ncbi_legrefseq: /* ??? */
3967                                            break;
3968                 }
3969             }
3970             if ( temp != NULL )
3971                 VPathRelease ( temp );
3972         }
3973     }
3974     return rc;
3975 }
3976 
VFSManagerGetConfig(const struct VFSManager * self)3977 LIB_EXPORT const struct KConfig* CC VFSManagerGetConfig(const struct VFSManager * self)
3978 {
3979     if ( self == NULL )
3980         return NULL;
3981     return self->cfg;
3982 }
3983 
3984 /*
3985  * Object Id / Object name bindings for accessions and dbGaP files
3986  */
3987 
3988 #define MAX_OBJID_SIZE 20
3989 #define MAX_NAME_SIZE 4096
3990 
VFSManagerSetBindingsFile(struct VFSManager * self,const char * path)3991 LIB_EXPORT void VFSManagerSetBindingsFile(struct VFSManager * self, const char* path)
3992 {
3993     if (self != NULL)
3994         KKeyStoreSetBindingsFile( self->keystore, path);
3995 }
3996 
VFSManagerGetBindingsFile(struct VFSManager * self)3997 LIB_EXPORT const char* VFSManagerGetBindingsFile(struct VFSManager * self)
3998 {
3999     if (self == NULL)
4000         return NULL;
4001     return KKeyStoreGetBindingsFile(self->keystore);
4002 }
4003 
VFSManagerRegisterObject(struct VFSManager * self,uint32_t oid,const struct VPath * obj)4004 LIB_EXPORT rc_t CC VFSManagerRegisterObject(struct VFSManager* self, uint32_t oid, const struct VPath* obj)
4005 {
4006     rc_t rc = 0;
4007     if ( self == NULL )
4008         rc = RC ( rcVFS, rcMgr, rcRegistering, rcSelf, rcNull );
4009     else if ( obj == NULL )
4010         rc = RC ( rcVFS, rcMgr, rcRegistering, rcParam, rcNull );
4011 
4012 /* VDB-3503: VFSManagerRegisterObject is used just to register oid<->filename
4013              mapping when working with kart files.
4014              The following tests were added to make sure 'obj' is correct to
4015              generate cache location of protected files */
4016     else if ( obj -> path_type == vpNameOrOID )
4017         rc = RC ( rcVFS, rcMgr, rcRegistering, rcPath, rcWrongType );
4018     else if ( obj -> scheme_type != vpuri_ncbi_acc &&
4019               obj -> scheme_type != vpuri_ncbi_file )
4020         rc = RC ( rcVFS, rcMgr, rcRegistering, rcPath, rcWrongType );
4021     else if ( obj -> query . size == 0 )
4022         rc = RC ( rcVFS, rcMgr, rcRegistering, rcQuery, rcEmpty );
4023 
4024     else
4025     {
4026         const String* newName;
4027         rc = VPathMakeString (obj, &newName);
4028         if (rc == 0)
4029         {
4030             rc = KKeyStoreRegisterObject(self->keystore, oid, newName);
4031             StringWhack(newName);
4032         }
4033     }
4034     return rc;
4035 }
4036 
VFSManagerGetObject(const struct VFSManager * self,uint32_t oid,struct VPath ** obj)4037 LIB_EXPORT rc_t CC VFSManagerGetObject(const struct VFSManager* self, uint32_t oid, struct VPath** obj)
4038 {
4039     rc_t rc = 0;
4040     if ( self == NULL )
4041         rc = RC ( rcVFS, rcMgr, rcRetrieving, rcSelf, rcNull );
4042     else if ( obj == NULL )
4043         rc = RC ( rcVFS, rcMgr, rcRetrieving, rcParam, rcNull );
4044     else
4045     {
4046         const String* objName;
4047         rc = KKeyStoreGetObjectName(self->keystore, oid, &objName);
4048         if (rc == 0)
4049         {
4050             rc = VFSManagerMakePath (self, obj, "%S", objName);
4051             StringWhack(objName);
4052         }
4053     }
4054     return rc;
4055 }
4056 
VFSManagerGetObjectId(const struct VFSManager * self,const struct VPath * obj,uint32_t * oid)4057 LIB_EXPORT rc_t CC VFSManagerGetObjectId(const struct VFSManager* self, const struct VPath* obj, uint32_t* oid)
4058 {
4059     rc_t rc = 0;
4060     if ( self == NULL )
4061         rc = RC ( rcVFS, rcMgr, rcRetrieving, rcSelf, rcNull );
4062     else if ( obj == NULL || oid == NULL)
4063         rc = RC ( rcVFS, rcMgr, rcRetrieving, rcParam, rcNull );
4064     else
4065     {
4066         const String* pathString;
4067         rc = VPathMakeString(obj, &pathString);
4068         if (rc == 0)
4069         {
4070             rc = VKKeyStoreGetObjectId(self->keystore, pathString, oid);
4071             StringWhack(pathString);
4072         }
4073     }
4074     return rc;
4075 }
4076 
4077 
4078 static const char * default_path_key = "/repository/user/default-path";
4079 
VFSManagerGetCacheRoot(const VFSManager * self,struct VPath const ** path)4080 LIB_EXPORT rc_t CC VFSManagerGetCacheRoot ( const VFSManager * self,
4081     struct VPath const ** path )
4082 {
4083     rc_t rc;
4084     if ( path == NULL )
4085         rc = RC ( rcVFS, rcMgr, rcListing, rcParam, rcNull );
4086     else
4087     {
4088         * path = NULL;
4089         if ( self == NULL )
4090             rc = RC ( rcVFS, rcMgr, rcListing, rcSelf, rcNull );
4091         else if ( self -> cfg == NULL )
4092             rc = RC ( rcVFS, rcMgr, rcListing, rcItem, rcNull );
4093         else
4094         {
4095             struct String * spath;
4096             rc = KConfigReadString ( self -> cfg, default_path_key, &spath );
4097             if ( rc == 0 )
4098             {
4099                 struct VPath * vp;
4100                 rc = VFSManagerMakePath ( self, &vp, "%S", spath );
4101                 if ( rc == 0 )
4102                     *path = vp;
4103                 StringWhack( spath );
4104             }
4105         }
4106     }
4107     return rc;
4108 }
4109 
4110 
4111 /*
4112     repo-path for instance '/repository/user/main/public'
4113     read $(repo-path)/root, put it into frozen-list ( if is not already there )
4114     write $(repository/user/default-path)/public as value into it ( just in case )
4115 */
4116 static const char * indirect_root = "$(repository/user/default-path)/%s";
4117 
VFSManagerSetCacheRoot(const VFSManager * self,struct VPath const * path)4118 LIB_EXPORT rc_t CC VFSManagerSetCacheRoot ( const VFSManager * self,
4119     struct VPath const * path )
4120 {
4121     rc_t rc;
4122     if ( path == NULL )
4123         rc = RC ( rcVFS, rcMgr, rcSelecting, rcParam, rcNull );
4124     else if ( self == NULL )
4125         rc = RC ( rcVFS, rcMgr, rcSelecting, rcSelf, rcNull );
4126     else if ( self -> cfg == NULL )
4127         rc = RC ( rcVFS, rcMgr, rcSelecting, rcItem, rcNull );
4128     else
4129     {
4130         /* loop through the user-repositories to set the root property to the indirect path */
4131         KRepositoryMgr * repo_mgr;
4132         rc = KConfigMakeRepositoryMgrUpdate ( self -> cfg, &repo_mgr );
4133         if ( rc == 0 )
4134         {
4135             KRepositoryVector user_repos;
4136             rc = KRepositoryMgrUserRepositories ( repo_mgr, &user_repos );
4137             if ( rc == 0 )
4138             {
4139                 uint32_t start = VectorStart( &user_repos );
4140                 uint32_t count = VectorLength( &user_repos );
4141                 uint32_t idx;
4142                 for ( idx = 0; rc == 0 && idx < count; ++idx )
4143                 {
4144                     KRepository * repo = VectorGet ( &user_repos, idx + start );
4145                     if ( repo != NULL )
4146                     {
4147                         /* ask the repository to add it's current root to the root-history */
4148                         rc = KRepositoryAppendToRootHistory( repo, NULL );
4149                         if ( rc == 0 )
4150                         {
4151                             char repo_name[ 512 ];
4152                             size_t repo_name_len;
4153                             rc = KRepositoryName( repo, repo_name, sizeof repo_name, &repo_name_len );
4154                             if ( rc == 0 )
4155                             {
4156                                 char new_root[ 4096 ];
4157                                 size_t num_writ;
4158                                 repo_name[ repo_name_len ] = 0;
4159                                 rc = string_printf( new_root, sizeof new_root, &num_writ, indirect_root, repo_name );
4160                                 if ( rc == 0 )
4161                                     rc = KRepositorySetRoot( repo, new_root, string_size( new_root ) );
4162                             }
4163                         }
4164                     }
4165                 }
4166                 KRepositoryVectorWhack ( &user_repos );
4167             }
4168             KRepositoryMgrRelease ( repo_mgr );
4169         }
4170 
4171         /* write the new indirect path */
4172         if ( rc == 0 )
4173         {
4174             String const * spath = NULL;
4175             rc = VPathMakeString ( path, &spath );
4176             if ( rc == 0 )
4177             {
4178                 /* in case the path ends in a '/' ( the path-separator ) we have to remove it... */
4179                 if ( spath->addr[ spath->len - 1 ] == '/' )
4180                 {
4181                     String * p = ( String * )spath;
4182                     p->len -= 1;
4183                     p->size -= 1;
4184                     ( ( char * )p->addr )[ p->len ] = 0;
4185                 }
4186                 rc = KConfigWriteSString( self -> cfg, default_path_key, spath );
4187                 StringWhack( spath );
4188                 /*
4189                     we do not commit, because ticket VDB-3060:
4190                     GBench wants to change the cache-root, but to automatically revert to previous value
4191                     when GBench exits, this is achieved by not commiting here.
4192                 if ( rc == 0 )
4193                     rc = KConfigCommit ( self -> cfg );
4194                 */
4195             }
4196         }
4197     }
4198     return rc;
4199 }
4200 
4201 
inspect_file(KDirectory * dir,KTime_t date,const char * path)4202 static rc_t inspect_file( KDirectory * dir, KTime_t date, const char * path )
4203 {
4204     KTime_t file_date;
4205     rc_t rc = KDirectoryDate ( dir, &file_date, "%s", path );
4206     if ( rc == 0 )
4207     {
4208         if ( file_date < date )
4209             KDirectoryRemove ( dir, false, "%s", path );
4210     }
4211     return rc;
4212 }
4213 
4214 
inspect_dir(KDirectory * dir,KTime_t date,const char * path)4215 static rc_t inspect_dir( KDirectory * dir, KTime_t date, const char * path )
4216 {
4217     KNamelist * itemlist;
4218     rc_t rc = KDirectoryList( dir, &itemlist, NULL, NULL, "%s", path );
4219     if ( rc == 0 )
4220     {
4221         uint32_t count, idx;
4222         rc = KNamelistCount ( itemlist, &count );
4223         for ( idx = 0; rc == 0 && idx < count; idx++ )
4224         {
4225             const char * item;
4226             rc = KNamelistGet ( itemlist, idx, &item );
4227             {
4228                 char item_path[ 4096 ];
4229                 size_t num_writ;
4230                 rc = string_printf ( item_path, sizeof item_path, &num_writ, "%s/%s", path, item );
4231                 if ( rc == 0 )
4232                 {
4233                     uint32_t pathtype = KDirectoryPathType( dir, "%s", item_path );
4234                     switch( pathtype )
4235                     {
4236                         case kptFile : rc = inspect_file( dir, date, item_path ); break;
4237                         case kptDir  : rc = inspect_dir( dir, date, item_path ); break; /* recursion! */
4238                         default : break;
4239                     }
4240                 }
4241             }
4242         }
4243         KNamelistRelease( itemlist );
4244     }
4245     else
4246     {
4247 		if ( ( GetRCModule( rc ) == rcFS ) &&
4248 			 ( GetRCTarget( rc ) == rcDirectory ) &&
4249 			 ( GetRCContext( rc ) == rcListing ) &&
4250 			 ( GetRCObject( rc ) == ( enum RCObject )rcPath ) &&
4251 			 ( GetRCState( rc ) == rcNotFound ) )
4252 		{
4253 			rc = 0;
4254 		}
4255 		else
4256 		{
4257 			PLOGERR( klogErr, ( klogErr, rc, "KDirectoryList( '$(P)' )", "P=%s", path ) );
4258 		}
4259     }
4260     return rc;
4261 }
4262 
4263 
VFSManagerDeleteCacheOlderThan(const VFSManager * self,uint32_t days)4264 LIB_EXPORT rc_t CC VFSManagerDeleteCacheOlderThan ( const VFSManager * self,
4265     uint32_t days )
4266 {
4267     rc_t rc;
4268     if ( self == NULL )
4269         rc = RC ( rcVFS, rcMgr, rcSelecting, rcSelf, rcNull );
4270     else if ( self -> cfg == NULL )
4271         rc = RC ( rcVFS, rcMgr, rcSelecting, rcItem, rcNull );
4272     else
4273     {
4274         /* loop through the user-repositories to get the root property */
4275         const KRepositoryMgr * repo_mgr;
4276         rc = KConfigMakeRepositoryMgrRead ( self -> cfg, &repo_mgr );
4277         if ( rc == 0 )
4278         {
4279             KRepositoryVector user_repos;
4280             rc = KRepositoryMgrUserRepositories ( repo_mgr, &user_repos );
4281             if ( rc == 0 )
4282             {
4283                 uint32_t start = VectorStart( &user_repos );
4284                 uint32_t count = VectorLength( &user_repos );
4285                 uint32_t idx;
4286                 for ( idx = 0; rc == 0 && idx < count; ++idx )
4287                 {
4288                     KRepository * repo = VectorGet ( &user_repos, idx + start );
4289                     if ( repo != NULL )
4290                     {
4291                         char path[ 4096 ];
4292                         size_t root_size;
4293                         rc = KRepositoryRoot ( repo, path, sizeof path, &root_size );
4294                         if ( rc == 0 )
4295                         {
4296                             KTime_t date = KTimeStamp() - ( days * 60 * 60 * 24 );
4297                             rc = inspect_dir( self->cwd, date, path );
4298                         }
4299                     }
4300                 }
4301                 KRepositoryVectorWhack ( &user_repos );
4302             }
4303             KRepositoryMgrRelease ( repo_mgr );
4304         }
4305     }
4306     return rc;
4307 }
4308 
4309 LIB_EXPORT
VFSManagerSetAdCaching(VFSManager * self,bool enabled)4310 rc_t CC VFSManagerSetAdCaching(VFSManager * self, bool enabled)
4311 {
4312     if (self != NULL)
4313         return KNSManagerSetAdCaching(self->kns, enabled);
4314     return 0;
4315 }
4316 
4317 #define RELEASE(type, obj) do { rc_t rc2 = type##Release(obj); \
4318     if (rc2 && !rc) { rc = rc2; } obj = NULL; } while (false)
4319 
VFSManagerCheckEnvAndAdImpl(const VFSManager * self,const VPath * inPath,const VPath ** outPath,bool checkEnv)4320 static bool VFSManagerCheckEnvAndAdImpl(const VFSManager * self,
4321     const VPath * inPath, const VPath ** outPath, bool checkEnv)
4322 {
4323     /* *outPath can be not NULL: in this case it's just reset to a new value;
4324                                  DON'T RELEASE THE OLD ONE! */
4325 
4326     /* if path = "/S/S.sra";
4327        or path = "/S/S_dbGaP-NNN.sra"
4328        then inPath  is S
4329             outPath is /S/S*.sra */
4330     bool found = false;
4331     rc_t rc = 0;
4332     const KNgcObj * ngc = NULL;
4333     uint32_t projectId = 0;
4334     String spath;
4335     const char *slash = NULL;
4336     char rs[PATH_MAX] = "";
4337 
4338     VQuality quality = VDBManagerGetQuality(NULL);
4339     assert(quality >= 0);
4340 
4341     if (outPath == NULL)
4342         return RC(rcVFS, rcPath, rcResolving, rcParam, rcNull);
4343 
4344     if (self == NULL)
4345         return RC(rcVFS, rcPath, rcResolving, rcMgr, rcNull);
4346 
4347     if (VPathGetPath(inPath, &spath) != 0)
4348         return false;
4349     if (checkEnv) {
4350         const VPath * adPath = NULL;
4351         if (LocalMagicResolve(self->cwd, &spath, &adPath) == 0
4352             && adPath != NULL)
4353         {
4354             *outPath = adPath;
4355             return true;
4356         }
4357     }
4358     if ((KDirectoryPathType(self->cwd, spath.addr) & ~kptAlias) != kptDir)
4359         return false;
4360 
4361     rc = KDirectoryResolvePath(self->cwd, true,
4362         rs, sizeof rs, "%s", spath.addr);
4363     if (rc != 0)
4364         return false;
4365 
4366     slash = strrchr(rs, '/');
4367     if (slash)
4368         ++slash;
4369     else
4370         slash = rs;
4371 
4372     rc = KNgcObjMakeFromCmdLine(&ngc);
4373     if (ngc != NULL) {
4374         rc = KNgcObjGetProjectId(ngc, &projectId);
4375         if (rc == 0) {
4376             if (quality < eQualLast
4377                 && (quality == eQualDefault || quality == eQualNo))
4378             {
4379                 if ((KDirectoryPathType(self->cwd, "%s/%s_dbGaP-%d.noqual.sra",
4380                     rs, slash, projectId) & ~kptAlias) == kptFile)
4381                 {
4382                     rc_t r = VFSManagerMakePath(self, (VPath **)outPath,
4383                         "%s/%s_dbGaP-%d.noqual.sra", rs, slash, projectId);
4384                     if (r == 0)
4385                         found = true;
4386                 }
4387             }
4388             if (!found && (quality == eQualDefault || quality == eQualFull
4389                 || quality >= eQualLast))
4390             {
4391                 if ((KDirectoryPathType(self->cwd, "%s/%s_dbGaP-%d.sra",
4392                     rs, slash, projectId) & ~kptAlias) == kptFile)
4393                 {
4394                     rc_t r = VFSManagerMakePath(self, (VPath **)outPath,
4395                         "%s/%s_dbGaP-%d.sra", rs, slash, projectId);
4396                     if (r == 0)
4397                         found = true;
4398                 }
4399             }
4400         }
4401     }
4402 
4403     if (!found) {
4404         if (quality < eQualLast
4405             && (quality == eQualDefault || quality == eQualNo))
4406         {
4407             if ((KDirectoryPathType(self->cwd, "%s/%s.noqual.sra", rs, slash) &
4408                 ~kptAlias) == kptFile)
4409             {
4410                 rc_t r = VFSManagerMakePath(self, (VPath**)outPath,
4411                     "%s/%s.noqual.sra", rs, slash);
4412                 if (r != 0)
4413                     rc = 0;
4414                 else {
4415                     rc = VPathSetQuality((VPath*)outPath, eQualNo);
4416                     found = true;
4417                 }
4418             }
4419         }
4420         if (!found && (quality == eQualDefault || quality == eQualFull
4421             || quality >= eQualLast))
4422         {
4423             if ((KDirectoryPathType(self->cwd, "%s/%s.sra", rs, slash) &
4424                 ~kptAlias) == kptFile)
4425             {
4426                 rc_t r = VFSManagerMakePath(self, (VPath **)outPath,
4427                     "%s/%s.sra", rs, slash);
4428                 if (r == 0)
4429                     found = true;
4430                 rc = 0;
4431             }
4432         }
4433     }
4434 
4435     /* TODO: add processing of eQualFullOnly and eQualDblOnly */
4436 
4437     if (found) {
4438         VPath * vdbcache = NULL;
4439         const String * thePath = NULL;
4440 
4441         assert(outPath && *outPath);
4442         thePath = &((*outPath)->path);
4443 
4444         DBGMSG(DBG_VFS, DBG_FLAG(DBG_VFS), (
4445             "VFSManagerCheckEnvAndAd: '%s' found in '%S'\n", slash, thePath));
4446 
4447         if (KDirectoryPathType(self->cwd, "%.*s.vdbcache",
4448             (int)thePath->size, thePath->addr) == kptFile)
4449         {
4450             rc = VPathMakeFmt(&vdbcache, "%S.vdbcache", thePath);
4451             if (rc == 0) {
4452                 assert(vdbcache);
4453                 DBGMSG(DBG_VFS, DBG_FLAG(DBG_VFS), (
4454                     "VFSManagerCheckEnvAndAd: '%s.vdbcache' found in '%S'\n",
4455                     slash, &vdbcache->path));
4456             }
4457         }
4458         if (rc == 0)
4459             rc = VPathAttachVdbcache((VPath*)(*outPath), vdbcache);
4460 
4461         RELEASE(VPath, vdbcache);
4462     }
4463 
4464     RELEASE(KNgcObj, ngc);
4465 
4466     return found;
4467 }
4468 
4469 /* CheckEnvAndAd
4470  *  Verify that inPath is path/to/Accession-as-Directory (AD)
4471  *  if inPath is AD - resolve run in AD as outPath and return true
4472  *  otherwise - return false, don't set outPath.
4473  *
4474  *  Magic env. var. is respected.
4475  */
VFSManagerCheckEnvAndAd(const VFSManager * self,const VPath * inPath,const VPath ** outPath)4476 LIB_EXPORT bool CC VFSManagerCheckEnvAndAd(const VFSManager * self,
4477     const VPath * inPath, const VPath ** outPath)
4478 {
4479     return VFSManagerCheckEnvAndAdImpl(self, inPath, outPath, true);
4480 }
4481 
4482 /* CheckAd
4483  *  Verify that inPath is path/to/Accession-as-Directory (AD)
4484  *  if inPath is AD - resolve run in AD as outPath and return true
4485  *  otherwise - return false, don't set outPath.
4486  *
4487  *  Magic env. var. is ignored.
4488  */
VFSManagerCheckAd(const VFSManager * self,const VPath * inPath,const VPath ** outPath)4489 LIB_EXPORT bool CC VFSManagerCheckAd(const VFSManager * self,
4490     const VPath * inPath, const VPath ** outPath)
4491 {
4492     return VFSManagerCheckEnvAndAdImpl(self, inPath, outPath, false);
4493 }
4494