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