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