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