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, ¬FoundNodes);
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