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/kfg-priv.h> /* KConfigFixMainResolverCgiNode */
28
29 #include <klib/printf.h> /* string_printf */
30 #include <klib/strings.h> /* SDL_CGI */
31
32 #include "util.hpp" // CStdIn
33
34 #include <sstream> // ostringstream
35
36 #include <climits> /* PATH_MAX */
37 #ifndef PATH_MAX
38 #define PATH_MAX 4096
39 #endif
40
41 using std::string;
42
Read(char * buffer,size_t bsize,size_t * num_read)43 rc_t CStdIn::Read(char *buffer, size_t bsize, size_t *num_read) {
44 size_t dummy = 0;
45 if (num_read == NULL) {
46 if (DEBUG) OUTMSG(("<<< Read: num_read == NULL\n"));
47 num_read = &dummy;
48 }
49
50 if (bsize == 0) {
51 *num_read = 0;
52 return 0;
53 }
54
55 rc_t rc = KFileRead(m_Self, m_Pos, buffer, bsize, num_read);
56 if (rc == 0) {
57 m_Pos += *num_read;
58 size_t last = *num_read;
59 if (*num_read >= bsize) {
60 last = bsize - 1;
61 }
62
63 while (true) {
64 buffer[last] = '\0';
65 if (last == 0) {
66 break;
67 }
68 --last;
69 if (buffer[last] != '\n' && buffer[last] != '\r') {
70 break;
71 }
72 --*num_read;
73 }
74 }
75
76 if (DEBUG) OUTMSG(("<<< Read: num_read = %d\n", *num_read));
77
78 return rc;
79 }
80
CanWriteFile(const CString & dir,bool verbose) const81 rc_t CKDirectory::CanWriteFile(const CString &dir, bool verbose) const {
82 bool ok = true;
83 rc_t rc = 0;
84 char path[PATH_MAX] = "";
85 if (verbose) {
86 OUTMSG(("checking whether %S is writable... ", dir.Get()));
87 }
88 for (int i = 0; i < 10000 && rc == 0; ++i) {
89 size_t path_len = 0;
90 rc = string_printf(path, sizeof path, &path_len,
91 "%S/.tmp%d.tmp", dir.Get(), i);
92 if (rc != 0) {
93 break;
94 }
95 assert(path_len <= sizeof path);
96 if (Exists(path)) {
97 KDirectoryRemove(m_Self, false, path);
98 }
99 else {
100 KFile *f = NULL;
101 rc = KDirectoryCreateFile(m_Self,
102 &f, false, m_PrivateAccess, kcmCreate, path);
103 if (rc == 0) {
104 rc = KFileWrite(f, 0, path, path_len, NULL);
105 }
106 RELEASE(KFile, f);
107 const KFile *cf = NULL;
108 if (rc == 0) {
109 rc = KDirectoryOpenFileRead(m_Self, &cf, path);
110 }
111 char buffer[PATH_MAX] = "";
112 size_t num_read = 0;
113 if (rc == 0) {
114 rc = KFileRead(cf, 0, buffer, sizeof buffer, &num_read);
115 }
116 if (rc == 0) {
117 if (path_len != num_read || string_cmp(path,
118 path_len, buffer, num_read, sizeof buffer) != 0)
119 {
120 if (verbose) {
121 OUTMSG(("no\n"));
122 }
123 OUTMSG(("Warning: "
124 "NCBI Home directory is not writable"));
125 ok = false;
126 }
127 }
128 RELEASE(KFile, cf);
129 if (rc == 0) {
130 KDirectoryRemove(m_Self, false, path);
131 }
132 break;
133 }
134 }
135 if (verbose && ok) {
136 if (rc == 0) {
137 OUTMSG(("yes\n"));
138 }
139 else {
140 OUTMSG(("failed\n"));
141 }
142 }
143 return rc;
144 }
145
CheckAccess(const CString & path,bool & updated,bool isPrivate,bool verbose) const146 rc_t CKDirectory::CheckAccess(const CString &path,
147 bool &updated, bool isPrivate, bool verbose) const
148 {
149 updated = false;
150 const String *str = path.Get();
151 if (str == NULL) {
152 return 0;
153 }
154 uint32_t access = 0;
155 if (verbose) {
156 OUTMSG(("checking %S file mode... ", path.Get()));
157 }
158 rc_t rc = KDirectoryAccess(m_Self, &access, str->addr);
159 if (rc != 0) {
160 OUTMSG(("failed\n"));
161 }
162 else {
163 if (verbose) {
164 OUTMSG(("%o\n", access));
165 }
166 if (isPrivate) {
167 if (access != m_PrivateAccess) {
168 uint32_t access = 0777;
169 if (verbose) {
170 OUTMSG(("updating %S to %o... ", str, access));
171 }
172 rc = KDirectorySetAccess(m_Self, false,
173 m_PrivateAccess, access, str->addr);
174 if (rc == 0) {
175 OUTMSG(("ok\n"));
176 updated = true;
177 }
178 else {
179 OUTMSG(("failed\n"));
180 }
181 }
182 }
183 else {
184 if ((access & m_PrivateAccess) != m_PrivateAccess) {
185 uint32_t access = 0700;
186 if (verbose) {
187 OUTMSG(("updating %S to %o... ", str, access));
188 }
189 rc = KDirectorySetAccess(m_Self, false,
190 m_PrivateAccess, access, str->addr);
191 if (rc == 0) {
192 OUTMSG(("ok\n"));
193 updated = true;
194 }
195 else {
196 OUTMSG(("failed\n"));
197 }
198 }
199 }
200 }
201 return rc;
202 }
203
CreateNonExistingDir(bool verbose,uint32_t access,const char * path,va_list args) const204 rc_t CKDirectory::CreateNonExistingDir(bool verbose,
205 uint32_t access, const char *path, va_list args) const
206 {
207 char str[PATH_MAX] = "";
208 rc_t rc = string_vprintf(str, sizeof str, NULL, path, args);
209 if (rc != 0) {
210 OUTMSG(("error: cannot generate path string\n"));
211 return rc;
212 }
213
214 return CreateNonExistingDir(str, access, verbose, true);
215 }
216
CreateNonExistingDir(const string & path,uint32_t access,bool verbose,bool checkExistance) const217 rc_t CKDirectory::CreateNonExistingDir(const string &path,
218 uint32_t access, bool verbose, bool checkExistance) const
219 {
220 const char *str = path.c_str();
221
222 if (checkExistance) {
223 if (verbose) {
224 OUTMSG(("checking whether %s exists... ", str));
225 }
226 if (Exists(str)) {
227 if (verbose) {
228 OUTMSG(("found\n"));
229 }
230 return 0;
231 }
232 }
233
234 if (verbose) {
235 OUTMSG(("creating... "));
236 }
237
238 rc_t rc = KDirectoryCreateDir(m_Self, access,
239 (kcmCreate | kcmParents), str);
240 if (verbose) {
241 if (rc == 0) {
242 OUTMSG(("ok\n"));
243 }
244 else {
245 OUTMSG(("failed\n"));
246 }
247 }
248
249 return rc;
250 }
251
CreateNonExistingDir(const CString & path,uint32_t access,bool verbose) const252 rc_t CKDirectory::CreateNonExistingDir(const CString &path,
253 uint32_t access, bool verbose) const
254 {
255 const String *str = path.Get();
256 if (str == NULL) {
257 return 0;
258 }
259
260 if (verbose) {
261 OUTMSG(("checking whether %S exists... ", str));
262 }
263
264 if (Exists(str->addr)) {
265 if (verbose) {
266 OUTMSG(("found\n"));
267 }
268 return 0;
269 }
270
271 if (verbose) {
272 OUTMSG(("creating... "));
273 }
274
275 rc_t rc = KDirectoryCreateDir(m_Self, access,
276 (kcmCreate | kcmParents), str->addr);
277 if (verbose) {
278 if (rc == 0) {
279 OUTMSG(("ok\n"));
280 }
281 else {
282 OUTMSG(("failed\n"));
283 }
284 }
285
286 return rc;
287 }
288
CKConfig(bool verbose)289 CKConfig::CKConfig(bool verbose)
290 : m_Self(NULL), m_Updated(false)
291 , m_RepositoryRemoteAuxDisabled ("repository/remote/aux/NCBI/disabled")
292 , m_RepositoryRemoteMainDisabled("repository/remote/main/CGI/disabled")
293 , m_RepositoryUserRoot ("repository/user/main/public/root")
294 {
295 if (verbose)
296 OUTMSG(("loading configuration... "));
297 rc_t rc = KConfigMakeLocal(&m_Self, NULL);
298 if (rc == 0) {
299 if (verbose)
300 OUTMSG(("ok\n"));
301 }
302 else {
303 if (verbose)
304 OUTMSG(("failed\n"));
305 throw rc;
306 }
307 }
308
Commit(void)309 rc_t CKConfig::Commit(void)
310 {
311 if (!m_Updated) {
312 return 0;
313 }
314
315 rc_t rc = KConfigCommit(m_Self);
316 if ( rc == 0 )
317 {
318 m_Updated = false;
319 }
320 return rc;
321 }
322
CreateRemoteRepositories(bool fix)323 rc_t CKConfig::CreateRemoteRepositories(bool fix) {
324 bool updated = NodeExists("/repository_remote/CGI/resolver-cgi/trace");
325
326 rc_t rc = 0;
327
328 {
329 const string name("/repository/remote/main/CGI/resolver-cgi");
330 if (!updated || !NodeExists(name)) {
331 rc_t r2 = UpdateNode(name,
332 "https://trace.ncbi.nlm.nih.gov/Traces/names/names.fcgi");
333 if (r2 != 0 && rc == 0)
334 rc = r2;
335 }
336 }
337
338 if (fix) {
339 const string name("/repository/remote/main/CGI/disabled");
340 if (NodeExists(name)) {
341 rc_t r2 = UpdateNode(name.c_str(), "false");
342 if (r2 != 0 && rc == 0) {
343 rc = r2;
344 }
345 }
346 }
347
348 {
349 const string name("/repository/remote/protected/CGI/resolver-cgi");
350 if (!updated || !NodeExists(name)) {
351 rc_t r2 = UpdateNode(name,
352 "https://trace.ncbi.nlm.nih.gov/Traces/names/names.fcgi");
353 if (r2 != 0 && rc == 0)
354 rc = r2;
355 }
356 }
357
358 if (fix) {
359 const string name("/repository/remote/disabled");
360 if (NodeExists(name)) {
361 rc_t r2 = UpdateNode(name.c_str(), "false");
362 if (r2 != 0 && rc == 0) {
363 rc = r2;
364 }
365 }
366 }
367
368 {
369 const string name("/repository/remote/main/SDL.2/resolver-cgi");
370 if (!NodeExists(name)) {
371 rc_t r2 = UpdateNode(name, SDL_CGI);
372 if (r2 != 0 && rc == 0)
373 rc = r2;
374 }
375 }
376
377 {
378 const string name("/repository/remote/protected/SDL.2/resolver-cgi");
379 if (!NodeExists(name)) {
380 rc_t r2 = UpdateNode(name, SDL_CGI);
381 if (r2 != 0 && rc == 0)
382 rc = r2;
383 }
384 }
385
386 return rc;
387 }
388
CreateUserRepository(string repoName,bool fix)389 rc_t CKConfig::CreateUserRepository(string repoName, bool fix) {
390 if (repoName.size() == 0)
391 repoName = "public";
392
393 CString cRoot(ReadString("/repository/user/default-path"));
394
395 string root;
396 if (cRoot.Empty())
397 root = "$(HOME)/ncbi";
398 else
399 root = cRoot.GetString();
400
401 std::ostringstream s;
402 s << "/repository/user/" << (repoName == "public" ? "main" : "protected")
403 << "/" << repoName;
404 string repoNode(s.str());
405 string name(repoNode + "/root");
406
407 rc_t rc = 0;
408 /* create all nodes but root;
409 bool toFix = true;
410 if (fix)
411 toFix = !NodeExists(name);
412 if (toFix)
413 rc = UpdateNode(name, (root + "/public").c_str());
414
415 {
416 rc_t r2 = UpdateNode(repoNode + "/cache-enabled", "true");
417 if (r2 != 0 && rc == 0)
418 rc = r2;
419 } */
420
421 {
422 string name ( repoNode + "/apps/file/volumes/flat" );
423 if ( ! NodeExists ( name ) ) {
424 rc_t r2 = UpdateNode ( name, "files" );
425 if ( r2 != 0 && rc == 0 )
426 rc = r2;
427 }
428 }
429 {
430 string name ( repoNode + "/apps/sra/volumes/sraFlat" );
431 if ( ! NodeExists ( name ) ) {
432 rc_t r2 = UpdateNode ( name, "sra" );
433 if ( r2 != 0 && rc == 0 )
434 rc = r2;
435 }
436 }
437
438 if ( repoName != "public" )
439 return rc;
440
441 {
442 string name(repoNode + "/apps/sraPileup/volumes/withExtFlat");
443 if (!NodeExists(name)) {
444 rc_t r2 = UpdateNode(name, "sra");
445 if (r2 != 0 && rc == 0)
446 rc = r2;
447 }
448 }
449 {
450 string name(repoNode + "/apps/sraRealign/volumes/withExtFlat");
451 if (!NodeExists(name)) {
452 rc_t r2 = UpdateNode(name, "sra");
453 if (r2 != 0 && rc == 0)
454 rc = r2;
455 }
456 }
457 {
458 string name ( repoNode + "/apps/nakmer/volumes/nakmerFlat" );
459 if ( ! NodeExists ( name ) ) {
460 rc_t r2 = UpdateNode ( name, "nannot" );
461 if ( r2 != 0 && rc == 0 )
462 rc = r2;
463 }
464 }
465 {
466 string name ( repoNode + "/apps/nannot/volumes/nannotFlat" );
467 if ( ! NodeExists ( name ) ) {
468 rc_t r2 = UpdateNode ( name, "nannot" );
469 if ( r2 != 0 && rc == 0 )
470 rc = r2;
471 }
472 }
473 {
474 string name ( repoNode + "/apps/refseq/volumes/refseq" );
475 if ( ! NodeExists ( name ) ) {
476 rc_t r2 = UpdateNode ( name, "refseq" );
477 if ( r2 != 0 && rc == 0 )
478 rc = r2;
479 }
480 }
481 {
482 string name ( repoNode + "/apps/wgs/volumes/wgsFlat" );
483 if ( ! NodeExists ( name ) ) {
484 rc_t r2 = UpdateNode ( name, "wgs" );
485 if ( r2 != 0 && rc == 0 )
486 rc = r2;
487 }
488 }
489
490 return rc;
491 }
492
DisableRemoteRepository(bool disable)493 rc_t CKConfig::DisableRemoteRepository(bool disable) {
494 const char *value = disable ? "true" : "false";
495 rc_t rc = UpdateNode(m_RepositoryRemoteMainDisabled, value);
496
497 rc_t r2 = UpdateNode(m_RepositoryRemoteAuxDisabled, value);
498 if (r2 != 0 && rc == 0) {
499 rc = r2;
500 }
501
502 return rc;
503 }
504
IsRemoteRepositoryDisabled(void) const505 bool CKConfig::IsRemoteRepositoryDisabled(void) const {
506 const CString disabled(ReadString(m_RepositoryRemoteMainDisabled));
507
508 if (disabled.Equals("true")) {
509 const CString disabled(ReadString(m_RepositoryRemoteAuxDisabled));
510 return disabled.Equals("true");
511 }
512
513 return false;
514 }
515
NodeExists(const string & path) const516 bool CKConfig::NodeExists(const string &path) const {
517 const KConfigNode *n = OpenNodeRead(path.c_str());
518 if (n == NULL) {
519 return false;
520 }
521 KConfigNodeRelease(n);
522 return true;
523 }
524
OpenNodeRead(const char * path,...) const525 const KConfigNode* CKConfig::OpenNodeRead(const char *path, ...) const {
526 va_list args;
527 va_start(args, path);
528
529 const KConfigNode *node = NULL;
530 rc_t rc = KConfigVOpenNodeRead(m_Self, &node, path, args);
531
532 va_end(args);
533
534 if (rc != 0) {
535 return NULL;
536 }
537
538 return node;
539 }
540
ReadString(const char * path) const541 const String* CKConfig::ReadString(const char *path) const {
542 String *result = NULL;
543 rc_t rc = KConfigReadString(m_Self, path, &result);
544
545 if (rc != 0) {
546 return NULL;
547 }
548 return result;
549 }
550
Reload(bool verbose)551 void CKConfig::Reload(bool verbose) {
552 if (verbose) {
553 OUTMSG(("reloading configuration... "));
554 }
555
556 rc_t rc = KConfigRelease(m_Self);
557 m_Self = NULL;
558
559 if (rc == 0) {
560 rc = KConfigMakeLocal(&m_Self, NULL);
561 }
562
563 if (rc == 0) {
564 if (verbose) {
565 OUTMSG(("ok\n"));
566 }
567 m_Updated = false;
568 }
569 else {
570 if (verbose) {
571 OUTMSG(("failed\n"));
572 }
573 throw rc;
574 }
575 }
576
UpdateNode(const char * path,const char * buffer,bool verbose,size_t size)577 rc_t CKConfig::UpdateNode(const char *path,
578 const char *buffer, bool verbose, size_t size)
579 {
580 if (DEBUG) {
581 OUTMSG(("CKConfig::UpdateNode(%s, %s, %d)\n", path, buffer, size));
582 }
583
584 if (verbose) {
585 OUTMSG(("%s = ... ", path));
586 }
587
588 if (size == (size_t)~0) {
589 size = string_size(buffer);
590 }
591
592 KConfigNode *node = NULL;
593 rc_t rc = KConfigOpenNodeUpdate(m_Self, &node, path);
594 // TODO do not write empty node if node itself is empty
595 if (rc == 0) {
596 rc = KConfigNodeWrite(node, buffer, size);
597 }
598 if (rc == 0) {
599 m_Updated = true;
600 }
601 RELEASE(KConfigNode, node);
602
603 if (rc == 0) {
604 if (verbose) {
605 OUTMSG(("\"%s\"\n", buffer));
606 }
607 }
608 else {
609 if (verbose) {
610 OUTMSG(("failed: %R\n", buffer, rc));
611 }
612 else {
613 OUTMSG(("%s = ... failed: %R\n", path, rc));
614 }
615 }
616
617 return rc;
618 }
619
UpdateUserRepositoryRootPath(const CString & path)620 rc_t CKConfig::UpdateUserRepositoryRootPath(const CString &path) {
621 const String *str = path.Get();
622
623 if (str == NULL) {
624 return 0;
625 }
626 return UpdateUserRepositoryRootPath(str->addr, str->size);
627 }
628
StringRelease(const String * self)629 rc_t StringRelease(const String *self) {
630 free((void*)self);
631 return 0;
632 }
633
Test(void)634 rc_t CSplitter::Test(void) {
635 String s;
636 { StringInit(&s, NULL, 0, 0);
637 CSplitter p(&s);
638 assert(!p.HasNext());
639 }
640 { CONST_STRING(&s, "");
641 CSplitter p(&s);
642 assert(!p.HasNext());
643 }
644 {
645 CONST_STRING(&s, "a");
646 CSplitter p(&s);
647 assert(p.HasNext());
648 assert(p.Next() == "a");
649 assert(!p.HasNext());
650 }
651 {
652 CONST_STRING(&s, "a:");
653 CSplitter p(&s);
654 assert(p.HasNext());
655 assert(p.Next() == "a");
656 assert(!p.HasNext());
657 }
658 {
659 CONST_STRING(&s, "a::");
660 CSplitter p(&s);
661 assert(p.HasNext());
662 assert(p.Next() == "a");
663 assert(!p.HasNext());
664 }
665 {
666 CONST_STRING(&s, "::a::");
667 CSplitter p(&s);
668 assert(p.HasNext());
669 assert(p.Next() == "a");
670 assert(!p.HasNext());
671 }
672 {
673 CONST_STRING(&s, "aa:bbb");
674 CSplitter p(&s);
675 assert(p.HasNext());
676 assert(p.Next() == "aa");
677 assert(p.HasNext());
678 assert(p.Next() == "bbb");
679 assert(!p.HasNext());
680 } return 0;
681 }
682
CUserConfigData(const CUserRepositories & repos,const CString & dflt)683 CUserConfigData::CUserConfigData(const CUserRepositories &repos,
684 const CString &dflt)
685 : m_DefaultRoot(dflt.GetString())
686 , m_CurrentRoot(repos.GetMainPublicRoot())
687 , m_CacheEnabled(repos.IsMainPublicCacheEnabled())
688 {}
689
CreateNonExistingPublicDir(bool verbose,const char * path,...) const690 rc_t CKDirectory::CreateNonExistingPublicDir(bool verbose,
691 const char *path, ...) const
692 {
693 va_list args;
694 va_start(args, path);
695
696 rc_t rc = CreateNonExistingDir(verbose, m_PublicAccess, path, args);
697
698 va_end(args);
699
700 return rc;
701 }
702
IsDirectory(const char * path,...) const703 bool CKDirectory::IsDirectory(const char *path, ...) const {
704 va_list args;
705 va_start(args, path);
706
707 KPathType type = KDirectoryVPathType(m_Self, path, args);
708
709 va_end(args);
710
711 return type == kptDir;
712 }
713
Exists(const CString & path) const714 bool CKDirectory::Exists(const CString &path) const {
715 const String *str = path.Get();
716
717 if (str == NULL) {
718 return false;
719 }
720 return Exists(str->addr);
721 }
722
CheckPublicAccess(const CString & path,bool verbose) const723 rc_t CKDirectory::CheckPublicAccess(const CString &path, bool verbose) const {
724 bool updated = false;
725 return CheckAccess(path, updated, false, verbose);
726 }
727
Canonical(const char * path) const728 std::string CKDirectory::Canonical ( const char * path ) const {
729 char resolved [ PATH_MAX ] = "";
730 rc_t rc =
731 KDirectoryResolvePath ( m_Self, true, resolved, sizeof resolved, path );
732 if ( rc != 0 )
733 return "";
734 size_t size = string_measure ( path, NULL );
735 if ( string_cmp
736 ( path, size, resolved, string_measure ( resolved, NULL ), size ) == 0 )
737 return "";
738 return resolved;
739 }
740
741
UpdateNode(bool verbose,const char * value,const char * name,...)742 rc_t CKConfig::UpdateNode(bool verbose,
743 const char *value, const char *name, ...)
744 {
745 va_list args;
746 va_start(args, name);
747
748 char dst[4096] = "";
749 size_t num_writ = 0;
750 rc_t rc = string_vprintf(dst, sizeof dst, &num_writ, name, args);
751 if (rc == 0) {
752 rc = UpdateNode(dst, value, verbose);
753 }
754
755 va_end(args);
756
757 return rc;
758 }
759
FixResolverCgiNodes(void)760 rc_t CKConfig::FixResolverCgiNodes ( void ) {
761 rc_t rc = KConfigFixMainResolverCgiNode ( m_Self );
762 rc_t r2 = KConfigFixProtectedResolverCgiNode ( m_Self );
763 if ( rc == 0 && r2 == 0 ) {
764 m_Updated = true;
765 } else {
766 if ( rc == 0 ) {
767 rc = r2;
768 }
769 }
770 return rc;
771 }
772
773
CApp(const CKDirectory & dir,const CKConfigNode & rep,const string & root,const string & name)774 CApp::CApp(const CKDirectory &dir, const CKConfigNode &rep,
775 const string &root, const string &name)
776 : m_HasVolume(false)
777 , m_AppVolPath("apps/" + name + "/volumes")
778 {
779 const KConfigNode *vols = rep.OpenNodeRead(m_AppVolPath);
780 KNamelist *typeNames = NULL;
781 rc_t rc = KConfigNodeListChildren(vols, &typeNames);
782 if (rc != 0) {
783 return;
784 }
785 uint32_t count = 0;
786 rc = KNamelistCount(typeNames, &count);
787 if (rc == 0) {
788 for (uint32_t idx = 0; idx < count; ++idx) {
789 const char *typeName = NULL;
790 rc = KNamelistGet(typeNames, idx, &typeName);
791 if (rc != 0) {
792 continue;
793 }
794 const KConfigNode *alg = NULL;
795 rc = KConfigNodeOpenNodeRead(vols, &alg, typeName);
796 if (rc != 0) {
797 continue;
798 }
799 String *volList = NULL;
800 rc = KConfigNodeReadString(alg, &volList);
801 if (rc == 0) {
802 if (volList != NULL && volList->addr != NULL) {
803 m_Volumes[typeName]
804 = CAppVolume(typeName, volList->addr);
805 }
806 CSplitter volArray(volList);
807 while (volArray.HasNext()) {
808 const string vol(volArray.Next());
809 if (dir.IsDirectory("%s/%s", root.c_str(), vol.c_str()))
810 {
811 m_HasVolume = true;
812 break;
813 }
814 }
815 }
816 RELEASE(String, volList);
817 RELEASE(KConfigNode, alg);
818 }
819 }
820 RELEASE(KNamelist, typeNames);
821 RELEASE(KConfigNode, vols);
822 }
823
Update(CKConfig & kfg,string & node,bool verbose)824 rc_t CRepository::Update(CKConfig &kfg, string &node, bool verbose) {
825 char root[4096] = "";
826 rc_t rc = string_printf(root, sizeof root, NULL, "/repository/%s/%s/%s",
827 m_Category.c_str(), m_SubCategory.c_str(), m_Name.c_str());
828 if (rc != 0) {
829 OUTMSG(("ERROR\n"));
830 return rc;
831 }
832
833 if (DEBUG) {
834 OUTMSG(("CRepository::Update: root = %s\n", root));
835 }
836
837 node.assign(root);
838
839 for (CApps::TCI it = m_Apps.begin(); it != m_Apps.end(); ++it) {
840 rc_t r2 = (*it).second->Update(kfg, root, verbose);
841 if (r2 != 0 && rc == 0) {
842 rc = r2;
843 }
844 }
845
846 rc_t r2 = kfg.UpdateNode(verbose, m_Root.c_str(), "%s/root", root);
847 if (r2 != 0 && rc == 0) {
848 rc = r2;
849 }
850
851 return rc;
852 }
853
CRepository(const string & category,const string & type,const string & name,const string & root)854 CRepository::CRepository(const string &category, const string &type,
855 const string &name, const string &root)
856 : m_Disabled(false)
857 , m_Category(category)
858 , m_SubCategory(type)
859 , m_Name(name)
860 , m_Root(root)
861 {}
862
CRepository(const CKDirectory & dir,const CKConfigNode & repo,const string & category,const string & subCategory,const string & name)863 CRepository::CRepository(const CKDirectory &dir, const CKConfigNode &repo,
864 const string &category, const string &subCategory,
865 const string &name)
866 : m_Disabled(false)
867 , m_Category(category)
868 , m_SubCategory(subCategory)
869 , m_Name(name)
870 , m_Root(repo.ReadString("root"))
871 {
872 m_Apps.Update(dir, repo, m_Root, "sra");
873 m_Apps.Update(dir, repo, m_Root, "refseq");
874 string disabled(repo.ReadString("disabled"));
875 if (disabled == "true") {
876 m_Disabled = true;
877 }
878 }
879
Dump(void) const880 string CRepository::Dump(void) const {
881 char node[4096] = "";
882 rc_t rc = string_printf(node, sizeof node, NULL,
883 "/repository/%s/%s/%s", m_Category.c_str(),
884 m_SubCategory.c_str(), m_Name.c_str(), m_Root.c_str());
885 if (rc != 0) {
886 OUTMSG(("ERROR\n"));
887 return "";
888 }
889
890 for (CApps::TCI it = m_Apps.begin(); it != m_Apps.end(); ++it) {
891 (*it).second->Dump(node);
892 }
893
894 if (m_Root.size() > 0) {
895 OUTMSG(("%s/root = \"%s\"\n", node, m_Root.c_str()));
896 }
897
898 return node;
899 }
900
Is(const string & subCategory,const string & name) const901 bool CRepository::Is(const string &subCategory, const string &name)
902 const
903 {
904 if (name.size() <= 0) {
905 return m_SubCategory == subCategory;
906 }
907
908 return m_SubCategory == subCategory && m_Name == name;
909 }
910
GetRoot(const string & stack,char needle)911 string CRemoteRepository::GetRoot(const string &stack, char needle)
912 {
913 if (EndsWith(stack, needle)) {
914 return "";
915 }
916 else {
917 return stack;
918 }
919 }
920
GetCgi(const string & stack,char needle)921 string CRemoteRepository::GetCgi(const string &stack, char needle)
922 {
923 if (EndsWith(stack, needle)) {
924 return stack;
925 }
926 else {
927 return "";
928 }
929 }
930
EndsWith(const string & stack,char needle)931 bool CRemoteRepository::EndsWith(const string &stack, char needle) {
932 if (stack.size() <= 0) {
933 return false;
934 }
935 return stack[stack.size() - 1] == needle;
936 }
937
Fix(CKConfig & kfg,bool disable,bool verbose)938 rc_t CRemoteRepository::Fix(CKConfig &kfg, bool disable, bool verbose) {
939 if (verbose) {
940 OUTMSG(("checking %s %s remote repository\n",
941 GetCategory().c_str(), GetSubCategory().c_str()));
942 }
943
944 Disable(disable);
945
946 if (Is("main")) {
947 m_ResolverCgi
948 = "https://trace.ncbi.nlm.nih.gov/Traces/names/names.fcgi";
949 ClearApps();
950 }
951 else {
952 m_ResolverCgi = "";
953 FixApps();
954 SetRoot("https://ftp-trace.ncbi.nlm.nih.gov/sra");
955 }
956
957 return Update(kfg);
958 }
959
Fix(CKConfig & kfg,const CUserConfigData * data,const string * root)960 rc_t CUserRepository::Fix(CKConfig &kfg,
961 const CUserConfigData *data, const string *root)
962 {
963 Disable(false);
964
965 if (DEBUG) {
966 OUTMSG((__FILE__ " CUserRepository::Fix: data = %d\n", data));
967 }
968
969 if (data != NULL) {
970 m_CacheEnabled = data->GetCacheEnabled();
971 const string root(data->GetCurrentRoot());
972 if (root.size() > 0) {
973 if (DEBUG) {
974 OUTMSG((__FILE__ " CUserRepository::Fix: SetRoot to %s\n",
975 root.c_str()));
976 }
977 SetRoot(root);
978 }
979 }
980 else {
981 m_CacheEnabled = true;
982 assert(root);
983 SetRoot(*root);
984 }
985
986 FixApps();
987
988 return Update(kfg, DEBUG);
989 }
990
Load(const CKConfig & kfg,const CKDirectory & dir)991 rc_t CUserRepositories::Load(const CKConfig &kfg, const CKDirectory &dir) {
992 const string category("main");
993
994 OUTMSG(("loading %s user repository... ", category.c_str()));
995 const KConfigNode *userNode = kfg.OpenNodeRead
996 ("/repository/user/%s", category.c_str());
997 if (userNode == NULL) {
998 OUTMSG(("not found\n"));
999 return 0;
1000 }
1001 const CKConfigNode user(userNode);
1002 KNamelist *userNames = NULL;
1003 rc_t rc = KConfigNodeListChildren(userNode, &userNames);
1004 if (rc != 0) {
1005 OUTMSG(("failed\n"));
1006 }
1007 uint32_t count = 0;
1008 if (rc == 0) {
1009 rc = KNamelistCount(userNames, &count);
1010 }
1011 if (rc != 0) {
1012 OUTMSG(("failed\n"));
1013 }
1014 for (uint32_t idx = 0; idx < count && rc == 0; ++idx) {
1015 const char *userName = NULL;
1016 rc = KNamelistGet(userNames, idx, &userName);
1017 if (rc != 0) {
1018 rc = 0;
1019 continue;
1020 }
1021 OUTMSG(("%s ", userName));
1022 const KConfigNode *userRepo = user.OpenNodeRead(userName);
1023 if (userRepo == NULL) {
1024 continue;
1025 }
1026 CKConfigNode node(userRepo);
1027 push_back(new CUserRepository(dir, node, category, userName));
1028 }
1029 RELEASE(KNamelist, userNames);
1030
1031 if (rc == 0) {
1032 OUTMSG(("ok\n"));
1033 }
1034 else {
1035 OUTMSG(("failed\n"));
1036 }
1037
1038 return rc;
1039 }
1040
FindMainPublic(void) const1041 const CUserRepository *CUserRepositories::FindMainPublic(void) const {
1042 for (TCI it = begin(); it != end(); ++it) {
1043 CUserRepository *r = *it;
1044 assert(r);
1045 if (DEBUG) {
1046 OUTMSG(("MainPublic not found\n"));
1047 }
1048 if (r->Is("main", "public")) {
1049 return r;
1050 }
1051 }
1052
1053 return NULL;
1054 }
1055
MkAppVolumes(const CKDirectory & dir,bool verbose) const1056 rc_t CUserRepositories::MkAppVolumes(const CKDirectory &dir, bool verbose)
1057 const
1058 {
1059 rc_t rc = 0;
1060
1061 for (TCI it = begin(); it != end(); ++it) {
1062 CUserRepository *r = *it;
1063 assert(r);
1064 const string root(r->GetRoot());
1065 if (root.size() <= 0) {
1066 continue;
1067 }
1068
1069 for (CApps::TCI it = r->AppsBegin(); it != r->AppsEnd(); ++it) {
1070 const CApp *a = (*it).second;
1071 assert(a);
1072 //a->Dump("a->Dump");
1073 for (CApp::TCAppVolumesCI it = a->VolumesBegin();
1074 it != a->VolumesEnd(); ++it)
1075 {
1076 const CAppVolume &v((*it).second);
1077 const string path(v.GetPath());
1078 if (path.size() <= 0) {
1079 continue;
1080 }
1081 CSplitter s(path);
1082 while (s.HasNext()) {
1083 rc_t r2 = dir.CreateNonExistingPublicDir
1084 (verbose, "%s/%s", root.c_str(), s.Next().c_str());
1085 if (r2 != 0 && rc == 0) {
1086 rc = r2;
1087 }
1088 }
1089 }
1090 }
1091 }
1092
1093 return rc;
1094 }
1095
Load(const CKConfig & kfg,const CKDirectory & dir)1096 rc_t CRemoteRepositories::Load(const CKConfig &kfg, const CKDirectory &dir) {
1097 rc_t rc = 0;
1098 for (int i = 0; i < 2; ++i) {
1099 string category;
1100 switch (i) {
1101 case 0:
1102 category = "main";
1103 break;
1104 case 1:
1105 category = "aux";
1106 break;
1107 default:
1108 assert(0);
1109 break;
1110 }
1111 OUTMSG(("loading %s remote repository... ", category.c_str()));
1112 const KConfigNode *remoteNode = kfg.OpenNodeRead
1113 ("/repository/remote/%s", category.c_str());
1114 if (remoteNode == NULL) {
1115 OUTMSG(("not found\n"));
1116 continue;
1117 }
1118 const CKConfigNode remote(remoteNode);
1119 KNamelist *remoteNames = NULL;
1120 rc = KConfigNodeListChildren(remoteNode, &remoteNames);
1121 if (rc != 0) {
1122 OUTMSG(("failed\n"));
1123 }
1124 uint32_t count = 0;
1125 if (rc == 0) {
1126 rc = KNamelistCount(remoteNames, &count);
1127 }
1128 if (rc != 0) {
1129 OUTMSG(("failed\n"));
1130 }
1131 for (uint32_t idx = 0; idx < count && rc == 0; ++idx) {
1132 const char *remoteName = NULL;
1133 rc = KNamelistGet(remoteNames, idx, &remoteName);
1134 if (rc != 0) {
1135 rc = 0;
1136 continue;
1137 }
1138 OUTMSG(("%s ", remoteName));
1139 const KConfigNode *remoteRepo = remote.OpenNodeRead(remoteName);
1140 if (remoteRepo == NULL) {
1141 continue;
1142 }
1143 CKConfigNode node(remoteRepo);
1144 push_back(new CRemoteRepository(dir,
1145 node, category, remoteName));
1146 }
1147 RELEASE(KNamelist, remoteNames);
1148 if (rc == 0) {
1149 OUTMSG(("ok\n"));
1150 }
1151 else {
1152 OUTMSG(("failed\n"));
1153 }
1154 }
1155 return rc;
1156 }
1157
Fix(CKConfig & kfg,bool disable,bool verbose)1158 void CRemoteRepositories::Fix(CKConfig &kfg, bool disable, bool verbose) {
1159 CRemoteRepository *main = NULL;
1160 CRemoteRepository *protectd = NULL;
1161
1162 for (TCI it = begin(); it != end(); ++it) {
1163 CRemoteRepository *r = *it;
1164 assert(r);
1165 bool toDisable = disable;
1166 const string category(r->GetCategory());
1167 if (category == "aux") {
1168 continue;
1169 }
1170 else if (category == "main") {
1171 main = r;
1172 }
1173 else if (category == "protected") {
1174 protectd = r;
1175 toDisable = false;
1176 }
1177 r->Fix(kfg, toDisable, verbose);
1178 }
1179
1180 const string cgi
1181 ("https://trace.ncbi.nlm.nih.gov/Traces/names/names.fcgi");
1182 if (main == NULL) {
1183 main = new CRemoteRepository("main", "CGI", cgi);
1184 main->Fix(kfg, disable);
1185 push_back(main);
1186 }
1187
1188 if (protectd == NULL) {
1189 protectd = new CRemoteRepository("protected", "CGI", cgi);
1190 if (verbose) {
1191 OUTMSG(("creating %s %s remote repository\n",
1192 protectd->GetSubCategory().c_str(),
1193 protectd->GetName().c_str()));
1194 }
1195 protectd->Fix(kfg, false);
1196 push_back(protectd);
1197 }
1198 }
1199