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 <kfg/extern.h>
28 
29 #include <kfg/repository.h>
30 #include <kfg/kfg-priv.h> /* KConfigMakeLocal */
31 #include <kfg/ngc.h>
32 
33 #include <kfs/file.h>
34 #include <kfs/directory.h>
35 #include <kfs/impl.h>
36 #include <klib/refcount.h>
37 #include <klib/text.h>
38 #include <klib/printf.h>
39 #include <klib/vector.h>
40 #include <klib/namelist.h>
41 #include <klib/rc.h>
42 
43 #include "kfg-priv.h" /* KConfigGetNgcFile */
44 #include "ngc-priv.h" /* KNgcObjMakeFromCmdLine */
45 
46 #include <sysalloc.h>
47 
48 #include <assert.h>
49 #include <ctype.h> /* isdigit */
50 #include <os-native.h>
51 #include <stdlib.h>
52 #include <string.h>
53 
54 #include <limits.h> /* PATH_MAX */
55 #ifndef PATH_MAX
56 #define PATH_MAX 4096
57 #endif
58 
59 /*--------------------------------------------------------------------------
60  * KRepository
61  *  presents structured access to a storage repository
62  *  as modeled in KConfig.
63  *
64  *  all objects are obtained via KRepositoryMgr ( see below )
65  */
66 struct KRepository
67 {
68     const KConfigNode *node;
69     String name;
70     KRefcount refcount;
71     KRepCategory category;
72     KRepSubCategory subcategory;
73     bool fromNgc; /* auto-generated from --ngc */
74 };
75 
76 
77 /* Whack
78  */
79 static
KRepositoryWhack(KRepository * self)80 rc_t KRepositoryWhack ( KRepository *self )
81 {
82     KConfigNodeRelease ( self -> node );
83     free ( self );
84     return 0;
85 }
86 
87 /* Sort
88  */
89 static
KRepositorySort(const void ** a,const void ** b,void * ignore)90 int64_t CC KRepositorySort ( const void **a, const void **b, void *ignore )
91 {
92     const KRepository *left = * a;
93     const KRepository *right = * b;
94 
95     if ( left -> category != right -> category )
96         return (int64_t)left -> category - (int64_t)right -> category;
97 
98     if ( left -> subcategory != right -> subcategory )
99         return (int64_t)left -> subcategory - (int64_t)right -> subcategory;
100 
101     return StringCompare ( & left -> name, & right -> name );
102 }
103 
104 /* Make
105  */
106 static
KRepositoryMake(KRepository ** rp,const KConfigNode * node,const char * name,KRepCategory category,KRepSubCategory subcategory)107 rc_t KRepositoryMake ( KRepository **rp, const KConfigNode *node,
108     const char *name, KRepCategory category, KRepSubCategory subcategory )
109 {
110     rc_t rc;
111     KRepository *r = NULL;
112     String name_str;
113 
114     /* measure string */
115     StringInitCString ( & name_str, name );
116 
117     /* create object */
118     r = calloc ( 1, sizeof * r + name_str . size + 1 );
119     if ( r == NULL )
120         return RC ( rcKFG, rcNode, rcConstructing, rcMemory, rcExhausted );
121 
122     rc = KConfigNodeAddRef ( node );
123     if ( rc != 0 )
124     {
125         free ( r );
126         return rc;
127     }
128 
129     r -> node = node;
130     r -> name = name_str;
131     r -> name . addr = ( char* ) ( r + 1 );
132     KRefcountInit ( & r -> refcount, 1, "KRepository", "make", name );
133     r -> category = category;
134     r -> subcategory = subcategory;
135     memmove ( r + 1, name, name_str . size );
136     ( ( char* ) ( r + 1 ) ) [ name_str . size ] = 0;
137 
138     * rp = r;
139 
140     return 0;
141 }
142 
143 
144 /* AddRef
145  * Release
146  */
KRepositoryAddRef(const KRepository * self)147 LIB_EXPORT rc_t CC KRepositoryAddRef ( const KRepository *self )
148 {
149     if ( self != NULL )
150     {
151         switch ( KRefcountAdd ( & self -> refcount, "KRepository" ) )
152         {
153         case krefLimit:
154             return RC ( rcKFG, rcNode, rcAttaching, rcRange, rcExcessive );
155         }
156     }
157     return 0;
158 }
159 
KRepositoryRelease(const KRepository * self)160 LIB_EXPORT rc_t CC KRepositoryRelease ( const KRepository *self )
161 {
162     if ( self != NULL )
163     {
164         switch ( KRefcountDrop ( & self -> refcount, "KRepository" ) )
165         {
166         case krefWhack:
167             return KRepositoryWhack ( ( KRepository* ) self );
168         case krefNegative:
169             return RC ( rcKFG, rcNode, rcReleasing, rcRange, rcExcessive );
170         }
171     }
172     return 0;
173 }
174 
175 
176 /* WhackEntry
177  *  for cleaning up these vectors
178  */
179 static
KRepositoryWhackEntry(void * item,void * ignore)180 void CC KRepositoryWhackEntry ( void *item, void *ignore )
181 {
182     KRepository *self = item;
183     KRepositoryRelease ( self );
184 }
185 
186 
187 /* Category
188  * SubCategory
189  *  tells what the repository category or sub-category are
190  *  or returns "bad" if the repository object is not usable.
191  */
KRepositoryCategory(const KRepository * self)192 LIB_EXPORT KRepCategory CC KRepositoryCategory ( const KRepository *self )
193 {
194     if ( self != NULL )
195         return self -> category;
196     return krepBadCategory;
197 }
198 
KRepositorySubCategory(const KRepository * self)199 LIB_EXPORT KRepSubCategory CC KRepositorySubCategory ( const KRepository *self )
200 {
201     if ( self != NULL )
202         return self -> subcategory;
203     return krepBadSubCategory;
204 }
205 
206 
207 /* Name
208  *  get the repository name
209  *  attempts to copy NUL-terminated name into provided buffer
210  *
211  *  "buffer" [ OUT ] and "bsize" [ IN ] - name output parameter
212  *
213  *  "name_size" [ OUT, NULL OKAY ] - returns the name size in
214  *  bytes, excluding any NUL termination.
215  */
KRepositoryName(const KRepository * self,char * buffer,size_t bsize,size_t * name_size)216 LIB_EXPORT rc_t CC KRepositoryName ( const KRepository *self,
217     char *buffer, size_t bsize, size_t *name_size )
218 {
219     if ( self == NULL )
220         return RC ( rcKFG, rcNode, rcAccessing, rcSelf, rcNull );
221 
222     if ( name_size != NULL )
223         * name_size = self -> name . size;
224 
225     if ( bsize < self -> name . size )
226         return RC ( rcKFG, rcNode, rcAccessing, rcBuffer, rcInsufficient );
227 
228     if ( buffer == NULL )
229         return RC ( rcKFG, rcNode, rcAccessing, rcBuffer, rcNull );
230 
231     memmove ( buffer, self -> name . addr, self -> name . size );
232 
233     if ( bsize > self -> name . size )
234         buffer [ self -> name . size ] = 0;
235 
236     return 0;
237 }
238 
239 
240 /* DisplayName
241  *  get the repository display name,
242  *  if different from its actual name
243  *
244  *  attempts to copy NUL-terminated name into provided buffer
245  *
246  *  "buffer" [ OUT ] and "bsize" [ IN ] - name output parameter
247  *
248  *  "name_size" [ OUT, NULL OKAY ] - returns the name size in
249  *  bytes, excluding any NUL termination.
250  */
KRepositoryDisplayName(const KRepository * self,char * buffer,size_t bsize,size_t * name_size)251 LIB_EXPORT rc_t CC KRepositoryDisplayName ( const KRepository *self,
252     char *buffer, size_t bsize, size_t *name_size )
253 {
254     rc_t rc;
255 
256     if ( self == NULL )
257         rc = RC ( rcKFG, rcNode, rcAccessing, rcSelf, rcNull );
258     else
259     {
260         const KConfigNode *node;
261 
262         if ( name_size != NULL )
263             * name_size = 0;
264 
265         rc = KConfigNodeOpenNodeRead ( self -> node, & node, "display-name" );
266         if ( rc != 0 )
267             rc = KRepositoryName ( self, buffer, bsize, name_size );
268         else
269         {
270             size_t num_read, remaining;
271             rc = KConfigNodeRead ( node, 0, buffer, bsize, & num_read, & remaining );
272             KConfigNodeRelease ( node );
273 
274             if ( rc == 0 )
275             {
276                 if ( name_size != NULL )
277                     * name_size = num_read + remaining;
278 
279                 if ( remaining != 0 )
280                     rc = RC ( rcKFG, rcNode, rcAccessing, rcBuffer, rcInsufficient );
281                 else if ( num_read < bsize )
282                     buffer [ num_read ] = 0;
283             }
284         }
285     }
286 
287     return rc;
288 }
289 
290 
291 /* Root
292  *  read the root path as a POSIX path or URL
293  *
294  *  attempts to copy NUL-terminated path into provided buffer
295  *
296  *  "buffer" [ OUT ] and "bsize" [ IN ] - path output parameter
297  *
298  *  "root_size" [ OUT, NULL OKAY ] - returns the path size in
299  *  bytes, excluding any NUL termination.
300  */
KRepositoryRoot(const KRepository * self,char * buffer,size_t bsize,size_t * root_size)301 LIB_EXPORT rc_t CC KRepositoryRoot ( const KRepository *self,
302     char *buffer, size_t bsize, size_t *root_size )
303 {
304     rc_t rc;
305 
306     if ( self == NULL )
307         rc = RC ( rcKFG, rcNode, rcAccessing, rcSelf, rcNull );
308     else
309     {
310         const KConfigNode *node;
311 
312         if ( root_size != NULL )
313             * root_size = 0;
314 
315         rc = KConfigNodeOpenNodeRead ( self -> node, & node, "root" );
316         if ( rc == 0 )
317         {
318             size_t num_read, remaining;
319             rc = KConfigNodeRead ( node, 0, buffer, bsize, & num_read, & remaining );
320             KConfigNodeRelease ( node );
321 
322             if ( rc == 0 )
323             {
324                 if ( root_size != NULL )
325                     * root_size = num_read + remaining;
326 
327                 if ( remaining != 0 )
328                     rc = RC ( rcKFG, rcNode, rcAccessing, rcBuffer, rcInsufficient );
329                 else if ( num_read < bsize )
330                     buffer [ num_read ] = 0;
331             }
332         }
333     }
334 
335     return rc;
336 }
337 
KRepositorySetRoot(KRepository * self,const char * root,size_t root_size)338 LIB_EXPORT rc_t CC KRepositorySetRoot(KRepository *self,
339     const char *root, size_t root_size)
340 {
341     rc_t rc = 0;
342 
343     if (self == NULL) {
344         return RC(rcKFG, rcNode, rcUpdating, rcSelf, rcNull);
345     }
346     else if (root == NULL) {
347         return RC(rcKFG, rcNode, rcUpdating, rcParam, rcNull);
348     }
349     else {
350         KConfigNode *self_node = (KConfigNode*)self->node;
351         KConfigNode *node = NULL;
352 
353         rc = KConfigNodeOpenNodeUpdate(self_node, &node, "root");
354         if (rc == 0) {
355             rc = KConfigNodeWrite(node, root, root_size);
356             KConfigNodeRelease(node);
357         }
358     }
359 
360     return rc;
361 }
362 
363 
364 const char root_history_key[] = "root/history";
365 
366 /* RootHistory
367  *  read the root-history as a semicolon separated list of POSIX paths
368  *
369  *  attempts to copy NUL-terminated path into provided buffer
370  *
371  *  "buffer" [ OUT ] and "bsize" [ IN ] - path output parameter
372  *
373  *  "roothistory_size" [ OUT, NULL OKAY ] - returns the root-history
374  *  size in bytes, excluding any NUL termination.
375  */
KRepositoryRootHistory(const KRepository * self,char * buffer,size_t bsize,size_t * roothistory_size)376 LIB_EXPORT rc_t CC KRepositoryRootHistory ( const KRepository *self,
377     char *buffer, size_t bsize, size_t *roothistory_size )
378 {
379     rc_t rc;
380 
381     if ( self == NULL )
382         rc = RC ( rcKFG, rcNode, rcAccessing, rcSelf, rcNull );
383     else
384     {
385         const KConfigNode *node;
386 
387         if ( roothistory_size != NULL )
388             * roothistory_size = 0;
389 
390         rc = KConfigNodeOpenNodeRead ( self -> node, & node, root_history_key );
391         if ( rc == 0 )
392         {
393             size_t num_read, remaining;
394             rc = KConfigNodeRead ( node, 0, buffer, bsize, & num_read, & remaining );
395             KConfigNodeRelease ( node );
396 
397             if ( rc == 0 )
398             {
399                 if ( roothistory_size != NULL )
400                     * roothistory_size = num_read + remaining;
401 
402                 if ( remaining != 0 )
403                     rc = RC ( rcKFG, rcNode, rcAccessing, rcBuffer, rcInsufficient );
404                 else if ( num_read < bsize )
405                     buffer [ num_read ] = 0;
406             }
407         }
408     }
409 
410     return rc;
411 
412 }
413 
414 
415 /* SetRootHistory
416  *  set the root-history list of paths
417  *
418  *  "roothistory" [ IN ] and "roothistory_size" [ IN ] - path input parameter
419  */
KRepositorySetRootHistory(KRepository * self,const char * roothistory,size_t roothistory_size)420 LIB_EXPORT rc_t CC KRepositorySetRootHistory( KRepository *self,
421     const char *roothistory, size_t roothistory_size )
422 {
423     rc_t rc = 0;
424     if ( self == NULL )
425         return RC(rcKFG, rcNode, rcUpdating, rcSelf, rcNull);
426     else if ( roothistory == NULL )
427         return RC(rcKFG, rcNode, rcUpdating, rcParam, rcNull);
428     else
429     {
430         KConfigNode *self_node = ( KConfigNode* )self->node;
431         KConfigNode *node = NULL;
432 
433         rc = KConfigNodeOpenNodeUpdate( self_node, &node, root_history_key );
434         if ( rc == 0 )
435         {
436             rc = KConfigNodeWrite( node, roothistory, roothistory_size );
437             KConfigNodeRelease( node );
438         }
439     }
440     return rc;
441 }
442 
443 
append_to_root_history(KRepository * self,const char * item)444 static rc_t append_to_root_history( KRepository *self, const char *item )
445 {
446     size_t required;
447     rc_t rc = KRepositoryRootHistory( self, NULL, 0, &required );
448     if ( GetRCState( rc ) == rcNotFound && GetRCObject( rc ) == ( enum RCObject ) rcPath )
449     {
450         /* we do not have a root-history yet */
451         rc = KRepositorySetRootHistory( self, item, string_size( item ) );
452     }
453     else if ( GetRCState( rc ) == rcInsufficient && GetRCObject( rc ) == ( enum RCObject ) rcBuffer )
454     {
455         /* we expect the buffer to be insufficient, because we tested for size by giving a NULL as buffer */
456         char * temp = malloc( required + 1 );
457         if ( temp == NULL )
458             rc = RC( rcKFG, rcNode, rcUpdating, rcMemory, rcExhausted );
459         else
460         {
461             rc = KRepositoryRootHistory( self, temp, required, NULL );
462             if ( rc == 0 )
463             {
464                 VNamelist * list;
465                 temp[ required ] = 0;
466                 rc = VNamelistFromStr ( &list, temp, ':' );
467                 if ( rc == 0 )
468                 {
469                     int32_t idx;
470                     rc = VNamelistContainsStr( list, item, &idx );
471                     if ( rc == 0 && idx < 0 )
472                     {
473                         rc = VNamelistAppend ( list, item );
474                         if ( rc == 0 )
475                         {
476                             const String * new_value;
477                             rc = VNamelistJoin( list, ':', &new_value );
478                             if ( rc == 0 )
479                             {
480                                 rc = KRepositorySetRootHistory( self, new_value -> addr, new_value -> size );
481                                 StringWhack( new_value );
482                             }
483                         }
484                     }
485                     VNamelistRelease ( list );
486                 }
487             }
488             free( temp );
489         }
490     }
491     return rc;
492 }
493 
494 
495 /* AppendToRootHistory
496  *  append to the root-history
497  *
498  *  "roothistory" [ IN ] and "roothistory_size" [ IN ] - path input parameter
499  *  if item == NULL, add the current root to the root-history
500  */
KRepositoryAppendToRootHistory(KRepository * self,const char * item)501 LIB_EXPORT rc_t CC KRepositoryAppendToRootHistory( KRepository *self, const char *item )
502 {
503     rc_t rc = 0;
504     if ( self == NULL )
505         return RC( rcKFG, rcNode, rcUpdating, rcSelf, rcNull );
506     else if ( item == NULL )
507     {
508         size_t curr_root_size;
509         rc = KRepositoryRoot( self, NULL, 0, &curr_root_size );
510         if ( GetRCState( rc ) == rcInsufficient && GetRCObject( rc ) == ( enum RCObject ) rcBuffer )
511         {
512             char * root = malloc( curr_root_size + 1 );
513             if ( root == NULL )
514                 rc = RC( rcKFG, rcNode, rcUpdating, rcMemory, rcExhausted );
515             else
516             {
517                 rc = KRepositoryRoot( self, root, curr_root_size, NULL );
518                 if ( rc == 0 )
519                 {
520                     root[ curr_root_size ] = 0;
521                     rc = append_to_root_history( self, root );
522                 }
523                 else
524                 {
525                     /* we cannot determine the current root, because it is not stored */
526                     rc = 0;
527                 }
528                 free( root );
529             }
530         }
531         else
532         {
533             /* we cannot determine the current root, because it is not stored */
534             rc = 0;
535         }
536     }
537     else
538         rc = append_to_root_history( self, item );
539     return rc;
540 }
541 
542 
543 /* Resolver
544  *  read the url of the CGI-resolver
545  *
546  *  attempts to copy NUL-terminated path into provided buffer
547  *
548  *  "buffer" [ OUT ] and "bsize" [ IN ] - path output parameter
549  *
550  *  "written" [ OUT, NULL OKAY ] - returns the url size in
551  *  bytes, excluding any NUL termination.
552  */
KRepositoryResolver(const KRepository * self,char * buffer,size_t bsize,size_t * written)553 LIB_EXPORT rc_t CC KRepositoryResolver ( const KRepository *self,
554     char *buffer, size_t bsize, size_t *written )
555 {
556     rc_t rc;
557 
558     if ( self == NULL )
559         rc = RC ( rcKFG, rcNode, rcAccessing, rcSelf, rcNull );
560     else
561     {
562         const KConfigNode *node;
563 
564         if ( written != NULL )
565             * written = 0;
566 
567         rc = KConfigNodeOpenNodeRead ( self -> node, & node, "resolver-cgi" );
568         if ( rc == 0 )
569         {
570             size_t num_read, remaining;
571             rc = KConfigNodeRead ( node, 0, buffer, bsize, & num_read, & remaining );
572             KConfigNodeRelease ( node );
573 
574             if ( rc == 0 )
575             {
576                 if ( written != NULL )
577                     * written = num_read + remaining;
578 
579                 if ( remaining != 0 )
580                     rc = RC ( rcKFG, rcNode, rcAccessing, rcBuffer, rcInsufficient );
581                 else if ( num_read < bsize )
582                     buffer [ num_read ] = 0;
583             }
584         }
585     }
586 
587     return rc;
588 }
589 
590 
591 /* Disabled
592  *  discover whether the repository is enabled
593  */
KRepositoryDisabled(const KRepository * self)594 LIB_EXPORT bool CC KRepositoryDisabled ( const KRepository *self )
595 {
596     if ( self != NULL )
597     {
598         const KConfigNode *node;
599         rc_t rc = KConfigNodeOpenNodeRead ( self -> node, & node, "disabled" );
600         if ( rc == 0 )
601         {
602             bool disabled = false;
603             rc = KConfigNodeReadBool ( node, & disabled );
604             KConfigNodeRelease ( node );
605             if ( rc == 0 )
606                 return disabled;
607         }
608     }
609 
610     return false;
611 }
612 
613 
614 static const char * STR_TRUE  = "true";
615 static const char * STR_FALSE = "false";
616 
KRepositorySetDisabled(const KRepository * self,bool disabled)617 LIB_EXPORT rc_t CC KRepositorySetDisabled ( const KRepository *self, bool disabled )
618 {
619     rc_t rc = RC ( rcKFG, rcNode, rcAccessing, rcSelf, rcNull );
620     if ( self != NULL )
621     {
622         KConfigNode * self_node = ( KConfigNode * )self->node;  /* casting away const-ness */
623         KConfigNode * node;
624         rc = KConfigNodeOpenNodeUpdate ( self_node, &node, "disabled" );
625         if ( rc == 0 )
626         {
627             const char * value = disabled ? STR_TRUE : STR_FALSE;
628             rc = KConfigNodeWrite ( node, value, string_size( value ) );
629             if ( rc == 0 )
630             {
631                 KConfig * cfg;
632                 rc = KConfigNodeGetMgr( self->node, &cfg );
633                 if ( rc == 0 )
634                 {
635                     rc = KConfigCommit ( cfg );
636                     KConfigRelease ( cfg );
637                 }
638             }
639             KConfigNodeRelease ( node );
640         }
641     }
642     return rc;
643 }
644 
645 
646 /* CacheEnabled
647  *  discover whether the repository supports caching
648  */
KRepositoryCacheEnabled(const KRepository * self)649 LIB_EXPORT bool CC KRepositoryCacheEnabled ( const KRepository *self )
650 {
651     if ( self != NULL )
652     {
653         const KConfigNode *node;
654         rc_t rc = KConfigNodeOpenNodeRead ( self -> node, & node, "cache-enabled" );
655         if ( rc == 0 )
656         {
657             bool enabled = false;
658             rc = KConfigNodeReadBool ( node, & enabled );
659             KConfigNodeRelease ( node );
660             if ( rc == 0 )
661                 return enabled;
662         }
663     }
664 
665     return false;
666 }
667 
668 
669 /* DownloadTicket
670  *  return any associated download ticket
671  *
672  *  attempts to copy NUL-terminated ticket into provided buffer
673  *
674  *  "buffer" [ OUT ] and "bsize" [ IN ] - ticket output parameter
675  *
676  *  "ticket_size" [ OUT, NULL OKAY ] - returns the ticket size in
677  *  bytes, excluding any NUL termination.
678  */
KRepositoryDownloadTicket(const KRepository * self,char * buffer,size_t bsize,size_t * ticket_size)679 LIB_EXPORT rc_t CC KRepositoryDownloadTicket ( const KRepository *self,
680     char *buffer, size_t bsize, size_t *ticket_size )
681 {
682     rc_t rc;
683 
684     if ( self == NULL )
685         rc = RC ( rcKFG, rcNode, rcAccessing, rcSelf, rcNull );
686     else
687     {
688         const KConfigNode *node;
689 
690         if ( ticket_size != NULL )
691             * ticket_size = 0;
692 
693         rc = KConfigNodeOpenNodeRead ( self -> node, & node, "download-ticket" );
694         if ( rc == 0 )
695         {
696             size_t num_read, remaining;
697             rc = KConfigNodeRead ( node, 0, buffer, bsize, & num_read, & remaining );
698             KConfigNodeRelease ( node );
699 
700             if ( rc == 0 )
701             {
702                 if ( ticket_size != NULL )
703                     * ticket_size = num_read + remaining;
704 
705                 if ( remaining != 0 )
706                     rc = RC ( rcKFG, rcNode, rcAccessing, rcBuffer, rcInsufficient );
707                 else if ( num_read < bsize )
708                     buffer [ num_read ] = 0;
709             }
710         }
711     }
712 
713     return rc;
714 }
715 
716 
717 /* EncryptionKey
718  *  return any associated encryption key
719  *
720  *  attempts to copy NUL-terminated key into provided buffer
721  *
722  *  "buffer" [ OUT ] and "bsize" [ IN ] - encryption key output parameter
723  *
724  *  "key_size" [ OUT, NULL OKAY ] - returns the key size in
725  *  bytes, excluding any NUL termination.
726  */
KRepositoryEncryptionKey(const KRepository * self,char * buffer,size_t bsize,size_t * key_size)727 LIB_EXPORT rc_t CC KRepositoryEncryptionKey ( const KRepository *self,
728     char *buffer, size_t bsize, size_t *key_size )
729 {
730     rc_t rc;
731 
732     if ( self == NULL )
733         rc = RC ( rcKFG, rcNode, rcAccessing, rcSelf, rcNull );
734     else
735     {
736         const KConfigNode *node;
737 
738         if ( key_size != NULL )
739             * key_size = 0;
740 
741         rc = KConfigNodeOpenNodeRead ( self -> node, & node, "encryption-key" );
742         if ( rc == 0 )
743         {
744             size_t num_read, remaining;
745             rc = KConfigNodeRead ( node, 0, buffer, bsize, & num_read, & remaining );
746             KConfigNodeRelease ( node );
747 
748             if ( rc == 0 )
749             {
750                 if ( key_size != NULL )
751                     * key_size = num_read + remaining;
752 
753                 if ( remaining != 0 )
754                     rc = RC ( rcKFG, rcNode, rcAccessing, rcBuffer, rcInsufficient );
755                 else if ( num_read < bsize )
756                     memset ( & buffer [ num_read ], 0, bsize - num_read );
757             }
758         }
759         else if ( GetRCState ( rc ) == rcNotFound )
760         {
761             char path [ 4096 ];
762             rc_t rc2 = KRepositoryEncryptionKeyFile ( self, path, sizeof path, NULL );
763             if ( rc2 == 0 )
764             {
765                 KDirectory *wd;
766                 rc2 = KDirectoryNativeDir ( & wd );
767                 if ( rc2 == 0 )
768                 {
769                     const KFile *keyFile;
770                     rc2 = KDirectoryOpenFileRead ( wd, & keyFile, "%s", path );
771                     KDirectoryRelease ( wd );
772                     if ( rc2 == 0 )
773                     {
774                         size_t num_read;
775                         rc = KFileReadAll ( keyFile, 0, buffer, bsize, & num_read );
776                         if ( rc == 0 )
777                         {
778                             if ( num_read == bsize )
779                             {
780                                 uint64_t eof;
781                                 rc = KFileSize ( keyFile, & eof );
782                                 if ( rc == 0 )
783                                     num_read = ( size_t ) eof;
784                                 else
785                                     num_read = 0;
786 
787                                 rc = RC ( rcKFG, rcFile, rcReading, rcBuffer, rcInsufficient );
788                                 memset ( buffer, 0, bsize );
789                             }
790                             else if ( num_read == 0 )
791                             {
792                                 rc = RC ( rcKFG, rcFile, rcReading, rcFile, rcEmpty );
793                                 memset ( buffer, 0, bsize );
794                             }
795                             else
796                             {
797                                 char *eoln = string_chr ( buffer, num_read, '\n' );
798                                 if ( eoln != NULL )
799                                 {
800                                     if ( eoln == buffer )
801                                         num_read = 0;
802                                     else if ( eoln [ -1 ] == '\r' )
803                                         num_read = eoln - buffer - 1;
804                                     else
805                                         num_read = eoln - buffer;
806                                 }
807 
808                                 if ( key_size != NULL )
809                                     * key_size = num_read;
810 
811                                 memset ( & buffer [ num_read ], 0, bsize - num_read );
812                             }
813                         }
814 
815                         KFileRelease ( keyFile );
816                     }
817                 }
818             }
819         }
820     }
821 
822     return rc;
823 }
824 
825 
826 /* EncryptionKeyFile
827  *  return path to any associated encryption key file
828  *
829  *  attempts to copy NUL-terminated path into provided buffer
830  *
831  *  "buffer" [ OUT ] and "bsize" [ IN ] - key file path output parameter
832  *
833  *  "path_size" [ OUT, NULL OKAY ] - returns the path size in
834  *  bytes, excluding any NUL termination.
835  */
KRepositoryEncryptionKeyFile(const KRepository * self,char * buffer,size_t bsize,size_t * path_size)836 LIB_EXPORT rc_t CC KRepositoryEncryptionKeyFile ( const KRepository *self,
837     char *buffer, size_t bsize, size_t *path_size )
838 {
839     rc_t rc;
840 
841     if ( self == NULL )
842         rc = RC ( rcKFG, rcNode, rcAccessing, rcSelf, rcNull );
843     else
844     {
845         const KConfigNode *node;
846 
847         if ( path_size != NULL )
848             * path_size = 0;
849 
850         rc = KConfigNodeOpenNodeRead ( self -> node, & node, "encryption-key-path" );
851         if ( rc == 0 )
852         {
853             size_t num_read, remaining;
854             rc = KConfigNodeRead ( node, 0, buffer, bsize, & num_read, & remaining );
855             KConfigNodeRelease ( node );
856 
857             if ( rc == 0 )
858             {
859                 if ( path_size != NULL )
860                     * path_size = num_read + remaining;
861 
862                 if ( remaining != 0 )
863                     rc = RC ( rcKFG, rcNode, rcAccessing, rcBuffer, rcInsufficient );
864                 else if ( num_read < bsize )
865                     buffer [ num_read ] = 0;
866             }
867         }
868     }
869 
870     return rc;
871 }
872 
873 
874 /* Description
875  *  return any associated descriptive text
876  *
877  *  attempts to copy NUL-terminated description into provided buffer
878  *
879  *  "buffer" [ OUT ] and "bsize" [ IN ] - description text output parameter
880  *
881  *  "desc_size" [ OUT, NULL OKAY ] - returns the text size in
882  *  bytes, excluding any NUL termination.
883  */
KRepositoryDescription(const KRepository * self,char * buffer,size_t bsize,size_t * desc_size)884 LIB_EXPORT rc_t CC KRepositoryDescription ( const KRepository *self,
885     char *buffer, size_t bsize, size_t *desc_size )
886 {
887     rc_t rc;
888 
889     if ( self == NULL )
890         rc = RC ( rcKFG, rcNode, rcAccessing, rcSelf, rcNull );
891     else
892     {
893         const KConfigNode *node;
894 
895         if ( desc_size != NULL )
896             * desc_size = 0;
897 
898         rc = KConfigNodeOpenNodeRead ( self -> node, & node, "description" );
899         if ( rc == 0 )
900         {
901             size_t num_read, remaining;
902             rc = KConfigNodeRead ( node, 0, buffer, bsize, & num_read, & remaining );
903             KConfigNodeRelease ( node );
904 
905             if ( rc == 0 )
906             {
907                 if ( desc_size != NULL )
908                     * desc_size = num_read + remaining;
909 
910                 if ( remaining != 0 )
911                     rc = RC ( rcKFG, rcNode, rcAccessing, rcBuffer, rcInsufficient );
912                 else if ( num_read < bsize )
913                     buffer [ num_read ] = 0;
914             }
915         }
916     }
917 
918     return rc;
919 }
920 
921 
922 /* ProjectId
923  *  return project id for protected user repository
924  *  return RC when repository is not user protected
925  *
926  *  "projectId" [ OUT ] - returns the project id
927  */
KRepositoryProjectId(const KRepository * self,uint32_t * projectId)928 LIB_EXPORT rc_t CC KRepositoryProjectId
929     ( const KRepository * self, uint32_t * projectId )
930 {
931     rc_t rc = 0;
932 
933     if ( projectId == NULL )
934         rc = RC ( rcKFG, rcMgr, rcAccessing, rcParam, rcNull );
935     else if ( self == NULL )
936         rc = SILENT_RC ( rcKFG, rcMgr, rcAccessing, rcSelf, rcNull );
937     else if ( self -> category != krepUserCategory
938            || self -> subcategory != krepProtectedSubCategory )
939         rc = RC ( rcKFG, rcMgr, rcAccessing, rcSelf, rcWrongType );
940     else {
941         uint32_t id = 0;
942         const char prefix [] = "dbGaP-";
943         char localName [512] = "";
944         size_t localNumWrit = 0;
945 
946         * projectId = 0;
947 
948         KRepositoryName (self, localName, sizeof ( localName ), & localNumWrit);
949         assert ( localNumWrit < sizeof localName );
950 
951         if ( strcase_cmp ( localName, localNumWrit,
952             prefix, sizeof prefix - 1, sizeof prefix - 1) == 0)
953         {
954             int i = sizeof prefix - 1;
955             for ( i = sizeof prefix - 1; i < localNumWrit; ++ i ) {
956                 if ( ! isdigit ( localName [ i ] ) ) {
957                     rc = RC (rcKFG, rcMgr, rcAccessing, rcSelf, rcUnrecognized);
958                     break;
959                 }
960                 id = id * 10 + localName [ i ] - '0';
961             }
962 
963             if ( rc == 0 ) {
964                 * projectId = id;
965                 return 0;
966             }
967         }
968 
969         rc = RC (rcKFG, rcMgr, rcAccessing, rcSelf, rcUnrecognized);
970     }
971 
972     return rc;
973 }
974 
975 
976 /*--------------------------------------------------------------------------
977  * KRepositoryVector
978  *  uses Vector API
979  *  holds zero or more KRepository objects
980  */
981 
982 
983 /* Whack
984  *  destroy your vector
985  */
KRepositoryVectorWhack(KRepositoryVector * self)986 LIB_EXPORT rc_t CC KRepositoryVectorWhack ( KRepositoryVector *self )
987 {
988     if ( self == NULL )
989         return RC ( rcKFG, rcVector, rcDestroying, rcSelf, rcNull );
990 
991     VectorWhack ( self, KRepositoryWhackEntry, NULL );
992     return 0;
993 }
994 
995 
996 /*--------------------------------------------------------------------------
997  * KRepositoryMgr
998  *  manages structured access to repositories
999  */
1000 struct KRepositoryMgr
1001 {
1002     const KConfig *ro_cfg;
1003     KConfig *rw_cfg;
1004     KRefcount refcount;
1005 };
1006 
1007 
1008 /* Whack
1009  */
1010 static
KRepositoryMgrWhack(KRepositoryMgr * self)1011 rc_t KRepositoryMgrWhack ( KRepositoryMgr *self )
1012 {
1013     if ( self -> ro_cfg )
1014         KConfigRelease ( self -> ro_cfg );
1015     if ( self -> rw_cfg )
1016         KConfigRelease ( self -> rw_cfg );
1017     free ( self );
1018     return 0;
1019 }
1020 
1021 
1022 /* Make
1023  *  create a repository manager
1024  *  uses values from "self"
1025  */
KConfigMakeRepositoryMgrRead(const KConfig * self,const KRepositoryMgr ** mgrp)1026 LIB_EXPORT rc_t CC KConfigMakeRepositoryMgrRead ( const KConfig *self, const KRepositoryMgr **mgrp )
1027 {
1028     rc_t rc;
1029 
1030     if ( mgrp == NULL )
1031         rc = RC ( rcKFG, rcMgr, rcConstructing, rcParam, rcNull );
1032     else
1033     {
1034         if ( self == NULL )
1035             rc = RC ( rcKFG, rcMgr, rcConstructing, rcSelf, rcNull );
1036         else
1037         {
1038             KRepositoryMgr *mgr = calloc ( 1, sizeof * mgr );
1039             if ( mgr == NULL )
1040                 rc = RC ( rcKFG, rcMgr, rcConstructing, rcMemory, rcExhausted );
1041             else
1042             {
1043                 rc = KConfigAddRef ( self );
1044                 if ( rc == 0 )
1045                 {
1046                     mgr -> ro_cfg = self;
1047                     KRefcountInit ( & mgr -> refcount, 1, "KRepositoryMgr", "make-read", "mgr" );
1048                     * mgrp = mgr;
1049                     return 0;
1050                 }
1051 
1052                 free ( mgr );
1053             }
1054         }
1055 
1056         * mgrp = NULL;
1057     }
1058 
1059     return rc;
1060 }
1061 
KConfigMakeRepositoryMgrUpdate(KConfig * self,KRepositoryMgr ** mgrp)1062 LIB_EXPORT rc_t CC KConfigMakeRepositoryMgrUpdate ( KConfig *self, KRepositoryMgr **mgrp )
1063 {
1064     rc_t rc;
1065 
1066     if ( mgrp == NULL )
1067         rc = RC ( rcKFG, rcMgr, rcConstructing, rcParam, rcNull );
1068     else
1069     {
1070         if ( self == NULL )
1071             rc = RC ( rcKFG, rcMgr, rcConstructing, rcSelf, rcNull );
1072         else
1073         {
1074             KRepositoryMgr *mgr = calloc ( 1, sizeof * mgr );
1075             if ( mgr == NULL )
1076                 rc = RC ( rcKFG, rcMgr, rcConstructing, rcMemory, rcExhausted );
1077             else
1078             {
1079                 rc = KConfigAddRef ( self );
1080                 if ( rc == 0 )
1081                 {
1082                     mgr -> rw_cfg = self;
1083                     KRefcountInit ( & mgr -> refcount, 1, "KRepositoryMgr", "make-update", "mgr" );
1084                     * mgrp = mgr;
1085                     return 0;
1086                 }
1087 
1088                 free ( mgr );
1089             }
1090         }
1091 
1092         * mgrp = NULL;
1093     }
1094 
1095     return rc;
1096 }
1097 
1098 
1099 /* AddRef
1100  * Release
1101  */
KRepositoryMgrAddRef(const KRepositoryMgr * self)1102 LIB_EXPORT rc_t CC KRepositoryMgrAddRef ( const KRepositoryMgr *self )
1103 {
1104     if ( self != NULL )
1105     {
1106         switch ( KRefcountAdd ( & self -> refcount, "KRepositoryMgr" ) )
1107         {
1108         case krefLimit:
1109             return RC ( rcKFG, rcMgr, rcAttaching, rcRange, rcExcessive );
1110         }
1111     }
1112     return 0;
1113 }
1114 
KRepositoryMgrRelease(const KRepositoryMgr * self)1115 LIB_EXPORT rc_t CC KRepositoryMgrRelease ( const KRepositoryMgr *self )
1116 {
1117     if ( self != NULL )
1118     {
1119         switch ( KRefcountDrop ( & self -> refcount, "KRepositoryMgr" ) )
1120         {
1121         case krefWhack:
1122             return KRepositoryMgrWhack ( ( KRepositoryMgr* ) self );
1123         case krefNegative:
1124             return RC ( rcKFG, rcMgr, rcReleasing, rcRange, rcExcessive );
1125         }
1126     }
1127     return 0;
1128 }
1129 
1130 
1131 static
KRepositoryMgrGetROKConfig(const KRepositoryMgr * self)1132 const KConfig *KRepositoryMgrGetROKConfig ( const KRepositoryMgr *self )
1133 {
1134     return self -> ro_cfg ? self -> ro_cfg : self -> rw_cfg;
1135 }
1136 
1137 static
KRepositoryMgrSubCategoryRepositories(const KConfigNode * sub,KRepCategory category,KRepSubCategory subcategory,KRepositoryVector * repositories)1138 rc_t KRepositoryMgrSubCategoryRepositories ( const KConfigNode *sub,
1139     KRepCategory category, KRepSubCategory subcategory, KRepositoryVector *repositories )
1140 {
1141     KNamelist *repo_names;
1142     rc_t rc = KConfigNodeListChildren ( sub, & repo_names );
1143     if ( rc == 0 )
1144     {
1145         uint32_t i, count;
1146         rc = KNamelistCount ( repo_names, & count );
1147         for ( i = 0; i < count && rc == 0; ++ i )
1148         {
1149             const char *repo_name;
1150             rc = KNamelistGet ( repo_names, i, & repo_name );
1151             if ( rc == 0 )
1152             {
1153                 const KConfigNode *node;
1154                 rc = KConfigNodeOpenNodeRead ( sub, & node, "%s", repo_name );
1155                 if ( rc == 0 )
1156                 {
1157                     KRepository *repo;
1158                     rc = KRepositoryMake ( & repo, node, repo_name, category, subcategory );
1159                     if ( rc == 0 )
1160                     {
1161                         rc = VectorAppend ( repositories, NULL, repo );
1162                         if ( rc != 0 )
1163                             KRepositoryWhack ( repo );
1164                     }
1165 
1166                     KConfigNodeRelease ( node );
1167                 }
1168             }
1169         }
1170 
1171         KNamelistRelease ( repo_names );
1172     }
1173 
1174     return rc;
1175 }
1176 
1177 static
KRepositoryMgrCategoryRepositories(const KConfigNode * cat,KRepCategory category,KRepositoryVector * repositories)1178 rc_t KRepositoryMgrCategoryRepositories ( const KConfigNode *cat,
1179     KRepCategory category, KRepositoryVector *repositories )
1180 {
1181     KNamelist *sub_names;
1182     rc_t rc = KConfigNodeListChildren ( cat, & sub_names );
1183     if ( rc == 0 )
1184     {
1185         uint32_t i, count;
1186         rc = KNamelistCount ( sub_names, & count );
1187         for ( i = 0; i < count && rc == 0; ++ i )
1188         {
1189             const char *sub_name;
1190             rc = KNamelistGet ( sub_names, i, & sub_name );
1191             if ( rc == 0 )
1192             {
1193                 KRepSubCategory subcategory = krepBadSubCategory;
1194                 if ( strcmp ( "main", sub_name ) == 0 )
1195                     subcategory = krepMainSubCategory;
1196                 else if ( strcmp ( "aux", sub_name ) == 0 )
1197                     subcategory = krepAuxSubCategory;
1198                 else if ( strcmp ( "protected", sub_name ) == 0 )
1199                     subcategory = krepProtectedSubCategory;
1200 
1201                 if ( subcategory != krepBadSubCategory )
1202                 {
1203                     const KConfigNode *sub;
1204                     rc = KConfigNodeOpenNodeRead ( cat, & sub, "%s", sub_name );
1205                     if ( rc == 0 )
1206                     {
1207                         rc = KRepositoryMgrSubCategoryRepositories ( sub, category, subcategory, repositories );
1208                         KConfigNodeRelease ( sub );
1209                     }
1210                 }
1211             }
1212         }
1213 
1214         KNamelistRelease ( sub_names );
1215     }
1216 
1217     return rc;
1218 }
1219 
1220 
1221 /* UserRepositories
1222  *  retrieve all user repositories in a Vector
1223  */
KRepositoryMgrGetRepositories(const KRepositoryMgr * self,KRepCategory category,KRepositoryVector * repositories)1224 LIB_EXPORT rc_t CC KRepositoryMgrGetRepositories ( const KRepositoryMgr * self, KRepCategory category,
1225     KRepositoryVector * repositories )
1226 {
1227     rc_t rc;
1228 
1229     if ( repositories == NULL )
1230         rc = RC ( rcKFG, rcMgr, rcAccessing, rcParam, rcNull );
1231     else
1232     {
1233         VectorInit ( repositories, 0, 8 );
1234 
1235         if ( self == NULL )
1236             rc = RC ( rcKFG, rcMgr, rcAccessing, rcSelf, rcNull );
1237         else
1238         {
1239             const KConfig * kfg = KRepositoryMgrGetROKConfig ( self );
1240 
1241             const KConfigNode * node;
1242             switch( category )
1243             {
1244                 case krepUserCategory   : rc = KConfigOpenNodeRead ( kfg, & node, "/repository/user" ); break;
1245                 case krepSiteCategory   : rc = KConfigOpenNodeRead ( kfg, & node, "/repository/site" ); break;
1246                 case krepRemoteCategory : rc = KConfigOpenNodeRead ( kfg, & node, "/repository/remote" ); break;
1247                 default : rc = RC ( rcKFG, rcMgr, rcAccessing, rcParam, rcInvalid );
1248             }
1249             if ( rc == 0 )
1250             {
1251                 rc = KRepositoryMgrCategoryRepositories ( node, category, repositories );
1252                 KConfigNodeRelease ( node );
1253                 if ( rc == 0 )
1254                     VectorReorder ( repositories, KRepositorySort, NULL );
1255             }
1256 
1257             if ( rc != 0 )
1258                 KRepositoryVectorWhack ( repositories );
1259         }
1260     }
1261     return rc;
1262 }
1263 
1264 
KRepositoryMgrCategoryDisabled(const KRepositoryMgr * self,KRepCategory category)1265 LIB_EXPORT bool CC KRepositoryMgrCategoryDisabled ( const KRepositoryMgr *self, KRepCategory category )
1266 {
1267     bool res = false;
1268 
1269     if ( self != NULL )
1270     {
1271         const KConfig * kfg = KRepositoryMgrGetROKConfig ( self );
1272         if ( kfg != NULL )
1273         {
1274             switch( category )
1275             {
1276                 case krepUserCategory   : KConfigReadBool ( kfg, "/repository/user/disabled", &res ); break;
1277                 case krepSiteCategory   : KConfigReadBool ( kfg, "/repository/site/disabled", &res ); break;
1278                 case krepRemoteCategory : KConfigReadBool ( kfg, "/repository/remote/disabled", &res ); break;
1279             }
1280         }
1281     }
1282     return res;
1283 }
1284 
1285 
KRepositoryMgrCategorySetDisabled(const KRepositoryMgr * self,KRepCategory category,bool disabled)1286 LIB_EXPORT rc_t CC KRepositoryMgrCategorySetDisabled ( const KRepositoryMgr *self, KRepCategory category, bool disabled )
1287 {
1288     rc_t rc = 0;
1289     if ( self == NULL )
1290         rc = RC ( rcKFG, rcMgr, rcAccessing, rcSelf, rcNull );
1291     else
1292     {
1293         KConfig * kfg = ( KConfig * ) KRepositoryMgrGetROKConfig ( self );
1294         if ( kfg == NULL )
1295             rc = RC ( rcKFG, rcMgr, rcAccessing, rcParam, rcNull );
1296         else
1297         {
1298             switch( category )
1299             {
1300                 case krepUserCategory   : rc = KConfigWriteBool ( kfg, "/repository/user/disabled", disabled ); break;
1301                 case krepSiteCategory   : rc = KConfigWriteBool ( kfg, "/repository/site/disabled", disabled ); break;
1302                 case krepRemoteCategory : rc = KConfigWriteBool ( kfg, "/repository/remote/disabled", disabled ); break;
1303                 default : rc = RC ( rcKFG, rcMgr, rcAccessing, rcParam, rcInvalid );
1304             }
1305         }
1306     }
1307     return rc;
1308 }
1309 
1310 
KRepositoryMgrUserRepositories(const KRepositoryMgr * self,KRepositoryVector * user_repositories)1311 LIB_EXPORT rc_t CC KRepositoryMgrUserRepositories ( const KRepositoryMgr * self,
1312     KRepositoryVector * user_repositories )
1313 {
1314     return KRepositoryMgrGetRepositories ( self, krepUserCategory, user_repositories );
1315 }
1316 
1317 
1318 /* SiteRepositories
1319  *  retrieve all site repositories in a Vector
1320  */
KRepositoryMgrSiteRepositories(const KRepositoryMgr * self,KRepositoryVector * site_repositories)1321 LIB_EXPORT rc_t CC KRepositoryMgrSiteRepositories ( const KRepositoryMgr *self,
1322     KRepositoryVector *site_repositories )
1323 {
1324     return KRepositoryMgrGetRepositories ( self, krepSiteCategory, site_repositories );
1325 }
1326 
1327 
1328 /* RemoteRepositories
1329  *  retrieve all remote repositories in a Vector
1330  */
KRepositoryMgrRemoteRepositories(const KRepositoryMgr * self,KRepositoryVector * remote_repositories)1331 LIB_EXPORT rc_t CC KRepositoryMgrRemoteRepositories ( const KRepositoryMgr *self,
1332     KRepositoryVector *remote_repositories )
1333 {
1334     return KRepositoryMgrGetRepositories ( self, krepRemoteCategory, remote_repositories );
1335 }
1336 
1337 
1338 #define RELEASE(type, obj) do { rc_t rc2 = type##Release(obj); \
1339     if (rc2 && !rc) { rc = rc2; } obj = NULL; } while (false)
1340 
KRepositoryCurrentProtectedRepositoryForNgc(const KRepository ** self)1341 static rc_t KRepositoryCurrentProtectedRepositoryForNgc(
1342     const KRepository ** self)
1343 {
1344     const KNgcObj * ngc = NULL;
1345 
1346     rc_t rc = KNgcObjMakeFromCmdLine(&ngc);
1347 
1348     if (ngc == NULL) {
1349         if (rc != 0)
1350             return rc;
1351         else
1352             return SILENT_RC(rcKFG, rcMgr, rcAccessing, rcNode, rcNotFound);
1353     }
1354     else {
1355         KConfig * kfg = NULL;
1356         const KRepositoryMgr * mgr = NULL;
1357         KRepositoryVector vc;
1358         uint32_t id = 0;
1359         char name[512] = "";
1360         size_t nameLen = 0;
1361         char n[512] = "";
1362         char v[512] = "";
1363 
1364         if (rc == 0)
1365             rc = KNgcObjGetProjectId(ngc, &id);
1366         if (rc == 0)
1367             rc = KConfigMakeLocal(&kfg, NULL);
1368 
1369         if (rc == 0)
1370             rc = string_printf(name, sizeof name, &nameLen, "dbGaP-%d", id);
1371 
1372         if (rc == 0)
1373             rc = KNgcObjGetEncryptionKey(ngc, v, sizeof v, NULL);
1374         if (rc == 0)
1375             rc = string_printf(n, sizeof n, NULL,
1376                 "/repository/user/protected/%s/encryption-key", name);
1377         if (rc == 0)
1378             rc = KConfigWriteString(kfg, n, v);
1379 
1380         if (rc == 0)
1381             rc = KNgcObjGetTicket(ngc, v, sizeof v, NULL);
1382         if (rc == 0)
1383             rc = string_printf(n, sizeof n, NULL,
1384                 "/repository/user/protected/%s/download-ticket", name);
1385         if (rc == 0)
1386             rc = KConfigWriteString(kfg, n, v);
1387 
1388         if (rc == 0)
1389             rc = KConfigMakeRepositoryMgrRead(kfg, &mgr);
1390         if (rc == 0)
1391             rc = KRepositoryMgrUserRepositories(mgr, &vc);
1392 
1393         assert(self);
1394         *self = NULL;
1395 
1396         if (rc == 0) {
1397             uint32_t i = 0;
1398             uint32_t count = VectorLength(&vc);
1399             for (i = 0; i < count; ++i) {
1400                 bool found = false;
1401                 KRepository * r = (void*)VectorGet(&vc, i);
1402                 if (r->subcategory == krepProtectedSubCategory) {
1403                     char lclName[512] = "";
1404                     size_t lNumWrit = 0;
1405                     rc = KRepositoryName(r, lclName, sizeof lclName, &lNumWrit);
1406                     if (rc == 0) {
1407                         assert(lNumWrit < sizeof lclName);
1408                         if (strcase_cmp(lclName, lNumWrit,
1409                             name, nameLen, sizeof name) == 0)
1410                         {
1411                             found = true;
1412                         }
1413                     }
1414                 }
1415                 if (found) {
1416                     rc = KRepositoryAddRef(r);
1417                     if (rc == 0) {
1418                         r->fromNgc = true;
1419                         *self = r;
1420                         break;
1421                     }
1422                 }
1423             }
1424             KRepositoryVectorWhack(&vc);
1425         }
1426 
1427         if (rc == 0 && * self == NULL)
1428             rc = RC(rcKFG, rcMgr, rcAccessing, rcNode, rcNotFound);
1429 
1430         RELEASE(KRepositoryMgr, mgr);
1431         RELEASE(KConfig, kfg);
1432         RELEASE(KNgcObj, ngc);
1433     }
1434 
1435     return rc;
1436 }
1437 
1438 /* vdb-config -i, when importing an ngc file,
1439     sometimes created an unuable protected repository
1440     having juts a single 'root' node.
1441     This function detects such repository. */
1442 static
KRepositoryIsBadRepository(const KRepository * self,bool * bad)1443 rc_t KRepositoryIsBadRepository(const KRepository * self, bool * bad)
1444 {
1445     rc_t rc = 0;
1446 
1447     KNamelist * names = NULL;
1448     uint32_t count = 0;
1449 
1450     assert(self && bad);
1451     *bad = false;
1452 
1453     rc = KConfigNodeListChildren(self->node, &names);
1454     if (rc == 0)
1455         rc = KNamelistCount(names, &count);
1456 
1457     if (rc == 0 && count == 1) {
1458         const char * name = NULL;
1459         rc = KNamelistGet(names, 0, &name);
1460         if (rc == 0) {
1461             const char root[] = "root";
1462             if (string_cmp(root, sizeof root - 1, name,
1463                 string_measure(name, NULL), sizeof root) == 0)
1464             {
1465                 *bad = true;
1466             }
1467         }
1468     }
1469 
1470     RELEASE(KNamelist, names);
1471 
1472     return rc;
1473 }
1474 
1475 /* CurrentProtectedRepository
1476  *  returns the currently active user protected repository
1477  */
KRepositoryMgrCurrentProtectedRepository(const KRepositoryMgr * self,const KRepository ** protected)1478 LIB_EXPORT rc_t CC KRepositoryMgrCurrentProtectedRepository ( const KRepositoryMgr *self, const KRepository **protected )
1479 {
1480     rc_t rc = 0;
1481 
1482     if ( protected == NULL )
1483         rc = RC ( rcKFG, rcMgr, rcAccessing, rcParam, rcNull );
1484 
1485     else
1486     {
1487         * protected = NULL;
1488         rc = KRepositoryCurrentProtectedRepositoryForNgc ( protected );
1489 
1490 #if 0 /* VDB-4394: stop supporting old configuration for protected repos */
1491         if ( self == NULL )
1492             rc = RC ( rcKFG, rcMgr, rcAccessing, rcSelf, rcNull );
1493         else
1494         {
1495             KRepositoryVector v;
1496             rc = KRepositoryMgrUserRepositories ( self, & v );
1497             if ( rc == 0 )
1498             {
1499                 KDirectory *wd;
1500                 rc = KDirectoryNativeDir ( & wd );
1501                 if ( rc == 0 )
1502                 {
1503                     /* we need services of system directory */
1504                     struct KSysDir *sysDir = KDirectoryGetSysDir ( wd );
1505 
1506                     /* allocate buffer space for 3 paths */
1507                     const size_t path_size = 4096;
1508                     char *wd_path = malloc ( path_size * 3 );
1509                     if ( wd_path == NULL )
1510                         rc = RC ( rcKFG, rcMgr, rcAccessing, rcMemory, rcExhausted );
1511                     else
1512                     {
1513                         /* the working directory already has a canonical path */
1514                         rc = KDirectoryResolvePath ( wd, true, wd_path, path_size, "." );
1515                         if ( rc == 0 )
1516                         {
1517                             size_t wd_size = string_size ( wd_path );
1518 
1519                             /* look for all protected user repositories */
1520                             uint32_t i, count = VectorLength ( & v );
1521                             for ( i = 0; i < count; ++ i )
1522                             {
1523                                 const KRepository *r = ( const void* ) VectorGet ( & v, i );
1524                                 if ( r -> subcategory == krepProtectedSubCategory )
1525                                 {
1526                                   bool bad = false;
1527                                   rc = KRepositoryIsBadRepository(r, &bad);
1528                                   if (rc != 0)
1529                                     break;
1530                                   else if (bad)
1531                                     continue;
1532                                   else {
1533                                     rc_t rc2 = 0;
1534                                     size_t resolved_size;
1535                                     char *resolved = wd_path + path_size;
1536 
1537                                     /* get stated root path to repository */
1538                                     char *root = resolved + path_size;
1539                                     rc2 = KRepositoryRoot ( r,
1540                                         root, path_size, NULL );
1541                                     if ( rc2 != 0 ) {
1542                                         /* VDB-1096:
1543                                         We cannot get repository root:
1544                                         is it a bad repository configuration?
1545                                         Then ignore this repository node
1546                                         and try another repository */
1547                                         continue;
1548                                     }
1549 
1550                                     /* get its canonical path */
1551                                     rc2 = KSysDirRealPath ( sysDir,
1552                                                             resolved, path_size, "%s", root );
1553                                     if ( rc2 != 0 ) {
1554                                         /* VDB-1096:
1555                       Invalid cannot get repository root? Ignore and continue */
1556                                         continue;
1557                                     }
1558 
1559                                     /* we know the current directory's canonical path size
1560                                        and we know the repository's canonical path size.
1561                                        to be "within" the repository, the current directory's
1562                                        size must be >= repository path size, and must match
1563                                        exactly the repository path itself over those bytes. */
1564                                     resolved_size = string_size ( resolved );
1565                                     if ( resolved_size <= wd_size && memcmp ( wd_path, resolved, resolved_size ) == 0 )
1566                                     {
1567                                         /* still have a little more to check */
1568                                         if ( resolved_size == wd_size ||
1569                                              wd_path [ resolved_size ] == '/' )
1570                                         {
1571                                             /* we are in the repository */
1572                                             rc = KRepositoryAddRef ( r );
1573                                             if ( rc == 0 )
1574                                                 * protected = r;
1575                                             break;
1576                                         }
1577                                     }
1578 
1579                                   }
1580                                 }
1581                             }
1582                         }
1583 
1584                         free ( wd_path );
1585                     }
1586 
1587                     KDirectoryRelease ( wd );
1588                 }
1589 
1590                 KRepositoryVectorWhack ( & v );
1591             }
1592             else if (rc ==
1593                 SILENT_RC(rcKFG, rcNode, rcOpening, rcPath, rcNotFound))
1594             {
1595                 return SILENT_RC ( rcKFG, rcMgr, rcAccessing, rcNode, rcNotFound );
1596             }
1597 
1598             if (rc == 0 && * protected == NULL)
1599                 rc = KRepositoryCurrentProtectedRepositoryForNgc(protected);
1600         }
1601 #endif
1602 
1603     }
1604 
1605     return rc;
1606 }
1607 
1608 
1609 /* GetProtectedRepository
1610  *  retrieves a user protected repository by its associated project-id
1611  */
KRepositoryMgrGetProtectedRepository(const KRepositoryMgr * self,uint32_t projectId,const KRepository ** protected)1612 LIB_EXPORT rc_t CC KRepositoryMgrGetProtectedRepository ( const KRepositoryMgr *self,
1613     uint32_t projectId,
1614     const KRepository **protected )
1615 {
1616     rc_t rc;
1617 
1618     if ( protected == NULL )
1619         rc = RC ( rcKFG, rcMgr, rcAccessing, rcParam, rcNull );
1620     else
1621     {
1622         if ( self == NULL )
1623             rc = RC ( rcKFG, rcMgr, rcAccessing, rcSelf, rcNull );
1624         else
1625         {
1626             char repNodeName[512] = "";
1627             size_t numWrit = 0;
1628             KRepositoryVector v;
1629             rc = string_printf(repNodeName, sizeof repNodeName, &numWrit, "dbgap-%u", projectId); /* go case-insensitive */
1630             assert(numWrit < sizeof(repNodeName));
1631 
1632             rc = KRepositoryMgrUserRepositories ( self, & v );
1633             if ( rc == 0 )
1634             {  /* look for all protected user repositories */
1635                 uint32_t i, count = VectorLength ( & v );
1636                 for ( i = 0; i < count; ++ i )
1637                 {
1638                     const KRepository *r = ( const void* ) VectorGet ( & v, i );
1639                     assert(r);
1640                     if ( r -> subcategory == krepProtectedSubCategory )
1641                     {
1642                         char nm[512] = "";
1643                         size_t w = 0;
1644                         KRepositoryName(r, nm, sizeof nm, &w);
1645                         assert(w < sizeof nm);
1646                         if (strcase_cmp(repNodeName, numWrit, nm, w, sizeof nm)
1647                             == 0)
1648                         {
1649                           bool bad = false;
1650                           rc = KRepositoryIsBadRepository(r, &bad);
1651                           if (rc == 0 && !bad) {
1652                             rc = KRepositoryAddRef ( r );
1653                             if ( rc == 0 )
1654                             {
1655                                 * protected = r;
1656                                 KRepositoryVectorWhack(&v);
1657                                 return 0;
1658                             }
1659                           }
1660                         }
1661                     }
1662                 }
1663                 KRepositoryVectorWhack(&v);
1664                 rc = RC ( rcKFG, rcMgr, rcAccessing, rcNode, rcNotFound );
1665             }
1666         }
1667     }
1668 
1669     return rc;
1670 }
1671 
1672 
find_repository_in_vector(KRepositoryVector * v,KRepository ** repository,const char * name,uint32_t name_len)1673 static rc_t find_repository_in_vector( KRepositoryVector * v, KRepository **repository, const char * name, uint32_t name_len )
1674 {
1675     rc_t rc = 0;
1676     KRepository * found = NULL;
1677     uint32_t count = VectorLength ( v );
1678     uint32_t i;
1679     for ( i = 0; i < count && found == NULL; ++ i )
1680     {
1681         char r_name[ 512 ];
1682         size_t written = 0;
1683         KRepository * r = ( KRepository * ) VectorGet ( v, i );
1684         rc = KRepositoryName( r, r_name, sizeof r_name , &written );
1685         if ( strcase_cmp( name, name_len, r_name, written, sizeof r_name ) == 0 )
1686         {
1687             found = r;
1688         }
1689     }
1690     if ( found == NULL )
1691         rc = RC ( rcKFG, rcMgr, rcSearching, rcName, rcNotFound );
1692     else
1693         *repository = found;
1694     return rc;
1695 }
1696 
1697 
create_child_node(const KConfigNode * self,const char * child_name,const char * child_val,uint32_t len)1698 static rc_t create_child_node( const KConfigNode * self, const char * child_name, const char * child_val, uint32_t len )
1699 {
1700     KConfigNode * child_node;
1701     rc_t rc = KConfigNodeOpenNodeUpdate( ( KConfigNode * )self, &child_node, "%s", child_name );
1702     if ( rc == 0 )
1703     {
1704         rc_t rc_2;
1705         rc = KConfigNodeWrite( child_node, child_val, len );
1706         rc_2 = KConfigNodeRelease( child_node );
1707         if ( rc == 0 ) rc = rc_2;
1708     }
1709     return rc;
1710 }
1711 
1712 
make_writable_file(struct KFile ** dst,const char * path)1713 static rc_t make_writable_file( struct KFile ** dst, const char * path )
1714 {
1715     KDirectory * dir;
1716     rc_t rc = KDirectoryNativeDir( &dir );
1717     if ( rc == 0 )
1718     {
1719         rc = KDirectoryCreateFile ( dir, dst, false, 0600, ( kcmInit | kcmParents ), "%s", path );
1720         KDirectoryRelease( dir );
1721     }
1722     return rc;
1723 }
1724 
1725 
make_key_file(KRepositoryMgr * self,const struct KNgcObj * ngc,char * buffer,size_t buffer_size,size_t * written)1726 static rc_t make_key_file( KRepositoryMgr * self, const struct KNgcObj * ngc, char * buffer, size_t buffer_size, size_t * written )
1727 {
1728     struct String * home;
1729     rc_t rc = KConfigReadString ( self->rw_cfg, "HOME", &home );
1730     if ( rc == 0 )
1731     {
1732         rc = string_printf( buffer, buffer_size, written, "%S", home );
1733         if ( rc == 0 )
1734         {
1735             size_t written2;
1736             rc = string_printf( &buffer[ *written ], buffer_size - *written, &written2, "/.ncbi/dbGap-%u.enc_key", ngc->projectId );
1737             if ( rc == 0 )
1738                 *written += written2;
1739         }
1740         StringWhack ( home );
1741     }
1742     if ( rc == 0 )
1743     {
1744         struct KFile * key_file;
1745         rc = make_writable_file( &key_file, buffer );
1746         if ( rc == 0 )
1747         {
1748             rc = KNgcObjWriteKeyToFile ( ngc, key_file );
1749             KFileRelease( key_file );
1750         }
1751     }
1752     return rc;
1753 }
1754 
1755 /******************************************************************************/
1756 
_KRepositoryAppsNodeFix(KConfigNode * self,const char * path,const char * val,size_t len,uint32_t * modifications)1757 static rc_t _KRepositoryAppsNodeFix(KConfigNode *self,
1758     const char *path, const char *val, size_t len, uint32_t *modifications)
1759 {
1760     rc_t rc = 0;
1761 
1762     KConfigNode *node = NULL;
1763 
1764     assert(self && modifications);
1765 
1766     rc = KConfigNodeOpenNodeUpdate(self, &node, path);
1767     if (rc == 0) {
1768         bool update = false;
1769         char buffer[8] = "";
1770         size_t num_read = 0;
1771         size_t remaining = 0;
1772         rc_t rc = KConfigNodeRead(node, 0,
1773             buffer, sizeof buffer, &num_read, &remaining);
1774         if ((rc != 0) || (string_cmp(buffer, num_read, val, len, len) != 0)) {
1775             update = true;
1776         }
1777 
1778         if (update) {
1779             rc = KConfigNodeWrite(node, val, len);
1780             if (rc == 0) {
1781                 *modifications = INP_UPDATE_APPS;
1782             }
1783         }
1784     }
1785 
1786     RELEASE(KConfigNode, node);
1787 
1788     return rc;
1789 }
1790 
_KRepositoryFixApps(KRepository * self,uint32_t * modifications)1791 static rc_t _KRepositoryFixApps(KRepository *self, uint32_t *modifications) {
1792     rc_t rf = 0;
1793     rc_t rs = 0;
1794 
1795     KConfigNode *self_node = NULL;
1796 
1797     assert(self);
1798 
1799     self_node = (KConfigNode*)self->node;
1800 
1801     rf = _KRepositoryAppsNodeFix(self_node, "apps/file/volumes/flat",
1802         "files", 5, modifications);
1803 
1804     rs = _KRepositoryAppsNodeFix(self_node, "apps/sra/volumes/sraFlat",
1805         "sra"  , 3, modifications);
1806 
1807     return rf != 0 ? rf : rs;
1808 }
1809 
1810 /* we have not found a repository named repo_name, let us create a new one... */
create_new_protected_repository(KRepositoryMgr * self,const struct KNgcObj * ngc,const char * location,uint32_t location_len,const char * repo_name,uint32_t name_len)1811 static rc_t create_new_protected_repository( KRepositoryMgr * self,
1812     const struct KNgcObj * ngc, const char * location, uint32_t location_len, const char * repo_name, uint32_t name_len )
1813 {
1814     KConfigNode * new_repository;
1815     rc_t rc = KConfigOpenNodeUpdate( self->rw_cfg, &new_repository, "/repository/user/protected/dbGaP-%u", ngc->projectId );
1816     if ( rc == 0 )
1817     {
1818         rc = create_child_node( new_repository, "download-ticket", ngc->downloadTicket.addr, ngc->downloadTicket.len );
1819 
1820         if ( rc == 0 )
1821             rc = create_child_node( new_repository, "description", ngc->description.addr, ngc->description.len );
1822 
1823         if ( rc == 0 )
1824             rc = create_child_node( new_repository, "apps/file/volumes/flat", "files", 5 );
1825 
1826         if ( rc == 0 )
1827             rc = create_child_node( new_repository, "apps/sra/volumes/sraFlat", "sra", 3 );
1828 
1829         if ( rc == 0 )
1830             rc = create_child_node( new_repository, "cache-enabled", "true", 4 );
1831 
1832         if ( rc == 0 )
1833             rc = create_child_node( new_repository, "root", location, location_len );
1834 
1835         if ( rc == 0 )
1836         {
1837             size_t written;
1838             char key_file_path[ 4096 ];
1839             rc = make_key_file( self, ngc, key_file_path, sizeof key_file_path, &written );
1840             if ( rc == 0 )
1841                 rc = create_child_node(new_repository,
1842                     "encryption-key-path", key_file_path, (uint32_t)written);
1843         }
1844         KConfigNodeRelease( new_repository );
1845     }
1846     return rc;
1847 }
1848 
1849 
check_for_modifications(const KRepository * repository,const KNgcObj * ngc,uint32_t * modifications,uint32_t * notFoundNodes)1850 static rc_t check_for_modifications(
1851     const KRepository *repository, const KNgcObj *ngc,
1852     uint32_t *modifications, uint32_t *notFoundNodes)
1853 {
1854     rc_t rc = 0;
1855     size_t written;
1856     char buffer[ 1024 ];
1857     assert(modifications && notFoundNodes);
1858 
1859     if (rc == 0) {
1860         rc = KRepositoryDownloadTicket(repository,
1861             buffer, sizeof buffer, &written);
1862         if (rc == 0) {
1863             if (strcase_cmp(buffer, written, ngc->downloadTicket.addr,
1864                 ngc->downloadTicket.len, sizeof buffer) != 0)
1865             {
1866                 *modifications |= INP_UPDATE_DNLD_TICKET;
1867             }
1868         }
1869         else if (rc == SILENT_RC(rcKFG, rcNode, rcOpening, rcPath, rcNotFound))
1870         {
1871             rc = 0;
1872             *notFoundNodes |= INP_UPDATE_DNLD_TICKET;
1873         }
1874     }
1875 
1876     if (rc == 0) {
1877         rc = KRepositoryEncryptionKey ( repository, buffer, sizeof buffer, &written );
1878         if (rc == 0) {
1879             if (strcase_cmp(buffer, written, ngc->encryptionKey.addr,
1880                 ngc->encryptionKey.len, sizeof buffer) != 0)
1881             {
1882                 *modifications |= INP_UPDATE_ENC_KEY;
1883             }
1884         }
1885         else if (rc == SILENT_RC(rcKFG, rcNode, rcOpening, rcPath, rcNotFound))
1886         {
1887             rc = 0;
1888             *notFoundNodes |= INP_UPDATE_ENC_KEY;
1889         }
1890     }
1891 
1892     if (rc == 0) {
1893         rc = KRepositoryDescription ( repository, buffer, sizeof buffer, &written );
1894         if (rc == 0) {
1895             if (strcase_cmp(buffer, written, ngc->description.addr,
1896                 ngc->description.len, sizeof buffer) != 0)
1897             {
1898                 *modifications |= INP_UPDATE_DESC;
1899             }
1900         }
1901         else if (rc == SILENT_RC(rcKFG, rcNode,
1902             rcOpening, rcPath, rcNotFound))
1903         {
1904             rc = 0;
1905             *notFoundNodes |= INP_UPDATE_DESC;
1906         }
1907     }
1908 
1909     return rc;
1910 }
1911 
1912 
check_for_root_modification(const KRepository * repository,const char * root,uint32_t * modifications)1913 static rc_t check_for_root_modification(const KRepository *repository,
1914     const char *root, uint32_t *modifications)
1915 {
1916     rc_t rc = 0;
1917     size_t root_size = 0;
1918     char buffer[PATH_MAX] = "";
1919     size_t bsize = 0;
1920 
1921     if (root == NULL || modifications == NULL) {
1922         return RC(rcKFG, rcMgr, rcAccessing, rcSelf, rcNull);
1923     }
1924 
1925     rc = KRepositoryRoot(repository, buffer, sizeof buffer, &root_size);
1926     if (rc != 0) {
1927         return rc;
1928     }
1929 
1930     bsize = string_measure(root, NULL);
1931     if (strcase_cmp(buffer, root_size, root, bsize, sizeof buffer) != 0) {
1932         *modifications |= INP_UPDATE_ROOT;
1933     }
1934 
1935     return rc;
1936 }
1937 
1938 /* we have an existing repository that corresponds with the given ngc-object, see if we have to / or can update its values */
update_existing_protected_repository(KRepositoryMgr * self,KRepository * repository,const struct KNgcObj * ngc,uint32_t modifications)1939 static rc_t update_existing_protected_repository( KRepositoryMgr * self,
1940     KRepository * repository, const struct KNgcObj * ngc, uint32_t modifications )
1941 {
1942     rc_t rc = 0;
1943     /* make the changes... */
1944     if ( modifications & INP_UPDATE_DNLD_TICKET )
1945     {
1946         rc = create_child_node( repository->node, "download-ticket", ngc->downloadTicket.addr, ngc->downloadTicket.len );
1947     }
1948 
1949     if ( rc == 0 && ( modifications & INP_UPDATE_ENC_KEY ) )
1950     {
1951         size_t written;
1952         char key_file_path[ 4096 ];
1953         rc = make_key_file( self, ngc, key_file_path, sizeof key_file_path, &written );
1954         if ( rc == 0 )
1955             rc = create_child_node(repository->node,
1956                 "encryption-key-path", key_file_path, (uint32_t)written);
1957     }
1958 
1959     if ( rc == 0 && ( modifications & INP_UPDATE_DESC ) )
1960     {
1961         rc = create_child_node( repository->node, "description", ngc->description.addr, ngc->description.len );
1962     }
1963     return rc;
1964 }
1965 
1966 
KRepositoryMgrImportNgcObj(KRepositoryMgr * self,const struct KNgcObj * ngc,const char * location,uint32_t permissions,uint32_t * result_flags)1967 LIB_EXPORT rc_t CC KRepositoryMgrImportNgcObj( KRepositoryMgr * self,
1968     const struct KNgcObj * ngc, const char * location, uint32_t permissions, uint32_t * result_flags )
1969 {
1970     rc_t rc = 0;
1971     if ( self == NULL )
1972         rc = RC ( rcKFG, rcMgr, rcUpdating, rcSelf, rcNull );
1973     if ( ngc == NULL || location == NULL || result_flags == NULL )
1974         rc = RC ( rcKFG, rcMgr, rcUpdating, rcParam, rcNull );
1975     else
1976     {
1977         KRepositoryVector user_repositories;
1978         size_t written;
1979         char ngc_repo_name[ 512 ];
1980         *result_flags = 0;
1981         memset(&user_repositories, 0, sizeof user_repositories);
1982         rc = string_printf( ngc_repo_name, sizeof ngc_repo_name, &written, "dbGaP-%u", ngc->projectId );
1983         if ( rc == 0 )
1984         {
1985             KRepository *repository = NULL;
1986             bool exists = false;
1987 
1988             rc = KRepositoryMgrUserRepositories ( self, &user_repositories );
1989             if ( rc == 0 )
1990             {
1991                 rc = find_repository_in_vector(&user_repositories,
1992                     &repository, ngc_repo_name, (uint32_t)written);
1993                 if ( rc == 0 )
1994                 {
1995                     uint32_t modifications = 0;
1996                     uint32_t notFoundNodes = 0;
1997 
1998                     exists = true;
1999 
2000                     /* test for any changes:
2001                        1. download ticket
2002                        2. enc. key
2003                        3. description
2004 
2005                        mark each bit that differs
2006                     */
2007                     rc = check_for_modifications(repository,
2008                         ngc, &modifications, &notFoundNodes);
2009                     if ( rc == 0 )
2010                     {
2011                         if (notFoundNodes != 0) {
2012                             permissions |= notFoundNodes;
2013                             modifications |= notFoundNodes;
2014                         }
2015 
2016                         /* reject if any modification was not authorized */
2017                         if ( ( modifications & ( modifications ^ permissions ) ) != 0 )
2018                         {
2019                             /* tell what was wrong, set rc */
2020                             * result_flags = modifications & ( modifications ^ permissions );
2021                             rc = RC(rcKFG, rcMgr, rcUpdating,
2022                                 rcConstraint, rcViolated);
2023                         }
2024                         else if ( modifications != 0 )
2025                         {
2026                             /* apply changes - all are authorized */
2027 
2028                             rc = update_existing_protected_repository( self, repository, ngc, modifications );
2029                             if ( rc == 0 )
2030                                 *result_flags |= modifications;
2031                         }
2032                     }
2033                 }
2034             }
2035 
2036             if (! exists) {
2037                 if (permissions & INP_CREATE_REPOSITORY) {
2038                     uint32_t location_len = string_measure (location, NULL);
2039                     rc = create_new_protected_repository(
2040                         self, ngc, location, location_len,
2041                         ngc_repo_name, (uint32_t)written);
2042                     if (rc == 0) {
2043                         *result_flags |= INP_CREATE_REPOSITORY;
2044                     }
2045                 }
2046                 else {
2047                     *result_flags |= INP_CREATE_REPOSITORY;
2048                     rc = RC(rcKFG, rcMgr, rcUpdating, rcConstraint, rcViolated);
2049                 }
2050             }
2051             else {
2052                 if (rc == 0 && permissions & INP_UPDATE_ROOT) {
2053                     uint32_t modifications = 0;
2054                     rc = check_for_root_modification(
2055                         repository, location, &modifications);
2056                     if (rc == 0) {
2057                         if (modifications & INP_UPDATE_ROOT) {
2058                             uint32_t location_len
2059                                 = string_measure(location, NULL);
2060                             rc = KRepositorySetRoot(repository,
2061                                 location, location_len);
2062                             if (rc == 0) {
2063                                 *result_flags |= INP_UPDATE_ROOT;
2064                             }
2065                         }
2066                         else if (modifications != 0) {
2067                             *result_flags |= INP_UPDATE_ROOT;
2068                             rc = RC(rcKFG, rcMgr, rcCreating,
2069                                 rcConstraint, rcViolated);
2070                         }
2071                     }
2072                 }
2073                 if (rc == 0) {
2074                     uint32_t modifications = 0;
2075                     rc = _KRepositoryFixApps(repository, &modifications);
2076                     if (rc == 0 && modifications != 0) {
2077                         *result_flags |= INP_UPDATE_APPS;
2078                     }
2079                 }
2080             }
2081         }
2082 
2083         KRepositoryVectorWhack ( &user_repositories );
2084     }
2085 
2086     return rc;
2087 }
2088 
2089 
2090 LIB_EXPORT
KRepositoryMgrHasRemoteAccess(const KRepositoryMgr * self)2091 bool CC KRepositoryMgrHasRemoteAccess(const KRepositoryMgr *self)
2092 {
2093     bool has = false;
2094 
2095     rc_t rc = 0, r2 = 0;
2096 
2097     uint32_t len = 0;
2098 
2099     KRepositoryVector remote_repositories;
2100     memset(&remote_repositories, 0, sizeof remote_repositories);
2101 
2102     rc = KRepositoryMgrRemoteRepositories(self, &remote_repositories);
2103 
2104     if (rc == 0) {
2105         len = VectorLength(&remote_repositories);
2106     }
2107 
2108     if (rc == 0 && len > 0) {
2109         uint32_t i = 0;
2110         if (! KRepositoryMgrCategoryDisabled(self, krepRemoteCategory)) {
2111             for (i = 0; i < len; ++ i) {
2112                 const KRepository *r = VectorGet(&remote_repositories, i);
2113                 if (r != NULL) {
2114                     if (KRepositoryDisabled(r)) {
2115                         continue;
2116                     }
2117 
2118                     if (KRepositorySubCategory(r)
2119                         != krepProtectedSubCategory)
2120                     {
2121                         has = true;
2122                     }
2123                 }
2124             }
2125         }
2126     }
2127 
2128     r2 = KRepositoryVectorWhack(&remote_repositories);
2129     if (r2 != 0 && rc == 0) {
2130         rc = r2;
2131     }
2132 
2133     if (rc != 0) {
2134         return false;
2135     }
2136 
2137     return has;
2138 }
2139 
KRepositoryFromNgc(const struct KRepository * self)2140 bool KRepositoryFromNgc(const struct KRepository * self) {
2141     if (self == NULL)
2142         return false;
2143     else
2144         return self->fromNgc;
2145 }
2146