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 <klib/rc.h>
28 #include <klib/out.h>
29 #include <klib/container.h>
30 #include <klib/namelist.h>
31 #include <klib/refcount.h>
32 #include <klib/printf.h>
33 #include <kproc/lock.h>
34
35 #include <kfs/directory.h>
36 #include <kfs/file.h>
37 #include <kns/manager.h>
38 #include <kns/http.h>
39 #include <kns/stream.h>
40
41 #include <xfs/path.h>
42
43 #include "schwarzschraube.h"
44 #include "xhttp.h"
45 #include "zehr.h"
46 #include "lockdpt.h"
47
48 #include <sysalloc.h>
49
50 #include <ctype.h>
51 #include <os-native.h>
52 #include <time.h>
53 #include <stdio.h> /* sscanf */
54
55 /*||*\
56 || Lyrics:
57 || That file contains interface to SRA archive at
58 ||
59 || https://sra-download.ncbi.nlm.nih.gov/sra
60 ||
61 || If we will enter 'DRR000001' subdirectory, we will file here :
62 ||
63 || (https://sra-download.ncbi.nlm.nih.gov/srapub/DRR000001/)
64 ||
65 || DRR000001.sra 26-May-2014 07:22 569M
66 ||
67 || So, code could looks little weird, parsing and serving that format
68 ||
69 \*||*/
70
71 /*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*/
72
73 /*)) XFSHttp and XFSHttpEntry and _HttpED ( EntryDepot ) structs are
74 || living here
75 ((*/
76
77 /*))
78 // Status we will use in that module
79 ((*/
80
81 /*)) Forward
82 ((*/
83 struct _HttpHs;
84
85 /*))
86 // EntryDepot this is responsible for sharing HTTP resources
87 ((*/
88 struct _HttpED {
89 BSTree tree;
90 KRefcount refcount;
91 KLock * mutabor;
92
93 struct XFSLockDepot * mutabors;
94 struct _HttpHs * http_hs;
95 };
96
97 /*))
98 // Just a URL base to access entry by relative path.
99 ((*/
100 struct XFSHttp {
101 KRefcount refcount;
102
103 const char * base_url;
104 };
105
106 /*))
107 // Just a URL base to access entry by relative path.
108 ((*/
109 struct XFSHttpEntry {
110 BSTNode node;
111 KRefcount refcount;
112
113 const char * name;
114 const char * url;
115 uint32_t url_hash;
116
117 bool is_folder;
118
119 struct VNamelist * list; /* is null if not a folder */
120 uint64_t size; /* is ZERO if a folder */
121 KTime_t time;
122
123 XFSStatus status;
124 };
125
126 struct XFSHttpReader {
127 KRefcount refcount;
128
129 const struct XFSHttpEntry * entry;
130 };
131
132 /*) Usefuls
133 (*/
134 static const char * _sXFSHttpED_classname = "XFSHttpEntryDepot";
135 static const char * _sXFSHttp_classname = "XFSHttp";
136 static const char * _sXFSHttpEntry_classname = "XFSHttpEntry";
137 static const char * _sXFSHttpReader_classname = "XFSHttpReader";
138
139 /*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*/
140 /* _HttpHs/_HttpHsEn Methods ... */
141 /*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*/
142
143 #define DEFAULT_PIPIRDA_SIZE 64
144
145 struct _HttpHsEn {
146 struct _HttpHsEn * next;
147 struct _HttpHsEn * prev;
148
149 const struct XFSHttpEntry * entry;
150 const struct KFile * file;
151 };
152
153 struct _HttpHs {
154 KLock * mutabor;
155
156 uint32_t size;
157 uint32_t qty;
158
159 struct _HttpHsEn * kopf;
160 struct _HttpHsEn * arse;
161 };
162
163 static
164 rc_t CC
_HttpHsEnMake(struct XFSHttpEntry * Entry,struct _HttpHsEn ** HsEn)165 _HttpHsEnMake ( struct XFSHttpEntry * Entry, struct _HttpHsEn ** HsEn )
166 {
167 struct _HttpHsEn * TheSi = NULL;
168
169 if ( HsEn != NULL ) {
170 * HsEn = NULL;
171 }
172
173 if ( Entry == NULL || HsEn == NULL ) {
174 return XFS_RC ( rcNull );
175 }
176
177 TheSi = calloc ( 1, sizeof ( struct _HttpHsEn ) );
178 if ( TheSi == NULL ) {
179 return XFS_RC ( rcExhausted );
180 }
181
182 TheSi -> entry = Entry;
183
184 * HsEn = TheSi;
185
186 return 0;
187 } /* _HttpHsEnMake () */
188
189 static
190 rc_t CC
_HttpHsEnDispose(struct _HttpHsEn * self)191 _HttpHsEnDispose ( struct _HttpHsEn * self )
192 {
193 if ( self == NULL ) {
194 return 0;
195 }
196
197 if ( self -> file != NULL ) {
198 KFileRelease ( self -> file );
199
200 self -> file = NULL;
201 }
202
203 self -> next = self -> prev = NULL;
204 self -> entry = NULL;
205
206 free ( self );
207
208 return 0;
209 } /* _HttpHsEnDispose () */
210
211 static
212 rc_t CC
_HttpHsEnConnect(struct _HttpHsEn * self)213 _HttpHsEnConnect ( struct _HttpHsEn * self )
214 {
215 rc_t RCt;
216 const struct KNSManager * Manager;
217 const struct KFile * File;
218
219 RCt = 0;
220 Manager = NULL;
221 File = NULL;
222
223 if ( self == NULL ) {
224 return XFS_RC ( rcNull ) ;
225 }
226
227 if ( self -> entry == NULL ) {
228 return XFS_RC ( rcInvalid );
229 }
230
231 if ( self -> entry -> url == NULL ) {
232 return XFS_RC ( rcInvalid );
233 }
234
235 if ( self -> entry -> is_folder ) {
236 return XFS_RC ( rcInvalid );
237 }
238
239 /*)) Not sure about it ((*/
240 if ( self -> file != NULL ) {
241 return 0;
242 }
243
244 /*] Here we are [*/
245 Manager = XFS_KnsManager ();
246 if ( Manager == NULL ) {
247 RCt = XFS_RC ( rcExhausted );
248 }
249 else {
250 RCt = KNSManagerMakeHttpFile (
251 Manager,
252 & File,
253 NULL, /* no open connections */
254 0x01010000,
255 self -> entry -> url
256 );
257 if ( RCt == 0 ) {
258 self -> file = File;
259 }
260 }
261
262 return RCt;
263 } /* _HttpHsEnConnect () */
264
265 static
266 void CC
_HttpHsRemNoLock(struct _HttpHs * self,struct _HttpHsEn * HsEn)267 _HttpHsRemNoLock ( struct _HttpHs * self, struct _HttpHsEn * HsEn )
268 {
269 if ( self == NULL || HsEn == NULL ) {
270 return;
271 }
272
273 if ( HsEn -> prev == NULL ) { /* at the kopf */
274 if ( HsEn -> next == NULL ) {
275 self -> kopf = self -> arse = NULL;
276 }
277 else {
278 self -> kopf = HsEn -> next;
279 self -> kopf -> prev = NULL;
280 }
281 }
282 else {
283 if ( HsEn -> next == NULL ) { /* at the arse */
284 self -> arse = HsEn -> prev;
285 self -> arse -> next = NULL;
286 }
287 else { /* in between */
288 HsEn -> prev -> next = HsEn -> next;
289 HsEn -> next -> prev = HsEn -> prev;
290 }
291 }
292
293 HsEn -> prev = HsEn -> next = NULL;
294
295 self -> qty ++;
296 } /* _HttpHsRemNoLock () */
297
298 static
299 void CC
_HttpHsAddNoLock(struct _HttpHs * self,struct _HttpHsEn * HsEn)300 _HttpHsAddNoLock ( struct _HttpHs * self, struct _HttpHsEn * HsEn )
301 {
302 if ( self == NULL || HsEn == NULL ) {
303 return;
304 }
305
306 /*)) Note, addidng always to head
307 ((*/
308 if ( self -> kopf == NULL ) {
309 HsEn -> next = HsEn -> prev = NULL;
310 self -> kopf = self -> arse = HsEn;
311 }
312 else {
313 self -> kopf -> prev = HsEn;
314 HsEn -> next = self -> kopf;
315 self -> kopf = HsEn;
316 }
317
318 self -> qty ++;
319 } /* _HttpHsAddNoLock () */
320
321 static
322 void CC
_HttpHsMakeSlotNoLock(const struct _HttpHs * self)323 _HttpHsMakeSlotNoLock ( const struct _HttpHs * self )
324 {
325 struct _HttpHsEn * HsEn;
326
327 if ( self == NULL ) {
328 return;
329 }
330
331 if ( self -> arse == NULL ) {
332 return;
333 }
334
335 while ( self -> size <= self -> qty ) {
336 HsEn = self -> arse;
337 if ( HsEn == NULL ) {
338 break;
339 }
340
341 _HttpHsRemNoLock ( ( struct _HttpHs * ) self, HsEn );
342 _HttpHsEnDispose ( HsEn );
343 }
344 } /* _HttpHsMakeSlotNoLock () */
345
346 static
347 struct _HttpHsEn * CC
_HttpHsFindNoLock(const struct _HttpHs * self,const struct XFSHttpEntry * Entry)348 _HttpHsFindNoLock (
349 const struct _HttpHs * self,
350 const struct XFSHttpEntry * Entry
351 )
352 {
353 struct _HttpHsEn * HsEn = NULL;
354
355 if ( self == NULL || Entry == NULL ) {
356 return NULL;
357 }
358
359 HsEn = self -> kopf;
360
361 while ( HsEn != NULL ) {
362 if ( HsEn -> entry == Entry ) {
363 _HttpHsRemNoLock ( ( struct _HttpHs * ) self, HsEn );
364 _HttpHsAddNoLock ( ( struct _HttpHs * ) self, HsEn );
365 return HsEn;
366 }
367
368 HsEn = HsEn -> next;
369 }
370
371 return NULL;
372 } /* _HttpHsFindNoLock () */
373
374 static
375 rc_t CC
_HttpHsMake(uint32_t Size,struct _HttpHs ** Hs)376 _HttpHsMake ( uint32_t Size, struct _HttpHs ** Hs )
377 {
378 rc_t RCt;
379 struct _HttpHs * TheHs;
380
381 RCt = 0;
382 TheHs = NULL;
383
384 if ( Hs == NULL ) {
385 return XFS_RC ( rcNull );
386 }
387 * Hs = NULL;
388
389 TheHs = calloc ( 1, sizeof ( struct _HttpHs ) );
390 if ( TheHs == NULL ) {
391 return XFS_RC ( rcExhausted );
392 }
393
394 RCt = KLockMake ( & ( TheHs -> mutabor ) );
395 if ( RCt == 0 ) {
396 TheHs -> size = Size == 0 ? DEFAULT_PIPIRDA_SIZE : Size ;
397 TheHs -> qty = 0;
398 * Hs = TheHs;
399 }
400 else {
401 free ( TheHs );
402 }
403
404 return RCt;
405 } /* _HttpHsMake () */
406
407 static
408 rc_t CC
_HttpHsDispose(struct _HttpHs * self)409 _HttpHsDispose ( struct _HttpHs * self )
410 {
411 bool AbleToLock;
412 struct _HttpHsEn * HsEn;
413
414 AbleToLock = false;
415 HsEn = NULL;
416
417 if ( self == NULL ) {
418 return 0;
419 }
420
421 if ( self -> mutabor != NULL ) {
422 AbleToLock = KLockAcquire ( self -> mutabor ) == 0;
423 }
424
425 while ( self -> kopf != NULL ) {
426 HsEn = self -> kopf;
427
428 _HttpHsRemNoLock ( ( struct _HttpHs * ) self, HsEn );
429 _HttpHsEnDispose ( HsEn );
430 }
431
432 self -> kopf = self -> arse = NULL;
433 self -> size = self -> qty = 0;
434
435 if ( self -> mutabor != NULL ) {
436 if ( AbleToLock ) {
437 KLockUnlock ( self -> mutabor );
438 }
439 KLockRelease ( self -> mutabor );
440 }
441
442 free ( self );
443
444 return 0;
445 } /* _HttpHsDispose () */
446
447 static
448 rc_t CC
_HttpHsFindOrCreate(const struct _HttpHs * self,const struct XFSHttpEntry * Entry,const struct _HttpHsEn ** HsEn)449 _HttpHsFindOrCreate (
450 const struct _HttpHs * self,
451 const struct XFSHttpEntry * Entry,
452 const struct _HttpHsEn ** HsEn
453 )
454 {
455 rc_t RCt;
456 struct _HttpHsEn * TheSi;
457
458 RCt = 0;
459 TheSi = NULL;
460
461 if ( HsEn != NULL ) {
462 * HsEn = NULL;
463 }
464
465 if ( self == NULL || Entry == NULL || HsEn == NULL ) {
466 return XFS_RC ( rcNull );
467 }
468
469 RCt = KLockAcquire ( self -> mutabor );
470 if ( RCt == 0 ) {
471 /* First we are trying to find appropriate HttpHsEn
472 */
473 TheSi = _HttpHsFindNoLock ( self, Entry );
474 if ( TheSi == NULL ) {
475 RCt = _HttpHsEnMake (
476 ( struct XFSHttpEntry * ) Entry,
477 & TheSi
478 );
479 if ( RCt == 0 ) {
480 _HttpHsMakeSlotNoLock ( self );
481 _HttpHsAddNoLock ( ( struct _HttpHs * ) self, TheSi );
482 }
483 else {
484 TheSi = NULL;
485 _HttpHsEnDispose ( TheSi );
486 }
487 }
488
489 KLockUnlock ( self -> mutabor );
490 }
491
492 if ( RCt == 0 ) {
493 if ( TheSi == NULL ) {
494 RCt = XFS_RC ( rcInvalid );
495 }
496 else {
497 RCt = _HttpHsEnConnect ( TheSi );
498 if ( RCt == 0 ) {
499 * HsEn = TheSi;
500 }
501 }
502 }
503
504 return RCt;
505 } /* _HttpHsFindOrCreate () */
506
507 static
508 rc_t CC
_HttpHsDelete(const struct _HttpHs * self,const struct XFSHttpEntry * Entry)509 _HttpHsDelete (
510 const struct _HttpHs * self,
511 const struct XFSHttpEntry * Entry
512 )
513 {
514 rc_t RCt;
515 struct _HttpHsEn * HsEn;
516
517 RCt = 0;
518 HsEn = NULL;
519
520 if ( self == NULL || Entry == NULL ) {
521 return XFS_RC ( rcNull );
522 }
523
524 RCt = KLockAcquire ( self -> mutabor );
525 if ( RCt == 0 ) {
526 HsEn = _HttpHsFindNoLock ( self, Entry );
527 if ( HsEn != NULL ) {
528 _HttpHsRemNoLock ( ( struct _HttpHs * ) self, HsEn );
529 _HttpHsEnDispose ( HsEn );
530 }
531
532 KLockUnlock ( self -> mutabor );
533 }
534
535 return RCt;
536 } /* _HttpHsDelele () */
537
538 static
539 rc_t CC
_HttpHsGetKFile(const struct _HttpHs * self,const struct XFSHttpEntry * Entry,const struct KFile ** File)540 _HttpHsGetKFile (
541 const struct _HttpHs * self,
542 const struct XFSHttpEntry * Entry,
543 const struct KFile ** File
544 )
545 {
546 rc_t RCt;
547 const struct _HttpHsEn * HsEn;
548
549 RCt = 0;
550 HsEn = NULL;
551
552 RCt = _HttpHsFindOrCreate ( self, Entry, & HsEn );
553 if ( RCt == 0 ) {
554 RCt = KFileAddRef ( HsEn -> file );
555 if ( RCt == 0 ) {
556 * File = HsEn -> file;
557 }
558 }
559
560 return RCt;
561 } /* _HttpHsGetKFile () */
562
563 /*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*/
564 /* _HttpED Methods ... */
565 /*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*/
566
567 static struct _HttpED * _sHttpED = NULL;
568
569 static
570 struct _HttpED * CC
_ED()571 _ED ()
572 {
573 return _sHttpED;
574 } /* _ED () */
575
576 static
577 void CC
_HttpEDWhackCallback(BSTNode * Node,void * unused)578 _HttpEDWhackCallback ( BSTNode * Node, void * unused )
579 {
580 if ( Node != NULL ) {
581 XFSHttpEntryRelease ( ( struct XFSHttpEntry * ) Node );
582 }
583 } /* _HttpEDWhackCallback () */
584
585 static
586 rc_t CC
_HttpEDDisposeImpl(struct _HttpED * self)587 _HttpEDDisposeImpl ( struct _HttpED * self )
588 {
589 rc_t RCt;
590
591 RCt = 0;
592
593 if ( self != NULL ) {
594 BSTreeWhack (
595 & ( self -> tree ),
596 _HttpEDWhackCallback,
597 NULL
598 );
599
600 KRefcountWhack (
601 & ( self -> refcount ),
602 _sXFSHttpED_classname
603 );
604
605 XFSLockDepotDispose ( self -> mutabors );
606 _HttpHsDispose ( self -> http_hs );
607
608 if ( self -> mutabor != NULL ) {
609 KLockRelease ( self -> mutabor );
610 self -> mutabor = NULL;
611 }
612
613 free ( self );
614 }
615
616 return RCt;
617 } /* _HttpEDDisposeImpl () */
618
619 static
620 rc_t CC
_HttpEDMakeImpl(struct _HttpED ** HttpED)621 _HttpEDMakeImpl ( struct _HttpED ** HttpED )
622 {
623 rc_t RCt;
624 struct _HttpED * TheED;
625
626 RCt = 0;
627 TheED = NULL;
628
629 if ( HttpED != NULL ) {
630 * HttpED = NULL;
631 }
632
633 if ( HttpED == NULL ) {
634 return XFS_RC ( rcNull );
635 }
636
637 TheED = calloc ( 1, sizeof ( struct _HttpED ) );
638 if ( TheED == NULL ) {
639 return XFS_RC ( rcExhausted );
640 }
641
642 RCt = XFSLockDepotMake ( 0, & ( TheED -> mutabors ) );
643 if ( RCt == 0 ) {
644
645 RCt = _HttpHsMake ( 0, & ( TheED -> http_hs ) );
646 if ( RCt == 0 ) {
647
648 RCt = KLockMake ( & ( TheED -> mutabor ) );
649 if ( RCt == 0 ) {
650 BSTreeInit ( & ( TheED -> tree ) );
651
652 KRefcountInit (
653 & ( TheED -> refcount ),
654 1,
655 _sXFSHttpED_classname,
656 "_HttpEDMake",
657 "HttpED"
658 );
659
660 * HttpED = TheED;
661 }
662 }
663 }
664
665 if ( RCt != 0 ) {
666 * HttpED = NULL;
667 _HttpEDDisposeImpl ( TheED );
668 }
669
670 return RCt;
671 } /* _HttpEDMakeImpl () */
672
673 static
674 rc_t CC
_HttpEDDispose()675 _HttpEDDispose ()
676 {
677 struct _HttpED * HttpED;
678
679 /* Sorry, there is no any mutex available, so dummy
680 * TODO ... think about global lock ...
681 */
682 HttpED = _sHttpED;
683 _sHttpED = NULL;
684
685 if ( HttpED != NULL ) {
686 _HttpEDDisposeImpl ( HttpED );
687 }
688
689 return 0;
690 } /* _HttpEDDispose () */
691
692 static
693 rc_t CC
_HttpEDMake()694 _HttpEDMake ()
695 {
696 rc_t RCt;
697 struct _HttpED * HttpED;
698
699 RCt = 0;
700 HttpED = NULL;
701
702 if ( _sHttpED == NULL ) {
703
704 RCt = _HttpEDMakeImpl ( & HttpED );
705 if ( RCt == 0 ) {
706 /* Sorry, there is no any mutex available, so dummy
707 * TODO ... think about global lock ...
708 */
709 if ( _sHttpED == NULL ) {
710 _sHttpED = HttpED;
711 }
712 else {
713 _HttpEDDisposeImpl ( HttpED );
714 }
715 }
716 }
717
718 return RCt;
719 } /* _HttpEDMake () */
720
721 static
722 rc_t CC
_HttpEDAddRef()723 _HttpEDAddRef ()
724 {
725 rc_t RCt;
726 struct _HttpED * HttpED;
727
728 RCt = 0;
729 HttpED = _ED ();
730
731 if ( HttpED == NULL ) {
732 RCt = _HttpEDMake ( );
733 if ( RCt == 0 ) {
734 }
735 }
736 else {
737 RCt = KLockAcquire ( HttpED -> mutabor );
738 if ( RCt == 0 ) {
739 switch ( KRefcountAdd ( & ( HttpED -> refcount ), _sXFSHttpED_classname ) ) {
740 case krefOkay :
741 RCt = 0;
742 break;
743 case krefZero :
744 case krefLimit :
745 case krefNegative :
746 RCt = XFS_RC ( rcInvalid );
747 break;
748 default :
749 RCt = XFS_RC ( rcUnknown );
750 break;
751 }
752 KLockUnlock ( HttpED -> mutabor );
753 }
754 }
755
756 return RCt;
757 } /* _HttpEDAddRef () */
758
759 static
760 rc_t CC
_HttpEDRelease()761 _HttpEDRelease ()
762 {
763 rc_t RCt;
764 struct _HttpED * HttpED;
765 bool DisposeED;
766
767 RCt = 0;
768 HttpED = _ED ();
769 DisposeED = false;
770
771 if ( HttpED != NULL ) {
772 RCt = KLockAcquire ( HttpED -> mutabor );
773 if ( RCt == 0 ) {
774 switch ( KRefcountDrop ( & ( HttpED -> refcount ), _sXFSHttpED_classname ) ) {
775 case krefOkay :
776 case krefZero :
777 RCt = 0;
778 break;
779 case krefWhack :
780 RCt = 0;
781 DisposeED = true;
782 break;
783 case krefNegative :
784 RCt = XFS_RC ( rcInvalid );
785 break;
786 default :
787 RCt = XFS_RC ( rcUnknown );
788 break;
789 }
790
791 KLockUnlock ( HttpED -> mutabor );
792 }
793 if ( DisposeED ) {
794 _HttpEDDispose ();
795 };
796 }
797
798 return RCt;
799 } /* _HttpEDRelease () */
800
801 static
802 int64_t CC
_HttpEntryCmpCallback(const void * Item,const BSTNode * Node)803 _HttpEntryCmpCallback ( const void * Item, const BSTNode * Node )
804 {
805 const char * Str1, * Str2;
806
807 Str1 = ( const char * ) Item;
808
809 Str2 = Node == NULL
810 ? NULL
811 : ( ( struct XFSHttpEntry * ) Node ) -> url
812 ;
813 return XFS_StringCompare4BST_ZHR ( Str1, Str2 );
814 } /* _HttpEntryCmpCallback () */
815
816 static
817 rc_t CC
_HttpEDGetNoLock(struct _HttpED * self,const char * Url,const struct XFSHttpEntry ** Entry)818 _HttpEDGetNoLock (
819 struct _HttpED * self,
820 const char * Url,
821 const struct XFSHttpEntry ** Entry
822 )
823 {
824 const struct XFSHttpEntry * RetVal = NULL;
825
826 if ( Entry != NULL ) {
827 * Entry = NULL;
828 }
829
830 if ( self == NULL || Url == NULL || Entry == NULL ) {
831 return XFS_RC ( rcNull );
832 }
833
834 RetVal = ( const struct XFSHttpEntry * ) BSTreeFind (
835 & ( self -> tree ),
836 Url,
837 _HttpEntryCmpCallback
838 );
839
840
841 * Entry = RetVal;
842
843 return 0;
844 } /* _HttpEDGetNoLock () */
845
846 static
847 rc_t CC
_HttpEDGet(const char * Url,const struct XFSHttpEntry ** Entry)848 _HttpEDGet ( const char * Url, const struct XFSHttpEntry ** Entry )
849 {
850 rc_t RCt;
851 struct _HttpED * ED;
852
853 RCt = 0;
854 ED = _ED ();
855
856 if ( ED == NULL ) {
857 return XFS_RC ( rcInvalid );
858 }
859
860 RCt = KLockAcquire ( ED -> mutabor );
861 if ( RCt == 0 ) {
862 RCt = _HttpEDGetNoLock ( ED, Url, Entry );
863
864 KLockUnlock ( ED -> mutabor );
865 }
866
867 return RCt;
868 } /* _HttpEDGet () */
869
870 static
871 int64_t CC
_HttpEntryAddCallback(const BSTNode * N1,const BSTNode * N2)872 _HttpEntryAddCallback ( const BSTNode * N1, const BSTNode * N2 )
873 {
874 return XFS_StringCompare4BST_ZHR (
875 ( ( struct XFSHttpEntry * ) N1 ) -> url,
876 ( ( struct XFSHttpEntry * ) N2 ) -> url
877 );
878 } /* _HttpEntryAddCallback () */
879
880 static
881 rc_t CC
_HttpEDAddNoLock(struct _HttpED * self,const char * Url,const struct XFSHttpEntry * Entry)882 _HttpEDAddNoLock (
883 struct _HttpED * self,
884 const char * Url,
885 const struct XFSHttpEntry * Entry
886 )
887 {
888 rc_t RCt;
889 const struct XFSHttpEntry * TheEntry;
890
891 RCt = 0;
892 TheEntry = NULL;
893
894 if ( self == NULL || Url == NULL || Entry == NULL ) {
895 return XFS_RC ( rcNull );
896 }
897
898 RCt = _HttpEDGetNoLock ( self, Url, & TheEntry );
899 if ( RCt == 0 ) {
900 if ( TheEntry == NULL ) {
901 RCt = XFSHttpEntryAddRef ( Entry );
902 if ( RCt == 0 ) {
903 RCt = BSTreeInsert (
904 & ( self -> tree ),
905 ( struct BSTNode * ) & ( Entry -> node ),
906 _HttpEntryAddCallback
907 );
908 if ( RCt != 0 ) {
909 XFSHttpEntryRelease ( Entry );
910 }
911 }
912 }
913 }
914
915 return RCt;
916 } /* _HttpEDAddNoLock () */
917
918 static
919 rc_t CC
_HttpEDAdd(const struct XFSHttpEntry * Entry)920 _HttpEDAdd ( const struct XFSHttpEntry * Entry )
921 {
922 rc_t RCt;
923 struct _HttpED * ED;
924
925 RCt = 0;
926 ED = _ED ();
927
928 if ( ED == NULL ) {
929 return XFS_RC ( rcInvalid );
930 }
931
932 RCt = KLockAcquire ( ED -> mutabor );
933 if ( RCt == 0 ) {
934 RCt = _HttpEDAddNoLock ( ED, Entry -> url, Entry );
935
936 KLockUnlock ( ED -> mutabor );
937 }
938 return RCt;
939 } /* _HttpEDAdd () */
940
941 #ifdef NOT_NEED_YET
942 static
943 rc_t CC
_HttpEDDelNoLock(struct _HttpED * self,const char * Url)944 _HttpEDDelNoLock ( struct _HttpED * self, const char * Url )
945 {
946 rc_t RCt;
947 const struct XFSHttpEntry * Entry;
948 bool DelSucc;
949
950 RCt = 0;
951 Entry = NULL;
952 DelSucc = false;
953
954 if ( self == NULL ) {
955 return XFS_RC ( rcNull );
956 }
957
958 RCt = _HttpEDGetNoLock ( self, Url, & Entry );
959 if ( RCt == 0 ) {
960 if ( Entry != NULL ) {
961 DelSucc = BSTreeUnlink (
962 & ( self -> tree ),
963 ( struct BSTNode * ) & ( Entry -> node )
964 );
965 if ( DelSucc ) {
966 _HttpHsDelete ( self -> http_hs, Entry );
967 XFSHttpEntryRelease ( Entry );
968 }
969 }
970 }
971
972 return RCt;
973 } /* _HttpEDDelNoLock () */
974
975 static
976 rc_t CC
_HttpEDDel(const char * Url)977 _HttpEDDel ( const char * Url )
978 {
979 rc_t RCt;
980 struct _HttpED * ED;
981
982 RCt = 0;
983 ED = _ED ();
984
985 if ( ED == NULL ) {
986 return XFS_RC ( rcInvalid );
987 }
988
989 RCt = KLockAcquire ( ED -> mutabor );
990 if ( RCt == 0 ) {
991 RCt = _HttpEDDelNoLock ( ED, Url );
992
993 KLockUnlock ( ED -> mutabor );
994 }
995
996 return RCt;
997 } /* _HttpEDGet () */
998 #endif /* NOT_NEED_YET */
999
1000 static
1001 rc_t CC
_HttpEDClearNoLock(struct _HttpED * self)1002 _HttpEDClearNoLock ( struct _HttpED * self )
1003 {
1004 if ( self == NULL ) {
1005 return XFS_RC ( rcNull );
1006 }
1007
1008 BSTreeWhack ( & ( self -> tree ), _HttpEDWhackCallback, NULL );
1009 BSTreeInit ( & ( self -> tree ) );
1010
1011 return 0;
1012 } /* _HttpEDClearNoLock () */
1013
1014 static
1015 rc_t CC
_HttpEDClear()1016 _HttpEDClear ()
1017 {
1018 rc_t RCt;
1019 struct _HttpED * ED;
1020
1021 RCt = 0;
1022 ED = _ED ();
1023
1024 if ( ED == NULL ) {
1025 return XFS_RC ( rcInvalid );
1026 }
1027
1028 RCt = KLockAcquire ( ED -> mutabor );
1029 if ( RCt == 0 ) {
1030 RCt = _HttpEDClearNoLock ( ED );
1031
1032 KLockUnlock ( ED -> mutabor );
1033 }
1034
1035 return RCt;
1036 } /* _HttpEDClear () */
1037
1038 static
1039 rc_t CC
_HttpEDLock(uint32_t HashValue)1040 _HttpEDLock ( uint32_t HashValue )
1041 {
1042 struct _HttpED * ED = _ED ();
1043
1044 if ( ED == NULL ) {
1045 return XFS_RC ( rcNull );
1046 }
1047
1048 if ( ED -> mutabors == NULL ) {
1049 return XFS_RC ( rcInvalid );
1050 }
1051
1052 return XFSLockDepotAcquire ( ED -> mutabors, HashValue );
1053 } /* _HttpEDLock () */
1054
1055 static
1056 rc_t CC
_HttpEDUnlock(uint32_t HashValue)1057 _HttpEDUnlock ( uint32_t HashValue )
1058 {
1059 struct _HttpED * ED = _ED ();
1060
1061 if ( ED == NULL ) {
1062 return XFS_RC ( rcNull );
1063 }
1064
1065 if ( ED -> mutabors == NULL ) {
1066 return XFS_RC ( rcInvalid );
1067 }
1068
1069 return XFSLockDepotUnlock ( ED -> mutabors, HashValue );
1070 } /* _HttpEDUnlock () */
1071
1072 static
1073 rc_t CC
_HttpEDGetFileForEntry(const struct XFSHttpEntry * Entry,const struct KFile ** File)1074 _HttpEDGetFileForEntry (
1075 const struct XFSHttpEntry * Entry,
1076 const struct KFile ** File
1077 )
1078 {
1079 struct _HttpED * ED = _ED ();
1080
1081 if ( File != NULL ) {
1082 * File = NULL;
1083 }
1084
1085 if ( ED == NULL ) {
1086 return XFS_RC ( rcNull );
1087 }
1088
1089 if ( ED -> http_hs == NULL ) {
1090 return XFS_RC ( rcInvalid );
1091 }
1092
1093 if ( Entry == NULL || File == NULL ) {
1094 return XFS_RC ( rcNull );
1095 }
1096
1097 return _HttpHsGetKFile ( ED -> http_hs, Entry, File );
1098 } /* _HttpEDHttpHs () */
1099
1100 /*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*/
1101 /* Misk Methods ... */
1102 /*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*/
1103 /*))
1104 // MISKA 1: Will concatenate base_url and Path.
1105 ((*/
1106 static
1107 rc_t CC
_HttpMakeUrlFromPath(const char * BaseUrl,const char * Path,const char ** Url)1108 _HttpMakeUrlFromPath (
1109 const char * BaseUrl,
1110 const char * Path,
1111 const char ** Url
1112 )
1113 {
1114 size_t PathSize, BaseSize, RetSize;
1115 char * RetUrl;
1116
1117 PathSize = BaseSize = RetSize = 0;
1118 RetUrl = NULL;
1119
1120 if ( Url != NULL ) {
1121 * Url = NULL;
1122 }
1123
1124 if ( BaseUrl == NULL || Path == NULL || Url == NULL ) {
1125 return XFS_RC ( rcNull );
1126 }
1127
1128 PathSize = string_size ( Path );
1129 BaseSize = string_size ( BaseUrl );
1130
1131 /* First we are calculating string size with some extra
1132 */
1133 RetSize = PathSize
1134 + 1 /* slash */
1135 + BaseSize
1136 + 1 /* 0 at the end of string */
1137 ;
1138 /* Second we are allocating string
1139 */
1140 RetUrl = calloc ( RetSize, sizeof ( char ) );
1141 if ( RetUrl == NULL ) {
1142 return XFS_RC ( rcExhausted );
1143 }
1144
1145 /* Third we are copying base_url and removing exess of slashes
1146 */
1147 string_copy ( RetUrl, RetSize, BaseUrl, BaseSize );
1148 if ( RetUrl [ BaseSize - 1 ] == '/' ) {
1149 BaseSize --;
1150 RetUrl [ BaseSize ] = 0;
1151 }
1152
1153 /* Fourth, adding trailing slash if it is necessary
1154 */
1155 if ( * Path != '/' ) {
1156 RetUrl [ BaseSize ] = '/';
1157 BaseSize ++;
1158 }
1159
1160 /* Fith we are copying Path
1161 */
1162 string_copy ( RetUrl + BaseSize, RetSize - BaseSize, Path, PathSize );
1163
1164 * Url = RetUrl;
1165
1166 return 0;
1167 } /* _HttpMakeUrlFromPath () */
1168
1169 /*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*/
1170 /* XFSHttpEntry Make/Dispose Methods ... */
1171 /*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*/
1172 static rc_t CC _HttpEntryDispose ( struct XFSHttpEntry * self );
1173
1174 static
1175 rc_t CC
_HttpCreateEntry(const char * BaseUrl,const char * Path,bool IsFolder,uint64_t Size,KTime_t Time,struct XFSHttpEntry ** Entry)1176 _HttpCreateEntry (
1177 const char * BaseUrl,
1178 const char * Path,
1179 bool IsFolder,
1180 uint64_t Size,
1181 KTime_t Time,
1182 struct XFSHttpEntry ** Entry
1183 )
1184 {
1185 rc_t RCt;
1186 struct XFSHttpEntry * RetEntry;
1187 size_t PathSize;
1188
1189 RCt = 0;
1190 RetEntry = NULL;
1191 PathSize = 0;
1192
1193 if ( Entry != NULL ) {
1194 * Entry = NULL;
1195 }
1196
1197 if ( BaseUrl == NULL || Path == NULL || Entry == NULL ) {
1198 return XFS_RC ( rcNull );
1199 }
1200 PathSize = string_size ( Path );
1201 if ( PathSize == 0 ) {
1202 return XFS_RC ( rcInvalid );
1203 }
1204
1205 RetEntry = calloc ( 1, sizeof ( struct XFSHttpEntry ) );
1206 if ( RetEntry == NULL ) {
1207 return XFS_RC ( rcExhausted );
1208 }
1209
1210 RetEntry -> status = kxfsInvalid;
1211
1212 RCt = VNamelistMake ( & ( RetEntry -> list ), 128 );
1213 if ( RCt == 0 ) {
1214 RCt = _HttpMakeUrlFromPath ( BaseUrl, Path, & ( RetEntry -> url ) );
1215 if ( RCt == 0 ) {
1216 RCt = XFS_NameFromPath_ZHR ( Path, & ( RetEntry -> name ), false );
1217 if ( RCt == 0 ) {
1218 KRefcountInit (
1219 & ( RetEntry -> refcount ),
1220 1,
1221 _sXFSHttpEntry_classname,
1222 "_HttpCreateEntry",
1223 "HttpEntry"
1224 );
1225 RetEntry -> is_folder = IsFolder;
1226 RetEntry -> size = IsFolder ? 0 : Size;
1227 RetEntry -> time = Time;
1228 RetEntry -> url_hash = string_hash (
1229 RetEntry -> url,
1230 string_size ( RetEntry -> url )
1231 );
1232 /* Last thing to do, it is Ready, not Complete !!! */
1233 RetEntry -> status = kxfsReady;
1234
1235 * Entry = RetEntry;
1236 }
1237 }
1238 }
1239
1240 if ( RCt != 0 ) {
1241 * Entry = NULL;
1242
1243 if ( RetEntry != NULL ) {
1244 _HttpEntryDispose ( RetEntry );
1245 }
1246 }
1247
1248 return RCt;
1249 } /* _HttpCreateEntry () */
1250
1251 /*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*/
1252 /* XFSHttp Methods ... */
1253 /*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*/
1254 LIB_EXPORT
1255 rc_t CC
XFSHttpMake(const char * BaseUrl,const struct XFSHttp ** TheHttp)1256 XFSHttpMake ( const char * BaseUrl, const struct XFSHttp ** TheHttp )
1257 {
1258 rc_t RCt;
1259 struct XFSHttp * RetHttp;
1260 struct XFSHttpEntry * Entry;
1261 size_t UrlSize;
1262
1263 RCt = 0;
1264 RetHttp = NULL;
1265
1266 if ( TheHttp != NULL ) {
1267 * TheHttp = NULL;
1268 }
1269
1270 if ( TheHttp == NULL || BaseUrl == NULL ) {
1271 return XFS_RC ( rcNull );
1272 }
1273
1274 /* First we should be sure that HttpED is good and trusty
1275 */
1276 RCt = _HttpEDAddRef ();
1277 if ( RCt != 0 ) {
1278 return RCt;
1279 }
1280
1281 RetHttp = calloc ( 1, sizeof ( struct XFSHttp ) );
1282 if ( RetHttp == NULL ) {
1283 return XFS_RC ( rcExhausted );
1284 }
1285
1286 KRefcountInit (
1287 & ( RetHttp -> refcount ),
1288 1,
1289 _sXFSHttp_classname,
1290 "XFSHttpMake",
1291 "Http"
1292 );
1293
1294 RCt = XFS_StrDup ( BaseUrl, & ( RetHttp -> base_url ) );
1295 if ( RCt == 0 ) {
1296 /* Here we are stripping last 'slash' if it is
1297 */
1298 UrlSize = string_size ( RetHttp -> base_url );
1299 while ( 0 < UrlSize ) {
1300 if ( RetHttp -> base_url [ UrlSize - 1 ] == '/' ) {
1301 ( ( char * ) RetHttp -> base_url ) [ UrlSize - 1 ] = 0;
1302 UrlSize --;
1303 }
1304 else {
1305 break;
1306 }
1307 }
1308
1309 RCt = _HttpCreateEntry (
1310 RetHttp -> base_url,
1311 "/",
1312 true,
1313 0,
1314 0,
1315 & Entry
1316 );
1317 if ( RCt == 0 ) {
1318 RCt = _HttpEDAdd ( Entry );
1319
1320 if ( RCt != 0 ) {
1321 _HttpEntryDispose ( Entry );
1322
1323 /* Really it is not error, and something else
1324 * already created that entry
1325 */
1326 RCt = 0;
1327 }
1328 * TheHttp = RetHttp;
1329 }
1330 }
1331
1332 if ( RCt != 0 ) {
1333 * TheHttp = NULL;
1334
1335 XFSHttpDispose ( RetHttp );
1336 }
1337
1338 return RCt;
1339 } /* XFSHttpMake () */
1340
1341 LIB_EXPORT
1342 rc_t CC
XFSHttpDispose(const struct XFSHttp * self)1343 XFSHttpDispose ( const struct XFSHttp * self )
1344 {
1345 struct XFSHttp * Http = ( struct XFSHttp * ) self;
1346
1347 if ( Http != NULL ) {
1348 if ( Http -> base_url != NULL ) {
1349 free ( ( char * ) Http -> base_url );
1350 Http -> base_url = NULL;
1351 }
1352
1353 KRefcountWhack ( & ( Http -> refcount ), _sXFSHttp_classname );
1354
1355 free ( Http );
1356
1357 _HttpEDRelease ();
1358 }
1359
1360 return 0;
1361 } /* XFSHttpDispose () */
1362
1363 LIB_EXPORT
1364 rc_t CC
XFSHttpAddRef(const struct XFSHttp * self)1365 XFSHttpAddRef ( const struct XFSHttp * self )
1366 {
1367 rc_t RCt;
1368 struct XFSHttp * Http;
1369
1370 RCt = 0;
1371 Http = ( struct XFSHttp * ) self;
1372
1373 if ( Http == NULL ) {
1374 return XFS_RC ( rcNull );
1375 }
1376
1377 switch ( KRefcountAdd ( & ( Http -> refcount ), _sXFSHttp_classname ) ) {
1378 case krefOkay :
1379 RCt = 0;
1380 break;
1381 case krefZero :
1382 case krefLimit :
1383 case krefNegative :
1384 RCt = XFS_RC ( rcInvalid );
1385 break;
1386 default :
1387 RCt = XFS_RC ( rcUnknown );
1388 break;
1389 }
1390
1391 return RCt;
1392 } /* XFSHttpAddRef () */
1393
1394 LIB_EXPORT
1395 rc_t CC
XFSHttpRelease(const struct XFSHttp * self)1396 XFSHttpRelease ( const struct XFSHttp * self )
1397 {
1398 rc_t RCt;
1399 struct XFSHttp * Http;
1400
1401 RCt = 0;
1402 Http = ( struct XFSHttp * ) self;
1403
1404 if ( Http == NULL ) {
1405 return XFS_RC ( rcNull );
1406 }
1407
1408 switch ( KRefcountDrop ( & ( Http -> refcount ), _sXFSHttp_classname ) ) {
1409
1410 case krefOkay :
1411 case krefZero :
1412 RCt = 0;
1413 break;
1414 case krefWhack :
1415 RCt = XFSHttpDispose ( ( struct XFSHttp * ) Http );
1416 break;
1417 case krefNegative :
1418 RCt = XFS_RC ( rcInvalid );
1419 break;
1420 default :
1421 RCt = XFS_RC ( rcUnknown );
1422 break;
1423 }
1424
1425 return RCt;
1426 } /* XFSHttpRelease () */
1427
1428 LIB_EXPORT
1429 const char * CC
XFSHttpBaseUrl(const struct XFSHttp * self)1430 XFSHttpBaseUrl ( const struct XFSHttp * self )
1431 {
1432 if ( self != NULL ) {
1433 return self -> base_url;
1434 }
1435 return NULL;
1436 } /* XFSHttpBaseUrl () */
1437
1438 LIB_EXPORT
1439 bool CC
XFSHttpHasEntry(const struct XFSHttp * self,const char * Path)1440 XFSHttpHasEntry ( const struct XFSHttp * self, const char * Path )
1441 {
1442 return XFSHttpGetEntry ( self, Path ) != NULL;
1443 } /* XFSHttpHasEntry () */
1444
1445 LIB_EXPORT
1446 const struct XFSHttpEntry * CC
XFSHttpGetEntry(const struct XFSHttp * self,const char * EntryPath)1447 XFSHttpGetEntry ( const struct XFSHttp * self, const char * EntryPath )
1448 {
1449 rc_t RCt;
1450 const char * Url;
1451 const struct XFSHttpEntry * RetEntry;
1452
1453 RCt = 0;
1454 Url = NULL;
1455 RetEntry = NULL;
1456
1457 if ( self != NULL && EntryPath != NULL ) {
1458 RCt = _HttpMakeUrlFromPath ( self -> base_url, EntryPath, & Url );
1459
1460 if ( RCt == 0 ) {
1461 RCt = _HttpEDGet ( Url, & RetEntry );
1462 if ( RCt != 0 ) {
1463 RetEntry = NULL;
1464 }
1465 free ( ( char * ) Url );
1466 }
1467 }
1468
1469 return RetEntry;
1470 } /* XFSHttpGetEntry () */
1471
1472 static rc_t CC _HttpLoadDirEntry ( const struct XFSHttpEntry * self );
1473
1474 static
1475 rc_t CC
_MakeValidPath(const char * Path,const struct XFSPath ** xPath,uint32_t * xPathQty)1476 _MakeValidPath (
1477 const char * Path,
1478 const struct XFSPath ** xPath,
1479 uint32_t * xPathQty
1480 )
1481 {
1482 rc_t RCt;
1483 char BF [ XFS_SIZE_4096 ];
1484 const char * P;
1485
1486 RCt = 0;
1487 * BF = 0;
1488 P = NULL;
1489
1490 if ( xPath != NULL ) {
1491 * xPath = NULL;
1492 }
1493
1494 if ( xPathQty != NULL ) {
1495 * xPathQty = 0;
1496 }
1497
1498 if ( xPath == NULL || Path == NULL || xPathQty == NULL ) {
1499 return XFS_RC ( rcNull );
1500 }
1501
1502 if ( * Path == '/' ) {
1503 P = Path;
1504 }
1505 else {
1506 * BF = '/';
1507 string_copy_measure ( BF + 1, sizeof ( BF ) - 1, Path );
1508
1509 P = BF;
1510 }
1511
1512 RCt = XFSPathMake ( xPath, true, P );
1513 if ( RCt == 0 ) {
1514 * xPathQty = XFSPathPartCount ( * xPath );
1515 }
1516
1517 return RCt;
1518 } /* _MakeValidPath () */
1519
1520 static
1521 rc_t CC
_HttpOrCreateEntry(const struct XFSHttp * self,const char * Path,const struct XFSHttpEntry ** Entry)1522 _HttpOrCreateEntry (
1523 const struct XFSHttp * self,
1524 const char * Path,
1525 const struct XFSHttpEntry ** Entry
1526 )
1527 {
1528 rc_t RCt;
1529 const struct XFSPath * xPath;
1530 char BF [ XFS_SIZE_1024 ];
1531 uint32_t xQty;
1532 const struct XFSHttpEntry * Parent;
1533 const struct XFSPath * xParent;
1534
1535 RCt = 0;
1536 xPath = NULL;
1537 * BF = 0;
1538 xQty = 0;
1539 Parent = NULL;
1540 xParent = NULL;
1541
1542 if ( Entry != NULL ) {
1543 * Entry = NULL;
1544 }
1545
1546 if ( self == NULL || Path == NULL || Entry == NULL ) {
1547 return XFS_RC ( rcNull );
1548 }
1549
1550 RCt = _MakeValidPath ( Path, & xPath, & xQty );
1551 if ( RCt == 0 ) {
1552 if ( xQty < 2 ) {
1553 /* Not an error ???
1554 RCt = XFS_RC ( rcInvalid );
1555 */
1556 }
1557 else {
1558 /* Path to parent directory */
1559 RCt = XFSPathParent ( xPath, & xParent );
1560 if ( RCt == 0 ) {
1561 /* Trying to get ready one */
1562 Parent = XFSHttpGetEntry ( self, XFSPathGet ( xParent ) );
1563 if ( Parent == NULL ) {
1564 /* Creating new one */
1565 RCt = _HttpCreateEntry (
1566 self -> base_url,
1567 XFSPathGet ( xParent ),
1568 true,
1569 0,
1570 0,
1571 ( struct XFSHttpEntry ** ) & Parent
1572 );
1573 if ( RCt == 0 ) {
1574 RCt = _HttpEDAdd ( Parent );
1575 }
1576 }
1577
1578 if ( RCt == 0 ) {
1579 /* Checking and loading parent entry */
1580 if ( Parent -> status == kxfsReady ) {
1581 RCt = _HttpLoadDirEntry ( Parent );
1582 }
1583
1584 /* Check if we obtained necessary node */
1585 if ( RCt == 0 ) {
1586 Parent = XFSHttpGetEntry ( self, Path );
1587 if ( Parent == NULL ) {
1588 RCt = XFS_RC ( rcNull );
1589 }
1590 else {
1591 * Entry = Parent;
1592 }
1593
1594 }
1595 }
1596
1597 XFSPathRelease ( xParent );
1598 }
1599 }
1600
1601 XFSPathRelease ( xPath );
1602 }
1603
1604 return RCt;
1605 } /* _HttpOrCreateEntry () */
1606
1607 LIB_EXPORT
1608 rc_t CC
XFSHttpGetOrCreateEntry(const struct XFSHttp * self,const char * Path,const struct XFSHttpEntry ** Entry)1609 XFSHttpGetOrCreateEntry (
1610 const struct XFSHttp * self,
1611 const char * Path,
1612 const struct XFSHttpEntry ** Entry
1613 )
1614 {
1615 rc_t RCt;
1616 const struct XFSHttpEntry * TheEntry;
1617
1618 RCt = 0;
1619 TheEntry = NULL;
1620
1621 if ( Entry != NULL ) {
1622 * Entry = NULL;
1623 }
1624
1625 if ( self == NULL || Entry == NULL || Path == NULL ) {
1626 return XFS_RC ( rcNull );
1627 }
1628
1629 TheEntry = XFSHttpGetEntry ( self, Path );
1630 if ( TheEntry != NULL ) {
1631 * Entry = TheEntry;
1632 }
1633 else {
1634 /*)) we should find an parent directory and load it.
1635 || after that we should search throught that directory
1636 ((*/
1637 RCt = _HttpOrCreateEntry ( self, Path , & TheEntry );
1638 if ( RCt == 0 ) {
1639 * Entry = TheEntry;
1640 }
1641 }
1642
1643 return RCt;
1644 } /* XFSHttpGetOrCreateEntry () */
1645
1646 static
1647 rc_t CC
_HttpEntryDispose(struct XFSHttpEntry * self)1648 _HttpEntryDispose ( struct XFSHttpEntry * self )
1649 {
1650 if ( self != NULL ) {
1651 self -> status = kxfsInvalid;
1652
1653 KRefcountWhack (
1654 & ( self -> refcount ),
1655 _sXFSHttpEntry_classname
1656 );
1657 if ( self -> name != NULL ) {
1658 free ( ( char * ) self -> name ) ;
1659 self -> name = NULL;
1660 }
1661 if ( self -> url != NULL ) {
1662 free ( ( char * ) self -> url ) ;
1663 self -> url = NULL;
1664 }
1665 self -> url_hash = 0;
1666 self -> is_folder = false;
1667
1668 if ( self -> list != NULL ) {
1669 VNamelistRelease ( self -> list );
1670 self -> list = NULL;
1671 }
1672
1673 self -> size = 0;
1674 self -> time = 0;
1675
1676 free ( self );
1677 }
1678
1679 return 0;
1680 } /* _HttpEntryDispose () */
1681
1682
1683 /*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*/
1684 /* XFSHttpEntry Methods ... */
1685 /*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*/
1686 LIB_EXPORT
1687 rc_t CC
XFSHttpEntryAddRef(const struct XFSHttpEntry * self)1688 XFSHttpEntryAddRef ( const struct XFSHttpEntry * self )
1689 {
1690 rc_t RCt;
1691
1692 RCt = 0;
1693
1694 if ( self == NULL ) {
1695 return XFS_RC ( rcNull );
1696 }
1697
1698 switch ( KRefcountAdd ( & ( self -> refcount ), _sXFSHttpEntry_classname ) ) {
1699 case krefOkay :
1700 RCt = 0;
1701 break;
1702 case krefZero :
1703 case krefLimit :
1704 case krefNegative :
1705 RCt = XFS_RC ( rcInvalid );
1706 break;
1707 default :
1708 RCt = XFS_RC ( rcUnknown );
1709 break;
1710 }
1711
1712 return RCt;
1713 } /* XFSHttpEntryAddRef () */
1714
1715 LIB_EXPORT
1716 rc_t CC
XFSHttpEntryRelease(const struct XFSHttpEntry * self)1717 XFSHttpEntryRelease ( const struct XFSHttpEntry * self )
1718 {
1719 rc_t RCt;
1720
1721 RCt = 0;
1722
1723 if ( self == NULL ) {
1724 return XFS_RC ( rcNull );
1725 }
1726
1727 switch ( KRefcountDrop ( & ( self -> refcount ), _sXFSHttpEntry_classname ) ) {
1728
1729 case krefOkay :
1730 case krefZero :
1731 RCt = 0;
1732 break;
1733 case krefWhack :
1734 RCt = _HttpEntryDispose ( ( struct XFSHttpEntry * ) self );
1735 break;
1736 case krefNegative :
1737 RCt = XFS_RC ( rcInvalid );
1738 break;
1739 default :
1740 RCt = XFS_RC ( rcUnknown );
1741 break;
1742 }
1743
1744 return RCt;
1745 } /* XFSHttpEntryRelease () */
1746
1747 LIB_EXPORT
1748 bool CC
XFSHttpEntryIsFolder(const struct XFSHttpEntry * self)1749 XFSHttpEntryIsFolder ( const struct XFSHttpEntry * self )
1750 {
1751 return self == NULL ? false : ( self -> is_folder );
1752 } /* XFSHttpEntryIsFolder () */
1753
1754 LIB_EXPORT
1755 const char * CC
XFSHttpEntryName(const struct XFSHttpEntry * self)1756 XFSHttpEntryName ( const struct XFSHttpEntry * self )
1757 {
1758 return self == NULL ? NULL : ( self -> name );
1759 } /* XFSHttpEntryName () */
1760
1761 LIB_EXPORT
1762 const char * CC
XFSHttpEntryUrl(const struct XFSHttpEntry * self)1763 XFSHttpEntryUrl ( const struct XFSHttpEntry * self )
1764 {
1765 return self == NULL ? NULL : ( self -> url );
1766 } /* XFSHttpEntryUrl () */
1767
1768 LIB_EXPORT
1769 uint32_t CC
XFSHttpEntryUrlHash(const struct XFSHttpEntry * self)1770 XFSHttpEntryUrlHash ( const struct XFSHttpEntry * self )
1771 {
1772 return self == NULL ? 0 : ( self -> url_hash );
1773 } /* XFSHttpEntryUrlHash () */
1774
1775 static
1776 rc_t CC
_HttpCheckLoadList(const struct XFSHttpEntry * self)1777 _HttpCheckLoadList ( const struct XFSHttpEntry * self )
1778 {
1779 rc_t RCt;
1780 struct XFSHttpEntry * Entry;
1781
1782 RCt = 0;
1783 Entry = ( struct XFSHttpEntry * ) self;
1784
1785 if ( self == NULL ) {
1786 return XFS_RC ( rcNull );
1787 }
1788
1789 if ( self -> is_folder ) {
1790 if ( self -> status == kxfsReady ) {
1791 RCt = _HttpLoadDirEntry ( self );
1792
1793 Entry -> status = ( RCt == 0 ? kxfsComplete : kxfsBroken );
1794 }
1795 }
1796
1797 if ( self -> status != kxfsComplete
1798 && self -> status != kxfsReady ) {
1799 RCt = XFS_RC ( rcInvalid );
1800 }
1801
1802 return RCt;
1803 } /* _HttpCheckLoadList () */
1804
1805 LIB_EXPORT
1806 rc_t CC
XFSHttpEntryList(const struct XFSHttpEntry * self,struct KNamelist ** List)1807 XFSHttpEntryList (
1808 const struct XFSHttpEntry * self,
1809 struct KNamelist ** List
1810 )
1811 {
1812 rc_t RCt;
1813
1814 RCt = 0;
1815
1816 if ( List != NULL ) {
1817 * List = NULL;
1818 }
1819
1820 if ( self == NULL || List == NULL ) {
1821 return XFS_RC ( rcNull );
1822 }
1823
1824 if ( ! self -> is_folder ) {
1825 return XFS_RC ( rcInvalid );
1826 }
1827
1828 RCt = _HttpCheckLoadList ( self );
1829 if ( RCt == 0 ) {
1830 /* TODO : think where to keep empty list ?
1831 */
1832 RCt = VNamelistToNamelist ( self -> list, List );
1833 }
1834
1835 return RCt;
1836 } /* XFSHttpEntryList () */
1837
1838 LIB_EXPORT
1839 rc_t CC
XFSHttpEntrySize(const struct XFSHttpEntry * self,uint64_t * Size)1840 XFSHttpEntrySize ( const struct XFSHttpEntry * self, uint64_t * Size )
1841 {
1842 if ( Size != NULL ) {
1843 * Size = 0;
1844 }
1845
1846 if ( self == NULL || Size == NULL ) {
1847 return XFS_RC ( rcNull );
1848 }
1849
1850 * Size = self -> size;
1851
1852 return 0;
1853 } /* XFSHttpEntrySize () */
1854
1855 LIB_EXPORT
1856 rc_t CC
XFSHttpEntryTime(const struct XFSHttpEntry * self,KTime_t * Time)1857 XFSHttpEntryTime ( const struct XFSHttpEntry * self, KTime_t * Time )
1858 {
1859 if ( Time != NULL ) {
1860 * Time = 0;
1861 }
1862
1863 if ( self == NULL || Time == NULL ) {
1864 return XFS_RC ( rcNull );
1865 }
1866
1867 * Time = self -> time;
1868
1869 return 0;
1870 } /* XFSHttpEntryTime () */
1871
1872 LIB_EXPORT
1873 bool CC
XFSHttpEntryGood(const struct XFSHttpEntry * self)1874 XFSHttpEntryGood ( const struct XFSHttpEntry * self )
1875 {
1876 if ( self != NULL ) {
1877 return self -> status == kxfsReady
1878 || self -> status == kxfsComplete;
1879 }
1880 return false;
1881 } /* XFSHttpEntryGood () */
1882
1883 LIB_EXPORT
1884 bool CC
XFSHttpEntryHas(const struct XFSHttpEntry * self,const char * ChildName)1885 XFSHttpEntryHas (
1886 const struct XFSHttpEntry * self,
1887 const char * ChildName
1888 )
1889 {
1890 rc_t RCt;
1891 uint32_t Cnt, llp;
1892 const char * Name;
1893 size_t CSz, NSz;
1894
1895 RCt = 0;
1896 Cnt = llp = 0;
1897 Name = NULL;
1898 CSz = NSz = 0;
1899
1900 if ( self != NULL && ChildName != NULL ) {
1901 CSz = string_size ( ChildName );
1902
1903 if ( self -> list != NULL ) {
1904 RCt = VNameListCount ( self -> list, & Cnt );
1905 if ( RCt == 0 ) {
1906 for ( llp = 0; llp < Cnt; llp ++ ) {
1907 RCt = VNameListGet ( self -> list, llp, & Name );
1908 if ( RCt == 0 ) {
1909 NSz = string_size ( Name );
1910 if ( NSz == CSz ) {
1911 if ( string_cmp ( ChildName, CSz, Name, CSz, CSz ) == 0 ) {
1912 return true;
1913 }
1914 }
1915 }
1916 }
1917 }
1918 }
1919 }
1920 return false;
1921 } /* XFSHttpEntryHas () */
1922
1923 LIB_EXPORT
1924 rc_t CC
XFSHttpEntryGet(const struct XFSHttpEntry * self,const char * ChildName,const struct XFSHttpEntry ** Child)1925 XFSHttpEntryGet (
1926 const struct XFSHttpEntry * self,
1927 const char * ChildName,
1928 const struct XFSHttpEntry ** Child
1929 )
1930 {
1931 rc_t RCt;
1932 const char * ChildPath;
1933 const struct XFSHttpEntry * RetChild;
1934
1935 RCt = 0;
1936 ChildPath = NULL;
1937
1938 if ( Child != NULL ) {
1939 * Child = NULL;
1940 }
1941
1942 if ( self == NULL || ChildName == NULL || Child == NULL ) {
1943 return XFS_RC ( rcNull );
1944 }
1945
1946 RCt = _HttpMakeUrlFromPath ( self -> url, ChildName, & ChildPath );
1947 if ( RCt == 0 ) {
1948 RCt = _HttpEDGet ( ChildPath, & RetChild );
1949 if ( RCt == 0 ) {
1950 * Child = RetChild;
1951 }
1952
1953 free ( ( char * ) ChildPath );
1954 ChildPath = NULL;
1955 }
1956
1957 return RCt;
1958 } /* XFSHttpEntryGet () */
1959
1960 /*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*/
1961
1962 LIB_EXPORT
1963 rc_t CC
XFSHttpRehash()1964 XFSHttpRehash ()
1965 {
1966 return _HttpEDClear () ;
1967 } /* XFSHttpRehash () */
1968
1969 /*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*/
1970
1971 /*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*/
1972 /* XFSHttpReader Methods ... */
1973 /*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*_*/
1974 LIB_EXPORT
1975 rc_t CC
XFSHttpReaderMake(const struct XFSHttpEntry * Entry,const struct XFSHttpReader ** Reader)1976 XFSHttpReaderMake (
1977 const struct XFSHttpEntry * Entry,
1978 const struct XFSHttpReader ** Reader
1979 )
1980 {
1981 rc_t RCt;
1982 struct XFSHttpReader * RetReader;
1983
1984 RCt = 0;
1985 RetReader = NULL;
1986
1987 if ( Reader != NULL ) {
1988 * Reader = NULL;
1989 }
1990
1991 if ( Entry == NULL || Reader == NULL ) {
1992 return XFS_RC ( rcNull );
1993 }
1994
1995 RetReader = calloc ( 1, sizeof ( struct XFSHttpReader ) );
1996 if ( RetReader == NULL ) {
1997 return XFS_RC ( rcExhausted );
1998 }
1999
2000 RCt = XFSHttpEntryAddRef ( Entry );
2001 if ( RCt == 0 ) {
2002 RetReader -> entry = Entry;
2003
2004 KRefcountInit (
2005 & ( RetReader -> refcount ),
2006 1,
2007 _sXFSHttpReader_classname,
2008 "XFSHttpReaderMake",
2009 "HttpReader"
2010 );
2011
2012 * Reader = RetReader;
2013 }
2014 else {
2015 free ( RetReader );
2016 }
2017
2018 return RCt;
2019 } /* XFSHttpReaderMake () */
2020
2021 LIB_EXPORT
2022 rc_t CC
XFSHttpReaderAddRef(const struct XFSHttpReader * self)2023 XFSHttpReaderAddRef ( const struct XFSHttpReader * self )
2024 {
2025 rc_t RCt;
2026 struct XFSHttpReader * Reader;
2027 uint32_t hash;
2028
2029 RCt = 0;
2030 Reader = ( struct XFSHttpReader * ) self;
2031 hash = 0;
2032
2033 if ( Reader == NULL ) {
2034 return XFS_RC ( rcNull );
2035 }
2036
2037 if ( Reader -> entry == NULL ) {
2038 return XFS_RC ( rcInvalid );
2039 }
2040
2041 hash = Reader -> entry -> url_hash;
2042 RCt = _HttpEDLock ( hash );
2043 if ( RCt == 0 ) {
2044 switch ( KRefcountAdd ( & ( Reader -> refcount ), _sXFSHttpReader_classname ) ) {
2045 case krefOkay :
2046 RCt = 0;
2047 break;
2048 case krefZero :
2049 case krefLimit :
2050 case krefNegative :
2051 RCt = XFS_RC ( rcInvalid );
2052 break;
2053 default :
2054 RCt = XFS_RC ( rcUnknown );
2055 break;
2056 }
2057
2058 RCt = _HttpEDUnlock ( hash );
2059 }
2060
2061 return RCt;
2062 } /* XFSHttpReaderAddRef () */
2063
2064 static
2065 rc_t CC
_HttpReaderDispose(const struct XFSHttpReader * self)2066 _HttpReaderDispose ( const struct XFSHttpReader * self )
2067 {
2068 struct XFSHttpReader * Reader;
2069
2070 Reader = ( struct XFSHttpReader * ) self;
2071
2072 if ( Reader == NULL ) {
2073 return 0;
2074 }
2075
2076 /* TODO We are not removing data from queue, it will die itself
2077 */
2078
2079 KRefcountWhack (
2080 & ( Reader -> refcount ),
2081 _sXFSHttpReader_classname
2082 );
2083
2084 if ( Reader -> entry != NULL ) {
2085 _HttpHsDelete ( _ED () -> http_hs, Reader -> entry );
2086
2087 XFSHttpEntryRelease ( Reader -> entry );
2088
2089 Reader -> entry = NULL;
2090 }
2091
2092 free ( Reader );
2093
2094 return 0;
2095 } /* _HttpReaderDispose () */
2096
2097 LIB_EXPORT
2098 rc_t CC
XFSHttpReaderRelease(const struct XFSHttpReader * self)2099 XFSHttpReaderRelease ( const struct XFSHttpReader * self )
2100 {
2101 rc_t RCt;
2102 struct XFSHttpReader * Reader;
2103 uint32_t hash;
2104
2105 RCt = 0;
2106 Reader = ( struct XFSHttpReader * ) self;
2107 hash = 0;
2108
2109 if ( Reader == NULL ) {
2110 return XFS_RC ( rcNull );
2111 }
2112
2113 if ( Reader -> entry == NULL ) {
2114 return XFS_RC ( rcInvalid );
2115 }
2116
2117 hash = Reader -> entry -> url_hash;
2118 RCt = _HttpEDLock ( hash );
2119 if ( RCt == 0 ) {
2120 switch ( KRefcountDrop ( & ( Reader -> refcount ), _sXFSHttpReader_classname ) ) {
2121 case krefOkay :
2122 case krefZero :
2123 RCt = 0;
2124 break;
2125 case krefWhack :
2126 RCt = 0;
2127 _HttpReaderDispose ( Reader );
2128 break;
2129 case krefNegative :
2130 RCt = XFS_RC ( rcInvalid );
2131 break;
2132 default :
2133 RCt = XFS_RC ( rcUnknown );
2134 break;
2135 }
2136
2137 RCt = _HttpEDUnlock ( hash );
2138 }
2139
2140 return RCt;
2141 } /* XFSHttpReaderRelease () */
2142
2143 static
2144 rc_t CC
_CheckResoveOpen(const struct XFSHttpEntry * self,const struct KFile ** File)2145 _CheckResoveOpen (
2146 const struct XFSHttpEntry * self,
2147 const struct KFile ** File
2148 )
2149 {
2150 rc_t RCt;
2151 struct XFSHttpEntry * Entry;
2152 const struct KFile * TheFile;
2153 uint64_t Size;
2154
2155 RCt = 0;
2156 Entry = ( struct XFSHttpEntry * ) self;
2157 TheFile = NULL;
2158 Size = 0;
2159
2160 if ( File != NULL ) {
2161 * File = NULL;
2162 }
2163
2164 if ( File == NULL || self == NULL ) {
2165 return XFS_RC ( rcNull );
2166 }
2167
2168 if ( self -> status == kxfsInvalid
2169 || self -> status == kxfsBroken ) {
2170 return XFS_RC ( rcInvalid );
2171 }
2172
2173
2174 RCt = _HttpEDGetFileForEntry ( self, & TheFile );
2175 if ( RCt != 0 ) {
2176 ( ( struct XFSHttpEntry * ) self ) -> status = kxfsBroken;
2177 }
2178 else {
2179 if ( self -> status == kxfsReady ) {
2180 if ( ! self -> is_folder ) {
2181 /* Here we are reading real file size */
2182 RCt = KFileSize ( TheFile, & Size );
2183 if ( RCt == 0 ) {
2184 Entry -> size = Size;
2185 }
2186 else {
2187 RCt = 0; // TODO: not sure about it
2188 }
2189 }
2190 }
2191
2192 ( ( struct XFSHttpEntry * ) self ) -> status = kxfsComplete;
2193 * File = TheFile;
2194 }
2195
2196 return RCt;
2197 } /* _CheckResoveOpen () */
2198
2199
2200 LIB_EXPORT
2201 rc_t CC
XFSHttpReaderRead(const struct XFSHttpReader * self,uint64_t Offset,void * Buffer,size_t BufferSize,size_t * NumRead)2202 XFSHttpReaderRead (
2203 const struct XFSHttpReader * self,
2204 uint64_t Offset,
2205 void * Buffer,
2206 size_t BufferSize,
2207 size_t * NumRead
2208 )
2209 {
2210 rc_t RCt;
2211 const struct KFile * File;
2212
2213 RCt = 0;
2214 File = NULL;
2215
2216 if ( self == NULL || Buffer == NULL || NumRead == NULL ) {
2217 return XFS_RC ( rcNull );
2218 }
2219
2220 if ( BufferSize == 0 ) {
2221 return XFS_RC ( rcInvalid );
2222 }
2223
2224 RCt = _HttpEDLock ( self -> entry -> url_hash );
2225 if ( RCt == 0 ) {
2226
2227 RCt = _CheckResoveOpen ( self -> entry, &File );
2228 if ( RCt == 0 ) {
2229 RCt = KFileRead (
2230 File,
2231 Offset,
2232 Buffer,
2233 BufferSize,
2234 NumRead
2235 );
2236 KFileRelease ( File );
2237 }
2238 _HttpEDUnlock ( self -> entry -> url_hash );
2239 }
2240
2241 return RCt;
2242 } /* XFSHttpReaderRead () */
2243
2244 static
2245 rc_t CC
_HttpMakeBuffer(uint64_t Size,void ** Buffer)2246 _HttpMakeBuffer ( uint64_t Size, void ** Buffer )
2247 {
2248 char * BF;
2249
2250 BF = NULL;
2251
2252 if ( Buffer == NULL ) {
2253 return XFS_RC ( rcNull );
2254 }
2255 * Buffer = NULL;
2256
2257 if ( Size == 0 ) {
2258 return XFS_RC ( rcInvalid );
2259 }
2260
2261 BF = calloc ( ( size_t ) Size, sizeof ( char ) );
2262 if ( BF == NULL ) {
2263 return XFS_RC ( rcExhausted );
2264 }
2265 BF [ Size - 1 ] = 0;
2266
2267 * Buffer = ( void * ) BF;
2268
2269 return 0;
2270 } /* _HttpMakeBuffer () */
2271
2272 /*))
2273 // We do suppose that size of readed data will not exceed 128K
2274 ((*/
2275 #define XFS_MAX_DIR_BUFFER 131072
2276
2277 static
2278 rc_t CC
_xStreamReadAll(const char * Url,void ** Buffer,size_t * NumRead)2279 _xStreamReadAll ( const char * Url, void ** Buffer, size_t * NumRead )
2280 {
2281 rc_t RCt;
2282 const struct XFSHttpStream * Stream;
2283 char * BF;
2284 uint64_t SZ, Off;
2285 size_t NumR;
2286
2287 RCt = 0;
2288 Stream = NULL;
2289 BF = NULL;
2290 SZ = XFS_MAX_DIR_BUFFER;
2291 Off = 0;
2292 NumR = 0;
2293
2294 if ( Buffer != NULL ) {
2295 * Buffer = NULL;
2296 }
2297
2298 if ( NumRead != NULL ) {
2299 * NumRead = 0;
2300 }
2301
2302 if ( Url == NULL || Buffer == NULL || NumRead == NULL ) {
2303 return XFS_RC ( rcNull );
2304 }
2305
2306 RCt = XFS_HttpStreamMake_ZHR ( Url, & Stream );
2307 if ( RCt == 0 ) {
2308 RCt = _HttpMakeBuffer ( SZ, ( void ** ) & BF );
2309 if ( RCt == 0 ) {
2310 while ( ! XFS_HttpStreamCompleted_ZHR ( Stream ) ) {
2311 RCt = XFS_HttpStreamRead_ZHR (
2312 Stream,
2313 BF + Off,
2314 ( size_t ) ( SZ - Off ),
2315 & NumR
2316 );
2317 if ( RCt != 0 ) {
2318 break;
2319 }
2320
2321 if ( NumR != 0 && SZ <= ( Off + NumR ) ) {
2322 RCt = XFS_RC ( rcInvalid );
2323
2324 break;
2325 }
2326
2327 Off += NumR;
2328 NumR = 0;
2329 }
2330
2331 if ( RCt == 0 ) {
2332 * Buffer = BF;
2333 * NumRead = ( size_t ) Off;
2334 }
2335 }
2336
2337 XFS_HttpStreamDispose_ZHR ( Stream );
2338 }
2339
2340 if ( RCt != 0 ) {
2341 * Buffer = NULL;
2342 * NumRead = 0;
2343
2344 if ( BF != NULL ) {
2345 free ( BF );
2346 }
2347 }
2348
2349 return RCt;
2350 } /* _xStreamReadAll () */
2351
2352 struct _BufferLR {
2353 const char * buffer;
2354 size_t length;
2355
2356 size_t line_start;
2357 size_t line_end;
2358 size_t line_no;
2359 };
2360
2361 static
2362 rc_t CC
_BufferLRInit(struct _BufferLR * self,const char * Buffer,size_t Length)2363 _BufferLRInit (
2364 struct _BufferLR * self,
2365 const char * Buffer,
2366 size_t Length
2367 )
2368 {
2369 if ( self == NULL ) {
2370 return XFS_RC ( rcNull );
2371 }
2372
2373 self -> buffer = Buffer;
2374 self -> length = Length;
2375 self -> line_start = 0;
2376 self -> line_end = 0;
2377 self -> line_no = 0;
2378
2379 return 0;
2380 } /* _BufferLRInit () */
2381
2382 static
2383 rc_t CC
_BufferLRWhack(struct _BufferLR * self)2384 _BufferLRWhack ( struct _BufferLR * self )
2385 {
2386 if ( self != NULL ) {
2387 self -> buffer = NULL;
2388 self -> length = 0;
2389 self -> line_start = 0;
2390 self -> line_end = 0;
2391 self -> line_no = 0;
2392 }
2393 return 0;
2394 } /* _BufferLRWhack () */
2395
2396 static
2397 bool CC
_BufferLRNext(struct _BufferLR * self,const char ** NextLine,size_t * Length)2398 _BufferLRNext (
2399 struct _BufferLR * self,
2400 const char ** NextLine,
2401 size_t * Length
2402 )
2403 {
2404 const char * start, * end, * kirdyk;
2405
2406 start = end = kirdyk = NULL;
2407
2408 if ( NextLine != NULL ) {
2409 * NextLine = NULL;
2410 }
2411
2412 if ( Length != NULL ) {
2413 * Length = 0;
2414 }
2415
2416 if ( self == NULL || NextLine == NULL || Length == NULL ) {
2417 return false;
2418 }
2419
2420 /* Line number, just for case */
2421 self -> line_no ++;
2422
2423 kirdyk = self -> buffer + self -> length;
2424 start = self -> buffer + self -> line_start;
2425 end = self -> buffer + self -> line_end;
2426
2427 /* First, we are looking for start of new line */
2428 start = NULL;
2429 while ( end < kirdyk ) {
2430 if ( isalnum ( * end ) || * end == '<' ) {
2431 start = end;
2432 break;
2433 }
2434 end ++;
2435 }
2436 if ( start == NULL ) {
2437 return false;
2438 }
2439
2440 /* Second we are looking for end of new line */
2441 end ++;
2442 while ( end < kirdyk ) {
2443 if ( * end == '\n' ) {
2444 break;
2445 }
2446
2447 end ++;
2448 }
2449
2450 self -> line_start = start - self -> buffer;
2451 self -> line_end = end - self -> buffer;
2452
2453 * NextLine = start;
2454 * Length = end - start;
2455
2456 return true;
2457 } /* _BufferLRNext () */
2458
2459 static
2460 bool CC
_GetAnchor(const char * Start,const char * End,const char ** AncStart,const char ** AncEnd)2461 _GetAnchor (
2462 const char * Start,
2463 const char * End,
2464 const char ** AncStart,
2465 const char ** AncEnd
2466 )
2467 {
2468 const char * AncS, * AncE, * AncP;
2469
2470 AncS = AncE = AncP = NULL;
2471
2472 /* We are looking for "<a href ... </a>" tag */
2473
2474 AncP = Start;
2475 while ( AncP < End ) {
2476 if ( * AncP == '<' ) {
2477 if ( 2 <= ( End - AncP ) ) {
2478 if ( * ( AncP + 1 ) == 'a' && * ( AncP + 2 ) == ' ' ) {
2479 AncS = AncP;
2480 AncP += 8;
2481
2482 break;
2483 }
2484 }
2485 }
2486
2487 AncP ++;
2488 }
2489
2490 if ( AncS == NULL ) {
2491 return false;
2492 }
2493
2494 while ( AncP < End ) {
2495 if ( * AncP == '<' ) {
2496 if ( 3 <= ( End - AncP ) ) {
2497 if ( * ( AncP + 1 ) == '/' && * ( AncP + 2 ) == 'a' && * ( AncP + 3 ) == '>' ) {
2498 AncE = AncP + 4;
2499
2500 break;
2501 }
2502 }
2503 }
2504
2505 AncP ++;
2506 }
2507
2508 if ( AncE == NULL ) {
2509 return false;
2510 }
2511
2512 * AncStart = AncS;
2513 * AncEnd = AncE;
2514
2515 return true;
2516 } /* _GetAnchor () */
2517
2518 static
2519 bool CC
_GetAnchorName(const char * Start,const char * End,char ** Name,bool * IsDir)2520 _GetAnchorName (
2521 const char * Start,
2522 const char * End,
2523 char ** Name,
2524 bool * IsDir
2525 )
2526 {
2527 const char * nS, * nE, * nP;
2528 bool Dir;
2529
2530 nS = nE = nP = NULL;
2531 Dir = false;
2532
2533 * Name = NULL;
2534 * IsDir = false;
2535
2536 nP = Start;
2537 while ( nP < End ) {
2538 if ( * nP == '"' ) {
2539 if ( 1 <= ( End - nP ) ) {
2540 nP ++;
2541 nS = nP;
2542 }
2543 break;
2544 }
2545
2546 nP ++;
2547 }
2548 if ( nS == NULL ) {
2549 return false;
2550 }
2551
2552 while ( nP < End ) {
2553 if ( * nP == '"' ) {
2554 nE = nP;
2555
2556 break;
2557 }
2558
2559 nP ++;
2560 }
2561 if ( nE == NULL ) {
2562 return false;
2563 }
2564
2565 if ( * ( nE - 1 ) == '/' ) {
2566 Dir = true;
2567 nE --;
2568 }
2569
2570 if ( nE == nS ) {
2571 return false;
2572 }
2573
2574 * Name = string_dup ( nS, nE - nS );
2575 * IsDir = Dir;
2576
2577 return * Name != NULL;
2578 } /* _GetAnchorName () */
2579
2580 static
2581 rc_t CC
_GetNameFrom(const char * Start,const char * End,char ** Name,bool * IsDir,const char ** Next)2582 _GetNameFrom (
2583 const char * Start,
2584 const char * End,
2585 char ** Name,
2586 bool * IsDir,
2587 const char ** Next
2588 )
2589 {
2590 char * TheName;
2591 const char * aS, * aE;
2592
2593 TheName = NULL;
2594 aS = aE = NULL;
2595
2596 if ( Name != NULL ) {
2597 * Name = NULL;
2598 }
2599
2600 if ( Next != NULL ) {
2601 * Next = NULL;
2602 }
2603
2604 if ( IsDir != NULL ) {
2605 * IsDir = false;
2606 }
2607
2608 if ( Start == NULL || End == NULL || Name == NULL || Next == NULL || IsDir == NULL ) {
2609 return XFS_RC ( rcNull );
2610 }
2611
2612 if ( ! _GetAnchor ( Start, End, & aS, & aE ) ) {
2613 return XFS_RC ( rcInvalid );
2614 }
2615
2616 if ( ! _GetAnchorName ( aS, aE, & TheName, IsDir ) ) {
2617 return XFS_RC ( rcInvalid );
2618 }
2619
2620 * Name = TheName;
2621 * Next = aE + 1;
2622
2623 return 0;
2624 } /* _GetNameFrom () */
2625
2626 static
2627 rc_t CC
_GetTimeFrom(const char * Start,const char * End,int64_t * Time,const char ** Next)2628 _GetTimeFrom (
2629 const char * Start,
2630 const char * End,
2631 int64_t * Time,
2632 const char ** Next
2633 )
2634 {
2635 static const char * MNT [ 12 ] = {
2636 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
2637 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
2638 };
2639 const char * Pos;
2640 int Day, Year, Hour, Minute, Ret;
2641 char Month [ 8 ];
2642 struct tm Tm;
2643
2644 Pos = NULL;
2645 Day = Year = Hour = Minute = Ret = 0;
2646 * Month = 0;
2647 memset ( & Tm, 0, sizeof ( struct tm ) );
2648
2649 if ( Time != NULL ) {
2650 * Time = 0;
2651 }
2652 if ( Next != NULL ) {
2653 * Next = NULL;
2654 }
2655
2656 if ( Start == NULL || End == NULL || Time == NULL || Next == NULL ) {
2657 return XFS_RC ( rcNull );
2658 }
2659
2660 /* We are parsing format "dd-mmm-YYYY HH:MM"
2661 */
2662 Start = XFS_SkipSpaces_ZHR ( Start, End );
2663 if ( Start == NULL ) {
2664 return XFS_RC ( rcInvalid );
2665 }
2666
2667 Pos = Start + 17;
2668 Pos = XFS_SkipSpaces_ZHR ( Pos, End );
2669
2670 Ret = sscanf (
2671 Start,
2672 "%2d-%3s-%4d %2d:%2d",
2673 & Day,
2674 Month,
2675 & Year,
2676 & Hour,
2677 & Minute
2678 );
2679 if ( Ret != 5 ) {
2680 return XFS_RC ( rcInvalid );
2681 }
2682
2683 for ( Ret = 0; Ret < 12; Ret ++ ) {
2684 if ( strncmp ( MNT [ Ret ], Month, 3 ) == 0 ) {
2685 break;
2686 }
2687 }
2688
2689 if ( Ret == 12 ) {
2690 return XFS_RC ( rcInvalid );
2691 }
2692
2693 Tm . tm_min = Minute;
2694 Tm . tm_hour = Hour;
2695 Tm . tm_year = Year - 1900;
2696 Tm . tm_mon = Ret;
2697 Tm . tm_mday = Day;
2698
2699 * Time = mktime ( & Tm );
2700 * Next = Pos;
2701
2702 return 0;
2703 } /* _GetTimeFrom () */
2704
2705 static
2706 rc_t CC
_GetSizeFrom(const char * Start,const char * End,uint64_t * Size,const char ** Next)2707 _GetSizeFrom (
2708 const char * Start,
2709 const char * End,
2710 uint64_t * Size,
2711 const char ** Next
2712 )
2713 {
2714 const char * Pos;
2715 uint64_t TheSize;
2716 float PP;
2717 int Ret;
2718
2719 Pos = NULL;
2720 TheSize = 0;
2721 PP = 0;
2722 Ret = 0;
2723
2724 if ( Size != NULL ) {
2725 * Size = 0;
2726 }
2727
2728 if ( Next != NULL ) {
2729 * Next = NULL;
2730 }
2731
2732 if ( Start == NULL || End == NULL || Size == NULL || Next == NULL ) {
2733 return XFS_RC ( rcNull );
2734 }
2735
2736 Start = XFS_SkipSpaces_ZHR ( Start, End );
2737 if ( Start == NULL ) {
2738 return XFS_RC ( rcInvalid );
2739 }
2740
2741 Pos = XFS_SkipLetters_ZHR ( Start, End );
2742 if ( Pos == NULL ) {
2743 return XFS_RC ( rcInvalid );
2744 }
2745
2746 Ret = sscanf ( Start, "%f", & PP );
2747 if ( Ret != 1 ) {
2748 return XFS_RC ( rcInvalid );
2749 }
2750
2751 switch ( * ( Pos - 1 ) ) {
2752 case 'K' : TheSize = ( uint64_t ) ( PP * 1024.0 ); break;
2753 case 'M' : TheSize = ( uint64_t ) ( PP * 1048576.0 ); break;
2754 case 'G' : TheSize = ( uint64_t ) ( PP * 1073741824.0 ); break;
2755 default : TheSize = ( uint64_t ) ( PP * 1.0 ); break;
2756 }
2757
2758 * Size = TheSize;
2759 * Next = Pos;
2760
2761 return 0;
2762 } /* _GetSizeFrom () */
2763
2764 /*|
2765 |* Very simple format of line. For file :
2766 *|
2767 |* name dd-MMM-YYYY HH:MM size
2768 *|
2769 |* For directory :
2770 *|
2771 |* name/ dd-MMM-YYYY HH:MM -
2772 *|
2773 |* Bad thing : ther is no method to convert string to time
2774 *|
2775 |*/
2776
2777 static
2778 rc_t CC
_HttpParseLine(const char * Line,size_t Length,char ** Name,uint64_t * Size,int64_t * Time,bool * IsDir)2779 _HttpParseLine (
2780 const char * Line,
2781 size_t Length,
2782 char ** Name,
2783 uint64_t * Size,
2784 int64_t * Time,
2785 bool * IsDir
2786 )
2787 {
2788 rc_t RCt;
2789 const char * start, * end, * pos;
2790 char * TheName;
2791 bool TheIsDir;
2792
2793
2794 RCt = 0;
2795 start = end = pos = NULL;
2796 TheName = NULL;
2797 TheIsDir = false;
2798
2799 if ( Name != NULL ) {
2800 * Name = NULL;
2801 }
2802
2803 if ( Size != NULL ) {
2804 * Size = 0;
2805 }
2806
2807 if ( Time != NULL ) {
2808 * Time = 0;
2809 }
2810
2811 if ( IsDir != NULL ) {
2812 * IsDir = false;
2813 }
2814
2815 if ( Line == NULL || Length == 0 || Name == NULL || Size == NULL || Time == NULL || IsDir == NULL ) {
2816 return XFS_RC ( rcNull );
2817 }
2818
2819 /* first we are extracting Name of entry */
2820 start = Line;
2821 end = start + Length;
2822 RCt = _GetNameFrom ( start, end, & TheName, & TheIsDir, & start );
2823 if ( RCt == 0 ) {
2824
2825 RCt = _GetTimeFrom ( start, end, Time, & start );
2826 if ( RCt == 0 ) {
2827
2828 if ( ! TheIsDir ) {
2829 RCt = _GetSizeFrom ( start, end, Size, & start );
2830 }
2831
2832 }
2833 }
2834
2835 if ( RCt == 0 ) {
2836 * Name = TheName;
2837 * IsDir = TheIsDir;
2838 }
2839 else {
2840 free ( TheName );
2841 }
2842
2843 return RCt;
2844 } /* _HttpParseLine () */
2845
2846 static
2847 rc_t CC
_HttpParseEntry(const struct XFSHttpEntry * self,const char * Line,size_t Length)2848 _HttpParseEntry (
2849 const struct XFSHttpEntry * self,
2850 const char * Line,
2851 size_t Length
2852 )
2853 {
2854 rc_t RCt;
2855 struct XFSHttpEntry * NewEntry;
2856 char * Name;
2857 uint64_t Size;
2858 int64_t Time;
2859 bool IsDir;
2860
2861 RCt = 0;
2862 NewEntry = NULL;
2863 Name = NULL;
2864 Size = 0;
2865 Time = 0;
2866 IsDir = false;
2867
2868 if ( self == NULL || Line == NULL ) {
2869 return XFS_RC ( rcNull );
2870 }
2871
2872 if ( Length == 0 ) {
2873 return XFS_RC ( rcInvalid );
2874 }
2875
2876 RCt = _HttpParseLine (
2877 Line,
2878 Length,
2879 & Name,
2880 & Size,
2881 & Time,
2882 & IsDir
2883 );
2884 if ( RCt == 0 ) {
2885 /*) First we should add name to list of items
2886 (*/
2887 RCt = VNamelistAppend ( self -> list, Name );
2888 if ( RCt == 0 ) {
2889 /*) Second we should add new entry to ED
2890 (*/
2891 RCt = _HttpCreateEntry (
2892 self -> url,
2893 Name,
2894 IsDir,
2895 Size,
2896 Time,
2897 & NewEntry
2898 );
2899 if ( RCt == 0 ) {
2900 RCt = _HttpEDAdd ( NewEntry );
2901 if ( RCt != 0 ) {
2902 _HttpEntryDispose ( NewEntry );
2903 }
2904 }
2905 }
2906
2907 free ( Name );
2908 }
2909
2910 return 0;
2911 } /* _HttpParseEntry () */
2912
2913 static
2914 rc_t CC
_HttpParseFolder(const struct XFSHttpEntry * self,char * Buffer,size_t BufferSize)2915 _HttpParseFolder (
2916 const struct XFSHttpEntry * self,
2917 char * Buffer,
2918 size_t BufferSize
2919 )
2920 {
2921 rc_t RCt;
2922 struct _BufferLR LineReader;
2923 const char * Line;
2924 size_t LineLength;
2925
2926 RCt = 0;
2927 Line = NULL;
2928 LineLength = 0;
2929
2930 RCt = _BufferLRInit ( & LineReader, Buffer, BufferSize );
2931 if ( RCt == 0 ) {
2932 while ( _BufferLRNext ( & LineReader, & Line, & LineLength ) ) {
2933 if ( Line != NULL && LineLength != 0 ) {
2934 RCt = _HttpParseEntry ( self, Line, LineLength );
2935 if ( RCt != 0 ) {
2936 /*) TODO: It is OK, we will report on that only
2937 (*/
2938 RCt = 0;
2939 }
2940 }
2941 }
2942 _BufferLRWhack ( & LineReader );
2943 }
2944
2945 return RCt;
2946 } /* _HttpParseFolder () */
2947
2948 rc_t CC
_HttpLoadDirEntry(const struct XFSHttpEntry * self)2949 _HttpLoadDirEntry ( const struct XFSHttpEntry * self )
2950 {
2951 rc_t RCt;
2952 char * Buffer;
2953 size_t NumRead;
2954
2955 RCt = 0;
2956 Buffer = NULL;
2957 NumRead = 0;
2958
2959 if ( self == NULL ) {
2960 return XFS_RC ( rcNull );
2961 }
2962
2963 RCt = _xStreamReadAll (
2964 self -> url,
2965 ( void ** ) & Buffer,
2966 & NumRead
2967 );
2968 if ( RCt == 0 ) {
2969 if ( Buffer != NULL ) {
2970 RCt = _HttpParseFolder ( self, Buffer, NumRead );
2971 if ( RCt != 0 ) {
2972 /* I am not sure, but I will do it */
2973 RCt = 0;
2974
2975 ( ( struct XFSHttpEntry * ) self ) -> status
2976 = kxfsBroken;
2977 }
2978 else {
2979 ( ( struct XFSHttpEntry * ) self ) -> status
2980 = kxfsComplete;
2981 }
2982
2983 free ( Buffer );
2984 }
2985 }
2986
2987 return RCt;
2988 } /* _HttpLoadDirEntry () */
2989