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 #include <kfs/extern.h>
27 #include "karc-priv.h"
28 #include "toc-priv.h"
29 
30 #include <kfs/arc.h>
31 
32 #include <klib/debug.h>
33 #include <klib/log.h>
34 #include <klib/status.h>
35 #include <klib/out.h>
36 #include <klib/rc.h>
37 #include <klib/container.h>
38 #include <klib/vector.h>
39 #include <klib/pbstree.h>
40 #include <klib/text.h>
41 #include <klib/sort.h>
42 #include <klib/printf.h>
43 #include <klib/klib-priv.h> /* ReportRecordZombieFile */
44 
45 #include <kfs/directory.h>
46 #include <kfs/file.h>
47 #include <kfs/toc.h>
48 #include <kfs/sra.h>
49 #include <kfs/cacheteefile.h>
50 
51 #include <kns/http.h>
52 
53 #include <sysalloc.h>
54 
55 #include <atomic32.h>
56 #include <os-native.h>
57 
58 #include <assert.h>
59 #include <limits.h>
60 #include <stdio.h>
61 #include <stdlib.h>
62 #include <string.h>
63 
64 #include <va_copy.h>
65 
66 /* SHOULD NOT INCLUDE THESE DIRECTLY */
67 #include <fcntl.h>
68 #include <sys/stat.h>
69 
70 const char * get_mode_string (KCreateMode mode);
71 /* defined in dir_test.c */
72 
73 extern const char *gRCModule_str[];
74 extern const char *gRCTarget_str[];
75 extern const char *gRCContext_str[];
76 extern const char *gRCObject_str[];
77 extern const char *gRCState_str[];
78 #define _LOG_RC(level,rc)	PLOGMSG(( level,			\
79 					  "Return Code:: $(M):$(T):$(C):$(O):$(S)", \
80 					  PLOG_5(PLOG_U32(M),PLOG_U32(T),PLOG_U32(C),PLOG_U32(O),PLOG_U32(S)), \
81 					  GetRCModule(rc),		\
82 					  GetRCTarget(rc),		\
83 					  GetRCContext(rc),		\
84 					  GetRCObject(rc),		\
85 					  GetRCState(rc)))
86 #define LOG_RC(level,rc)	PLOGMSG(( level,			\
87 					  "Return Code:: $(M):$(T):$(C):$(O):$(S)", \
88 					  PLOG_5(PLOG_S(M),PLOG_S(T),PLOG_S(C),PLOG_S(O),PLOG_S(S)), \
89 					  gRCModule_str[GetRCModule(rc)], \
90 					  gRCTarget_str[GetRCTarget(rc)], \
91 					  gRCContext_str[GetRCContext(rc)], \
92 					  (GetRCObject(rc)<rcLastTarget_v1_0)? \
93 					  gRCTarget_str[GetRCObject(rc)]: \
94 					  gRCObject_str[1+GetRCObject(rc)-rcLastTarget_v1_0], \
95 					  gRCState_str[GetRCState(rc)]))
96 /* #define LOG_RC(level,rc)	\ */
97 /*     PLOGMSG(( level, "m $(R)",PLOG_S(R),gRCModule_str[GetRCModule(rc)])),	\ */
98 /* 	PLOGMSG(( level, "t $(R)",PLOG_S(R),gRCTarget_str[GetRCTarget(rc)])), \ */
99 /* 	PLOGMSG(( level, "c $(R)",PLOG_S(R),gRCContext_str[GetRCContext(rc)])), \ */
100 /* 	PLOGMSG(( level, "o $(R)",PLOG_S(R),(GetRCObject(rc)<rcLastTarget_v1_0)? \ */
101 /* 		  gRCTarget_str[GetRCObject(rc)]:			\ */
102 /* 		  gRCObject_str[1+GetRCObject(rc)-rcLastTarget_v1_0])), \ */
103 /* 	PLOGMSG(( level, "s $(R)",PLOG_S(R),gRCState_str[GetRCState(rc)])) */
104 
105 
106 #ifdef _DEBUGGING
107 #define FUNC_ENTRY() DBGMSG (DBG_KFS, DBG_FLAG(DBG_KFS_ARCENTRY), ("Enter: %s\n", __func__))
108 #define KFF_DEBUG(msg) DBGMSG (DBG_KFS, DBG_FLAG(DBG_KFS_ARC), msg)
109 #else
110 #define FUNC_ENTRY()
111 #define KFF_DEBUG(msg)
112 #endif
113 
114 
115 /* ----------------------------------------------------------------------
116  *
117  */
118 
119 /* -----
120  * define the specific types to be used in the templatish/inheritancish
121  * definition of vtables and their elements
122  */
123 #define KDIR_IMPL struct KArcDir
124 #define KFILE_IMPL struct KArcFile
125 #include <kfs/impl.h>
126 
127 static rc_t KArcDirResolvePathNode (const KArcDir *self,
128                                     enum RCContext ctx,
129                                     const char *path,
130                                     bool follow_sym_link,
131                                     const KTocEntry ** pnode,
132                                     KTocEntryType * ptype);
133 
134 
135 
136 /* ======================================================================
137  * Defines relevant to the whole compilation unit.
138  */
139 /* arbitrary number that was originially set much much higher than expected needs. */
140 #define	KARC_LINK_RESOLVE_LOOPMAX		(16)
141 
142 /* -----
143  * We use MAX_PATH if it is available but not religiously.  We handle most
144  * buffer over-runs with in the module only truncating paths at the border
145  * of the module where KDirectory doesn't handle path's longer than MAX_PATH
146  */
147 #ifdef MAX_PATH
148 #define	KARC_DEFAULT_PATH_ALLOC			(MAX_PATH)
149 #else
150 #define	KARC_DEFAULT_PATH_ALLOC			(4096)
151 #endif
152 
153 
154 
155 
156 
157 /* ======================================================================
158  * KArcDirIterator
159  *
160  * This very simple iterator steps in order through the nodes of the binary
161  * search tree that is a "directory" in a KToc and thus steps through the
162  * list of elements in a directory.  Only the name is made available at each
163  * step.  That worked better for sysdir than arcdir from where this was
164  * borrowed (it was called SysDirEnum there)
165  *
166  * It is primarily used to build a directory listing.
167  *
168  * This iterator is a once through iterator.  Whack must be called after Init
169  * or a dangling reference is left open.  Init can be called again but only if
170  * Whack was indeed called.
171  *
172  * NOTE:
173  * This class unlike most in the KFS system is built in place and is not
174  * constructed by default allocating memory in the constructor.
175  * This means it can not be truly opaque as the structure of the base struct
176  * has to be exposed so it can be created.
177  */
178 
179 
180 /*--------------------------------------------------------------------------
181  * KArcDirIterator
182  *
183  * a ArcDir directory enumerator/iterator getting the names of elements in
184  * the TOC.
185  *
186  * const KToc *	  toc		a keep alive so the BSTree won't go
187  *					away in the middle
188  * union                  u		A union to allow pointers to base and
189  *					derivative class
190  *					without casting
191  *   const BSTNode * 	  bnp		point to a node as a BSTNode
192  *   const KTocEntry *  tnp		point to a node as a KTocEntry
193  * bool                   isFirst;	upon creation this flag is set to true;
194  *					set to false the first next call
195  */
196 typedef struct KArcDirIterator
197 {
198     const KToc * toc;	        /* a keep alive so the BSTree won't go away in the middle */
199     union
200     {
201         const BSTNode * bnp;	/* point to a node as a BSTNode */
202         const KTocEntry * tnp;	/* point to a node as a KTocEntry */
203     }			u;
204     bool isFirst;	            /* upon creation this flag is set to true
205                                    set to false the first next call */
206 } KArcDirIterator;
207 
208 
209 /* ----------------------------------------------------------------------
210  * KArcDirIteratorWhack
211  * 	The Object destructor
212  * [INOUT] KArcDirIterator *self	Iterator self reference: object oriented in C
213  */
214 static
KArcDirIteratorWhack(KArcDirIterator * self)215 void KArcDirIteratorWhack (KArcDirIterator *self)
216 {
217     KTocRelease ( self -> toc );
218 }
219 
220 
221 /* ----------------------------------------------------------------------
222  * KArcDirIteratorInit
223  *
224  * The object constructor
225  *
226  * [OUT] KArcDirIterator *	self		Iterator self reference: object oriented in C
227  * [IN]  const KArcDir * 	arcdir		A directory that contains beneath it (or as it)
228  *						the directory to be iterated.
229  * [IN]	 const char * 		path		The directory to be iterated as referenced from
230  *						arcdir.
231  *
232  * To iterate arcdir use a path of ".".
233  */
234 static
KArcDirIteratorInit(KArcDirIterator * self,const KArcDir * arcdir,const char * path)235 rc_t KArcDirIteratorInit (KArcDirIterator *self, const KArcDir * arcdir,
236                           const char * path)
237 {
238     const BSTree * 	tree;
239     const KTocEntry * node;
240     const KToc *	toc;
241     KTocEntryType	type;
242     rc_t		rc;
243 
244     /* is self parameter possibly bad? */
245     if (self == NULL)
246         return RC (rcFS, rcDirectory, rcConstructing, rcSelf, rcNull);
247 
248     self->toc = NULL;
249     self->isFirst = true;	/* warning squelcher ? that breaks type opacity */
250     self->u.bnp = NULL;
251 
252     /* is another parameter possibly bad? */
253     if ((path == NULL)||(arcdir == NULL))
254         return RC (rcFS, rcDirectory, rcConstructing, rcParam, rcNull);
255 
256     if (KArcDirGetTOC(arcdir,&toc) != 0)
257         return RC (rcFS, rcDirectory, rcConstructing, rcParam, rcNotFound);
258 
259     self->toc = toc;
260     KTocAddRef(toc);
261 
262     /* get the KTocEntry from which all things are possible */
263     rc = KArcDirResolvePathNode (arcdir, rcConstructing, path, true, &node, &type);
264     if ( rc == 0 )
265     {
266         if ((type == ktocentrytype_dir) || (type == ktocentrytype_hardlink))
267         {
268             rc = KTocEntryGetBSTree (node, &tree);
269             if (rc == 0)
270             {
271                 /* success */
272                 self->u.bnp = BSTreeFirst(tree);
273                 return 0;
274             }
275         }
276         else
277         {
278             rc = RC (rcFS, rcDirectory, rcConstructing, rcParam, rcInvalid);
279         }
280     }
281 
282     /* failure */
283     KTocRelease (self->toc);
284     return rc;
285 }
286 
287 
288 /* ----------------------------------------------------------------------
289  * KArcDirIteratorNext
290  *
291  * Go to the next node (or the first node if the iterator has not been used.
292  *
293  * [RET]   const char * 			The return is the name of the next element
294  * [INOUT] KArcDirIterator *	self		Iterator self reference: object oriented in C
295  */
KArcDirIteratorNext(KArcDirIterator * self)296 static const char * KArcDirIteratorNext (KArcDirIterator *self)
297 {
298     const char * name;
299 
300     assert (self != NULL);
301 
302     /* -----
303      * The initialization put the first node's address into the pointer
304      * so do do nothing about the pointer before using it except say we
305      * need to update it next time.
306      */
307     if (self->isFirst)
308     {
309         self->isFirst = false;
310     }
311     /* -----
312      * After the first time we need to bump the pointer until it can't be bumped.
313      */
314     else
315     {
316         /* -----
317          * It's not specified in klib/container.h but BSTNodeNext
318          * returns NULL at end of tree
319          * [ WHAT ELSE WOULD IT RETURN? ]
320          */
321         self->u.bnp = BSTNodeNext (self->u.bnp);
322     }
323 
324     /* -----
325      * The first test isn't necesary so letting KTocEntryGetName return NULL
326      * could be used instead of the extra check.
327      * Checking against NULL adds a little to each call while not checking
328      * adds more but only to the last call.
329      * Pick your poison.
330      */
331     if ((self->u.bnp == NULL) || (KTocEntryGetName (self->u.tnp, &name) != 0))
332     {
333         return NULL;
334     }
335     return name;
336 }
337 
338 
339 /* ======================================================================
340  */
341 typedef struct KArcListing KArcListing;
342 
343 #define KNAMELIST_IMPL struct KArcListing
344 #include <klib/impl.h>
345 
346 /*--------------------------------------------------------------------------
347  * KArcListing
348  *  a directory listing
349  *
350  * NOTE:
351  * This is nearly identical to KSysDirListing but both are currently private to
352  * their compilation units.
353  */
354 struct KArcListing
355 {
356     KNamelist     dad;      /* base class */
357     const char ** namelist; /* pointer to a malloced array of pointers to names */
358     int           cnt;      /* specific size chosen by compiler for efficiency */
359 };
360 
361 
362 /* ----------------------------------------------------------------------
363  * KArcListingWhack
364  *
365  * Class destructor
366  *
367  *
368  * [RET] rc_t					0 for success; anything else for a failure
369  *						see itf/klib/rc.h for general details
370  * [INOUT] const KArcListing* self		Listing self reference: object oriented in C
371  */
372 static
KArcListingWhack(const KArcListing * self)373 rc_t CC KArcListingWhack (const KArcListing *self)
374 {
375     int ix;
376     for ( ix = 0; ix < self->cnt; ++ix )
377     {
378         free ( (void*)self->namelist[ix] );
379     }
380     free ( (void*)self->namelist );
381     return 0;
382 }
383 
384 /* ----------------------------------------------------------------------
385  * KArcListingDestroy
386  * Class destructor
387  *
388  *
389  * [RET] rc_t					0 for success; anything else for a failure
390  *						see itf/klib/rc.h for general details
391  * [INOUT] KArcListing *	self		Listing self reference: object oriented in C
392  */
393 static
KArcListingDestroy(KArcListing * self)394 rc_t CC KArcListingDestroy (KArcListing *self)
395 {
396     rc_t rc = KArcListingWhack (self);
397     if (rc == 0)
398         free (self);
399     return rc;
400 }
401 
402 
403 /* ----------------------------------------------------------------------
404  * KArcListingCount
405  *
406  *
407  * [RET] rc_t					0 for success; anything else for a failure
408  *						see itf/klib/rc.h for general details
409  * [IN]  const KArcListing *	self		Listing self reference: object oriented in C
410  * [OUT] uint32_t *		count		Where to put the count of names
411  */
KArcListingCount(const KArcListing * self,uint32_t * count)412 static rc_t CC KArcListingCount (const KArcListing *self, uint32_t *count)
413 {
414     *count = self->cnt;
415     return 0;
416 }
417 
418 
419 /* ----------------------------------------------------------------------
420  * KArcListingGet
421  *
422  *
423  * [RET] rc_t					0 for success; anything else for a failure
424  *						see itf/klib/rc.h for general details
425  * [IN]  const KArcListing *	self		Listing self reference: object oriented in C
426  * [IN]  uint32_t		idx		?
427  * [OUT] const char **		name		Where to put the name
428  */
KArcListingGet(const KArcListing * self,uint32_t idx,const char ** name)429 static rc_t CC KArcListingGet (const KArcListing *self, uint32_t idx, const char **name)
430 {
431     if (idx >= (uint32_t)self->cnt)
432         return RC (rcFS, rcNamelist, rcAccessing, rcParam, rcExcessive);
433     * name = self -> namelist [ idx ];
434     return 0;
435 }
436 
437 
438 /* ----------------------------------------------------------------------
439  * KArcListingSort
440  *
441  * This function has the signature needed to use with the NameList base class for
442  * KArcListings to determine the order of two names.  Matches the signature of
443  * strcmp() and other functions suitable for use by qsort() and others
444  *
445  * [RET] int					0:  if a == b
446  *						<0: if a < b
447  *						>0: if a > b
448  * [IN] const void *		a
449  * [IN] const void *		b
450  *
451  * Elements are typed as const void * to match the signature needed for
452  * a call to qsort() but they should be pointers to namelist elements
453  */
KArcListingSort(const void * a,const void * b,void * ignored)454 static int64_t CC KArcListingSort (const void *a, const void *b, void * ignored)
455 {
456     return strcmp (*(const char**)a, *(const char**)b);
457 }
458 
459 static KNamelist_vt_v1 vtKArcListing =
460 {
461     /* version 1.0 */
462     1, 0,
463 
464     /* start minor version 0 methods */
465     KArcListingDestroy,
466     KArcListingCount,
467     KArcListingGet
468     /* end minor version 0 methods */
469 };
470 
471 
472 /* ----------------------------------------------------------------------
473  * KArcListingInit
474  *
475  * [RET] rc_t					0 for success; anything else for a failure
476  *						see itf/klib/rc.h for general details
477  * [INOUT] KArcListing *	self		Listing self reference: object oriented in C
478  * [IN]    const char *		path		?
479  * [IN]    const KDirectory *	dir		?
480  * [IN]    bool (* 		f	)(const KDirectory*, const char*, void*),
481  *						This is a filter function - any listing element
482  *						passed to this function will generate a true ot
483  *						a false.  If flase that listing element is dropped.
484  *						If this parameter is NULL all elements are kept.
485  * [IN]	   void *		data		Ignored.  May use NULL if permitted
486  *						by 'f'.
487  */
KArcListingInit(KArcListing * self,const char * path,const KDirectory * dir,bool (CC * f)(const KDirectory *,const char *,void *),void * data)488 static rc_t KArcListingInit (KArcListing *self,
489                              const char *path,
490                              const KDirectory *dir,
491                              bool (CC* f) (const KDirectory*, const char*, void*),
492                              void *data)
493 {
494     rc_t rc;
495 
496     /* is self parameter possibly NULL? */
497     if (self == NULL)
498     {
499         return  RC (rcFS, rcDirectory, rcConstructing, rcSelf, rcNull);
500     }
501 
502     /* start with an empty name list */
503     self->namelist = NULL;
504     self->cnt = 0;
505 
506     /* initialize the Namelist base class */
507     if ((rc = KNamelistInit (& self -> dad,
508 			     (const KNamelist_vt*)&vtKArcListing)) == 0)
509     {
510         /* -----
511          * so we'll build a list iterator
512          */
513         KArcDirIterator listitr;
514 
515         if ((rc = KArcDirIteratorInit (& listitr, (const KArcDir*)dir, path)) == 0)
516         {
517 
518 #define	LEN_INCREMENT	(512)
519 
520             uint32_t len = LEN_INCREMENT;
521 
522             /* allocate heap for the default start size of a namelist */
523 
524             self->namelist = malloc (len * sizeof (self->namelist[0]));
525             if (self->namelist == NULL)
526             {
527                 rc = RC (rcFS, rcDirectory, rcListing, rcMemory, rcExhausted);
528             }
529             else
530             {
531                 void *r;
532                 const char *name;
533 
534                 /* -----
535                  * loop through the directory (the BSTree for a Archive TOC)
536                  */
537                 while ((name = KArcDirIteratorNext (&listitr)) != NULL)
538                 {
539                     /* if there is a filter function, run it */
540                     if (f != NULL)
541                     {
542                         /* skip if the filter doesn't say use it */
543                         if (! (*f) (dir, name, data))
544                             continue;
545                     }
546 
547                     /* if the buffer is full, reallocate it larger */
548                     if (self->cnt == len)
549                     {
550                         len += LEN_INCREMENT;
551                         if ( NULL == ( r = realloc ( (void*)self -> namelist,
552                                                      len * sizeof self -> namelist [ 0 ] ) ) )
553                         {
554                             /* -----
555                              * malloc failure so we fail too  - break not return so we can
556                              * free allocated memory
557                              */
558                             rc = RC (rcFS, rcDirectory, rcListing, rcMemory, rcExhausted);
559                             break;
560                         }
561                         self->namelist = r;
562                     }
563 
564                     /* get ourselves memory for the name */
565                     self->namelist[self->cnt] = malloc (strlen (name) + 1);
566                     if (self->namelist[self->cnt] == NULL)
567                     {
568                         /* oops a failure so we fail */
569                         rc = RC (rcFS, rcDirectory, rcListing, rcMemory, rcExhausted);
570                         break;
571                     }
572                     strcpy ((char*)self->namelist[self->cnt], name);
573                     ++self->cnt;
574                 }
575 
576                 if (rc == 0)
577                 {
578                     /* -----
579                      * now that we have our list and know how big it should have been we'll shrink it
580                      * if the count was zero this a effectively just a free()
581                      */
582                     r = realloc ( ( void* )self->namelist,
583                                   self->cnt * sizeof ( self->namelist[0] ) );
584                     /* -----
585                      * if we have a new non-NULL pointer we know we have a list of non-zero length
586                      * store the pointer and sort the list
587                      */
588                     if (r != NULL)
589                     {
590                         self -> namelist = r;
591                         ksort ((void*)r, self -> cnt, sizeof self -> namelist [ 0 ], KArcListingSort, NULL);
592                     }
593                     /* -----
594                      * If we have a NULL pointer but have a non-zero count, we have a malloc() heap
595                      * space failure
596                      */
597                     else if (self -> cnt != 0)
598                     {
599                         rc = RC (rcFS, rcDirectory, rcListing, rcMemory, rcExhausted);
600                     }
601                     /* -----
602                      * Or we have a NULL pointer and a count of zero so stow the NULL so its not
603                      * a dangling bad pointer
604                      */
605                     else
606                     {
607                         self->namelist = r;
608                     }
609                 }
610                 /* if we got here because of a problem, kill the listing */
611                 if (rc != 0)
612                 {
613                     KArcListingWhack (self);
614                     self->namelist = NULL;
615                     self->cnt = 0;
616                 }
617             }
618             /* we're done with the iterator so kill it */
619             KArcDirIteratorWhack (&listitr);
620         }
621     }
622     return rc;
623 }
624 
625 
626 /* ======================================================================
627  */
628 
629 /*--------------------------------------------------------------------------
630  * KArcDir
631  *  a directory inside an archive (tar or SRA for example)
632  *
633  * This type is being engineered to mimic KSysDir.
634  */
635 struct KArcDir
636 {
637     KDirectory		dad;					/* parent class as in inheritance */
638 
639     const KDirectory *  parent;					/* parent object */
640     const KToc *	toc;					/* table of contents class */
641     const KTocEntry *	node;					/* table of contents entry NULL for top level */
642     KArcFSType	arctype;
643     union
644     {
645 	const void *		v;
646 	const KFile *		f;
647 	const KDirectory * 	d;
648     } archive;
649 
650     uint32_t	  	root;					/* offset of / in path to treat as root */
651     uint32_t 	  	size;					/* length of path */
652     char 	  	path	 [KARC_DEFAULT_PATH_ALLOC];	/* name of archive = mount point */
653 
654 /* actual allocation is based on actual string length */
655 };
656 
657 static rc_t KArcDirMake (KArcDir ** self,
658                          enum RCContext ctx,
659                          const KDirectory * parent,
660                          const KToc * toc,
661                          const KTocEntry * node,
662                          const void * archive,
663                          KArcFSType baseType,
664                          uint32_t dad_root,
665                          const char *path,
666                          uint32_t path_size,
667                          bool update, /* ignored */
668                          bool chroot);
669 
670 
671 /* ----------------------------------------------------------------------
672  * KArcDirDestroy
673  */
KArcDirDestroy(KArcDir * self)674 static rc_t CC KArcDirDestroy (KArcDir *self)
675 {
676     if (self->toc != NULL)
677         KTocRelease (self->toc);
678 
679     if (self->archive.v != NULL) switch (self->arctype)
680 	{
681 	default:
682 	    free ((void*)self->archive.v);
683 	    break;
684 	case tocKFile:
685 	    KFileRelease (self->archive.f);
686 	    break;
687 	case tocKDirectory:
688 	    KDirectoryRelease (self->archive.d);
689 	    break;
690 	}
691     free (self);
692 
693     return 0;
694 }
695 
696 
697 
698 /* ----------------------------------------------------------------------
699  * KArcDirCanonPath
700  *
701  * In this context CanonPath means to make the path a pure /x/y/z with no back tracking
702  * by using ~/../~ or redundant ~/./~ or ~//~ here notations.  Not exactly the usage of
703  * canonical in describing a path in other places but consistent within KFS.  It matches
704  * the common meaning of canonical path as the one true path except that processing out
705  * of sym links isn't done here but would normally have been.  Not processing the
706  * links means potentially more than one canonical path can reach the same target
707  * violating the usual meaning of canonical path as the one true shortest path to any
708  * element.
709  *
710  * const KArcDir *		self		Object oriented C; KArcDir object for this method
711  * enum RCContext 		ctx
712  * char * 			path
713  * size_t			psize
714  */
715 static
KArcDirCanonPath(const KArcDir * self,enum RCContext ctx,char * path,size_t psize)716 rc_t		KArcDirCanonPath	(const KArcDir *self,
717 					 enum RCContext ctx,
718 					 char *path,
719 					 size_t psize)
720 {
721     char *	low;	/* a pointer to the root location in path; not changed after initialization */
722     char *	dst;	/* a target reference for compressing a path to remove . and .. references */
723     char *	last;	/* the end of the last processed facet of the path */
724     char *	end;	/* absolute end of the incoming path */
725     char * 	src;	/* the start of the current facet to be processed */
726 
727     /* end is the character after the end of the incoming path */
728     end = path + psize;
729 
730     /* point all other temp pointers at the root point in the incoming path */
731     last = path + self->root;
732 
733     /* handle windows / / network path starter */
734     if ((last == path) && (last[0] == '/') && (last[1] == '/'))
735       last ++;
736 
737     low = dst = last;
738 
739     for (;;)
740     {
741 
742         /* point at the first / after the most recent processed facet */
743         src = strchr (last + 1, '/');
744         if (src == NULL)	/* if no '/' point to the end */
745             src = end;
746 
747         /* detect special sequences */
748         switch (src - last)
749         {
750         case 1: /* / / (with nothing between) is a superflouous / hurting us to parse later;
751                  * /. is a here reference to the same directory as the previous */
752             if ((last[1] == '/')||(last[1] == '.'))
753             {
754                 /* skip over */
755                 last = src;
756                 if (src != end)
757                     continue;
758             }
759             break;
760         case 2: /* /./ is a "here" reference point and is omitted by not copying it over */
761             if (last[1] == '.')
762             {
763                 /* skip over */
764                 last = src;
765                 if (src != end)
766                     continue;
767             }
768             break;
769 
770         case 3: /* /../ is a up one directory and is processed by deleting the last facet copied */
771             if (last [1] == '.' && last [2] == '.')
772             {
773                 /* remove previous leaf in path */
774                 dst [ 0 ] = 0;
775                 dst = strrchr (path, '/');
776                 /* can't up a directory past the root */
777                 if (dst == NULL || dst < low)
778                 {
779                     return RC (rcFS, rcDirectory, ctx, rcPath, rcInvalid);
780                 }
781 
782                 last = src;
783                 if (src != end)
784                     continue;
785             }
786             break;
787         }
788 
789         /* if rewriting, copy leaf */
790         if (dst != last)
791         {
792             memmove (dst, last, src - last);
793         }
794 
795         /* move destination ahead */
796         dst += src - last;
797 
798         /* if we're done, go */
799         if (src == end)
800             break;
801 
802         /* find next separator */
803         last = src;
804     }
805 
806     /* NUL terminate if modified */
807     if (dst != end)
808         * dst = 0;
809 
810     /* say we did did it with no problems */
811     return 0;
812 }
813 
814 
815 /* ----------------------------------------------------------------------
816  * KArcDirMakePath
817  *
818  *  creates a full path from partial
819  *
820  * [IN]  const KArcDir *	self	object oriented self
821  * [IN]  enum RCContext		ctx	a hint for context in building
822  *					an error return rc_t
823  * [IN]  bool			canon	Should the output be made
824  *					canonical per KDirectory's
825  *					definition of canonical
826  * [OUT] char **		pbuffer The output path
827  * [IN]  const char *		path	The input path
828  * [IN]  va_list		args	Possible additions to path
829  */
830 static
KArcDirMakePath(const KArcDir * self,enum RCContext ctx,bool canon,char ** pbuffer,const char * path,va_list args)831 rc_t KArcDirMakePath (const KArcDir *self,
832 		      enum RCContext ctx,
833 		      bool canon,
834 		      char ** pbuffer,
835 		      const char *path,
836 		      va_list args)
837 {
838     int    psize;	/* 'printed' size - output from vsnprintf */
839     size_t asize;	/* allocated buffer size */
840     size_t bsize;	/* base size */
841     char * buffer;
842 
843     /* -----
844      * Validate parameters and fail if unusable
845      */
846     assert (path != NULL);
847     assert (pbuffer != NULL);
848 
849     if (path == NULL)
850     {
851 	return RC (rcFS, rcDirectory, ctx, rcPath, rcNull);
852     }
853     if (path[0] == 0)
854     {
855 	return RC (rcFS, rcDirectory, ctx, rcPath, rcInvalid);
856     }
857 
858     buffer = NULL;
859     asize = KARC_DEFAULT_PATH_ALLOC;
860     for (;;)
861     {
862 	/* -----
863 	 * allocate a buffer of the default size or a better size determined below
864 	 */
865 	buffer = realloc (buffer, asize);
866 	*pbuffer = buffer;
867 	if (buffer == NULL)
868 	{
869 	    return RC (rcFS, rcDirectory, rcAllocating, rcPath, rcExhausted);
870 	}
871 	/* -----
872 	 * inherited from linux/sysdir.c
873 	 *
874 	 * if path starts with % we build something out of va_list?
875 	 *
876 	 * use vsnprintf (printf to string with size limit and argument list
877 	 *	pointer instead of a list of arguments:
878 	 * build path to buffer using a path that is a printf format string
879 	 * with a requirement that the first thing in the format be a format inducing %
880          * VDB-4386: cannot treat va_list as a pointer!
881 	 */
882 	if (/*(args != NULL) &&*/ (path[0] == '%'))
883 	{
884 	    psize = vsnprintf (buffer, asize, path, args);
885 
886 	    /* -----
887 	     * decoding of path failed due a failure of printf
888 	     * <0 is an unspecified failure unspecified (check errno?)
889 	     */
890 	    if (psize < 0)
891             return RC (rcFS, rcDirectory, ctx, rcPath, rcUnknown);
892 
893 	    /* -----
894 	     * decoding of path failed due to length truncation
895 	     * try to realloc using a larger size
896 	     */
897 	    if ( (size_t)psize >= asize )
898 	    {
899             asize = psize;
900             continue;
901 	    }
902 
903 	    /* -----
904 	     * maybe the decoded path is a relative partial path
905 	     */
906 	    if (buffer[0] != '/')
907 	    {
908             /* -----
909              * if our KArcDir self has a mount point self->path of length more than 0
910              * but that length isn't too long to prepend it to the derived path than
911              * move the derived path over making room for the KArcDir base path and
912              * then insert that base at the beginning
913              */
914             bsize = self->size;
915             if (bsize + psize >= asize)
916             {
917                 asize = bsize + psize;
918                 continue;
919             }
920             /* make room */
921             memmove (buffer + self->size, buffer, psize+1);
922             /* fail if the kDirectory path doesn't end in /? (inherited) */
923             assert (self->path[bsize-1] == '/');
924             /* prepend self's path */
925             memmove (buffer, self->path, bsize);
926 	    }
927 
928 	    /* -----
929 	     * or maybe we have a path base for the KArcDir
930 	     */
931 	    else if ((bsize = self->root) != 0)
932 	    {
933             /* -----
934              * if we got a full path from the decoding do the same thing but only the
935              * amount of the self's path that is up to an effective "chroot" point
936              */
937             if (bsize + psize >= asize)
938             {
939                 asize = bsize + psize;
940                 continue;
941             }
942             memmove (buffer + self->size, buffer, psize+1);
943             assert (self->path [bsize-1] != '/');
944             memmove (buffer, self -> path, bsize);
945 	    }
946 	    /* -----
947 	     * or maybe the new path is cool as is.  unlikely?
948 	     */
949 	}
950 	else
951 	{
952 	    /* -----
953 	     * copy a partial/relative  path parameter into the buffer leaving room for the
954 	     * self's base path
955 	     */
956 	    if (path[0] != '/')
957 	    {
958             assert (self->path[self->size - 1] == '/');
959             memmove (buffer, self->path, bsize = self->size);
960 	    }
961 	    /* -----
962 	     * copy the pre-root portion of the self's path into the buffer
963 	     */
964 	    else if ((bsize = self->root) != 0)
965 	    {
966             assert (self->path[bsize-1] != '/');
967             memmove (buffer, self->path, bsize);
968 	    }
969 
970 	    /* -----
971 	     * okay use snprintf to append the incoming path into the buffer after the
972 	     * self's base or root either using a simple string format or again assuming
973 	     * that the path has printf format symbols if there are arguments in the
974 	     * va_list
975              * VDB-4386: cannot treat va_list as a pointer!
976 	     */
977 /*	    if (args == NULL)
978             psize = snprintf (buffer+bsize, asize-bsize, "%s", path);
979 	    else*/
980             psize = vsnprintf (buffer+bsize, asize-bsize, path, args);
981 
982 	    /* -----
983 	     * decoding of path failed due a failure of printf
984 	     * <0 is an unspecified failure unspecified (check errno?)
985 	     */
986 	    if (psize < 0)
987             return RC (rcFS, rcDirectory, ctx, rcPath, rcUnknown);
988 
989 	    /* -----
990 	     * decoding of path failed due to length truncation
991 	     * try to realloc using a larger size
992 	     */
993 	    if (bsize+psize >= asize)
994 	    {
995             asize = bsize+psize;
996             continue;
997 	    }
998 	}
999 	break;
1000     }
1001     /* -----
1002      * if the last character is a '/' get rid of it?
1003      */
1004     if (buffer[bsize+psize] == '/')
1005         buffer[bsize+(--psize)] = 0;
1006 
1007     /* -----
1008      * if the incoming path turns out to be a single character (I think) AND
1009      * we either have the canon flag set or if the the KArcDir root is not empty
1010      * "canonize" it.
1011      */
1012     if (canon || (self->root != 0))
1013     {
1014         return KArcDirCanonPath (self, ctx, *pbuffer, bsize+psize);
1015     }
1016     return 0;
1017 }
1018 
1019 static
KArcDirMakePath_noargs(const KArcDir * self,enum RCContext ctx,bool canon,char ** pbuffer,const char * path,...)1020 rc_t KArcDirMakePath_noargs (const KArcDir *self,
1021 		      enum RCContext ctx,
1022 		      bool canon,
1023 		      char ** pbuffer,
1024 		      const char *path,
1025               ...)
1026 {
1027     va_list vl;
1028     va_start( vl, path );
1029     rc_t ret = KArcDirMakePath( self, ctx, canon, pbuffer, path, vl );
1030     va_end(vl);
1031     return ret;
1032 }
1033 
1034 /* ----------------------------------------------------------------------
1035  * KArcDirList
1036  *  create a directory listing
1037  *
1038  *  "list" [ OUT ] - return parameter for list object
1039  *
1040  *  "path" [ IN, NULL OKAY ] - optional parameter for target
1041  *  directory. if NULL, interpreted to mean "."
1042  *
1043  * [RET] rc_t					0 for success; anything else for a failure
1044  *						see itf/klib/rc.h for general details
1045  * [IN]	 const KArcDir *	self		Object oriented C; KArcDir object for this method
1046  * [OUT] KNamelist **		listp,
1047  * [IN]  bool (* 		f	)(const KDirectory*,const char *, void *)
1048  * [IN]  void *			data
1049  * [IN]  const char *		path
1050  * [IN]  va_list		args
1051  */
1052 static
KArcDirList(const KArcDir * self,KNamelist ** listp,bool (CC * f)(const KDirectory * dir,const char * name,void * data),void * data,const char * path,va_list args)1053 rc_t CC KArcDirList (const KArcDir *self,
1054                      KNamelist **listp,
1055                      bool (CC* f) (const KDirectory *dir, const char *name, void *data),
1056                      void *data,
1057                      const char *path,
1058                      va_list args)
1059 {
1060     char * full_path;
1061     rc_t rc;
1062 
1063     rc = KArcDirMakePath (self, rcListing, true,
1064 			  &full_path, path, args);
1065     if (rc == 0)
1066     {
1067 	const KTocEntry * pnode;
1068 	KTocEntryType	type;
1069 	KArcDir * full_dir;
1070 
1071 	rc = KArcDirResolvePathNode(self, rcListing, full_path, true, &pnode, &type);
1072 	if (rc == 0)
1073 	{
1074 	    rc = KArcDirMake (&full_dir,
1075 			      rcListing,
1076 			      self->parent,
1077 			      self->toc,
1078 			      pnode,
1079 			      self->archive.v,
1080 			      self->arctype,
1081 			      self->root,
1082 			      full_path,
1083 			      (uint32_t)strlen(full_path),
1084 			      false,
1085 			      0);
1086 	    if (rc == 0)
1087 	    {
1088 		KArcListing *list = malloc (sizeof *list);
1089 
1090 		if (list == NULL)
1091 		{
1092 		    rc = RC (rcFS, rcDirectory, rcListing, rcMemory, rcExhausted);
1093 		}
1094 		else
1095 		{
1096 		    rc = KArcListingInit (list,
1097 					  full_dir->path,
1098 					  &full_dir->dad,
1099 					  f,
1100 					  data);
1101 
1102 		    if (rc != 0)
1103 		    {
1104 			free (list);
1105 		    }
1106 		    else
1107 		    {
1108 			*listp = &list->dad;
1109 		    }
1110 		}
1111 		KArcDirDestroy (full_dir);
1112 	    }
1113 	}
1114 	free (full_path);
1115     }
1116     return rc;
1117 }
1118 
1119 
1120 /* ----------------------------------------------------------------------
1121  * KArcDirFullPathType
1122  *
1123  * Get the KDirectory defined KPathType for whatever is referred to
1124  * by path that is accessible through the KArcDir self.  The path's
1125  * root is based on self's root (?) and a relative path is relative to
1126  * self.
1127  *
1128  * [RET] uint32_t			actually this is enum KPathType
1129  * [IN]  const KArcDir *	self	base KDirectory for the call to
1130  *					find the type of path
1131  * [IN]  const char * 		path	what path of which to type the
1132  *					last facet
1133  */
1134 static
KArcDirFullPathType(const KArcDir * self,const char * path)1135 uint32_t KArcDirFullPathType (const KArcDir *self, const char * path)
1136 {
1137     const KTocEntry * node;
1138     const char *	local_path = path;
1139     KTocEntryType	type;
1140     uint32_t		tt = 0;
1141     int			loopcount;
1142     rc_t		rc;
1143 
1144     assert (self != NULL);
1145     assert (path != NULL);
1146 
1147     for (loopcount = 0; loopcount < KARC_LINK_RESOLVE_LOOPMAX; ++loopcount)
1148     {
1149         rc = KArcDirResolvePathNode (self,
1150             rcConstructing, local_path, false, &node, &type);
1151         if (rc != 0)
1152         {
1153             /* TODO: filter rc into kptBadPath or kptNotFound... */
1154             return (tt | kptNotFound);
1155         }
1156         switch (type)
1157         {
1158         default:
1159             return kptBadPath;
1160 
1161         case ktocentrytype_unknown:
1162             return kptBadPath;
1163 
1164         case ktocentrytype_hardlink:
1165             return kptDir;
1166 
1167         case ktocentrytype_dir:
1168             return tt | kptDir;
1169 
1170         case ktocentrytype_file:
1171         case ktocentrytype_emptyfile:
1172             return tt | kptFile;
1173 
1174         case ktocentrytype_chunked:
1175             return tt | kptFile;
1176 
1177         case ktocentrytype_softlink:
1178             tt = kptAlias;
1179             if (KTocEntryGetSoftTarget(node,&local_path) != 0)
1180                 return kptAlias|kptNotFound;
1181             break;
1182 
1183         case ktocentrytype_zombiefile:
1184             PLOGMSG (klogWarn, (klogWarn,
1185                 "zombie file detected: '$(P)'", "P=%s", path));
1186             ReportRecordZombieFile();
1187             return tt | kptZombieFile;
1188 
1189         }
1190     }
1191     return kptBadPath;
1192 }
1193 
1194 
1195 /* ----------------------------------------------------------------------
1196  * KArcDirPathType
1197  *  returns a KPathType
1198  *
1199  *  "path" [ IN ] - NUL terminated string in directory-native character set
1200  * NOTE: Does not meet a design target of on stack (localized variable) allocation of single 4kb path
1201  *
1202  * [RET] uint32_t
1203  * [IN]  const KArcDir *	self		Object oriented C; KArcDir object for this method
1204  * [IN]  const char *		path
1205  * [IN]  va_list		args
1206  */
KArcDirPathType(const KArcDir * self,const char * path,va_list args)1207 static uint32_t CC KArcDirPathType (const KArcDir *self, const char *path, va_list args)
1208 {
1209     rc_t	rc;
1210     uint32_t 	type;
1211     char * 	full;
1212 
1213     rc = KArcDirMakePath (self, rcAccessing, false, &full, path, args);
1214 
1215     if (rc == 0)
1216     {
1217         type = KArcDirFullPathType (self, full);
1218         free (full);
1219     }
1220     else
1221     {
1222         type = kptBadPath;
1223     }
1224     return type;
1225 }
1226 
1227 
1228 /* ----------------------------------------------------------------------
1229  * KArcDirVisitDir
1230  *
1231  * [IN] KArcDirVisitData *	pb
1232  */
1233 typedef struct KArcDirVisitData
1234 {
1235     rc_t   (CC* f )(const KDirectory*, uint32_t, const char*, void*);
1236     void *      data;
1237     KArcDir *   dir;
1238     bool        recurse;
1239 } KArcDirVisitData;
1240 
1241 
1242 static
KArcDirVisitDir(KArcDirVisitData * pb)1243 rc_t KArcDirVisitDir(KArcDirVisitData *pb)
1244 {
1245     /* get a directory listing */
1246     KArcDirIterator 	listing;
1247     rc_t		rc;
1248 
1249     assert (pb != NULL);
1250 
1251     rc = KArcDirIteratorInit (&listing, pb->dir, pb->dir->path);
1252     if (rc == 0)
1253     {
1254         const char * base;
1255         const char * name;
1256         char * full_name = NULL;
1257         uint32_t 	size;
1258 
1259         size = pb->dir->size;
1260         base = pb->dir->path;
1261 
1262         for(pb->dir->size = size, name = KArcDirIteratorNext (&listing);
1263             name != NULL; name = KArcDirIteratorNext (&listing))
1264         {
1265             uint32_t len = (uint32_t)strlen (name);
1266             free(full_name);
1267             full_name = malloc(size + len + 1);
1268 
1269             if(full_name == NULL) {
1270                 rc = RC (rcFS, rcDirectory, rcVisiting, rcMemory, rcExhausted);
1271                 break;
1272             } else {
1273                 const KTocEntry *	pnode;
1274                 KTocEntryType		type;
1275                 /* -----
1276                 * build up the path from the base and the name
1277                 */
1278                 memmove(full_name, base, size);
1279                 memmove(full_name+size, name, len);
1280                 full_name[size+len] = 0;
1281 
1282                 rc = KArcDirResolvePathNode(pb->dir, rcVisiting, full_name,
1283                                             true, &pnode, &type);
1284                 if(rc != 0) {
1285                     break;
1286                 }
1287                 /* -----
1288                 * call the function per visit
1289                 */
1290                 /* type is wrong "type"  needs to be a kpt not karctoctype */
1291                 {
1292                     uint32_t kptype;
1293                     kptype = KArcDirFullPathType(pb->dir, full_name);
1294                     rc = pb->f(&pb->dir->dad, kptype, name, pb->data);
1295                 }
1296                 if(rc != 0) {
1297                     break;
1298                 }
1299                 if(pb->recurse && ((type == ktocentrytype_dir)||(type == ktocentrytype_hardlink))) {
1300                     KArcDir * rdir;
1301                     KArcDirVisitData rpb;
1302 
1303                     rc = KArcDirMake(&rdir, rcVisiting, pb->dir->parent, pb->dir->toc,
1304                                      pnode, pb->dir->archive.v, pb->dir->arctype, pb->dir->root,
1305                                      full_name, (uint32_t)strlen ( full_name ), false, false);
1306                     if(rc != 0) {
1307                         break;
1308                     }
1309                     rpb.f = pb->f;
1310                     rpb.data = pb->data;
1311                     rpb.dir = rdir;
1312                     rpb.recurse = pb->recurse;
1313                     rc = KArcDirVisitDir(&rpb);
1314                     KArcDirDestroy(rdir);
1315                     if(rc != 0) {
1316                         break;
1317                     }
1318                 }
1319             }
1320         }
1321         free(full_name);
1322         KArcDirIteratorWhack (& listing);
1323     }
1324     return rc;
1325 }
1326 
1327 
1328 /* ----------------------------------------------------------------------
1329  * KArcDirRelativePath
1330  *
1331  * KArcDirRelativePath
1332  *  makes "path" relative to "root"
1333  *  both "root" and "path" MUST be absolute
1334  *  both "root" and "path" MUST be canonical, i.e. have no "//", "/./" or "/../" sequences
1335  *
1336  * [RET] rc_t					0 for success; anything else for a failure
1337  *						see itf/klib/rc.h for general details
1338  * [IN] const KArcDir *		self		Object oriented C; KArcDir object for this method
1339  * [IN] enum RCContext 		ctx
1340  * [IN] const char *		root
1341  * [IN, OUT] char *			path
1342  * [IN] size_t			path_max
1343  */
1344 static
KArcDirRelativePath(const KArcDir * self,enum RCContext ctx,const char * root,char * path,size_t path_max)1345 rc_t KArcDirRelativePath (const KArcDir *self, enum RCContext ctx,
1346 			  const char *root, char *path, size_t path_max)
1347 {
1348     int backup;
1349     size_t bsize, psize;
1350 
1351     const char *r = root + self -> root;
1352     const char *p = path + self -> root;
1353 
1354     assert (r != NULL && r [ 0 ] == '/');
1355     assert (p != NULL && p [ 0 ] == '/');
1356 
1357     for (; * r == * p; ++ r, ++ p)
1358     {
1359         /* disallow identical paths */
1360         if (* r == 0)
1361             return RC (rcFS, rcDirectory, ctx, rcPath, rcInvalid);
1362     }
1363 
1364     /* paths are identical up to "r","p"
1365        if "r" is within a leaf name, then no backup is needed
1366        by counting every '/' from "r" to end, obtain backup count */
1367     for (backup = 0; * r != 0; ++ r)
1368     {
1369         if (* r == '/')
1370             ++ backup;
1371     }
1372 
1373     /* the number of bytes to be inserted */
1374     bsize = backup * 3;
1375 
1376     /* align "p" to last directory separator */
1377     while (p [ -1 ] != '/') -- p;
1378 
1379     /* the size of the remaining relative path */
1380     psize = strlen (p);
1381 
1382     /* open up space if needed */
1383     if ( (size_t)(p - path) < bsize )
1384     {
1385         /* prevent overflow */
1386         if (bsize + psize >= path_max)
1387             return RC (rcFS, rcDirectory, ctx, rcPath, rcExcessive);
1388 
1389         memmove (path + bsize, p, psize);
1390     }
1391 
1392     /* insert backup sequences */
1393     for (bsize = 0; backup > 0; bsize += 3, -- backup)
1394         memmove (& path [ bsize ], "../", 3);
1395 
1396     /* close gap */
1397     if ( (size_t)( p - path ) > bsize )
1398 	{
1399 		memmove (path + bsize, p, psize + 1);
1400 	}
1401 
1402 	return 0;
1403 }
1404 
1405 
1406 /* ----------------------------------------------------------------------
1407  * KArcDirResolvePathNode
1408  *
1409  * Resolve a path to a KToc Node with a triple return type of
1410  * success/failure, KTocEntry to use to access the leaf of the path,
1411  * and the type of the node that could have been easily obtained from
1412  * that node
1413  *
1414  * [RET] rc_t					0 for success; anything else for a failure
1415  *						see itf/klib/rc.h for general details
1416  * [IN]  const KArcDir *      self	OOP in C self/this pointer
1417  * [IN]  const char *         path	the path to resolve
1418  * [IN]  bool		      follow	Follow any links
1419  * [OUT] const KTocEntry ** pnode	a pointer that will point to the
1420  *					ArcTOCNode for the path
1421  * [OUT] KTocEntryType *    ptype	Archive specific type for the
1422  *					entry matching path
1423  * TODO: Make this prettier for human readabilty by breaking out into sub-functions?
1424  */
1425 static
KArcDirResolvePathNode(const KArcDir * self,enum RCContext ctx,const char * path,bool follow,const KTocEntry ** pnode,KTocEntryType * ptype)1426 rc_t	KArcDirResolvePathNode	(const KArcDir *	self,
1427 				 enum RCContext 	ctx,
1428 				 const char *		path,
1429 				 bool			follow,
1430 				 const KTocEntry ** 	pnode,
1431 				 KTocEntryType * ptype)
1432 {
1433     rc_t		rc = 0;
1434 
1435     assert (self != NULL);
1436     assert (path != NULL);
1437     assert (pnode != NULL);
1438     assert (ptype != NULL);
1439 
1440     *pnode = NULL;
1441     *ptype = ktocentrytype_unknown;
1442 
1443     if (path[0] == 0)
1444     {
1445         rc = RC (rcFS, rcDirectory, ctx, rcPath, rcInvalid);
1446     }
1447     else
1448     {
1449 	/* -----
1450 	 * This loop is to replace recursive approaches to resolving sym links in
1451 	 * the path.before the last facet.
1452 	 *
1453 	 * we used temp_path as an alias for path because we can "recur" by
1454 	 * going through the loop iteratively instead of recursively changing
1455 	 * temp_path each time where we would have called this function again
1456 	 */
1457 	const char *	temp_path = path;	/* no alloc */
1458 	const KToc *	toc = self->toc;	/* no alloc */
1459 	char *		allocated_path = NULL;	/* alloc; must free{} */
1460 	char * 		abpath = NULL;		/* alloc; must free{} */
1461 
1462 	while(rc == 0) /* loop as long as no failures or until break */
1463 	{
1464 	    /* -----
1465 	     * clean up the path to its KFS canonical form
1466 	     */
1467 	    if (abpath != NULL)
1468             free (abpath);
1469 	    rc = KArcDirMakePath_noargs (self, ctx, /* canon*/true, &abpath,
1470                               temp_path);
1471 	    if (rc != 0)
1472 	    {
1473             /* -----
1474              * If we couldn't "make the path" we'll just fail passing along
1475              * the fail reason from MakePath.
1476              */
1477             break;	/* TODO fix rc context? Object? */
1478 	    }
1479 	    else
1480 	    {
1481             const String * pathstring;
1482 
1483             rc = KTocGetPath (toc, &pathstring);
1484             /* -----
1485              * validate that this canonical path is in the TOC
1486              */
1487             if (strncmp(abpath, pathstring->addr, pathstring->size) != 0)
1488             {
1489                 /* -----
1490                  * This is a key return as it could be used to trigger a call to
1491                  * a containing "parent" KDirectory to try again outside of this KArcDir
1492                  * be it another KArcDir, KSysDir, or other KDirectory interface
1493                  * implementation.
1494                  */
1495                 rc = RC (rcFS, rcDirectory, ctx, rcPath, rcOutOfKDirectory);
1496                 break;
1497             }
1498             else
1499             {
1500                 const KTocEntry *	node;		/* no alloc */
1501                 const String *	toc_path_string;	/* no alloc */
1502                 const char *	toc_path;		/* no alloc */
1503                 const char *	left;		/* no alloc */
1504                 KTocEntryType	type  = ktocentrytype_unknown;
1505                 /* -----
1506                  * now get the path that is just that which is inside the TOC by pointing
1507                  * past the path of the TOC and get the relevant TOC.  Since the incoming path
1508                  * and the "makepath" path have all been ASCIZ so is this abbreviated path.
1509                  */
1510 
1511 
1512                 rc = KTocGetPath (toc, &toc_path_string);
1513                 toc_path = abpath + toc_path_string->size; /* point past toc's path to either NUL or '/' */
1514                 if (toc_path[0] == '/')		/* if '/' move forward one char */
1515                     toc_path++;
1516                 else if (toc_path[0] != 0x00)	/* if not NUL we are not in this TOC */
1517                 {
1518                     rc = RC (rcFS, rcDirectory, ctx, rcPath, rcOutOfKDirectory);
1519                     break;
1520                 }
1521 
1522                 /* if the called resolve failed then this resolve fails too */
1523                 rc = KTocResolvePathTocEntry (toc, &node, toc_path, strlen(toc_path), &type, &left);
1524                 if (rc != 0)
1525                 {
1526                     /* nothing? or fix ret? */
1527                 }
1528                 else if (type != ktocentrytype_softlink)
1529                 {
1530                     /* -----
1531                      * This is the non soft link successful result
1532                      */
1533                     *ptype = type;
1534                     *pnode = node;
1535                     /* rc is 0 at this point */
1536                     break; /* out of for (;;) */
1537                 }
1538                 else
1539                 {
1540                     size_t	lsize;
1541 
1542                     /* -----
1543                      * successful so far but there might still be some path left if we hit a soft link
1544                      */
1545                     lsize = strlen(left);	/* points to NUL for empty string if we got to the end */
1546 
1547                     if ((lsize == 0) && (! follow))
1548                     {
1549                         /* -----
1550                          * This is a soft link successful result
1551                          */
1552                         *ptype = type;
1553                         *pnode = node;
1554                         /* rc is 0 at this point */
1555                         break; /* out of for (;;) */
1556                     }
1557                     /* -----
1558                      * If we did hit a soft link with path remaining we have work to do resolving the
1559                      * facets in the path before the end.
1560                      *
1561                      * the remaining path could be as little as a single "/".
1562                      */
1563                     else
1564                     {
1565                         const char *	symlink_path;		/* no alloc */
1566                         rc = KTocEntryGetSoftTarget(node, &symlink_path);
1567                         if (rc != 0)
1568                         {
1569                             /* fix rc_t? */
1570                             break;
1571                         }
1572                         else
1573                         {
1574                             /* -----
1575                              * If the symbolic link's path starts with '/' it is an absolute path
1576                              */
1577                             if (symlink_path[0] == '/')
1578                             {
1579                                 temp_path = symlink_path;
1580                                 continue; /* back to for(;;) */
1581                             }
1582                             else
1583                             {
1584                                 /* -----
1585                                  * if the first character isn't '/' it is relative to the current
1586                                  * directory within the TOC
1587                                  */
1588                                 size_t		asize;		/* allocated size */
1589                                 size_t		fsize;		/* first - before symlink - size */
1590                                 size_t  	ssize;		/* symlink value size */
1591                                 const char * 	backtrack;
1592                                 /* -----
1593                                  * Backtrack across the last facet - which was the link name
1594                                  */
1595                                 for (backtrack = left - 1; *backtrack != '/'; --backtrack)
1596                                     ;
1597                                 backtrack++; /* get back the '/' */
1598 
1599                                 /* -----
1600                                  * we need enough space for the
1601                                  */
1602                                 fsize = backtrack - abpath;	/* current path through start of link */
1603                                 ssize = strlen(symlink_path);/* length of the link's replacement value */
1604                                 asize = fsize+ssize+lsize+1;/* total of the three pieces and NUL */
1605                                 allocated_path		/* get a temp buffer to build this new path */
1606                                     = realloc (allocated_path, asize);
1607                                 if (allocated_path == NULL)
1608                                 {
1609                                     rc = RC (rcFS, rcDirectory, ctx, rcMemory, rcExhausted);
1610                                     break; /* end for(;;) */
1611                                 }
1612                                 else
1613                                 {
1614                                     char * pc;
1615                                     /* -----
1616                                      * TODO verify that there is or is not a problem
1617                                      * with  "~//~" showing up from these memcopies
1618                                      * and that a final NUL is added add extra buffer
1619                                      * space as needed to asize
1620                                      */
1621                                     memmove (allocated_path, abpath, fsize);
1622                                     pc = allocated_path + fsize;
1623                                     memmove (pc, symlink_path, ssize);
1624                                     pc += ssize;
1625                                     if (*(pc-1) == '/')
1626                                         --pc;
1627                                     memmove (pc, left, lsize+1);
1628                                     temp_path = allocated_path;
1629                                     continue;
1630 
1631                                 } /* if (allocated_path == NULL) {} else { */
1632                             } /* if (symlink_path[0] == '/') {} else { */
1633                         } /* if (rc != 0) {} else { */
1634                     } /* if ((lsize == 0) && (! follow)) {} else { */
1635                 } /* if (rc != 0) {} else if (type != ktocentrytype_softlink) {} else { */
1636             } /* if (strncmp(abpath, self->path, self->size) != 0) {} else { */
1637 	    } /* if (rc != 0) {} else { */
1638 	} /* while(rc == 0) */
1639 	if (abpath != NULL)
1640 	    free (abpath);
1641 	if (allocated_path != NULL)
1642 	    free (allocated_path);
1643     } /* if (path[0] == 0) {} else { */
1644     return rc;
1645 }
1646 
1647 
1648 /* ======================================================================
1649  * KArcFile
1650  *  a file inside an archive
1651  */
1652 
1653 /*-----------------------------------------------------------------------
1654  * KArcFile
1655  *  an archive file including tar and sra
1656  */
1657 struct KArcFile
1658 {
1659     KFile		dad;
1660     const KToc *	toc;	/* not accessed directly but it owns the node so need a ref to it */
1661     const KTocEntry *	node;
1662     const KFile *	archive;
1663 };
1664 
1665 /*-----------------------------------------------------------------------
1666  * KArcFileDestroy
1667  *
1668  * Destructor for objects of class KArcFile.  Usually not called directly but instead called
1669  * when the reference count for the object drops to 0.
1670  *
1671  * [RET] rc_t					0 for success; anything else for a failure
1672  *						see itf/klib/rc.h for general details
1673  * [IN] KArcFile *		self		OOP self pointer - the object to be destroyed
1674  */
1675 static
KArcFileDestroy(KArcFile * self)1676 rc_t CC KArcFileDestroy (KArcFile *self)
1677 {
1678     rc_t ret1, ret2;
1679 
1680     assert (self != NULL);
1681 
1682     ret1 = KFileRelease (self->archive);
1683     ret2 = KTocRelease (self->toc);
1684     free (self);
1685 
1686     /* -----
1687      * this seems a tad silly but pass along one or the other failure
1688      * We chose to call the second release even of the first failed
1689      * erring on the side of releasing as much as possible
1690      */
1691     return (ret1 != 0) ? ret1 : ret2;
1692 }
1693 
1694 
1695 /*-----------------------------------------------------------------------
1696  * KArcFileGetSysFile
1697  *
1698  *  returns an underlying system file object
1699  *  and starting offset to contiguous region
1700  *  suitable for memory mapping, or NULL if
1701  *  no such file is available.
1702  * Returns the KSysFile/KFile associated with a KArcFile.  NULL if not appropriate.
1703  *
1704  * [RET] struct KSysFile *
1705  * [IN]  const KArcFile *	self		Object oriented C; KArcFile object for this method
1706  * [OUT] uint64_t *		offset		An offset into the KSysfile where the KArcFile's
1707  *						data starts.
1708  */
1709 static
KArcFileGetSysFile(const KArcFile * self,uint64_t * offset)1710 struct KSysFile *CC KArcFileGetSysFile (const KArcFile *self, uint64_t *offset)
1711 {
1712     rc_t rc;
1713     KTocEntryType type;
1714     struct KSysFile * fp;
1715     uint64_t fo;
1716     uint64_t ao;
1717 
1718     /* parameters must be non-NULL */
1719     assert (self != NULL);
1720     assert (offset != NULL);
1721 
1722     /* check the type which must be a contiguous file */
1723     rc = KTocEntryGetType (self->node, &type);
1724     if (rc == 0)
1725     {
1726 	if (type == ktocentrytype_file)
1727 	{
1728 	    /* recur into the KFile to see if it allows this */
1729 	    fp = KFileGetSysFile (self->archive, &ao);
1730 
1731 	    /* -----
1732 	     * if all this is true get the offset from the TOC entry and
1733 	     * return it
1734 	     */
1735 	    if (fp != NULL)
1736 	    {
1737 		if (KTocEntryGetFileOffset (self->node, &fo) == 0)
1738 		{
1739 		    *offset = ao + fo;
1740 		    return fp;
1741 		}
1742 	    }
1743 	}
1744     }
1745     /* any failure alng the way leads to returning NULL */
1746     *offset = 0;
1747     return NULL;
1748 }
1749 
1750 
1751 /*-----------------------------------------------------------------------
1752  * KArcFileRandomAccess
1753  *
1754  * Returns zero if Random access is allowed for this KFile
1755  *
1756  * [RET] rc_t					0 for success; anything else for a failure
1757  *						see itf/klib/rc.h for general details
1758  * [IN] const KArcFile *	self		Object oriented C; KArcFile object for this method
1759  */
1760 static
KArcFileRandomAccess(const KArcFile * self)1761 rc_t CC KArcFileRandomAccess (const KArcFile *self)
1762 {
1763     assert (self != NULL);
1764     return 0;
1765 }
1766 
1767 
1768 /*-----------------------------------------------------------------------
1769  * KArcFileType
1770  *  returns a KFileDesc
1771  *  not intended to be a content type,
1772  *  but rather an implementation class
1773  */
1774 static
KArcFileType(const KArcFile * self)1775 uint32_t CC KArcFileType ( const KArcFile *self )
1776 {
1777     return KFileType ( self -> archive );
1778 }
1779 
1780 
1781 /*-----------------------------------------------------------------------
1782  * KArcFileSize
1783  *
1784  * [RET] rc_t					0 for success; anything else for a failure
1785  *						see itf/klib/rc.h for general details
1786  * [IN]  const KArcFile *	self		Object oriented C; KArcFile object for this method
1787  * [OUT] uint64_t *		size		Where to put the virtual size of the file
1788  */
1789 static
KArcFileSize(const KArcFile * self,uint64_t * size)1790 rc_t CC KArcFileSize (const KArcFile *self, uint64_t *size)
1791 {
1792     rc_t	rc;
1793     uint64_t	fsize;
1794 
1795     assert (self != NULL);
1796     assert (size != NULL);
1797 
1798     rc = KTocEntryGetFileSize(self->node, &fsize);
1799     if (rc == 0)
1800     {
1801 	/* success */
1802 	*size = fsize;
1803     }
1804     /* pass along RC value */
1805     return rc;
1806 }
1807 
1808 
1809 /*-----------------------------------------------------------------------
1810  * KArcFileSetSize
1811  *
1812  * Change the size of the KFile.  Not supported for files inside archives.
1813  *
1814  * [RET] rc_t					0 for success; anything else for a failure
1815  *						see itf/klib/rc.h for general details
1816  * [IN] KArcFile *		self		Object oriented C; KArcFile object for this method
1817  * [IN] uint64_t		size
1818  */
1819 static
KArcFileSetSize(KArcFile * self,uint64_t size)1820 rc_t CC KArcFileSetSize (KArcFile *self, uint64_t size)
1821 {
1822     return RC (rcFS, rcFile, rcUpdating, rcArc, rcUnsupported);
1823 }
1824 
1825 
1826 
1827 /*-----------------------------------------------------------------------
1828  * KArcFileRead
1829  *
1830  * Read bytes from a file represented by this KArcFile
1831  *
1832  * [RET] rc_t					0 for success; anything else for a failure
1833  *						see itf/klib/rc.h for general details
1834  * [IN]  const KArcFile *	self		Object oriented C; KArcFile object for this method
1835  * [IN]  uint64_t		pos		Offset with in the file from where to start reading
1836  * [OUT] void *			buffer		buffer to which to write the read bytes
1837  * [IN]  size_t			bsize		how many bytes to read
1838  * [OUT] size_t *		num_read	how many bytes actually read. Will get written even
1839  *						in failure
1840  */
1841 /* ----------------------------------------------------------------------
1842  * KArcFileReadContiguous
1843  *
1844  * Read data from a contiguously stored file at a specified position
1845  *
1846  * The parameters are the same as KArcFileRead.  This private function could be
1847  * inlined.  It is broken out for human readabilty.
1848  *
1849  * We just fix the offset by adding the offset to the file within the archive
1850  * (we fixed the number to read before we got here) and pass the read to the
1851  * archive.
1852  */
1853 static
KArcFileReadContiguous(const KArcFile * self,uint64_t pos,void * buffer,size_t bsize,size_t * num_read)1854 rc_t KArcFileReadContiguous ( const KArcFile * self, uint64_t pos,
1855                               void * buffer, size_t bsize, size_t * num_read )
1856 {
1857     rc_t	rc;
1858     uint64_t	offset;
1859 
1860     assert ( self != NULL );
1861     assert ( buffer != NULL );
1862     assert ( num_read != NULL );
1863     assert ( bsize != 0 );
1864 
1865     rc = KTocEntryGetFileOffset ( self->node, &offset );
1866     if ( rc == 0 )
1867     {
1868         rc = KFileRead ( self->archive, pos + offset, buffer, bsize, num_read );
1869     }
1870     return rc;
1871 }
1872 
1873 /* ----------------------------------------------------------------------
1874  * KArcFileReadEmpty
1875  *
1876  * Read data from a file with no content.
1877  *
1878  * The parameters are the same as KArcFileRead.  This private function could be
1879  * inlined.  It is broken out for human readabilty.
1880  *
1881  * We just fix the offset by adding the offset to the file within the archive
1882  * (we fixed the number to read before we got here) and pass the read to the
1883  * archive.
1884  */
1885 static
KArcFileReadEmpty(const KArcFile * self,uint64_t pos,void * buffer,size_t bsize,size_t * num_read)1886 rc_t KArcFileReadEmpty (const KArcFile *self, uint64_t pos,
1887                         void *buffer, size_t bsize, size_t *num_read)
1888 {
1889     assert (self != NULL);
1890     assert (buffer != NULL);
1891     assert (num_read != NULL);
1892     assert (bsize != 0);
1893 
1894     *num_read = 0;
1895     return 0;
1896 }
1897 
1898 /* ----------------------------------------------------------------------
1899  * KArcFileReadChunked
1900  *
1901  * Read data from a  chunked file at a specified position
1902  *
1903  * The parameters are the same as KArcFileRead.  This private function could be
1904  * inlined.  It is broken out for human readabilty.
1905  */
1906 static
KArcFileReadChunked(const KArcFile * self,uint64_t pos,void * buffer,size_t bsize,size_t * num_read)1907 rc_t KArcFileReadChunked (const KArcFile *self,
1908 			  uint64_t pos,
1909 			  void *buffer,
1910 			  size_t bsize,
1911 			  size_t *num_read)
1912 {
1913     const KTocChunk *	pchunk;		/* pointer to the chunk table */
1914     size_t		count;		/* how many to read/write in an action */
1915     uint32_t		num_chunks;	/* how many chunks in the array */
1916     rc_t		rc;		/* general purpose return from calls and pass along */
1917 
1918     assert (self != NULL);
1919     assert (buffer != NULL);
1920     assert (num_read != NULL);
1921     assert (bsize != 0);
1922 
1923     /* -----
1924      * assume no read/write will happen or rather start with having read none;
1925      * this write could be superfluous but we need to prepare *num_read for += operations
1926      */
1927     *num_read = 0;
1928 
1929     /* -----
1930      * Get the count of chunks and a pointer to the array of chunks for this file
1931      */
1932     rc = KTocEntryGetChunks (self->node, &num_chunks, &pchunk);
1933     if (rc == 0)
1934     {
1935 	uint8_t *	pbuff;		/* access the buffer as an array of bytes */
1936 	uint64_t	end;		/* this will be set to the end offset */
1937 
1938 	pbuff = buffer;
1939 	end = pos + bsize;
1940 
1941 	/* -----
1942 	 * step through the chunks
1943 	 */
1944 	for (; (num_chunks) && (pos < end); --num_chunks, ++pchunk)
1945 	{
1946 	    uint64_t 	cend;		/* end offset of this chunk */
1947 
1948 	    /* -----
1949 	     * determine the end of this chunk
1950 	     */
1951 	    cend = pchunk->logical_position + pchunk->size;
1952 
1953 	    /* -----
1954 	     * if this chunk is entirely before the current position
1955 	     * we are looking for
1956 	     * skip to the next (if any) chunk
1957 	     */
1958 	    if (pos > cend)
1959 		continue;
1960 
1961 	    /* -----
1962 	     * handle any needed zero fill section before the next chunk
1963 	     */
1964 	    if (pos < pchunk->logical_position)
1965 	    {
1966 		/* -----
1967 		 * try to fake-read as many bytes of zero as possible
1968 		 * so start assuming you need enough zeros to reach the next chunk
1969 		 * but cut it back to the remaining requested if that was too many
1970 		 */
1971 		count = (size_t)( pchunk->logical_position - pos );
1972 		if (count > bsize)
1973 		    count = bsize;
1974 
1975 		/* fake read the zeros */
1976 		memset (pbuff, 0, count);
1977 
1978 		/* update tracking variables */
1979 		pbuff += count;
1980 		pos += count;
1981 		*num_read += count;
1982 	    }
1983 
1984 	    /* -----
1985 	     * handle a chunk section
1986 	     *
1987 	     * if we are here, then we still have bytes to get and
1988 	     * pos >= pchunk_logical_position
1989 	     *
1990 	     * Get the most we can from this chunk.
1991 	     * If there are enough bytes in this chunk to finish the read: do so.
1992 	     * Else read through the end of the chunk
1993 	     */
1994 	    count = (size_t)( (end <= cend) ? end - pos : cend - pos );
1995 
1996 	    /* -----
1997 	     * a little tricky is we call by value the wanted count and the function
1998 	     * called will over write that with the actual read count
1999 	     */
2000 	    rc = KFileRead (self->archive,
2001 			    pchunk->source_position + (pchunk->logical_position - pos),
2002 			    pbuff, count, &count);
2003 
2004 	    *num_read += count;
2005 	    if (rc != 0)
2006 	    {
2007 		/* failure so abort */
2008 		break;
2009 	    }
2010 	    pbuff += count;
2011 	    pos += count;
2012 	    *num_read += count;
2013 	}
2014 	/* -----
2015 	 * If eveything so far is okay but we have more bytes to read
2016 	 * yet no more chunks; then fill to the end with zeroes
2017 	 */
2018 	if ((rc == 0) && (pos < end))
2019 	{
2020 	    count = (size_t)( end - pos );
2021 	    memset (pbuff, 0, count);
2022 	    *num_read += count;
2023 	}
2024     }
2025     return rc;
2026 }
2027 /* ----------------------------------------------------------------------
2028  * Read
2029  *  read file from known position
2030  *
2031  *  "pos" [ IN ] - starting position within file
2032  *
2033  *  "buffer" [ OUT ] and "bsize" [ IN ] - return buffer for read
2034  *
2035  *  "num_read" [ OUT, NULL OKAY ] - optional return parameter
2036  *  giving number of bytes actually read
2037  */
2038 static
KArcFileRead(const KArcFile * self,uint64_t pos,void * buffer,size_t bsize,size_t * num_read)2039 rc_t CC KArcFileRead	(const KArcFile *self,
2040 			 uint64_t pos,
2041 			 void *buffer,
2042 			 size_t bsize,
2043 			 size_t *num_read)
2044 {
2045     KTocEntryType	type;
2046     rc_t		rc;
2047 
2048     /* -----
2049      * self and buffer were validated as not NULL before calling here
2050      *
2051      * So get the KTocEntry type: chunked files and contiguous files
2052      * are read differently.
2053      */
2054     assert (self != NULL);
2055     assert (buffer != NULL);
2056     assert (num_read != NULL);
2057     assert (bsize != 0);
2058 
2059     rc = KTocEntryGetType(self->node, &type);
2060 
2061     assert ((type == ktocentrytype_file) ||
2062             (type == ktocentrytype_chunked) ||
2063             (type == ktocentrytype_emptyfile));
2064 
2065     if (rc == 0)
2066     {
2067 	uint64_t	size;
2068 
2069 	/* -----
2070 	 * We have to validate the size to be read and will modify the number
2071 	 * down if necessary
2072 	 */
2073 	rc = KTocEntryGetFileSize (self->node, &size);
2074 	if (rc == 0)
2075 	{
2076 	    /* -----
2077 	     * if we are seeking beyond the end match sysfile.c's use of pread
2078 	     * and return number read as 0 to mark EOF
2079 	     */
2080 	    if (pos >= size)
2081 	    {
2082 		*num_read = 0;
2083 	    }
2084 	    else
2085 	    {
2086 		uint64_t	limit;
2087 
2088 		limit =
2089 		    (pos + bsize > size)	/* if attempt to read beyond end of file */
2090 		    ? size - pos		/* then force smaller read */
2091 		    : bsize;			/* else allow full read */
2092 
2093 		switch (type)
2094 		{
2095 		default:
2096 		case ktocentrytype_unknown:
2097 		case ktocentrytype_dir:
2098 		case ktocentrytype_softlink:
2099 		case ktocentrytype_hardlink:
2100 		    /* -----
2101 		     * We should not have been able to open these as a KArcFile
2102 		     * so this is probably superfluous
2103 		     */
2104 		    rc = RC (rcFS, rcFile, rcReading, rcArc, rcUnexpected);
2105 		    break;
2106 		case ktocentrytype_file:
2107 		    rc = KArcFileReadContiguous (self, pos, buffer, (size_t)limit, num_read);
2108 		    break;
2109 		case ktocentrytype_chunked:
2110 		    rc = KArcFileReadChunked (self, pos, buffer, (size_t)limit, num_read);
2111 		    break;
2112 		case ktocentrytype_emptyfile:
2113 		    rc = KArcFileReadEmpty (self, pos, buffer, (size_t)limit, num_read);
2114 		    break;
2115 		}
2116 	    }
2117 	}
2118     }
2119     return rc;
2120 }
2121 
2122 
2123 
2124 /*-----------------------------------------------------------------------
2125  * KArcFileWrite
2126  *
2127  * Write bytes to a file represented by this KArcFile.
2128  * Fails as unsupported for files inside archives.
2129  *
2130  * [RET] rc_t					0 for success; anything else for a failure
2131  *						see itf/klib/rc.h for general details
2132  * [IN]  KArcFile *		self		Object oriented C; KArcFile object for this method
2133  * [IN]  uint64_t 		pos		Offset within file to start writing (ignored)
2134  * [IN]  const void *		buffer		pointer to data to write (ignored)
2135  * [IN]  size_t 		size		how many bytes to write (ignored)
2136  * [OUT] size_t *		num_writ	how many bytes written - always set to 0
2137  */
2138 static
KArcFileWrite(KArcFile * self,uint64_t pos,const void * buffer,size_t size,size_t * num_writ)2139 rc_t CC KArcFileWrite (KArcFile *self, uint64_t pos,
2140 		       const void *buffer, size_t size,
2141 		       size_t *num_writ)
2142 {
2143     assert (num_writ != NULL);
2144 
2145     /* duplicates write in KFileWrite() so this can be deleted */
2146     *num_writ = 0;
2147 
2148     return RC (rcFS, rcArc, rcWriting, rcSelf, rcUnsupported);
2149 }
2150 
2151 
2152 
2153 static	KFile_vt_v1	vtKArcFile =
2154 {
2155     /* version */
2156     1, 1,
2157 
2158     /* 1.0 */
2159     KArcFileDestroy,
2160     KArcFileGetSysFile,
2161     KArcFileRandomAccess,
2162     KArcFileSize,
2163     KArcFileSetSize,
2164     KArcFileRead,
2165     KArcFileWrite,
2166 
2167     /* 1.1 */
2168     KArcFileType
2169 };
2170 
2171 /*-----------------------------------------------------------------------
2172  * KArcFileMake
2173  *
2174  * [RET] rc_t					0 for success; anything else for a failure
2175  *						see itf/klib/rc.h for general details
2176  * [OUT] KArcFile ** 		self		were to put a reference to the newly allocated
2177  *						KArcFile structure
2178  * [IN]  const KFile *		archive		The KFile for the archive containing this archive
2179  * [IN]  const KArcToc *	toc		The controlling TOC for the Archive File
2180  * [IN]  const KTocEntry *	node		The specific node somewhere in that TOC for this file
2181  */
2182 static
KArcFileMake(KArcFile ** self,const KFile * archive,const KToc * toc,const KTocEntry * node)2183 rc_t KArcFileMake (KArcFile ** self,
2184 		   const KFile * archive,
2185 		   const KToc * toc,
2186 		   const KTocEntry * node)
2187 {
2188     rc_t	rc;
2189     KArcFile *	pF;
2190     uint64_t    size;
2191 
2192     /* -----
2193      * we can not accept any of the four parameters as NULL
2194      */
2195     assert (self != NULL);
2196     assert (archive != NULL);
2197     assert (toc != NULL);
2198     assert (node != NULL);
2199 
2200     /* -----
2201      * Proceed with non-NULL parameters
2202      */
2203     rc = KFileSize (archive, &size);
2204     if (GetRCState(rc) == rcUnsupported)
2205     {
2206         size = ~(uint64_t)0;
2207         rc = 0;
2208     }
2209 
2210     if (rc == 0)
2211     {
2212         /* we need to check chunked files here as well */
2213         if (((node->type == ktocentrytype_file) &&
2214              (node->u.contiguous_file.file_size > 0) &&
2215              (size < (node->u.contiguous_file.file_size +
2216                       node->u.contiguous_file.archive_offset))) ||
2217             ((node->type == ktocentrytype_chunked) &&
2218              (node->u.chunked_file.file_size > 0) &&
2219              (size < (node->u.chunked_file.chunks[node->u.chunked_file.num_chunks-1].source_position +
2220                       node->u.chunked_file.chunks[node->u.chunked_file.num_chunks-1].size))))
2221             rc = RC (rcFS, rcFile, rcConstructing, rcArc, rcIncomplete);
2222         else
2223         {
2224             /* get space for the object */
2225             pF = malloc (sizeof * pF);
2226             if (pF == NULL)	/* allocation failed */
2227             {
2228                 /* fail */
2229                 rc = RC (rcFS, rcFile, rcConstructing, rcMemory, rcExhausted);
2230             }
2231             else
2232             {
2233                 rc = KFileInit (&pF->dad,				/* initialize base class */
2234                                 (const KFile_vt*)&vtKArcFile,	/* VTable for KArcFile */
2235                                 "KArcFile", "no-name",
2236                                 true,				/* read allowed */
2237                                 false);				/* write disallowed */
2238                 if (rc == 0)
2239                 {
2240                     /* succeed */
2241                     pF->toc = toc;					/* shared TOC */
2242                     KTocAddRef(toc);				/* keep alive reference */
2243                     pF->node = node;				/* file specific TOC entry */
2244                     pF->archive = archive;				/* shared archive file */
2245                     KFileAddRef(archive);				/* keep alive reference */
2246                     *self = pF;					/* and to the output */
2247                 }
2248                 if (rc != 0)
2249                     /* fail */
2250                     free (pF);
2251             }
2252 	}
2253     }
2254     return rc;
2255 }
2256 
2257 
2258 /* ----------------------------------------------------------------------
2259  * KArcDirVisit
2260  *  visit each path under designated directory,
2261  *  recursively if so indicated
2262  *
2263  *  "recurse" [ IN ] - if non-zero, recursively visit sub-directories
2264  *
2265  *  "f" [ IN ] and "data" [ IN, OPAQUE ] - function to execute
2266  *  on each path. receives a base directory and relative path
2267  *  for each entry, where each path is also given the leaf name
2268  *  for convenience. if "f" returns non-zero, the iteration will
2269  *  terminate and that value will be returned. NB - "dir" will not
2270  *  be the same as "self".
2271  *
2272  *  "path" [ IN ] - NUL terminated string in directory-native character set
2273  */
2274 static
KArcDirVisit(const KArcDir * self,bool recurse,rc_t (CC * f)(const KDirectory *,uint32_t,const char *,void *),void * data,const char * path,va_list args)2275 rc_t CC KArcDirVisit (const KArcDir *self,
2276                       bool recurse,
2277                       rc_t (CC* f) (const KDirectory *, uint32_t, const char *, void *),
2278                       void *data,
2279                       const char *path,
2280                       va_list args)
2281 {
2282     char * full_path;
2283     rc_t   rc;
2284 
2285 
2286     /* -----
2287      * First fix the path to make it useable
2288      */
2289     rc = KArcDirMakePath (self, rcVisiting, true, &full_path, path, args);
2290     if (rc != 0)
2291     {
2292 	LOGERR (klogInt, rc, "failed to make path in Visit");
2293     }
2294     else
2295     {
2296 	const KTocEntry * pnode;
2297 	KTocEntryType	type;
2298 
2299 	/* -----
2300 	 * Now find that path as a node and validate it is a directory
2301 	 */
2302 	rc = KArcDirResolvePathNode(self, rcListing, full_path, true, &pnode, &type);
2303 	if (rc != 0)
2304 	{
2305 	    PLOGERR (klogInt, (klogInt, rc, "failed to resolve path $(P) in Visit", "P=%s", full_path));
2306 	}
2307 	else
2308 	{
2309 	    if ((type == ktocentrytype_dir) || (type == ktocentrytype_hardlink))
2310 	    {
2311 		KArcDir * full_dir;
2312 		uint32_t path_size;
2313 
2314 		/* -----
2315 		 * make a locally accessible private KDirectory/KArcDir
2316 		 */
2317 		for ( path_size = (uint32_t)strlen ( full_path );
2318 		      ( path_size > self->root ) && ( full_path[ path_size - 1 ] == '/' );
2319 		      -- path_size )
2320 		{}
2321 		rc = KArcDirMake (&full_dir,
2322 				  rcVisiting,
2323 				  self->parent,
2324 				  self->toc,
2325 				  pnode,
2326 				  self->archive.v,
2327 				  self->arctype,
2328 				  self->root,
2329 				  full_path,
2330 				  path_size,
2331 				  true,
2332 				  false);
2333 		if (rc == 0)
2334 		{
2335 		    KArcDirVisitData pb;
2336 
2337 		    pb.f = f;
2338 		    pb.data = data;
2339 		    pb.dir = full_dir;
2340 		    pb.recurse = recurse;
2341 /*		    pb.dir.path[--pb.dir.size] = 0; */
2342 
2343 		    rc = KArcDirVisitDir (&pb);
2344 
2345 		    KArcDirDestroy (full_dir);
2346 		}
2347 	    }
2348 	    else
2349 	    {
2350 		rc = RC (rcFS, rcDirectory, rcVisiting, rcPath, rcIncorrect);
2351 		LOGERR (klogInt, rc, "Type is not a directory");
2352 	    }
2353 	}
2354 	free (full_path);
2355     }
2356     return rc;
2357 }
2358 
2359 static
KArcDirVisit_noargs(const KArcDir * self,bool recurse,rc_t (CC * f)(const KDirectory *,uint32_t,const char *,void *),void * data,const char * path,...)2360 rc_t CC KArcDirVisit_noargs (const KArcDir *self,
2361                       bool recurse,
2362                       rc_t (CC* f) (const KDirectory *, uint32_t, const char *, void *),
2363                       void *data,
2364                       const char *path,
2365                       ...)
2366 {
2367     va_list vl;
2368     va_start( vl, path );
2369     rc_t ret = KArcDirMakePath( self, recurse, f, data, path, vl );
2370     va_end(vl);
2371     return ret;
2372 }
2373 
2374 /* ----------------------------------------------------------------------
2375  * KArcDirVisitUpdate
2376  */
KArcDirVisitUpdate(KArcDir * self,bool recurse,rc_t (CC * f)(KDirectory *,uint32_t,const char *,void *),void * data,const char * path,va_list args)2377 static rc_t CC KArcDirVisitUpdate (KArcDir *self,
2378                                    bool recurse,
2379                                    rc_t (CC*f) (KDirectory *,uint32_t,const char *,void *),
2380                                    void *data,
2381                                    const char *path,
2382                                    va_list args)
2383 {
2384     return RC (rcFS, rcDirectory, rcUpdating, rcSelf, rcUnsupported);
2385 }
2386 
2387 /* ----------------------------------------------------------------------
2388  * KArcDirResolvePath
2389  *
2390  *  resolves path to an absolute or directory-relative path
2391  *
2392  * [IN]  const KArcDir *self		Objected oriented self
2393  * [IN]	 bool 		absolute	if non-zero, always give a path starting
2394  *  					with '/'. NB - if the directory is
2395  *					chroot'd, the absolute path
2396  *					will still be relative to directory root.
2397  * [OUT] char *		resolved	buffer for NUL terminated result path in
2398  *					directory-native character set
2399  * [IN]	 size_t		rsize		limiting size of resolved buffer
2400  * [IN]  const char *	path		NUL terminated string in directory-native
2401  *					character set denoting target path.
2402  *					NB - need not exist.
2403  *
2404  * NOTE: Does not meet a design target of on stack (localized variable) allocation of single 4kb path
2405  */
KArcDirResolvePath(const KArcDir * self,bool absolute,char * resolved,size_t rsize,const char * path,va_list args)2406 static rc_t CC KArcDirResolvePath (const KArcDir *self,
2407                                    bool absolute,
2408                                    char *resolved,
2409                                    size_t rsize,
2410                                    const char *path,
2411                                    va_list args)
2412 {
2413     char * full;
2414     rc_t   rc;
2415 
2416     assert (self != NULL);
2417     assert (resolved != NULL);
2418     assert (path != NULL);
2419 
2420     rc = KArcDirMakePath (self, rcResolving, true, &full, path, args);
2421 
2422     if (rc == 0)
2423     {
2424         uint32_t path_size = (uint32_t)strlen ( full );
2425 
2426         if (absolute)
2427         {
2428             /* test buffer capacity -  this is a limitation of KDirectory not in KArcDir */
2429             if ((path_size - self->root) >= rsize)
2430             {
2431                 rc =  RC (rcFS, rcDirectory, rcResolving, rcBuffer, rcInsufficient);
2432             }
2433             else
2434             {
2435                 /* ready to go */
2436                 strcpy (resolved, & full[self->root]);
2437                 assert (resolved[0] == '/');
2438             }
2439         }
2440         else
2441         {
2442             rc = KArcDirRelativePath (self, rcResolving, self->path, full, path_size);
2443             if (rc == 0)
2444             {
2445                 path_size = (uint32_t)strlen ( full );
2446                 /* test buffer capacity -  this is a limitation of KDirectory not in KArcDir */
2447                 if (path_size >= rsize)
2448                 {
2449                     rc = RC (rcFS, rcDirectory, rcResolving, rcBuffer, rcInsufficient);
2450                 }
2451                 else
2452                 {
2453                     strcpy (resolved, full);
2454                 }
2455             }
2456         }
2457     }
2458     if (full != NULL)
2459         free (full);
2460 
2461     return rc;
2462 }
2463 
2464 /* ----------------------------------------------------------------------
2465  * KArcDirResolveAlias
2466  *  resolves an alias path to its immediate target
2467  *  NB - the resolved path may be yet another alias
2468  *
2469  *  "alias" [ IN ] - NUL terminated string in directory-native
2470  *  character set denoting an object presumed to be an alias.
2471  *
2472  *  "resolved" [ OUT ] and "rsize" [ IN ] - buffer for
2473  *  NUL terminated result path in directory-native character set
2474  *
2475  * NOTE: Does not meet a design target of on stack (localized variable) allocation of single 4kb path
2476  */
KArcDirResolveAlias(const KArcDir * self,bool absolute,char * resolved,size_t rsize,const char * alias_fmt,va_list args)2477 static rc_t CC KArcDirResolveAlias (const KArcDir * self,
2478 				 bool absolute,
2479 				 char * resolved,
2480 				 size_t rsize,
2481 				 const char *alias_fmt,
2482 				 va_list args)
2483 {
2484     char *		full_path;
2485     const char *	link_path;
2486     const KTocEntry * pnode;
2487     KTocEntryType	type;
2488     rc_t		rc;
2489     size_t		ssize;
2490 
2491     assert (self != NULL);
2492     assert (resolved != NULL);
2493     assert (alias_fmt != NULL);
2494 
2495     rc = KArcDirMakePath (self, rcResolving, true,
2496 			  &full_path, alias_fmt, args);
2497 
2498     if (rc != 0)
2499     {
2500     	/* can't "fix" path */
2501 	    /*rc = RC (rcFS, rcDirectory, rcResolving, rcPath, rcInvalid); ? or tweak it? */
2502     }
2503     else
2504     {
2505     	/* first find the node and it has to be an alias */
2506         char alias[4096];
2507         /* VDB-4386: cannot treat va_list as a pointer! */
2508         int size = /*( args == NULL ) ?
2509             snprintf  ( alias, sizeof alias, "%s", alias_fmt ) : */
2510             vsnprintf ( alias, sizeof alias, alias_fmt, args );
2511 
2512         if ( size < 0 || size >= ( int ) sizeof alias )
2513             rc = RC ( rcFS, rcDirectory, rcResolving, rcPath, rcExcessive );
2514         else
2515         	rc = KArcDirResolvePathNode (self, rcResolving, alias, false, &pnode, &type);
2516 
2517     	if (rc != 0)
2518     	{
2519     	    /*rc = RC (rcFS, rcDirectory, rcResolving, rcPath, rcInvalid); ? or tweak it? */
2520     	}
2521     	else if (type != ktocentrytype_softlink)
2522     	{
2523     	    rc = RC (rcFS, rcDirectory, rcResolving, rcLink, rcInvalid);
2524     	}
2525     	else
2526     	{
2527     	    rc = KTocEntryGetSoftTarget(pnode, &link_path);
2528     	    if (rc != 0)
2529     	    {
2530         		/* can't "fix" path */
2531         		/*rc = RC (rcFS, rcDirectory, rcResolving, rcPath, rcInvalid); ? or tweak it? */
2532     	    }
2533     	    else
2534     	    {
2535     	    	ssize = strlen(link_path);
2536         		if (ssize > rsize)
2537         		{
2538     	    	    rc = RC (rcFS, rcDirectory,rcResolving, rcParam, rcInsufficient);
2539     		    }
2540         		else
2541         		{
2542     	    	    strcpy (resolved, link_path);
2543     		    }
2544     	    }
2545     	}
2546     }
2547     return rc;
2548 }
2549 
2550 /* ----------------------------------------------------------------------
2551  * KArcDirRename
2552  *  rename an object accessible from directory, replacing
2553  *  any existing target object of the same type
2554  *
2555  *  "from" [ IN ] - NUL terminated string in directory-native
2556  *  character set denoting existing object
2557  *
2558  *  "to" [ IN ] - NUL terminated string in directory-native
2559  *  character set denoting existing object
2560  */
2561 static
KArcDirRename(KArcDir * self,bool force,const char * from,const char * to)2562 rc_t CC KArcDirRename (KArcDir *self, bool force, const char *from, const char *to)
2563 {
2564     assert (self != NULL);
2565     assert (from != NULL);
2566     assert (to != NULL);
2567 
2568     return RC (rcFS, rcArc, rcUpdating, rcSelf, rcUnsupported);
2569 }
2570 
2571 /* ----------------------------------------------------------------------
2572  * KArcDirRemove
2573  *  remove an accessible object from its directory
2574  *
2575  *  "path" [ IN ] - NUL terminated string in directory-native
2576  *  character set denoting target object
2577  *
2578  *  "force" [ IN ] - if non-zero and target is a directory,
2579  *  remove recursively
2580  */
2581 static
KArcDirRemove(KArcDir * self,bool force,const char * path,va_list args)2582 rc_t CC KArcDirRemove (KArcDir *self, bool force, const char *path, va_list args)
2583 {
2584     assert (self != NULL);
2585     assert (path != NULL);
2586 
2587     return RC (rcFS, rcArc, rcUpdating, rcSelf, rcUnsupported);
2588 }
2589 
2590 /* ----------------------------------------------------------------------
2591  * KArcDirClearDir
2592  *  remove all directory contents
2593  *
2594  *  "path" [ IN ] - NUL terminated string in directory-native
2595  *  character set denoting target directory
2596  *
2597  *  "force" [ IN ] - if non-zero and directory entry is a
2598  *  sub-directory, remove recursively
2599  */
2600 static
KArcDirClearDir(KArcDir * self,bool force,const char * path,va_list args)2601 rc_t CC KArcDirClearDir (KArcDir *self, bool force, const char *path, va_list args)
2602 {
2603     assert (self != NULL);
2604     assert (path != NULL);
2605 
2606     return RC (rcFS, rcArc, rcUpdating, rcSelf, rcUnsupported);
2607 }
2608 
2609 /* ----------------------------------------------------------------------
2610  * KArcDirAccess
2611  *  get access to object
2612  *
2613  *  "access" [ OUT ] - return parameter for Unix access mode
2614  *
2615  *  "path" [ IN ] - NUL terminated string in directory-native
2616  *  character set denoting target object
2617  * NOTE: Does not meet a design target of on stack (localized variable) allocation of single 4kb path
2618  */
KArcDirVAccess(const KArcDir * self,uint32_t * access,const char * path_fmt,va_list args)2619 static rc_t CC KArcDirVAccess (const KArcDir *self,
2620 			    uint32_t *access,
2621 			    const char *path_fmt,
2622 			    va_list args)
2623 {
2624     rc_t rc;
2625     uint32_t acc;
2626     KTocEntryType type;
2627     char * full;
2628     const KTocEntry * entry;
2629 
2630     va_list args_copy;
2631 
2632     assert (self != NULL);
2633     assert (access != NULL);
2634     assert (path_fmt != NULL);
2635 
2636     /* MUST copy "args" if the intention is to use it twice */
2637     /* VDB-4386: cannot treat va_list as a pointer!*/
2638 /*    if ( args != NULL )*/
2639         va_copy ( args_copy, args );
2640 
2641     /* -----
2642      * by C standard the nested ifs (if A { if B { if C ... could have been if A && B && C
2643      */
2644     if ((rc = KArcDirMakePath (self, rcAccessing, false, &full, path_fmt, args)) == 0)
2645     {
2646         char path [ 4096 ];
2647         /* VDB-4386: cannot treat va_list as a pointer!*/
2648         int size = /*( args == NULL ) ?
2649             snprintf  ( path, sizeof path, "%s", path_fmt ) :*/
2650             vsnprintf ( path, sizeof path, path_fmt, args_copy );
2651 
2652         if ( size < 0 || size >= ( int ) sizeof path )
2653             rc = RC ( rcFS, rcDirectory, rcAccessing, rcPath, rcExcessive );
2654         else
2655         {
2656         	if ((rc = KArcDirResolvePathNode (self, rcAccessing, path, true, &entry, &type)) == 0)
2657         	{
2658         	    if ((rc = KTocEntryGetAccess (entry, &acc)) == 0)
2659         	    {
2660                     /*
2661                      * We want to filter the access because within an Archive
2662                      * a file is unwritable
2663                      */
2664             		*access = acc & ~(S_IWRITE|S_IWGRP|S_IWOTH);
2665             		rc = 0;
2666         	    }
2667         	}
2668         }
2669     }
2670 
2671 /*    if ( args != NULL )*/
2672         va_end ( args_copy );
2673 
2674     if (full != NULL)
2675         free (full);
2676     return rc;
2677 }
2678 
2679 /* ----------------------------------------------------------------------
2680  * KArcDirSetAccess
2681  *  set access to object a la Unix "chmod"
2682  *
2683  *  "path" [ IN ] - NUL terminated string in directory-native
2684  *  character set denoting target object
2685  *
2686  *  "access" [ IN ] and "mask" [ IN ] - definition of change
2687  *  where "access" contains new bit values and "mask defines
2688  *  which bits should be changed.
2689  *
2690  *  "recurse" [ IN ] - if non zero and "path" is a directory,
2691  *  apply changes recursively.
2692  */
KArcDirSetAccess(KArcDir * self,bool recurse,uint32_t access,uint32_t mask,const char * path,va_list args)2693 static rc_t CC KArcDirSetAccess (KArcDir *self,
2694 			      bool recurse,
2695 			      uint32_t access,
2696 			      uint32_t mask,
2697 			      const char *path,
2698 			      va_list args)
2699 {
2700     assert (self != NULL);
2701     assert (path != NULL);
2702 
2703     return RC (rcFS, rcArc, rcUpdating, rcSelf, rcUnsupported);
2704 }
2705 
2706 
KArcDirVDate(const KArcDir * self,KTime_t * date,const char * path_fmt,va_list args)2707 static	rc_t CC KArcDirVDate		(const KArcDir *self,
2708 					 KTime_t *date,
2709 					 const char *path_fmt,
2710 					 va_list args)
2711 {
2712 /*     const KToc *	toc; */
2713     rc_t 		rc;
2714     KTime_t		ldate;
2715     KTocEntryType	type;
2716     char * 		full;
2717     const KTocEntry * node;
2718 
2719     va_list args_copy;
2720 
2721     assert (self != NULL);
2722     assert (date != NULL);
2723     assert (path_fmt != NULL);
2724 
2725     /* MUST copy "args" if the intention is to use it twice */
2726     /* VDB-4386: cannot treat va_list as a pointer! */
2727 /*    if ( args != NULL )*/
2728         va_copy ( args_copy, args );
2729 
2730     /* -----
2731      * by C standard the nested ifs (if A { if B { if C ... could have been if A && B && C
2732      */
2733     if ((rc = KArcDirMakePath (self, rcAccessing, false, &full, path_fmt, args)) == 0)
2734     {
2735 #if 0
2736         if ((rc = KArcDirGetTOC (self, &toc)) == 0)
2737 #endif
2738         {
2739             /* THIS IS INCORRECT - IT SHOULD NOT RESOLVE ALIASES */
2740             char path [ 4096 ];
2741             int size = vsnprintf ( path, sizeof path, path_fmt, args_copy );
2742 
2743             if ( size < 0 || size >= ( int ) sizeof path )
2744                 rc = RC ( rcFS, rcDirectory, rcAccessing, rcPath, rcExcessive );
2745             else
2746             {
2747                 if ((rc = KArcDirResolvePathNode (self, rcAccessing, path, true, &node, &type)) == 0)
2748                 {
2749                     if ((rc = KTocEntryGetTime (node, &ldate)) == 0)
2750                     {
2751                         *date =  ldate;
2752                         rc = 0;
2753                     }
2754                 }
2755             }
2756         }
2757     }
2758 
2759 /*    if ( args != NULL )*/
2760         va_end ( args_copy );
2761 
2762     if (full != NULL)
2763         free (full);
2764     return rc;
2765 }
2766 
KArcDirSetDate(KArcDir * self,bool recurse,KTime_t date,const char * path,va_list args)2767 static	rc_t CC KArcDirSetDate		(KArcDir *self,
2768 					 bool recurse,
2769 					 KTime_t date,
2770 					 const char *path,
2771 					 va_list args)
2772 {
2773     assert (self != NULL);
2774     assert (path != NULL);
2775 
2776     return RC (rcFS, rcArc, rcUpdating, rcSelf, rcUnsupported);
2777 }
2778 
2779 static
KArcDirGetSysDir(const KArcDir * self)2780 struct KSysDir *CC KArcDirGetSysDir ( const KArcDir *self )
2781 {
2782     return NULL;
2783 }
2784 
2785 /* ----------------------------------------------------------------------
2786  * KArcDirCreateAlias
2787  *  creates a path alias according to create mode
2788  *
2789  *  "targ" [ IN ] - NUL terminated string in directory-native
2790  *  character set denoting target object
2791  *
2792  *  "alias" [ IN ] - NUL terminated string in directory-native
2793  *  character set denoting target alias
2794  *
2795  *  "access" [ IN ] - standard Unix directory access mode
2796  *  used when "mode" has kcmParents set and alias path does
2797  *  not exist.
2798  *
2799  *  "mode" [ IN ] - a creation mode (see explanation above).
2800  */
2801 static
KArcDirCreateAlias(KArcDir * self,uint32_t access,KCreateMode mode,const char * targ,const char * alias)2802 rc_t CC KArcDirCreateAlias (KArcDir *self,
2803 			 uint32_t access,
2804 			 KCreateMode mode,
2805 			 const char *targ,
2806 			 const char *alias)
2807 {
2808     assert (self != NULL);
2809     assert (targ != NULL);
2810     assert (alias != NULL);
2811 
2812     return RC (rcFS, rcArc, rcCreating, rcSelf, rcUnsupported);
2813 }
2814 
2815 /* ----------------------------------------------------------------------
2816  * KArcDirOpenFileRead
2817  *  opens an existing file with read-only access
2818  *
2819  *  "f" [ OUT ] - return parameter for newly opened file
2820  *
2821  *  "path" [ IN ] - NUL terminated string in directory-native
2822  *  character set denoting target file
2823  * NOTE: Does not meet a design target of on stack (localized variable) allocation of single 4kb path
2824  */
2825 static
KArcDirOpenFileRead(const KArcDir * self,const KFile ** f,const char * path,va_list args)2826 rc_t CC KArcDirOpenFileRead	(const KArcDir *self,
2827 					 const KFile **f,
2828 					 const char *path,
2829 					 va_list args)
2830 {
2831     char *	full_path = NULL;
2832     rc_t	rc;
2833 
2834     assert (self != NULL);
2835     assert (f != NULL);
2836     assert (path != NULL);
2837 
2838     rc = KArcDirMakePath (self, rcOpening, true, &full_path, path, args);
2839 
2840     if (rc == 0)
2841     {
2842 	const KTocEntry * pnode;
2843 	KTocEntryType     type;
2844 
2845 	rc = KArcDirResolvePathNode (self, rcOpening, full_path, true, &pnode, &type);
2846 
2847 	if (rc == 0)
2848 	{
2849 
2850 	    switch (type)
2851 	    {
2852 	    case ktocentrytype_unknown:
2853 	    case ktocentrytype_dir:
2854 	    case ktocentrytype_softlink:
2855 	    case ktocentrytype_hardlink:
2856 	    default:
2857 		rc = RC (rcFS, rcDirectory, rcOpening, rcFile, rcInvalid);
2858 		break;
2859 	    case ktocentrytype_emptyfile:
2860 	    case ktocentrytype_file:
2861 	    case ktocentrytype_chunked:
2862 		rc = KArcFileMake ((KArcFile**)f, self->archive.v, self->toc, pnode);
2863 		break;
2864 	    }
2865 	}
2866 	free (full_path);
2867     }
2868     return rc;
2869 }
2870 
2871 /* ----------------------------------------------------------------------
2872  * KArcDirOpenFileWrite
2873  *  opens an existing file with write access
2874  *
2875  *  "f" [ OUT ] - return parameter for newly opened file
2876  *
2877  *  "path" [ IN ] - NUL terminated string in directory-native
2878  *  character set denoting target file
2879  *
2880  *  "update" [ IN ] - if non-zero, open in read/write mode
2881  *  otherwise, open in write-only mode
2882  */
2883 static
KArcDirOpenFileWrite(KArcDir * self,KFile ** f,bool update,const char * path,va_list args)2884 rc_t CC KArcDirOpenFileWrite	(KArcDir *self,
2885 					 KFile **f,
2886 					 bool update,
2887 					 const char *path,
2888 					 va_list args)
2889 {
2890     assert (self != NULL);
2891     assert (f != NULL);
2892     assert (path != NULL);
2893 
2894     return RC (rcFS, rcArc, rcCreating, rcSelf, rcUnsupported);
2895 }
2896 
2897 /* ----------------------------------------------------------------------
2898  * KArcDirCreateFile
2899  *  opens a file with write access
2900  *
2901  *  "f" [ OUT ] - return parameter for newly opened file
2902  *
2903  *  "path" [ IN ] - NUL terminated string in directory-native
2904  *  character set denoting target file
2905  *
2906  *  "access" [ IN ] - standard Unix access mode, e.g. 0664
2907  *
2908  *  "update" [ IN ] - if non-zero, open in read/write mode
2909  *  otherwise, open in write-only mode
2910  *
2911  *  "mode" [ IN ] - a creation mode (see explanation above).
2912  */
2913 static
KArcDirCreateFile(KArcDir * self,KFile ** f,bool update,uint32_t access,KCreateMode cmode,const char * path,va_list args)2914 rc_t CC KArcDirCreateFile	(KArcDir *self,
2915 					 KFile **f,
2916 					 bool update,
2917 					 uint32_t access,
2918 					 KCreateMode cmode,
2919 					 const char *path,
2920 					 va_list args)
2921 {
2922     assert (self != NULL);
2923     assert (f != NULL);
2924     assert (path != NULL);
2925 
2926     return RC (rcFS, rcArc, rcCreating, rcSelf, rcUnsupported);
2927 }
2928 
2929 /* ----------------------------------------------------------------------
2930  * KArcDirFileLocator
2931  *  returns locator in bytes of target file
2932  *
2933  *  "path" [ IN ] - NUL terminated string in directory-native
2934  *  character set denoting target file
2935  *
2936  *  "locator" [ OUT ] - return parameter for file locator
2937  * NOTE: Does not meet a design target of on stack (localized variable) allocation of single 4kb path
2938  */
2939 static
KArcDirFileLocator(const KArcDir * self,uint64_t * locator,const char * path,va_list args)2940 rc_t CC KArcDirFileLocator		(const KArcDir *self,
2941 					 uint64_t *locator,
2942 					 const char *path,
2943 					 va_list args)
2944 {
2945     char *		full_path;
2946     rc_t		rc;
2947 
2948     assert (self != NULL);
2949     assert (locator != NULL);
2950     assert (path != NULL);
2951 
2952     rc = KArcDirMakePath (self, rcResolving, true,
2953 			  &full_path, path, args);
2954 
2955     if (rc != 0)
2956     {
2957 	/* can't "fix" path */
2958 	/*rc = RC (rcFS, rcDirectory, rcResolving, rcPath, rcInvalid); ? or tweak it? */
2959     }
2960     else
2961     {
2962 	const KTocEntry * pnode;
2963 	KTocEntryType     type;
2964 
2965 	rc = KArcDirResolvePathNode (self, rcResolving, full_path, /*follow links*/true, &pnode, &type);
2966 
2967 	if (rc != 0)
2968 	{
2969 	    /* can't resolve path */
2970 	    /*rc = RC (rcFS, rcDirectory, rcResolving, rcPath, rcInvalid); ? or tweak it? */
2971 	}
2972 	else
2973 	{
2974 	    uint64_t	flocator;
2975 
2976 	    rc = KTocEntryGetFileLocator(pnode, &flocator);
2977 	    if (rc != 0)
2978 	    {
2979 		/* can't "fix" path */
2980 		/*rc = RC (rcFS, rcDirectory, rcResolving, rcPath, rcInvalid); ? or tweak it? */
2981 	    }
2982 	    else
2983 	    {
2984 		*locator = flocator;
2985 	    }
2986 	}
2987 	free (full_path);
2988     }
2989     return rc;
2990 }
2991 
2992 /* ----------------------------------------------------------------------
2993  * KArcDirFileSize
2994  *  returns size in bytes of target file
2995  *
2996  *  "path" [ IN ] - NUL terminated string in directory-native
2997  *  character set denoting target file
2998  *
2999  *  "size" [ OUT ] - return parameter for file size
3000  * NOTE: Does not meet a design target of on stack (localized variable) allocation of single 4kb path
3001  */
3002 static
KArcDirFileSize(const KArcDir * self,uint64_t * size,const char * path,va_list args)3003 rc_t CC KArcDirFileSize		(const KArcDir *self,
3004 					 uint64_t *size,
3005 					 const char *path,
3006 					 va_list args)
3007 {
3008     char *		full_path;
3009     rc_t		rc;
3010 
3011     assert (self != NULL);
3012     assert (size != NULL);
3013     assert (path != NULL);
3014 
3015     rc = KArcDirMakePath (self, rcResolving, true,
3016 			  &full_path, path, args);
3017 
3018     if (rc != 0)
3019     {
3020 	/* can't "fix" path */
3021 	/*rc = RC (rcFS, rcDirectory, rcResolving, rcPath, rcInvalid); ? or tweak it? */
3022     }
3023     else
3024     {
3025 	const KTocEntry * pnode;
3026 	KTocEntryType     type;
3027 
3028 	rc = KArcDirResolvePathNode (self, rcResolving, full_path, /*follow links*/true, &pnode, &type);
3029 
3030 	if (rc != 0)
3031 	{
3032 	    /* can't resolve path */
3033 	    /*rc = RC (rcFS, rcDirectory, rcResolving, rcPath, rcInvalid); ? or tweak it? */
3034 	}
3035 	else
3036 	{
3037 	    uint64_t	fsize;
3038 
3039 	    rc = KTocEntryGetFileSize(pnode, &fsize);
3040 	    if (rc != 0)
3041 	    {
3042 		/* can't "fix" path */
3043 		/*rc = RC (rcFS, rcDirectory, rcResolving, rcPath, rcInvalid); ? or tweak it? */
3044 	    }
3045 	    else
3046 	    {
3047 		*size = fsize;
3048 	    }
3049 	}
3050 	free (full_path);
3051     }
3052     return rc;
3053 }
3054 
3055 /* ----------------------------------------------------------------------
3056  * KArcDirFileSize
3057  *  returns size in bytes of target file
3058  *
3059  *  "path" [ IN ] - NUL terminated string in directory-native
3060  *  character set denoting target file
3061  *
3062  *  "size" [ OUT ] - return parameter for file size
3063  * NOTE: Does not meet a design target of on stack (localized variable) allocation of single 4kb path
3064  */
3065 static
KArcDirFilePhysicalSize(const KArcDir * self,uint64_t * size,const char * path,va_list args)3066 rc_t CC KArcDirFilePhysicalSize		(const KArcDir *self,
3067 					 uint64_t *size,
3068 					 const char *path,
3069 					 va_list args)
3070 {
3071     char *		full_path;
3072     rc_t		rc;
3073 
3074     assert (self != NULL);
3075     assert (size != NULL);
3076     assert (path != NULL);
3077 
3078     rc = KArcDirMakePath (self, rcResolving, true,
3079 			  &full_path, path, args);
3080 
3081     if (rc != 0)
3082     {
3083 	/* can't "fix" path */
3084 	/*rc = RC (rcFS, rcDirectory, rcResolving, rcPath, rcInvalid); ? or tweak it? */
3085     }
3086     else
3087     {
3088 	const KTocEntry * pnode;
3089 	KTocEntryType     type;
3090 
3091 	rc = KArcDirResolvePathNode (self, rcResolving, full_path, /*follow links*/true, &pnode, &type);
3092 
3093 	if (rc != 0)
3094 	{
3095 	    /* can't resolve path */
3096 	    /*rc = RC (rcFS, rcDirectory, rcResolving, rcPath, rcInvalid); ? or tweak it? */
3097 	}
3098 	else
3099 	{
3100 	    uint64_t	fsize;
3101 
3102 	    rc = KTocEntryGetFilePhysicalSize(pnode, &fsize);
3103 	    if (rc != 0)
3104 	    {
3105 		/* can't "fix" path */
3106 		/*rc = RC (rcFS, rcDirectory, rcResolving, rcPath, rcInvalid); ? or tweak it? */
3107 	    }
3108 	    else
3109 	    {
3110 		*size = fsize;
3111 	    }
3112 	}
3113 	free (full_path);
3114     }
3115     return rc;
3116 }
3117 
3118 /* ----------------------------------------------------------------------
3119  * KArcDirSetFileSize
3120  *  sets size in bytes of target file
3121  *
3122  *  "path" [ IN ] - NUL terminated string in directory-native
3123  *  character set denoting target file
3124  *
3125  *  "size" [ IN ] - new file size
3126  */
3127 static
KArcDirSetFileSize(KArcDir * self,uint64_t size,const char * path,va_list args)3128 rc_t CC KArcDirSetFileSize	(KArcDir *self,
3129 					 uint64_t size,
3130 					 const char *path,
3131 					 va_list args)
3132 {
3133     assert (self != NULL);
3134     assert (path != NULL);
3135 
3136     return RC (rcFS, rcArc, rcWriting, rcSelf, rcUnsupported);
3137 }
3138 
3139 /* ----------------------------------------------------------------------
3140  * KArcDirOpenDirRead
3141  *
3142  *  opens a sub-directory
3143  *
3144  * [IN]  const KArcDir *	self	Object Oriented C KArcDir self
3145  * [OUT] const KDirectory **	subp	Where to put the new KDirectory/KArcDir
3146  * [IN]  bool			chroot	Create a chroot cage for this new subdirectory
3147  * [IN]  const char *		path	Path to the directory to open
3148  * [IN]  va_list		args	So far the only use of args is possible additions to path
3149  */
3150 static
KArcDirOpenDirRead(const KArcDir * self,const KDirectory ** subp,bool chroot,const char * path,va_list args)3151 rc_t CC KArcDirOpenDirRead	(const KArcDir *self,
3152 					 const KDirectory **subp,
3153 					 bool chroot,
3154 					 const char *path,
3155 					 va_list args)
3156 {
3157     char * full;
3158     rc_t rc;
3159 
3160     assert (self != NULL);
3161     assert (subp != NULL);
3162     assert (path != NULL);
3163 
3164     rc = KArcDirMakePath (self, rcOpening, true, &full, path, args);
3165     if (rc == 0)
3166     {
3167 	const KTocEntry *	pnode;
3168 	KTocEntryType		type;
3169 	size_t path_size = strlen (full);
3170 
3171 	/* -----
3172 	 * get rid of any extra '/' characters at the end of path
3173 	 */
3174 	while (path_size > 0 && full [ path_size - 1 ] == '/')
3175 	    full [ -- path_size ] = 0;
3176 
3177 	/* -----
3178 	 * get the node for this path
3179 	 */
3180 	rc = KArcDirResolvePathNode (self, rcOpening, full, true, &pnode, &type);
3181 	if (rc == 0)
3182 	{
3183             switch (type)
3184             {
3185             default:
3186 		/* fail */
3187 		rc = RC (rcFS, rcDirectory, rcOpening, rcPath, rcIncorrect);
3188                 break;
3189             case ktocentrytype_dir:
3190             case ktocentrytype_hardlink:
3191 	    {
3192 		KArcDir *	sub;
3193 
3194 		rc = KArcDirMake (&sub,
3195 				  rcOpening,
3196 				  self->parent,
3197 				  self->toc,
3198 				  pnode,
3199 				  self->archive.v,
3200 				  self->arctype,
3201 				  self->root,
3202 				  full,
3203 				  (uint32_t)path_size,
3204 				  false,
3205 				  chroot);
3206 		if (rc == 0)
3207 		{
3208 		    /* succeed */
3209 		    *subp = &sub->dad;
3210 		}
3211 	    }
3212             }
3213 	}
3214 	free (full);
3215     }
3216     return rc;
3217 }
3218 
3219 /* ----------------------------------------------------------------------
3220  * KArcDirOpenDirUpdate
3221  *  opens a sub-directory
3222  *
3223  *  "path" [ IN ] - NUL terminated string in directory-native
3224  *  character set denoting target directory
3225  *
3226  *  "chroot" [ IN ] - if non-zero, the new directory becomes
3227  *  chroot'd and will interpret paths beginning with '/'
3228  *  relative to itself.
3229  */
3230 static
KArcDirOpenDirUpdate(KArcDir * self,KDirectory ** subp,bool chroot,const char * path,va_list args)3231 rc_t CC KArcDirOpenDirUpdate	(KArcDir *self,
3232 					 KDirectory ** subp,
3233 					 bool chroot,
3234 					 const char *path,
3235 					 va_list args)
3236 {
3237     assert (self != NULL);
3238     assert (subp != NULL);
3239     assert (path != NULL);
3240 
3241     return RC (rcFS, rcArc, rcUpdating, rcSelf, rcUnsupported);
3242 }
3243 
3244 /* ----------------------------------------------------------------------
3245  * KArcDirCreateDir
3246  *  create a sub-directory
3247  *
3248  *  "path" [ IN ] - NUL terminated string in directory-native
3249  *  character set denoting target directory
3250  *
3251  *  "access" [ IN ] - standard Unix directory permissions
3252  *
3253  *  "mode" [ IN ] - a creation mode (see explanation above).
3254  */
3255 static
KArcDirCreateDir(KArcDir * self,uint32_t access,KCreateMode mode,const char * path,va_list args)3256 rc_t CC KArcDirCreateDir	(KArcDir *self,
3257 					 uint32_t access,
3258 					 KCreateMode mode,
3259 					 const char *path,
3260 					 va_list args)
3261 {
3262     assert (self != NULL);
3263     assert (path != NULL);
3264 
3265     return RC (rcFS, rcArc, rcCreating, rcSelf, rcUnsupported);
3266 }
3267 
3268 /* ----------------------------------------------------------------------
3269  * KArcDirDestroyFile
3270  */
3271 static
KArcDirDestroyFile(KArcDir * self,KFile * f)3272 rc_t CC KArcDirDestroyFile	(KArcDir *self,
3273 					 KFile * f)
3274 {
3275     assert (self != NULL);
3276     assert (f != NULL);
3277 
3278     return RC (rcFS, rcArc, rcDestroying, rcSelf, rcUnsupported);
3279 }
3280 
3281 /* ----------------------------------------------------------------------
3282  * KArcDirFileContiguous
3283  *
3284  *
3285  *  "path" [ IN ] - NUL terminated string in directory-native
3286  *  character set denoting target file
3287  *
3288  *  "contiguous" [ OUT ] - return parameter for file status
3289  * NOTE: Does not meet a design target of on stack (localized variable) allocation of single 4kb path
3290  */
3291 static
KArcDirFileContiguous(const KArcDir * self,bool * contiguous,const char * path,va_list args)3292 rc_t CC KArcDirFileContiguous		(const KArcDir *self,
3293                                          bool * contiguous,
3294 					 const char *path,
3295 					 va_list args)
3296 {
3297     char *		full_path;
3298     rc_t		rc;
3299 
3300     assert (self != NULL);
3301     assert (contiguous != NULL);
3302     assert (path != NULL);
3303 
3304     rc = KArcDirMakePath (self, rcResolving, true,
3305 			  &full_path, path, args);
3306 
3307     if (rc != 0)
3308     {
3309 	/* can't "fix" path */
3310 	/*rc = RC (rcFS, rcDirectory, rcResolving, rcPath, rcInvalid); ? or tweak it? */
3311     }
3312     else
3313     {
3314 	const KTocEntry * pnode;
3315 	KTocEntryType     type;
3316 
3317 	rc = KArcDirResolvePathNode (self, rcResolving, full_path, /*follow links*/true, &pnode, &type);
3318 
3319 	if (rc != 0)
3320 	{
3321 	    /* can't resolve path */
3322 	    /*rc = RC (rcFS, rcDirectory, rcResolving, rcPath, rcInvalid); ? or tweak it? */
3323 	}
3324 	else
3325 	{
3326 	    switch (type)
3327 	    {
3328 	    default:
3329                 *contiguous = false;
3330 		break;
3331 	    case ktocentrytype_emptyfile:
3332 	    case ktocentrytype_file:
3333                 *contiguous = true;
3334 		break;
3335 	    }
3336 	}
3337 	free (full_path);
3338     }
3339     return rc;
3340 }
3341 
3342 /* ----------------------------------------------------------------------
3343  *
3344  */
3345 static KDirectory_vt_v1 vtKArcDir =
3346 {
3347     /* version 1.0 */
3348     1, 3,
3349 
3350     /* start minor version 0 methods*/
3351     KArcDirDestroy,
3352     KArcDirList,
3353     KArcDirVisit,
3354     KArcDirVisitUpdate,
3355     KArcDirPathType,
3356     KArcDirResolvePath,
3357     KArcDirResolveAlias,
3358     KArcDirRename,
3359     KArcDirRemove,
3360     KArcDirClearDir,
3361     KArcDirVAccess,
3362     KArcDirSetAccess,
3363     KArcDirCreateAlias,
3364     KArcDirOpenFileRead,
3365     KArcDirOpenFileWrite,
3366     KArcDirCreateFile,
3367     KArcDirFileSize,
3368     KArcDirSetFileSize,
3369     KArcDirOpenDirRead,
3370     KArcDirOpenDirUpdate,
3371     KArcDirCreateDir,
3372     KArcDirDestroyFile,
3373     /* end minor version 0 methods*/
3374 
3375     /* start minor version 1 methods*/
3376     KArcDirVDate,
3377     KArcDirSetDate,
3378     KArcDirGetSysDir,
3379     /* end minor version 1 methods*/
3380 
3381     /* start minor version 2 methods*/
3382     KArcDirFileLocator,
3383     /* end minor version 2 methods*/
3384 
3385     /* start minor version 3 methods*/
3386     KArcDirFilePhysicalSize,
3387     KArcDirFileContiguous
3388     /* end minor version 3 methods*/
3389 };
3390 
3391 /* ----------------------------------------------------------------------
3392  * KArcDirMake
3393  *
3394  * [RET] rc_t					0 for success; anything else for a failure
3395  *						see itf/klib/rc.h for general details
3396  * [IN] KArcDir **		self		objected oriented c "self"
3397  * [IN] enum RCContext 		ctx		context to use when passing along rc_t
3398  * [IN] const KDirectory * 	parent		KDirectory type for path before the archive
3399  * [IN] const KToc * 	toc		table of contents for the archive
3400  * [IN] const KTocEntry * 	node		this directory's node within the TOC
3401  * [IN] const KFile * 		archive		open archive file as KFile
3402  * [IN] uint32_t 		dad_root	offset of end of "root" within the path
3403  * [IN] const char *		path		path all the way back to file system root not
3404  *						effective but real root
3405  * [IN] uint32_t		path_size	length of path
3406  * [IN] bool			update		!read_only -- ignored for now and forced read_only
3407  * [IN] bool			chroot		make this a chroot to dad root?
3408  */
3409 static
KArcDirMake(KArcDir ** self,enum RCContext ctx,const KDirectory * parent,const KToc * toc,const KTocEntry * node,const void * archive,KArcFSType baseType,uint32_t dad_root,const char * path,uint32_t path_size,bool update,bool chroot)3410 rc_t	KArcDirMake	(KArcDir ** self,
3411                          enum RCContext ctx,
3412                          const KDirectory * parent,
3413                          const KToc * toc,
3414                          const KTocEntry * node,
3415                          const void * archive,
3416                          KArcFSType baseType,
3417                          uint32_t dad_root,
3418                          const char *path,
3419                          uint32_t path_size,
3420                          bool update, /* ignored */
3421                          bool chroot)
3422 {
3423     KArcDir * dir;
3424     rc_t rc;
3425 
3426     assert (self != NULL);
3427     assert (parent != NULL);
3428     assert (toc != NULL);
3429     /* node will be NULL at base archive file */
3430     assert (archive != NULL);
3431     assert (path != NULL);
3432 
3433     dir = malloc ((sizeof(KArcDir) - sizeof dir->path) + path_size + 2);
3434 
3435     if (dir == NULL)
3436     {
3437         *self = NULL;
3438         return RC (rcFS, rcArc, rcCreating, rcMemory, rcExhausted);
3439     }
3440 
3441     dir->toc = NULL;
3442     dir->archive.v = NULL;
3443 
3444     rc = KDirectoryInit (&dir->dad, (const KDirectory_vt*) &vtKArcDir,
3445                          "KArcDir", path,
3446 			 /* update*/ false); /* force KDirectory to read_only here */
3447     if (rc != 0)
3448     {
3449         free (dir);
3450         return ResetRCContext (rc, rcFS, rcDirectory, ctx);
3451     }
3452 
3453     dir->parent = parent;
3454     dir->toc = toc;
3455     KTocAddRef(toc);
3456     dir->node = node;
3457     dir->arctype = baseType;
3458     dir->archive.v = archive;
3459 
3460     switch (baseType)
3461     {
3462     default:
3463         free (dir);
3464         return RC (rcFS, rcArc, rcConstructing, rcParam, rcInvalid);
3465     case tocKFile:
3466         KFileAddRef (archive);
3467         break;
3468     case tocKDirectory:
3469         KDirectoryAddRef (archive);
3470         break;
3471     }
3472     memmove (dir->path, path, path_size);
3473     dir->root = chroot ? path_size : dad_root;
3474     dir->size = path_size+1; /* make space for the next two operations */
3475     dir->path [path_size] = '/';
3476     dir->path [path_size+1] = 0;
3477     *self = dir;
3478     return 0;
3479 }
3480 
3481 
3482 /* ----------------------------------------------------------------------
3483  * KArcDirGetTOC
3484  *
3485  * [IN]  const KArcDir * 	self	Object oriented C
3486  * [OUT] const KToc ** 	toc	Where to put a pointer to the TOC for the KArcDir
3487  *
3488  * Set a pointer to point the TOC for this KArcDir(KDirectory)
3489  */
KArcDirGetTOC(const KArcDir * self,const struct KToc ** toc)3490 rc_t KArcDirGetTOC (const KArcDir * self,
3491                     const struct KToc ** toc)
3492 {
3493     assert (self != NULL);
3494     assert (toc != NULL);
3495 
3496     *toc = self->toc;
3497     return 0;
3498 }
3499 
3500 
3501 /* ----------------------------------------------------------------------
3502  * KDirectoryToKArcDir
3503  *
3504  * [IN]  const KDirectory * 	self	Object oriented C
3505  * [OUT] const KArcDir * 	cast	Object oriented C
3506  *
3507  *
3508  * Get a reference to a KArcDir from a KDirectory as a cast.  It is a new reference.
3509  */
3510 
KDirectoryToKArcDir(const KDirectory * self,const KArcDir ** cast)3511 LIB_EXPORT rc_t CC KDirectoryToKArcDir (const KDirectory * self, const KArcDir ** cast)
3512 {
3513     rc_t rc;
3514     if ( cast == NULL )
3515         rc = RC ( rcFS, rcArc, rcCasting, rcParam, rcNull );
3516     else
3517     {
3518         if ( self == NULL )
3519             rc = RC ( rcFS, rcArc, rcCasting, rcSelf, rcNull );
3520         else
3521         {
3522             if (self->vt != (const KDirectory_vt*)&vtKArcDir)
3523                 rc = RC ( rcFS, rcArc, rcCasting, rcSelf, rcIncorrect );
3524             else
3525             {
3526                 rc = KDirectoryAddRef ( self );
3527                 if ( rc == 0 )
3528                 {
3529                     * cast = (const KArcDir*)self;
3530                     return 0;
3531                 }
3532             }
3533         }
3534 
3535         * cast = NULL;
3536     }
3537 
3538     return rc;
3539 }
3540 
3541 
3542 static
KDirectoryOpenArcDirRead_intern(const KDirectory * self,const KDirectory ** pdir,bool chroot,bool silent,const char * path,KArcFSType baseType,void * _archive,rc_t (CC * parse)(KToc *,const void *,bool (CC *)(const KDirectory *,const char *,void *),void *),bool (CC * filter)(const KDirectory *,const char *,void *),void * filterparam)3543 rc_t KDirectoryOpenArcDirRead_intern( const KDirectory * self,
3544                                       const KDirectory ** pdir,
3545                                       bool chroot,
3546                                       bool silent,
3547                                       const char * path,
3548                                       KArcFSType baseType,
3549                                       void * _archive,
3550                                       rc_t ( CC * parse )( KToc *, const void *,
3551                                                            bool( CC* )( const KDirectory*,
3552                                                                         const char *, void*),
3553                                                            void * ),
3554                                       bool( CC* filter )( const KDirectory*, const char *, void * ),
3555                                       void * filterparam )
3556 {
3557     union
3558     {
3559         const void * v;
3560         const KFile * f;
3561         const KDirectory * d;
3562     } archive;
3563     KArcDir * arcdir = NULL;
3564     KToc   * toc = NULL;
3565     String   spath;
3566     size_t   pathlen;
3567     rc_t     rc = 0;
3568     rc_t     rcaux = 0;
3569     char     cpath [ 4096 ];
3570     uint32_t type;
3571 
3572     archive.v = _archive;
3573     /* -----
3574      * sanity check parameters  The first bunch is from the base class KDirectory.
3575      */
3576     if ( pdir == NULL )
3577     {
3578         if ( !silent )
3579             PLOGMSG ( klogErr, ( klogErr,
3580                       "NULL parameter for the root KArcDir for $(file)",
3581                        PLOG_S ( file ),
3582                        path ) );
3583         return RC ( rcFS, rcDirectory, rcOpening, rcDirectory, rcNull );
3584     }
3585     *pdir = NULL;
3586 
3587     if ( self == NULL )
3588     {
3589         if ( !silent )
3590             PLOGMSG ( klogErr, ( klogErr,
3591                       "NULL parameter for self for $(file)",
3592                       PLOG_S ( file ),
3593                       path ) );
3594         return RC ( rcFS, rcDirectory, rcOpening, rcSelf, rcNull );
3595     }
3596 
3597     if ( path == NULL )
3598     {
3599         if ( !silent )
3600             PLOGMSG ( klogErr,( klogErr,
3601                       "NULL parameter for the root KArcDir for $(file)",
3602                       PLOG_S ( file ),
3603                       path ) );
3604         return RC ( rcFS, rcDirectory, rcAccessing, rcPath, rcNull );
3605     }
3606 
3607     if ( path[0] == 0x00 )
3608     {
3609         if ( !silent )
3610             PLOGMSG ( klogErr,( klogErr,
3611                       "NULL string for the root KArcDir for $(file)",
3612                       PLOG_S ( file ),
3613                       path ) );
3614         return RC ( rcFS, rcDirectory, rcAccessing, rcPath, rcInvalid );
3615     }
3616 
3617     if (_archive == NULL)
3618     {
3619         /* -----
3620          * we got a local String type mixed in along with ASCIZ cstrings
3621          */
3622         rc = KDirectoryResolvePath ( self, true, cpath, sizeof (cpath), "%s", path );
3623         if ( rc == 0 )
3624         {
3625             size_t ln;
3626             ln = strlen (cpath);
3627             if ((cpath[ln-1] == '.')&&(cpath[ln-2] == '/'))
3628                 cpath[ln-2] = '\0';
3629         }
3630         else
3631             return rc;
3632     }
3633     else
3634     {
3635         size_t ln;
3636 
3637         rc = string_printf (cpath, sizeof cpath, &ln, "%s", path);
3638         if ((rc == 0) && (ln > sizeof cpath))
3639             rc = RC (rcFS, rcArc, rcOpening, rcBuffer, rcInsufficient);
3640     }
3641 
3642     StringInitCString ( &spath, cpath );
3643     pathlen = strlen ( cpath );
3644 
3645     if (_archive != NULL)
3646     {
3647         switch (baseType)
3648         {
3649         case tocKFile:
3650             rc = KFileAddRef (_archive);
3651             break;
3652         case tocKDirectory:
3653             rc = KDirectoryAddRef (_archive);
3654             break;
3655         default:
3656             /* i dunno */
3657             break;
3658         }
3659         if (rc)
3660             return rc;
3661     }
3662     else
3663     {
3664         type = KDirectoryPathType ( self, "%s", cpath );
3665         switch ( type & ~kptAlias )
3666         {
3667         default:
3668             rc = RC ( rcFS, rcArc, rcOpening, rcFile, rcUnexpected );
3669             if ( !silent )
3670                 LOGERR (klogErr, rc, "Unusable file type" );
3671             break;
3672         case kptNotFound:
3673         case kptBadPath:
3674             rc = RC ( rcFS, rcArc, rcOpening, rcFile, rcNotFound );
3675             break;
3676 
3677         case kptFile:
3678             /* -----
3679              * Open the archive file as a KFILE for internal use
3680              *
3681              * Fail / quit if we couldn't
3682              */
3683             if ( baseType != tocKFile )
3684             {
3685                 rc = RC ( rcFS, rcArc, rcOpening, rcFile, rcIncorrect );
3686                 if ( !silent )
3687                     LOGERR ( klogErr, rc, "Mismatch of file type and expected type" );
3688                 return rc;
3689             }
3690 
3691             rc = KDirectoryOpenFileRead ( self, &archive.f, "%s", cpath );
3692             if ( rc != 0 && !silent )
3693             {
3694                 PLOGERR ( klogErr, ( klogErr, rc,
3695                                      "Failed to open archive file $(file)",
3696                                      PLOG_S (file),
3697                                      path ) );
3698             }
3699 
3700             break;
3701 
3702         case kptDir:
3703             if ( baseType != tocKDirectory )
3704             {
3705                 rc = RC ( rcFS, rcArc, rcOpening, rcFile, rcInconsistent );
3706                 if ( !silent )
3707                     LOGERR ( klogErr, rc, "Mismatch of file type and expected type" );
3708                 return rc;
3709             }
3710 
3711             rc = KDirectoryOpenDirRead ( self, &archive.d, false, "%s", cpath );
3712             if ( rc != 0 && !silent )
3713             {
3714                 PLOGMSG ( klogErr,
3715                           ( klogErr, "Failed to open archive directory $(file)",
3716                             PLOG_S ( file ), path ) );
3717             }
3718             break;
3719         } /* switch ( type & ~kptAlias ) */
3720     }
3721     if ( rc == 0 )
3722     {
3723         /* -----
3724          * Build the TOC necessary to get to all internal files and subdirectories
3725          * Any sub KArcDir or KFile created will also need to reference the same TOC
3726          */
3727         rc = KTocInit ( &toc, &spath, baseType, archive.v, sraAlign4Byte );
3728         if ( rc != 0 )
3729         {
3730             if ( !silent )
3731                 PLOGERR ( klogErr,
3732                      ( klogErr, rc, "Failed to initialize Table of Contents for $(path)",
3733                      PLOG_S ( path ), cpath ) );
3734         }
3735         else
3736         {
3737             const KTocEntry * node;
3738 
3739             node = KTocGetRoot( toc );
3740 
3741             rc = KArcDirMake (&arcdir,      /* where to build the KArcDir */
3742                               rcAccessing,  /* funky RC replacement thingie */
3743                               self,         /* parent KDirectory - for previous path */
3744                               toc,          /* table of contents structure for this archive */
3745                               node,         /* archive "root" has no node */
3746                               archive.v,    /* KFile for the archive */
3747                               baseType,     /* base type o archive */
3748                               0,            /* dad_root */
3749                               cpath,        /* path to archive will be the path of the directory */
3750                               (uint32_t)pathlen, /* length of path (the Init will append "/") */
3751                               true,         /* readonly */
3752                               false);       /* not chroot */
3753             if ( rc != 0 )
3754             {
3755                 if ( !silent )
3756                 PLOGERR ( klogErr,
3757                           ( klogErr, rc, "Failed to allocate for the root KArcDir for $(file)",
3758                           PLOG_S ( file ), path ) );
3759             }
3760             else
3761             {
3762                 rc = parse( toc,archive.v, filter, filterparam );
3763                 if ( rc == SILENT_RC ( rcFS, rcArc, rcParsing, rcToc, rcIncomplete ) )
3764                 {
3765                     rcaux = rc;
3766                     rc = 0;
3767                 }
3768                 if ( rc != 0 )
3769                 {
3770                     if ( !silent )
3771                         PLOGERR ( klogErr,
3772                              ( klogErr, rc, "Failed to parse $(file)",
3773                              PLOG_S ( file ), cpath ) );
3774                 }
3775                 else
3776                 {
3777                     *pdir = &arcdir->dad;
3778                 }
3779             }
3780         }
3781     }
3782     /* -----
3783      * if rc is non-zero we failed somewhere above.
3784      * Release allocated memory and exit with that error code.
3785      */
3786     if ( archive.v != NULL )
3787     {
3788         switch ( baseType )
3789         {
3790         default:
3791             free ( (void*)archive.v );
3792             break;
3793         case tocKFile:
3794             KFileRelease ( archive.f );
3795             break;
3796         case tocKDirectory:
3797             KDirectoryRelease ( archive.d );
3798             break;
3799         }
3800     }
3801 
3802     rc = rc | rcaux;
3803 
3804     if ( rc != 0 )
3805     {
3806         if ( arcdir != NULL )
3807             KDirectoryRelease ( &arcdir->dad );
3808         *pdir = NULL;
3809     }
3810 
3811     if ( toc != NULL )
3812         KTocRelease ( toc );
3813 
3814     return rc;
3815 }
3816 
3817 
3818 /* ----------------------------------------------------------------------
3819  * KDirectoryOpenArcDirRead
3820  *  Open an archive file as a KDirectory derived type: made to match
3821  *  KDirectoryOpenDirRead() where parse could be the first element of arg
3822  *
3823  * Much of the code in this function is copied directly from KDirectoryVOpenDirRead
3824  *
3825  * [IN]  dir   A KDirectory (of any derived type) to reach the archive file
3826  * [OUT] pdir  The KDirectory (of type KArcDir)
3827  * [IN]  chroot if non-zero, the new directory becomes chroot'd and interprets paths
3828  *       stating with '/'
3829  * [IN]  path   The path to the archive - this will decome the directory path
3830  * [IN]  parse  A pointer to the function needed to build a TOC by parsing the file
3831  *
3832  * This function is made difficult because a path is not a global type.  Where we
3833  * would like to be able to take path and args and have them parsed nicely as they
3834  * are for KSysDir or KArcDir with nearly identical functions those functions are
3835  * not available here as self is a KDirectory but we do not know and should not know
3836  * whether it is a KSysDir or KArcDir.  Unfortunately KSysDir was made overly opaque.
3837  * [this is a result of providing full encapsulation, i.e. KDirectory is ONLY an
3838  *  interface and there is no implementation provided.][well very little]
3839  * If we could take path and args (path and ...) and pass them to a function
3840  * equivalent to KSysDirMakePath we would be able to do this right.  Or if we could
3841  * ask the self what it's path was and what it considered size and root we could do
3842  * the path build here and tidy up properly what we got.  .As is, we have  to be more
3843  * limited.
3844  *
3845  * We will have to wait and fix this right in directory.c where we can instead have
3846  * an attempt to open using KDirectory[V]OpenDirRead() check if when it tries to
3847  * open a directory but instead finds it has been given a path it will try to parse
3848  * the file using a known set of parse functions to see if the file can be treated
3849  * as a directory. Then this function can be called from KDirectoryOpenDirRead.
3850  */
KDirectoryOpenArcDirRead(const KDirectory * self,const KDirectory ** pdir,bool chroot,const char * path,KArcFSType baseType,rc_t (CC * parse)(KToc *,const void *,bool (CC *)(const KDirectory *,const char *,void *),void *),bool (CC * filter)(const KDirectory *,const char *,void *),void * filterparam)3851 LIB_EXPORT rc_t CC KDirectoryOpenArcDirRead( const KDirectory * self,
3852     const KDirectory ** pdir,
3853     bool chroot,
3854     const char * path,
3855     KArcFSType baseType,
3856     rc_t ( CC * parse )( KToc *, const void *,
3857         bool( CC * )( const KDirectory *, const char *, void * ), void * ),
3858     bool ( CC * filter )( const KDirectory*, const char *, void *),
3859     void * filterparam )
3860 {
3861     return KDirectoryOpenArcDirRead_intern( self,
3862         pdir,
3863         chroot,
3864         false,
3865         path,
3866         baseType,
3867         NULL,
3868         parse,
3869         filter,
3870         filterparam );
3871 }
3872 
3873 
KDirectoryOpenArcDirRead_silent(const KDirectory * self,const KDirectory ** pdir,bool chroot,const char * path,KArcFSType baseType,rc_t (CC * parse)(KToc *,const void *,bool (CC *)(const KDirectory *,const char *,void *),void *),bool (CC * filter)(const KDirectory *,const char *,void *),void * filterparam)3874 LIB_EXPORT rc_t CC KDirectoryOpenArcDirRead_silent( const KDirectory * self,
3875     const KDirectory ** pdir,
3876     bool chroot,
3877     const char * path,
3878     KArcFSType baseType,
3879     rc_t ( CC * parse )( KToc *, const void *,
3880         bool( CC * )( const KDirectory *, const char *, void * ), void * ),
3881     bool ( CC * filter )( const KDirectory*, const char *, void *),
3882     void * filterparam )
3883 {
3884     return KDirectoryOpenArcDirRead_intern( self,
3885         pdir,
3886         chroot,
3887         true,
3888         path,
3889         baseType,
3890         NULL,
3891         parse,
3892         filter,
3893         filterparam );
3894 }
KDirectoryOpenArcDirRead_silent_preopened(const KDirectory * self,const KDirectory ** pdir,bool chroot,const char * path,KArcFSType baseType,void * archive,rc_t (CC * parse)(KToc *,const void *,bool (CC *)(const KDirectory *,const char *,void *),void *),bool (CC * filter)(const KDirectory *,const char *,void *),void * filterparam)3895 LIB_EXPORT rc_t CC KDirectoryOpenArcDirRead_silent_preopened( const KDirectory * self,
3896     const KDirectory ** pdir,
3897     bool chroot,
3898     const char * path,
3899     KArcFSType baseType,
3900     void * archive,
3901     rc_t ( CC * parse )( KToc *, const void *,
3902         bool( CC * )( const KDirectory *, const char *, void * ), void * ),
3903     bool ( CC * filter )( const KDirectory*, const char *, void *),
3904     void * filterparam )
3905 {
3906     return KDirectoryOpenArcDirRead_intern( self,
3907         pdir,
3908         chroot,
3909         true,
3910         path,
3911         baseType,
3912         archive,
3913         parse,
3914         filter,
3915         filterparam );
3916 }
3917 
3918 
3919 /* ======================================================================
3920  *
3921  */
3922 typedef struct KArcDirPersistVisitFuncData
3923 {
3924     Vector * vector;
3925     KArcDir * dir;
3926     char path[4096];
3927 } KArcDirPersistVisitFuncData;
3928 
3929 
3930 static
KArcDirPersistVisitFunc(const KDirectory * dir,uint32_t unused_type,const char * name,void * data)3931 rc_t CC KArcDirPersistVisitFunc (const KDirectory * dir, uint32_t unused_type, const char * name, void * data)
3932 {
3933     KPathType type;
3934     KArcDirPersistVisitFuncData * vdata;
3935     char * path;
3936     size_t len = 0;
3937     rc_t rc;
3938 
3939     rc = 0;
3940     vdata = data;
3941 
3942     type = (KPathType)KDirectoryPathType (dir, "%s", name);
3943     switch (type)
3944     {
3945     default:
3946 	return 0;
3947     case kptDir:
3948 	len = strlen (vdata->path);
3949 	if (len > 0)
3950 	{
3951 	    vdata->path[len] = '/';
3952 	    strcpy (vdata->path+len+1, name);
3953 	}
3954 	else
3955 	    strcpy (vdata->path, name);
3956 
3957 
3958 /* this needs cleaning up - dir moved along but path did not.  path handling is weak through out */
3959 /* 	rc = KArcDirVisit ((const KArcDir*)dir, false, KArcDirPersistVisitFunc, data, vdata->path, NULL); */
3960 	rc = KArcDirVisit_noargs ((const KArcDir*)dir, false, KArcDirPersistVisitFunc, data, name);
3961 	if (rc != 0)
3962 	{
3963 	    LOGERR (klogInt, rc, "KArcDirPersist Visit failed");
3964 	}
3965 	vdata->path[len] = '\0';
3966 	return rc;
3967     case kptFile:
3968     case kptFile|kptAlias:
3969 	len = strlen (vdata->path);
3970 	if (len > 0)
3971 	{
3972 	    vdata->path[len] = '/';
3973 	    strcpy (vdata->path+len+1, name);
3974 	}
3975 	else
3976 	    strcpy (vdata->path, name);
3977 	path = malloc (strlen(vdata->path)+1);
3978 	if (path == NULL)
3979 	{
3980 	    rc = RC (rcFS, rcArc, rcReindexing, rcMemory, rcExhausted);
3981 	}
3982 	else
3983 	{
3984 	    strcpy (path, vdata->path);
3985 	    rc = VectorAppend (vdata->vector, NULL, path);
3986 	}
3987 	vdata->path[len] = '\0';
3988 
3989 	return rc;
3990     }
3991 }
3992 
3993 static
whack(void * item,void * data)3994 void CC whack ( void *item, void *data )
3995 {
3996     free (item);
3997 }
3998 
3999 /* ========================================
4000  * Build a Persisted version of a TOC in a buffer
4001  * return the allocated buffer
4002  */
4003 #ifdef _DEBUGGING
4004 static
write_entry(void * item,void * data)4005 void CC write_entry( void * item, void *data)
4006 {
4007     const char * path = item;
4008     uint32_t * count = data;
4009 
4010     TOC_SORT(("%3u: %s\n", *count, path));
4011 
4012     (*count)++;
4013 }
4014 #endif
KArcDirPersistHeader(const KArcDir * self,void ** buffer,size_t * buffer_size,uint64_t * file_size,KSRAFileAlignment align,rc_t (CC * usort)(const KDirectory *,Vector *))4015 rc_t KArcDirPersistHeader (const KArcDir * self,
4016                            void ** buffer,
4017                            size_t * buffer_size,
4018                            uint64_t * file_size,
4019                            KSRAFileAlignment align,
4020                            rc_t (CC*usort)(const KDirectory*, Vector*))
4021 {
4022     rc_t         rc;
4023     const KToc * toc;
4024 
4025     FUNC_ENTRY();
4026 
4027     if (self == NULL)
4028     {
4029 	rc = RC (rcFS, rcDirectory, rcPersisting, rcSelf, rcNull);
4030 	LOGERR (klogInt, rc, "KArcDirPersist Self is NULL");
4031 	return rc;
4032     }
4033     if (buffer == NULL)
4034     {
4035 	rc = RC (rcFS, rcDirectory, rcPersisting, rcParam, rcNull);
4036 	LOGERR (klogInt, rc, "KArcDirPersist buffer is NULL");
4037 	return rc;
4038     }
4039     rc = KArcDirGetTOC (self, &toc);
4040     if (rc != 0)
4041         LOGERR (klogInt, rc, "KArcDirPersist TOC retrieval failed");
4042     else
4043     {
4044         /* mutable field as it only applies to this specific operation */
4045         rc = KTocAlignmentSet ((KToc*)toc, align);
4046         if (rc != 0)
4047             LOGERR (klogInt, rc, "KArcDirPersist TOC alignment failed");
4048         else
4049         {
4050             Vector filevector;
4051             KArcDirPersistVisitFuncData	data;
4052 
4053             VectorInit (&filevector, 0, 0);
4054 
4055             data.path[0] = '\0'; /* looks like "" */
4056             data.vector = &filevector;
4057 
4058 
4059             rc = KArcDirVisit_noargs (self, false, KArcDirPersistVisitFunc, &data, ".");
4060             if (rc != 0)
4061             {
4062                 LOGERR (klogInt, rc, "KArcDirPersist Visit failed");
4063             }
4064             else
4065             {
4066 
4067 #ifdef _DEBUGGING
4068 /* this loop and the next just can be used in a debug build to verify the sorting function used */
4069                 {
4070                     uint32_t ix;
4071                     TOC_SORT (("Pre-sort order:\n"));
4072 
4073                     ix = 1;
4074                     VectorForEach ( &filevector, false, write_entry, &ix);
4075                 }
4076 #endif
4077 
4078                 if (usort)
4079                     rc = usort(&self->dad, &filevector);
4080 
4081 #ifdef _DEBUGGING
4082                 {
4083                     uint32_t ix;
4084                     TOC_SORT (("Post-sort order:\n"));
4085 
4086                     ix = 1;
4087                     VectorForEach ( &filevector, false, write_entry, &ix);
4088                 }
4089 #endif
4090 
4091 
4092                 if (rc != 0)
4093                 {
4094                     LOGERR (klogInt, rc, "KArcDirPersist user sort failed failed");
4095                 }
4096                 else
4097                 {
4098                     rc = KTocPersist (toc, buffer, buffer_size, file_size, &filevector);
4099                     if (rc != 0)
4100                         LOGERR (klogInt, rc, "KArcDirPersist TOC retrieval failed");
4101                 }
4102             }
4103 /*     free (data.path); */
4104             VectorWhack (&filevector, whack, NULL);
4105 	}
4106     }
4107 
4108     return rc;
4109 }
4110 
KDirectoryIsKArcDir(const KDirectory * self)4111 KFS_EXTERN bool CC KDirectoryIsKArcDir ( const KDirectory * self )
4112 {
4113     return self != NULL && &self -> vt -> v1 == &vtKArcDir;
4114 }
4115 
KArcDirIsFromRemote(const KArcDir * self)4116 KFS_EXTERN bool CC KArcDirIsFromRemote ( const KArcDir * self )
4117 {
4118     return self != NULL && self -> arctype == tocKFile &&
4119             ( KFileIsKCacheTeeFile ( self -> archive . f ) || KFileIsKHttpFile ( self -> archive . f ) );
4120 }
4121 
4122 
4123 /* end of file arc.c */
4124 
4125