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 <atomic32.h>
28 #include <klib/container.h>
29 #include <klib/vector.h>
30 #include <klib/pbstree.h>
31 #include <klib/text.h>
32 #include <kfs/arc.h>
33 #include <kfs/toc.h>
34 #include <kfs/directory.h>
35 #include <kfs/file.h>
36 #include <klib/log.h>
37 #include <klib/debug.h>
38 #include <klib/rc.h>
39 #include <klib/sort.h>
40 #include <sysalloc.h>
41 
42 #include "toc-priv.h"
43 
44 #include <assert.h>
45 #include <limits.h>
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #include <byteswap.h>
50 
51 
52 /* ======================================================================
53  * KTocEntry
54  *
55  * A private class used to keep track of a single entry (
56  */
57 
58 
59 /* ======================================================================
60  * KTocEntry method
61  *
62  * This class is not set up with a vtable at this point.  This API exposes
63  * (due to the nature of using a c struct as a class) much of it's opaque
64  * elements by providing accessor functions to most of them.  Since they
65  * are static in this file they are expected to be used only by a class
66  * that is like a C++ friend class by being implemented in the same
67  * compilation unit.
68  */
69 
70 /* NOTE data is not used but required to match the signature for a pointer to function */
KTocEntryWhack(BSTNode * n,void * data)71 void CC KTocEntryWhack ( BSTNode * n, void * data )
72 {
73     KTocEntry * p = (KTocEntry*)n;
74     /**(rc_t*)data = */ KTocEntryDelete (p);
75 }
76 
77 /* ----------------------------------------------------------------------
78  * KTocEntryDelete
79  * [INOUT] self the entry to delete
80  */
KTocEntryDelete(KTocEntry * self)81 rc_t KTocEntryDelete ( KTocEntry * self )
82 {
83     /* defensive programming ensure minimally valid pointer */
84     if (self == NULL)
85     {
86         return 0;
87 /* 	return RC (rcFS, rcToc, rcConstructing, rcSelf, rcNull); */
88     }
89 
90     switch (self->type)
91     {
92     case ktocentrytype_unknown:
93     case ktocentrytype_file:
94     case ktocentrytype_chunked:
95     case ktocentrytype_softlink:
96     case ktocentrytype_hardlink:
97     case ktocentrytype_zombiefile:
98     default:
99 	/* -----
100 	 * at this point in the implementation there is nothing we need to
101 	 * do with these entry types except free their "self" allocated memory.
102 	 *
103 	 * Used a switch in case we did for one or more of these.
104 	 */
105 	break;
106     case ktocentrytype_dir:
107 	/* -----
108 	 * directories have a BSTree below them that need to be
109 	 * deleted first
110 	 */
111 	BSTreeWhack (&self->u.dir.tree, KTocEntryWhack, NULL);
112 	break;
113     }
114     free (self);
115     return 0;
116 }
117 
118 /* ----------------------------------------------------------------------
119  * KTocEntryCmp2
120  *
121  * [RET] int					>0: if n > p
122  *						0:  if n == p
123  *						<0: if n < p
124  * [IN]  const BSTNode * 	n		where the pointer to a node matching the key is put
125  * [IN]  const BSTNode * 	p		where the pointer to a node matching the key is put
126  * This function fits the function signature needed for BSTreeInsert
127  *
128  * can not inline or make into a macro as it is referenced via a pointer
129  */
KTocEntryCmp2(const BSTNode * n,const BSTNode * p)130 int64_t CC KTocEntryCmp2 ( const BSTNode * n, const BSTNode * p )
131 {
132 
133     KTocEntry * nn;
134     KTocEntry * pp;
135     int64_t		  ii;
136 
137     nn = (KTocEntry *)n;
138     pp =  (KTocEntry *)p;
139     ii = StringCompare (&nn->name, &pp->name);
140     return ii;
141 }
142 
143 /* ----------------------------------------------------------------------
144  * KTocEntryCmpVoid
145  *
146  * [RET] int					>0: if n > p
147  *						0:  if n == p
148  *						<0: if n < p
149  * [IN]  const void * 		item		'key' to find a matching bject in the BSTree
150  * [OUT] const BSTNode *	node		where the pointer to a node matching the key is put
151  * This function fits the function signature needed for BSTreeFind
152  *
153  * can not inline or make into a macro as it is referenced via a pointer
154  */
KTocEntryCmpVoid(const void * item,const BSTNode * node)155 int64_t CC KTocEntryCmpVoid ( const void * item, const BSTNode * node )
156 {
157     const BSTNode * _item = item;
158     return KTocEntryCmp2 (_item, node);
159 }
160 
161 /* ----------------------------------------------------------------------
162  * KTocEntryNew
163  *
164  * [RET] rc_t					0 for success; anything else for a failure
165  *						see itf/klib/rc.h for general details
166  * [OUT] KTocEntry ** 	new_entry	where to put a pointer to the new TOC Entry
167  * [IN]  const char * 		name		name of the entry (file, link, directory...)
168  *						(not assumed to be ASCIZ)
169  * [IN]  size_t			name_size	length of name
170  * [IN]  uint32_t 		access		unix/posix style permission flags
171  * [IN]  size_t 		entry_specific	specific initialyers by entry type
172  */
173 static
KTocEntryNew(KTocEntry ** new_entry,const char * name,size_t name_size,KTime_t mtime,uint32_t access,size_t entry_specific)174 rc_t		KTocEntryNew		(KTocEntry ** new_entry,
175 					 const char * name,
176 					 size_t name_size,
177 					 KTime_t mtime,
178 					 uint32_t access,
179 					 size_t entry_specific)
180 {
181     KTocEntry * entry;
182     size_t	  nsize;
183     char *	  namep;
184 
185     nsize = entry_specific + name_size + 1; /* we want a NUL at end of name */
186 
187     entry = malloc (nsize);
188     if (entry == NULL)
189     {
190 	LOGMSG (klogErr,
191 		"Failed to allocate for a TOC File entry");
192 	return RC (rcFS, rcToc, rcAllocating, rcMemory, rcInsufficient);
193     }
194 
195     /* entry->entry is fine left as undefined */
196     namep =(char*)entry + entry_specific;
197     string_copy (namep, name_size+1, name, name_size);
198     StringInit (&(entry->name), namep, name_size, (uint32_t)name_size);
199 
200     entry->mtime = mtime;
201     entry->access = access;
202 
203     *new_entry = entry;
204     return 0;
205 }
206 
207 /* ----------------------------------------------------------------------
208  * KTocEntryNewFile
209  *
210  * [RET] rc_t					0 for success; anything else for a failure
211  *						see itf/klib/rc.h for general details
212  * [OUT] KTocEntry **		new_entry	where to put a pointer to the new TOC Entry
213  * [IN]  const char *		name		name of the file (not path) (not assumed to be ASCIZ)
214  * [IN]  size_t 		name_size	length of name
215  * [IN]  uint32_t 		access		unix/posix style permission flags
216  * [IN]  uint64_t		offset		starting offset within the archive file of this file
217  * [IN]  uint64_t 		size		number of bytes in the file
218  */
KTocEntryNewFile(KTocEntry ** new_entry,const char * name,size_t name_size,KTime_t mtime,uint32_t access,uint64_t offset,uint64_t size)219 rc_t KTocEntryNewFile ( KTocEntry ** new_entry,
220                         const char * name,
221                         size_t name_size,
222                         KTime_t mtime,
223                         uint32_t access,
224                         uint64_t offset,
225                         uint64_t size )
226 {
227     rc_t	rc;
228 
229     TOC_SORT (("%s: %s %lu %u\n", __func__, name, mtime, access));
230 
231     rc = KTocEntryNew (new_entry, name, name_size, mtime, access,
232 		       sizeof(KTocEntry)
233 		       - sizeof(union KTocEntryUnion)
234 		       + sizeof(struct KTocEntryFile));
235 
236     if (rc)
237 	return rc;
238 
239     if (size == 0)
240         (*new_entry)->type = ktocentrytype_emptyfile;
241 
242     else
243     {
244         (*new_entry)->type = ktocentrytype_file;
245 
246         (*new_entry)->u.contiguous_file.archive_offset = offset;
247         (*new_entry)->u.contiguous_file.file_size = size;
248     }
249 
250     return 0;
251 }
252 
253 
254 /* ----------------------------------------------------------------------
255  * KTocEntryNewZombieFile
256  *
257  * A zombie file is a file whose directory is in the archive but whose
258  * storage is not
259  *
260  * [RET] rc_t					0 for success; anything else
261  *						for a failure
262  *                                              see itf/klib/rc.h for general
263  *                                              details
264  * [OUT] KTocEntry **		new_entry	where to put a pointer to the
265  *                                              new TOC Entry
266  * [IN]  const char *		name		name of the file (not path)
267  *                                              (not assumed to be ASCIZ)
268  * [IN]  size_t 		name_size	length of name
269  * [IN]  uint32_t 		access		unix/posix style permission
270  *                                              flags
271  * [IN]  uint64_t		offset		starting offset within the
272  *                                              archive file of this file
273  * [IN]  uint64_t 		size		number of bytes in the file
274  */
KTocEntryNewZombieFile(KTocEntry ** new_entry,const char * name,size_t name_size,KTime_t mtime,uint32_t access,uint64_t offset,uint64_t size)275 rc_t KTocEntryNewZombieFile ( KTocEntry ** new_entry,
276                               const char * name,
277                               size_t name_size,
278                               KTime_t mtime,
279                               uint32_t access,
280                               uint64_t offset,
281                               uint64_t size )
282 {
283     rc_t	rc;
284 
285 /*     TOC_DEBUG (("%s: %s %lu\n", __func__, name, mtime)); */
286 
287     rc = KTocEntryNew (new_entry, name, name_size, mtime, access,
288 		       sizeof(KTocEntry)
289 		       - sizeof(union KTocEntryUnion)
290 		       + sizeof(struct KTocEntryFile));
291 
292     if (rc)
293 	return rc;
294 
295     if (size == 0)
296         (*new_entry)->type = ktocentrytype_emptyfile;
297 
298     else
299     {
300         (*new_entry)->type = ktocentrytype_zombiefile;
301 
302         (*new_entry)->u.contiguous_file.archive_offset = offset;
303         (*new_entry)->u.contiguous_file.file_size = size;
304     }
305 
306     return 0;
307 }
308 
309 /* ----------------------------------------------------------------------
310  * KTocEntryNewChunked
311  *
312  * [RET] rc_t					0 for success; anything else for a failure
313  *						see itf/klib/rc.h for general details
314  * [OUT] KTocEntry **		new_entry	where to put a pointer to the new TOC Entry
315  * [IN]  const char *		name		name of the file (not path) (not assumed to be ASCIZ)
316  * [IN]  size_t			name_size	length of name
317  * [IN]  uint32_t		access		unix/posix style permission flags
318  * [IN]  uint64_t 		size		virtual number of bytes in the file: not actual
319  *						number of stored bytes
320  * [IN]  const KTocChunk * 	chunks		pointer to an array of chunk structures
321  * [IN]  uint32_t 		num_chunks	number of chunks in the array above
322  */
323 static
chunkcmp(const void * a,const void * b,void * ignored)324 int64_t CC chunkcmp (const void * a, const void * b, void * ignored)
325 {
326     const KTocChunk *A = a;
327     const KTocChunk *B = b;
328     /* -----
329      * We can't rely on a cast down to int not getting messed up
330      * by overflow nor even on uint64_t - uint64_t not overflowing int64_t
331      */
332     if (A->logical_position == B->logical_position)
333 	return 0;
334     else if (A->logical_position > B->logical_position)
335 	return 1;
336     else
337 	return -1;
338 }
339 
KTocEntryNewChunked(KTocEntry ** new_entry,const char * name,size_t name_size,KTime_t mtime,uint32_t access,uint64_t size,const KTocChunk * chunks,uint32_t num_chunks)340 rc_t KTocEntryNewChunked ( KTocEntry ** new_entry,
341 					 const char * name,
342 					 size_t name_size,
343 					 KTime_t mtime,
344 					 uint32_t access,
345 					 uint64_t size,
346 					 const KTocChunk * chunks,
347 					 uint32_t num_chunks )
348 {
349     rc_t	rc;
350     KTocChunk * chunkp;
351     size_t	nsize;
352     size_t	csize;
353 
354     /* -----
355      * This is a bit ugly...
356      *
357      * first (Compile time optimizations does much of the heavy lifting) figure out how
358      * much is the extra malloc amount
359      *
360      * Take size of a generic entry - the size of the union part but add back the size of
361      * the chunked file part
362      *
363      * Add to that the size of a 64 bit integer.  This is 8 bytes extra from what is
364      * needed by the header alone.
365      *
366      * Mask that against the binary bit inverse of 1 less tha the size of a 64 bit integer.
367      *
368      * Now you have the size of the header plus the number of bytes needed to get to a 8
369      * byte address 0.  This is possibly more than is needed as 8 byte quantities could be
370      * read from 4 byte boundaries in many cases.
371      *
372      * Then add to that the size in bytes of the chunked data (all 64 bit numbers).
373      */
374     nsize = ~( ( size_t ) sizeof(uint64_t)-1) &
375 	(sizeof(KTocEntry)
376 	 - sizeof(union KTocEntryUnion)
377 	 + sizeof(struct KTocEntryChunkFile)
378 	 + sizeof(uint64_t));
379     csize = sizeof(KTocChunk) * num_chunks;
380 
381     if ((rc = KTocEntryNew (new_entry, name, name_size, mtime, access,
382 			    nsize + csize))
383 	!= 0)
384     {
385 	return rc;
386     }
387 
388     chunkp = (KTocChunk*)((char*)*new_entry + nsize);
389     (*new_entry)->type = ktocentrytype_chunked;
390     (*new_entry)->u.chunked_file.file_size = size;
391     (*new_entry)->u.chunked_file.chunks = chunkp;
392     (*new_entry)->u.chunked_file.num_chunks = num_chunks;
393     memmove(chunkp, chunks, csize);
394     ksort (chunkp, num_chunks, sizeof(KTocChunk), chunkcmp, NULL);
395     /* -----
396      * TODO: We currently do no validation of the chunks.
397      * We accept that after the sort (which is probably superfluous)
398      * that for each chunk
399      *
400      *	chunkp[N].logical_position + chunkp[N].size <= chunkp[N+1].logical_position
401      *
402      * We should probably verify this.
403      */
404     return 0;
405 }
406 
407 /* ----------------------------------------------------------------------
408  * KTocEntryNewSoft
409  *
410  * [RET] rc_t					0 for success; anything else for a failure
411  *						see itf/klib/rc.h for general details
412  * [OUT] KTocEntry **		new_entry	where to put a pointer to the new TOC Entry
413  * [IN]  const char * 		name		name of the file (not path) (not assumed to be ASCIZ)
414  * [IN]  size_t 		name_size	length of name
415  * [IN]  uint32_t		access		unix/posix style permission flags
416  * [IN]  const char * 		link		character array (string) holding the name of the
417  *						links target (not assumed to be ASCIZ)
418  * [IN]  size_t 		link_size	length of the target string
419  * Link is run time resolved
420  */
KTocEntryNewSoft(KTocEntry ** new_entry,const char * name,size_t name_size,KTime_t mtime,uint32_t access,const char * link,size_t link_size)421 rc_t KTocEntryNewSoft ( KTocEntry ** new_entry,
422 					 const char * name,
423 					 size_t name_size,
424 					 KTime_t mtime,
425 					 uint32_t access,
426 					 const char * link,
427 					 size_t link_size )
428 {
429     rc_t	rc;
430     char *	linkp;
431 
432     rc = KTocEntryNew (new_entry, name, name_size, mtime, access,
433 		       (sizeof(KTocEntry)
434 			- sizeof(union KTocEntryUnion))
435 		       + sizeof(struct KTocEntrySoftLink) + link_size + 1);
436     if (rc != 0)
437     {
438 	return rc;
439     }
440     (*new_entry)->type = ktocentrytype_softlink;
441     linkp =(char*)(*new_entry) + sizeof(KTocEntry) - sizeof(union KTocEntryUnion)
442 	+ sizeof(struct KTocEntrySoftLink);
443     string_copy (linkp, link_size+1, link, link_size);
444     StringInit ( &((*new_entry)->u.symbolic_link.link_path), linkp, link_size, (uint32_t)link_size );
445     return 0;
446 }
447 
448 /* ----------------------------------------------------------------------
449  * KTocEntryNewHard
450  *
451  * [RET] rc_t					0 for success; anything else for a failure
452  *						see itf/klib/rc.h for general details
453  * [OUT] KTocEntry ** 	new_entry	where to put a pointer to the new TOC Entry
454  * [IN]  const char * 		name		name of the file (not path) (not assumed to be ASCIZ)
455  * [IN]  size_t			name_size	length of name
456  * [IN]  uint32_t		access		unix/posix style permission flags
457  * Resolution of the link is not set up in this function
458  */
KTocEntryNewHard(KTocEntry ** new_entry,const char * name,size_t name_size,KTime_t mtime,uint32_t access,const KTocEntry * targ)459 rc_t KTocEntryNewHard ( KTocEntry ** new_entry,
460                         const char * name,
461                         size_t name_size,
462                         KTime_t mtime,
463                         uint32_t access,
464                         const KTocEntry * targ )
465 {
466     rc_t	rc;
467 
468     if ((rc = KTocEntryNew (new_entry, name, name_size, mtime, access,
469 			    sizeof(KTocEntry)
470 			    - sizeof(union KTocEntryUnion)
471 			    + sizeof(struct KTocEntryHardLink)))
472 	!= 0)
473     {
474 	return rc;
475     }
476     (*new_entry)->type = ktocentrytype_hardlink;
477     (*new_entry)->u.hard_link.ref = targ;
478 
479     return 0;
480 }
481 
482 /* ----------------------------------------------------------------------
483  * KTocEntryNewDirectory
484  *
485  * [RET] rc_t					0 for success; anything else for a failure
486  *						see itf/klib/rc.h for general details
487  * [OUT] KTocEntry **		new_entry	where to put a pointer to the new TOC Entry
488  * [IN]  const char *		name		name of the directory (not assumed to be ASCIZ)
489  * [IN]  size_t			name_size	length of name
490  * [IN]  uint32_t		access		unix/posix style permission flags
491  */
KTocEntryNewDirectory(KTocEntry ** new_entry,const char * name,size_t name_size,KTime_t mtime,uint32_t access)492 rc_t KTocEntryNewDirectory ( KTocEntry ** new_entry,
493 					 const char * name,
494 					 size_t name_size,
495 					 KTime_t mtime,
496 					 uint32_t access )
497 {
498     rc_t	rc;
499 
500     /* -----
501      * get rid of trailing '/' characters in a file name
502      */
503     while (name[name_size-1] == '/')
504 	--name_size;
505 
506     if ((rc = KTocEntryNew (new_entry, name, name_size, mtime, access,
507 			    sizeof(KTocEntry)
508 			    - sizeof(union KTocEntryUnion)
509 			    + sizeof(struct KTocEntryDir)))
510 	!= 0)
511     {
512 	return rc;
513     }
514     (*new_entry)->type = ktocentrytype_dir;
515     BSTreeInit(&(*new_entry)->u.dir.tree);	/* start with an empty tree */
516     return 0;
517 }
518 
519 /* ----------------------------------------------------------------------
520  *
521  */
KTocEntryGetTime(const KTocEntry * self,KTime_t * mtime)522 rc_t KTocEntryGetTime ( const KTocEntry *self, KTime_t *mtime )
523 {
524     if (self == NULL)
525     {
526 	return RC (rcFS, rcToc, rcAccessing, rcSelf, rcNull);
527     }
528     *mtime = self->mtime;
529     return 0;
530 }
531 
532 /* ----------------------------------------------------------------------
533  *
534  */
KTocEntryGetAccess(const KTocEntry * self,uint32_t * access)535 rc_t KTocEntryGetAccess ( const KTocEntry *self, uint32_t *access )
536 {
537     if (self == NULL)
538     {
539 	return RC (rcFS, rcToc, rcAccessing, rcSelf, rcNull);
540     }
541     *access = self->access;
542     return 0;
543 }
544 
545 /* ----------------------------------------------------------------------
546  *
547  */
KTocEntryGetType(const KTocEntry * self,KTocEntryType * type)548 rc_t KTocEntryGetType ( const KTocEntry *self, KTocEntryType* type )
549 {
550     if (self == NULL)
551     {
552 	return RC (rcFS, rcToc, rcAccessing, rcSelf, rcNull);
553     }
554     *type = self->type;
555     return 0;
556 }
557 
558 /* ----------------------------------------------------------------------
559  *
560  */
KTocEntryGetFileSize(const KTocEntry * self,uint64_t * size)561 rc_t KTocEntryGetFileSize ( const KTocEntry * self, uint64_t * size )
562 {
563     int	loopcount;
564     const KTocEntry * target;
565 
566     assert (self != NULL);
567     assert (size != NULL);
568 
569     *size = 0;
570 
571     for (loopcount = 0; loopcount < KARC_LINK_RESOLVE_LOOPMAX; ++loopcount)
572     {
573 	switch (self->type)
574 	{
575 	default:
576 	case ktocentrytype_unknown:
577 	case ktocentrytype_notfound:
578 	    return RC (rcFS, rcFile, rcAccessing, rcFile, rcInvalid);
579 
580 	case ktocentrytype_dir:
581 	    return RC (rcFS, rcFile, rcAccessing, rcFileDesc, rcIncorrect);
582 
583 	case ktocentrytype_file:
584 	    *size = self->u.contiguous_file.file_size;
585 	    return 0;
586 
587 	case ktocentrytype_chunked:
588 	    *size = self->u.chunked_file.file_size;
589 	    return 0;
590 
591 	case ktocentrytype_zombiefile:
592 	    *size = self->u.zombie_file.file_size;
593 	    return 0;
594 
595 	case ktocentrytype_softlink:
596 	    /* architect called for KArcDir to handle symbolic link resolution */
597 	    return RC (rcFS, rcFile, rcAliasing, rcLink, rcNoErr);
598 
599 	case ktocentrytype_hardlink:
600 	    if (KTocEntryGetHardTarget(self, &target) != 0)
601 		return RC (rcFS, rcFile, rcAccessing, rcFile, rcInvalid);
602 	    /* this breaks "object oriented rules" but lets us loop instead of recur */
603 	    self = target; /* catch bad returns at reiteration of switch */
604 	    /* only non-terminal path within the loop */
605 	    break;
606 
607         case ktocentrytype_emptyfile:
608 	    *size = 0;
609 	    return 0;
610 
611 	}
612     }
613     return RC (rcFS, rcFile, rcAccessing, rcFile, rcInvalid);
614 }
615 
KTocEntryGetFilePhysicalSize(const KTocEntry * self,uint64_t * size)616 rc_t KTocEntryGetFilePhysicalSize ( const KTocEntry * self, uint64_t * size )
617 {
618     int	loopcount;
619     const KTocEntry * target;
620 
621     assert (self != NULL);
622     assert (size != NULL);
623 
624     *size = 0;
625 
626     for (loopcount = 0; loopcount < KARC_LINK_RESOLVE_LOOPMAX; ++loopcount)
627     {
628 	switch (self->type)
629 	{
630 	default:
631 	case ktocentrytype_unknown:
632 	case ktocentrytype_notfound:
633 	    return RC (rcFS, rcFile, rcAccessing, rcFile, rcInvalid);
634 
635 	case ktocentrytype_dir:
636 	    return RC (rcFS, rcFile, rcAccessing, rcFileDesc, rcIncorrect);
637 
638 	case ktocentrytype_file:
639 	    *size = self->u.contiguous_file.file_size;
640 	    return 0;
641 
642 	case ktocentrytype_chunked:
643         {
644             uint64_t size_;
645             uint32_t ix;
646             for (size_ = 0, ix = 0; ix < self->u.chunked_file.num_chunks; ++ix)
647                 size_ += self->u.chunked_file.chunks[ix].size;
648             *size = size_;
649 	    return 0;
650         }
651 	case ktocentrytype_zombiefile:
652 	    *size = self->u.zombie_file.file_size;
653 	    return 0;
654 
655 	case ktocentrytype_softlink:
656 	    /* architect called for KArcDir to handle symbolic link resolution */
657 	    return RC (rcFS, rcFile, rcAliasing, rcLink, rcNoErr);
658 
659 	case ktocentrytype_hardlink:
660 	    if (KTocEntryGetHardTarget(self, &target) != 0)
661 		return RC (rcFS, rcFile, rcAccessing, rcFile, rcInvalid);
662 	    /* this breaks "object oriented rules" but lets us loop instead of recur */
663 	    self = target; /* catch bad returns at reiteration of switch */
664 	    /* only non-terminal path within the loop */
665 	    break;
666 
667         case ktocentrytype_emptyfile:
668 	    *size = 0;
669 	    return 0;
670 
671 	}
672     }
673     return RC (rcFS, rcFile, rcAccessing, rcFile, rcInvalid);
674 }
675 
676 /* ----------------------------------------------------------------------
677  *
678  */
KTocEntryGetFileLocator(const KTocEntry * self,uint64_t * locator)679 rc_t KTocEntryGetFileLocator ( const KTocEntry * self, uint64_t * locator )
680 {
681     int	loopcount;
682     const KTocEntry * target;
683 
684     assert (self != NULL);
685     assert (locator != NULL);
686 
687     *locator = 0;
688 
689     for (loopcount = 0; loopcount < KARC_LINK_RESOLVE_LOOPMAX; ++loopcount)
690     {
691 	switch (self->type)
692 	{
693 	default:
694 	case ktocentrytype_unknown:
695 	case ktocentrytype_notfound:
696 	    return RC (rcFS, rcFile, rcAccessing, rcFile, rcInvalid);
697 
698 	case ktocentrytype_dir:
699 	    return RC (rcFS, rcFile, rcAccessing, rcFileDesc, rcIncorrect);
700 
701 	case ktocentrytype_file:
702 	case ktocentrytype_zombiefile:
703 	    *locator = self->u.contiguous_file.archive_offset;
704 	    return 0;
705 	case ktocentrytype_chunked:
706         {
707             /* find lowest offset chunk */
708             if (self->u.chunked_file.num_chunks > 0)
709             {
710                 uint64_t loc;
711                 uint32_t ix;
712 
713                 *locator = self->u.chunked_file.chunks[0].source_position;
714                 for (ix = 1; ix < self->u.chunked_file.num_chunks; ++ix)
715                 {
716                     loc = self->u.chunked_file.chunks[ix].source_position;
717                     if (loc < *locator)
718                         *locator = loc;
719                 }
720             }
721             else
722                 *locator = 0;
723 
724 	    return 0;
725         }
726 	case ktocentrytype_softlink:
727 	    /* architect called for KArcDir to handle symbolic link resolution */
728 	    return RC (rcFS, rcFile, rcAliasing, rcLink, rcNoErr);
729 
730 	case ktocentrytype_hardlink:
731 	    if (KTocEntryGetHardTarget(self, &target) != 0)
732 		return RC (rcFS, rcFile, rcAccessing, rcFile, rcInvalid);
733 	    /* this breaks "object oriented rules" but lets us loop instead of recur */
734 	    self = target; /* catch bad returns at reiteration of switch */
735 	    /* only non-terminal path within the loop */
736 	    break;
737 
738         case ktocentrytype_emptyfile:
739 	    *locator = 0;
740 	    return 0;
741 
742 	}
743     }
744     return RC (rcFS, rcFile, rcAccessing, rcFile, rcInvalid);
745 }
746 
747 /* ----------------------------------------------------------------------
748  *
749  */
KTocEntryGetChunks(const KTocEntry * self,uint32_t * num_chunks,const KTocChunk ** chunks)750 rc_t KTocEntryGetChunks ( const KTocEntry * self,
751                           uint32_t * num_chunks,
752                           const KTocChunk ** chunks )
753 {
754     int	loopcount;
755     const KTocEntry * target;
756 
757     *chunks = NULL;
758     *num_chunks = 0;
759 
760     for (loopcount = 0; loopcount < KARC_LINK_RESOLVE_LOOPMAX; ++loopcount)
761     {
762 	switch (self->type)
763 	{
764 	default:
765 	case ktocentrytype_unknown:
766 	case ktocentrytype_notfound:
767 	    return RC (rcFS, rcFile, rcAccessing, rcFile, rcInvalid);
768 
769 	case ktocentrytype_dir:
770 	case ktocentrytype_file:
771 	    return RC (rcFS, rcFile, rcAccessing, rcFileDesc, rcIncorrect);
772 
773 	case ktocentrytype_chunked:
774 	    *chunks = self->u.chunked_file.chunks;
775 	    *num_chunks = self->u.chunked_file.num_chunks;
776 	    return 0;
777 
778 	case ktocentrytype_softlink:
779 	    /* architect called for KArcDir to handle symbolic link resolution */
780 	    return RC (rcFS, rcFile, rcAliasing, rcLink, rcNoErr);
781 
782 	case ktocentrytype_hardlink:
783 	    if (KTocEntryGetHardTarget(self, &target) != 0)
784 		return RC (rcFS, rcFile, rcAccessing, rcFile, rcInvalid);
785 	    /* this breaks "object oriented rules" but lets us loop instead of recur */
786 	    self = target; /* catch bad returns at reiteration of switch */
787 	    /* only non-terminal path within the loop */
788 	    break;
789 	}
790     }
791     return RC (rcFS, rcFile, rcAccessing, rcFile, rcInvalid);
792 }
793 
794 /* ----------------------------------------------------------------------
795  *
796  */
KTocEntryGetFileOffset(const KTocEntry * self,uint64_t * offset)797 rc_t KTocEntryGetFileOffset ( const KTocEntry * self, uint64_t * offset )
798 {
799     int			loopcount;
800     const KTocEntry * target;
801 
802     *offset = 0;
803 
804     for (loopcount = 0; loopcount < KARC_LINK_RESOLVE_LOOPMAX; ++loopcount)
805     {
806 	switch (self->type)
807 	{
808 	default:
809 	case ktocentrytype_unknown:
810 	case ktocentrytype_notfound:
811 	    return RC (rcFS, rcTocEntry, rcAccessing, rcFile, rcUnknown);
812 
813 	case ktocentrytype_dir:
814 	case ktocentrytype_chunked:
815 	    return RC (rcFS, rcTocEntry, rcAccessing, rcSelf, rcUnsupported);
816 
817 	case ktocentrytype_file:
818 	    *offset = self->u.contiguous_file.archive_offset;
819 	    return 0;
820 
821         case ktocentrytype_emptyfile:
822 	    *offset = 0;
823 	    return 0;
824 
825 	case ktocentrytype_softlink:
826 	    /* architect called for KArcDir to handle symbolic link resolution */
827 	    return RC (rcFS, rcTocEntry, rcAliasing, rcLink, rcNoErr);
828 
829 	case ktocentrytype_hardlink:
830 	    if (KTocEntryGetHardTarget(self, &target) != 0)
831 		return RC (rcFS, rcTocEntry, rcAccessing, rcSelf, rcInvalid);
832 
833 	    /* this breaks "object oriented rules" but lets us loop instead of recur */
834 	    self = target; /* catch bad returns at reiteration of switch */
835 	    /* only non-terminal path within the loop */
836 	    break;
837 	}
838     }
839     return RC (rcFS, rcToc, rcAccessing, rcSelf, rcInvalid);	/* loop fail - too many hard links */
840 }
841 
842 /* ----------------------------------------------------------------------
843  *
844  */
KTocEntryGetBSTree(const KTocEntry * self,const BSTree ** ptree)845 rc_t KTocEntryGetBSTree ( const KTocEntry * self,const BSTree ** ptree )
846 {
847     KTocEntryType	type;
848 
849     if (self == NULL)
850     {
851 	return RC (rcFS, rcToc, rcAccessing, rcSelf, rcNull);
852     }
853     if (KTocEntryGetType(self,&type) != 0)
854     {
855 	return RC  (rcFS, rcToc, rcAccessing, rcParam, rcInvalid);
856     }
857     if (type != ktocentrytype_dir)
858     {
859 	return RC  (rcFS, rcToc, rcAccessing, rcParam, rcInvalid);
860     }
861     *ptree = &self->u.dir.tree;
862     return 0;
863 }
864 
865 /* ----------------------------------------------------------------------
866  *
867  */
KTocEntryGetHardTarget(const KTocEntry * self,const KTocEntry ** target)868 rc_t KTocEntryGetHardTarget ( const KTocEntry *self, const KTocEntry ** target )
869 {
870     if (self == NULL)
871     {
872 	return RC (rcFS, rcToc, rcAccessing, rcSelf, rcNull);
873     }
874     if (target == NULL)
875     {
876 	return RC (rcFS, rcToc, rcAccessing, rcParam, rcNull);
877     }
878     *target = (self->type == ktocentrytype_hardlink) ? self->u.hard_link.ref : NULL;
879     return 0;
880 }
881 
882 /* ----------------------------------------------------------------------
883  *
884  */
KTocEntryGetSoftTarget(const KTocEntry * self,const char ** target)885 rc_t KTocEntryGetSoftTarget ( const KTocEntry *self,
886 				const char ** target )
887 {
888     if (self == NULL)
889     {
890 	return RC (rcFS, rcToc, rcAccessing, rcSelf, rcNull);
891     }
892     if (self->type != ktocentrytype_softlink)
893     {
894 	return RC  (rcFS, rcToc, rcAccessing, rcSelf, rcInvalid);
895     }
896     *target = self->u.symbolic_link.link_path.addr;
897     return 0;
898 }
899 
900 /* ----------------------------------------------------------------------
901  *
902  */
KTocEntryGetName(const KTocEntry * self,const char ** name)903 rc_t KTocEntryGetName ( const KTocEntry *self,
904 			  const char ** name )
905 {
906     if (self == NULL)
907     {
908 	return RC (rcFS, rcToc, rcAccessing, rcSelf, rcNull);
909     }
910     *name = self->name.addr;
911     return 0;
912 }
913 
914 /* ======================================================================
915  */
KTocEntryTypeGetString(KTocEntryType t)916 const char * KTocEntryTypeGetString(KTocEntryType t)
917 {
918     static const char * entryTypeString[] =
919 	{
920 	    "ktocentrytype_unknown",
921 	    "ktocentrytype_notfound",
922 	    "ktocentrytype_dir",
923 	    "ktocentrytype_file",
924 	    "ktocentrytype_chunked",
925 	    "ktocentrytype_softlink",
926 	    "ktocentrytype_hardlink",
927 	    "ktocentrytype_emptyfile"
928 	};
929 
930     switch (t)
931     {
932     case ktocentrytype_unknown:
933     case ktocentrytype_dir:
934     case ktocentrytype_file:
935     case ktocentrytype_chunked:
936     case ktocentrytype_softlink:
937     case ktocentrytype_hardlink:
938     case ktocentrytype_emptyfile:
939 	return entryTypeString[t+1];
940     default:
941 	return "ktocentrytype_error";
942     }
943 }
944 
945 /*
946  * preferred behavior of this needs to be determined
947  */
KTocEntryPersistWriteFunc(void * param,const void * buffer,size_t size,size_t * num_writ)948 LIB_EXPORT rc_t CC KTocEntryPersistWriteFunc ( void * param,
949                                                const void * buffer,
950                                                size_t size,
951                                                size_t * num_writ )
952 {
953     KTocEntryPersistWriteFuncData * data;
954     rc_t rc;
955     size_t to_write;
956 
957     assert (param != NULL);
958     assert (buffer != NULL);
959     assert (num_writ != NULL);
960 
961     rc = 0;
962     *num_writ = 0;
963     data = param;
964     if (size != 0)
965     {
966 	if ((data->buffptr + size) > data->limit)
967 	{
968 	    to_write = data->limit - data->buffptr;
969 	    rc = RC (rcFS, rcTocEntry, rcPersisting, rcBuffer, rcTooShort);
970 	}
971 	else
972 	    to_write = size;
973 	memmove (data->buffptr, buffer, to_write);
974 	data->buffptr += to_write;
975 	*num_writ = to_write;
976 #if 0
977 	{
978 	    size_t ix;
979 
980 	    for (ix = 0; ix < to_write; ix ++)
981 	    {
982 /* please do not delete commented out code */
983 /* 		if ((ix & 0xF) == 0x0) */
984 /* 		    printf ("%.08x : ", ix); */
985 /* 		printf( "%.02x ", ((uint8_t*)buffer)[ix]); */
986 
987 /* 		if ((ix & 0xF) == 0xF) */
988 /* 		    printf ("\n"); */
989 	    }
990 /*  	    printf ("\n"); */
991 	}
992 #endif
993     }
994     return rc;
995 }
996 
997 
998 static
KTocEntryPersistNodeCommon(void * param,const KTocEntry * n,size_t * num_writ,PTWriteFunc write,void * write_param)999 rc_t KTocEntryPersistNodeCommon (void * param, const KTocEntry * n,
1000 				 size_t * num_writ, PTWriteFunc write,
1001 				 void * write_param)
1002 {
1003     size_t all_written;
1004     size_t written;
1005     uint16_t nsize;
1006     const char * name;
1007     rc_t rc;
1008     KTocEntryType t;
1009     uint8_t b;
1010     KTime_t mtime;
1011     uint32_t access;
1012 
1013     rc = KTocEntryGetName (n, &name);
1014     if (rc != 0)
1015 	return rc;
1016     TOC_DEBUG (("%s %s\n", __func__, name));
1017     if (write)
1018     {
1019 
1020 /* please do not delete commented out code */
1021 /* 	printf ("----------\n"); */
1022 	nsize = (uint16_t)strlen(name);
1023 	rc = KTocEntryGetTime (n, &mtime);
1024 	if (rc != 0)
1025 	    return rc;
1026 	rc = KTocEntryGetAccess (n, &access);
1027 	if (rc != 0)
1028 	    return rc;
1029 	rc = KTocEntryGetType (n, &t);
1030 	if (rc != 0)
1031 	    return rc;
1032 	b = (uint8_t)t;
1033 /* 	printf ("name size\t"); */
1034 	rc = (*write) (write_param, &nsize, sizeof nsize, &all_written);
1035 	if (rc == 0)
1036 	{
1037 /* 	    printf("name %s\t", name); */
1038 	    rc = (*write) (write_param, name, nsize, &written);
1039 	    all_written += written;
1040 	    if (rc == 0)
1041 	    {
1042 /* 		printf("mtime\t"); */
1043 		rc = (*write) (write_param, &mtime, sizeof mtime, &written);
1044 		all_written += written;
1045 		if (rc == 0)
1046 		{
1047 /* 		    printf("access\t"); */
1048 		    rc = (*write) (write_param, &access, sizeof access, &written);
1049 		    all_written += written;
1050 		    if (rc == 0)
1051 		    {
1052 /* 			printf("type\t"); */
1053 			rc = (*write) (write_param, &b, sizeof b, &written);
1054 			all_written += written;
1055 		    }
1056 		}
1057 	    }
1058 	}
1059 	*num_writ = all_written;
1060 	return rc;
1061     }
1062     else
1063     {
1064 	*num_writ = (sizeof (nsize) + strlen (name) + sizeof (mtime) +
1065 		     sizeof (access) + sizeof (b));
1066 	return 0;
1067     }
1068 }
1069 
KTocEntryPersistNodeDir(void * param,const KTocEntry * n,size_t * num_writ,PTWriteFunc write,void * write_param)1070 rc_t KTocEntryPersistNodeDir ( void *param, const KTocEntry * n,
1071 			      size_t * num_writ,
1072 			      PTWriteFunc write, void * write_param )
1073 {
1074     rc_t rc;
1075 
1076 /*     size_t	start,end; */
1077 
1078     TOC_FUNC_ENTRY();
1079 
1080 
1081 /*     start = *num_writ; */
1082 
1083     rc = BSTreePersist (&n->u.dir.tree,
1084 			num_writ,
1085 			write,
1086 			write_param,
1087 			KTocEntryPersist,
1088 			NULL);
1089     if (rc != 0)
1090     {
1091         TOC_DEBUG (("KTocEntryPersistNodeDir: failure return from BSTreePersist"));
1092     }
1093 
1094 /*     end = *num_writ; */
1095     return rc;
1096 }
1097 
1098 static
KTocEntryPersistNodeFile(void * param,const KTocEntry * n,size_t * num_writ,PTWriteFunc write,void * write_param)1099 rc_t KTocEntryPersistNodeFile (void *param, const KTocEntry * n,
1100 			       size_t * num_writ,
1101 			       PTWriteFunc write, void * write_param)
1102 {
1103     TOC_FUNC_ENTRY();
1104 
1105     if (write)
1106     {
1107 	rc_t rc;
1108 	size_t all_written;
1109 	size_t written;
1110 
1111 /* please do not delete commented out code */
1112 /* 	printf("file offset\t"); */
1113 	rc = (*write) (write_param, &n->u.contiguous_file.archive_offset,
1114 		       sizeof n->u.contiguous_file.archive_offset, &all_written);
1115 	if (rc == 0)
1116 	{
1117 /* 	    printf("file size\t"); */
1118 	    rc = (*write) (write_param, &n->u.contiguous_file.file_size,
1119 			   sizeof n->u.contiguous_file.file_size, &written);
1120             all_written += written;
1121 	}
1122 	*num_writ = all_written;
1123 	return rc;
1124     }
1125     else
1126     {
1127 	*num_writ = (sizeof n->u.contiguous_file.archive_offset +
1128 		     sizeof n->u.contiguous_file.file_size);
1129 	return 0;
1130     }
1131 }
1132 
1133 static
KTocEntryPersistNodeChunked(void * param,const KTocEntry * n,size_t * num_writ,PTWriteFunc write,void * write_param)1134 rc_t KTocEntryPersistNodeChunked (void *param, const KTocEntry * n,
1135 				  size_t * num_writ,
1136 				  PTWriteFunc write, void * write_param)
1137 {
1138     KTocChunk * chunks;
1139     uint32_t count;
1140 
1141     count = n->u.chunked_file.num_chunks; /* used with write and no write */
1142     chunks = n->u.chunked_file.chunks;
1143     if (write)
1144     {
1145 	rc_t rc;
1146 	size_t all_written;
1147 	size_t written;
1148 
1149 /* please do not delete commented out code */
1150 /* 	printf("file size\t"); */
1151 	rc = (*write) (write_param, &n->u.chunked_file.file_size,
1152 		       sizeof n->u.chunked_file.file_size, &all_written);
1153 	if (rc == 0)
1154 	{
1155 /* 	    printf("chunk count\t"); */
1156 	    rc = (*write) (write_param, &count, sizeof count, &written);
1157 	    all_written += written;
1158 	    if (rc == 0)
1159 	    {
1160 		for ( ; count--; chunks++)
1161 		{
1162 /* 		    printf("chunk l position\t"); */
1163  		    rc = (*write) (write_param, &chunks->logical_position,
1164  				   sizeof chunks->logical_position, &written);
1165 		    all_written += written;
1166 		    if (rc != 0)
1167 			break;
1168 /* 		    printf("chunk s position\t"); */
1169 		    rc = (*write) (write_param, &chunks->source_position,
1170 				   sizeof chunks->source_position, &all_written);
1171 		    all_written += written;
1172 		    if (rc != 0)
1173 			break;
1174 /* 		    printf("chunk size\t"); */
1175 		    rc = (*write) (write_param, &chunks->size,
1176 				   sizeof chunks->size, &written);
1177 		    all_written += written;
1178 		    if (rc != 0)
1179 			break;
1180 		}
1181 	    }
1182 	}
1183 	*num_writ = all_written;
1184 	return rc;
1185     }
1186     else
1187     {
1188 	*num_writ = (sizeof n->u.chunked_file.file_size + sizeof count +
1189 		     count * (sizeof chunks->logical_position +
1190 			      sizeof chunks->source_position +
1191 			      sizeof chunks->size));
1192 	return 0;
1193     }
1194 }
1195 
1196 static
KTocEntryPersistNodeSym(void * param,const KTocEntry * n,size_t * num_writ,PTWriteFunc write,void * write_param)1197 rc_t KTocEntryPersistNodeSym (void *param, const KTocEntry * n,
1198 			      size_t * num_writ, PTWriteFunc write,
1199 			      void * write_param)
1200 {
1201     uint16_t nsize;
1202 
1203     nsize = (uint16_t)n->u.symbolic_link.link_path.size;
1204     if (write)
1205     {
1206 	rc_t rc;
1207 	size_t all_written;
1208 	size_t written;
1209 
1210 	rc = (*write) (write_param, &nsize, sizeof nsize, &all_written);
1211 	if (rc == 0)
1212 	{
1213 	    rc = (*write) (write_param,
1214 			   n->u.symbolic_link.link_path.addr,
1215 			   nsize,
1216 			   &written);
1217 	    all_written += written;
1218 	}
1219 	*num_writ = all_written;
1220 	return rc;
1221     }
1222     else
1223     {
1224 	*num_writ = (sizeof (nsize) + nsize);
1225 	return 0;
1226     }
1227 }
1228 
1229 static
KTocEntryPersistNodeLink(void * param,const KTocEntry * n,size_t * num_writ,PTWriteFunc write,void * write_param)1230 rc_t KTocEntryPersistNodeLink (void *param, const KTocEntry * n,
1231 			       size_t * num_writ,
1232 			       PTWriteFunc write, void * write_param)
1233 {
1234     uint16_t nsize;
1235 
1236     nsize = (uint16_t)n->u.hard_link.ref->name.size;
1237     if (write)
1238     {
1239 	rc_t rc;
1240 	size_t all_written;
1241 	size_t written;
1242 
1243 	rc = (*write) (write_param, &nsize, sizeof nsize, &all_written);
1244 	if (rc == 0)
1245 	{
1246 	    rc = (*write) (write_param,
1247 			   n->u.hard_link.ref->name.addr,
1248 			   nsize,
1249 			   &written);
1250 	    all_written += written;
1251 	}
1252 	*num_writ = all_written;
1253 	return rc;
1254     }
1255     else
1256     {
1257 	*num_writ = (sizeof (nsize) + nsize);
1258 	return 0;
1259     }
1260 }
1261 
KTocEntryPersist(void * param,const void * node,size_t * num_writ,PTWriteFunc write,void * write_param)1262 LIB_EXPORT rc_t CC KTocEntryPersist ( void *param, const void * node,
1263                                       size_t * num_writ,
1264                                       PTWriteFunc write, void * write_param )
1265 {
1266     rc_t rc;
1267     size_t all_written;
1268     size_t written;
1269     const KTocEntry * n;
1270 
1271     TOC_FUNC_ENTRY();
1272 
1273     all_written = 0;
1274     n = (const KTocEntry *)node;
1275     rc = KTocEntryPersistNodeCommon (param, n, &all_written, write, write_param);
1276     if (rc == 0)
1277     {
1278 	written = 0;
1279 	switch (n->type)
1280 	{
1281 	default:
1282 	    rc = RC (rcFS, rcTocEntry, rcPersisting, rcTocEntry, rcInvalid );
1283 	    LOGERR (klogInt, rc, "malformed node with bad type");
1284 	    break;
1285 
1286  	case ktocentrytype_notfound:
1287 	    rc = RC (rcFS, rcTocEntry, rcPersisting, rcTocEntry, rcCorrupt );
1288 	    LOGERR (klogInt, rc, "malformed tree node not found ");
1289  	    break;
1290 
1291 	case ktocentrytype_dir:
1292 	    /* recur */
1293 /* please do not delete commented out code */
1294 /* 	    printf("KTocEntryPersist Directory\n"); */
1295 	    rc = KTocEntryPersistNodeDir (param, n, &written, write, write_param);
1296 	    break;
1297 
1298 	case ktocentrytype_file:
1299 /* 	    printf("KTocEntryPersist File\n"); */
1300 	    rc = KTocEntryPersistNodeFile (param, n, &written, write, write_param);
1301 	    break;
1302 
1303 	case ktocentrytype_emptyfile:
1304 /* 	    printf("KTocEntryPersist Empty File\n"); */
1305 	    break;
1306 
1307 	case ktocentrytype_chunked:
1308 /* 	    printf("KTocEntryPersist chunked File\n"); */
1309 	    rc = KTocEntryPersistNodeChunked (param, n, &written, write, write_param);
1310 	    break;
1311 
1312 	case ktocentrytype_softlink:
1313 /* 	    printf("KTocEntryPersist soft link\n"); */
1314 	    rc = KTocEntryPersistNodeSym (param, n, &written, write, write_param);
1315 	    break;
1316 
1317 	case ktocentrytype_hardlink:
1318 /* 	    printf("KTocEntryPersist hard link\n"); */
1319 	    rc = KTocEntryPersistNodeLink (param, n, &written, write, write_param);
1320 	    break;
1321 	}
1322 	all_written += written;
1323     }
1324     *num_writ = all_written;
1325     return rc;
1326 }
1327 
1328 typedef
1329 struct KTocEntryInflateData
1330 {
1331     KToc * toc;
1332     const char * path;
1333     uint64_t arcsize;
1334     uint64_t offset;
1335     rc_t rc;
1336     bool rev;
1337 } KTocEntryInflateData;
1338 
1339 typedef
1340 struct KTocEntryInflateCommon
1341 {
1342     char * name;
1343     KTime_t mtime;
1344     uint32_t access;
1345     KTocEntryType type;
1346 } KTocEntryInflateCommon;
1347 /* TBD: replace the list of parameters in the inflatenode functions
1348 typedef
1349 struct KTocEntryInflateNodeData
1350 {
1351     KToc * toc;
1352     const void * ptr;
1353     const void * limit;
1354     char * name;
1355     KTime_t mtime;
1356     uint32_t access;
1357     KTocEntryType type;
1358     bool rev;
1359 } KTocEntryInflateNodeData;
1360 */
1361 
1362 static
check_limit(const void * ptr,const void * limit,size_t size)1363 bool check_limit (const void * ptr, const void * limit, size_t size)
1364 {
1365     const uint8_t * p = ptr;
1366     const uint8_t * l = limit;
1367     return ((p + size) > l);
1368 }
1369 
1370 #define read_scalar(N,T,S)	     \
1371     static rc_t N (const void ** _ptr, const void * limit, bool rev, T * pout) \
1372     {									\
1373 	const T * ptr;							\
1374 									\
1375 	if (check_limit (*_ptr, limit, sizeof (T)))			\
1376 	    return RC (rcFS, rcTocEntry, rcParsing, rcBuffer, rcTooShort); \
1377 	    								\
1378 	ptr = *_ptr;							\
1379 									\
1380 	if (rev)							\
1381 	{								\
1382 	    T t;							\
1383 	    memmove (&t, ptr, sizeof (T));				\
1384 	    *pout = S (t);						\
1385 	}								\
1386 	else								\
1387 	    memmove (pout, ptr, sizeof (T));                             \
1388 	*_ptr = ++ptr;							\
1389 	return 0;							\
1390     }
1391 
read_scalar(read_u16,uint16_t,bswap_16)1392 read_scalar (read_u16,uint16_t,bswap_16)
1393 read_scalar (read_u32,uint32_t,bswap_32)
1394 read_scalar (read_u64,uint64_t,bswap_64)
1395 read_scalar (read_i64,int64_t,bswap_64)
1396 
1397 static
1398 rc_t read_u8 (const void ** _ptr, const void * limit, uint8_t * pout)
1399 {
1400     const uint8_t * ptr;
1401 
1402     if (check_limit (*_ptr, limit, sizeof (uint8_t)))
1403 	return RC (rcFS, rcTocEntry, rcParsing, rcBuffer, rcTooShort);
1404 
1405     ptr = *_ptr;
1406     *pout = *ptr++;
1407     *_ptr = ptr;
1408     return 0;
1409 }
1410 
1411 static
KTocEntryInflateNodeCommon(const void ** ptr,const void * limit,KTocEntryInflateCommon * common,const char * path,bool rev)1412 rc_t KTocEntryInflateNodeCommon (const void ** ptr,
1413 				 const void * limit,
1414 				 KTocEntryInflateCommon * common,
1415 				 const char * path,
1416 				 bool rev)
1417 {
1418     rc_t rc;
1419     uint16_t plen;
1420     uint16_t nlen;
1421 
1422     rc = read_u16 (ptr, limit, rev, &nlen);
1423     if (rc)
1424 	return rc;
1425 
1426     if (check_limit (*ptr, limit, nlen))
1427 	return RC (rcFS, rcTocEntry, rcParsing, rcBuffer, rcTooShort);;
1428 
1429     plen = (uint16_t)strlen (path);
1430     if (plen == 0)
1431     {
1432 	common->name = malloc (nlen+1);
1433 	if (common->name == NULL)
1434 	{
1435 	    return RC (rcFS, rcTocEntry, rcInflating, rcMemory, rcExhausted);
1436 	}
1437 	memmove (common->name, *ptr, nlen);
1438 	common->name[nlen] = '\0';
1439     }
1440     else
1441     {
1442 	common->name = malloc (plen + 1 + nlen+1);
1443 	if (common->name == NULL)
1444 	{
1445 	    return RC (rcFS, rcTocEntry, rcInflating, rcMemory, rcExhausted);
1446 	}
1447 	memmove (common->name, path, plen);
1448 	common->name[plen] = '/';
1449 	memmove (common->name+plen+1, *ptr, nlen);
1450 	common->name[plen + nlen + 1] = '\0';
1451     }
1452 
1453     *ptr = ((uint8_t*)*ptr) + nlen;
1454 
1455     rc = read_i64 (ptr, limit, rev, &common->mtime);
1456     if (rc == 0)
1457     {
1458 	rc =read_u32 (ptr, limit, rev, &common->access);
1459 	if (rc == 0)
1460 	{
1461 	    uint8_t type;
1462 	    rc = read_u8 (ptr, limit, &type);
1463 	    if (rc == 0)
1464 	    {
1465 		common->type = type;
1466 		return 0;
1467 	    }
1468 	}
1469     }
1470     free (common->name);
1471     common->name = NULL;
1472     common->mtime = 0;
1473     common->access = 0;
1474     common->type = ktocentrytype_unknown;
1475     return rc;
1476 }
1477 
1478 
1479 static
KTocEntryInflateNodeDir(KToc * toc,KTocEntryInflateCommon * common,const void ** ptr,uint64_t offset,uint64_t arcsize,const void * limit,bool rev)1480 rc_t KTocEntryInflateNodeDir (KToc * toc, KTocEntryInflateCommon * common,
1481 			      const void ** ptr, uint64_t offset, uint64_t arcsize, const void * limit, bool rev)
1482 {
1483     rc_t rc;
1484 
1485     rc = KTocCreateDir (toc,
1486 			common->mtime,
1487 			common->access,
1488 			(KCreateMode)(kcmInit|kcmParents),
1489 			common->name);
1490     if (rc == 0)
1491     {
1492 	rc = KTocInflatePBSTree (toc, arcsize, *ptr, (uint32_t)( (uint8_t*)limit - (uint8_t*)*ptr ),
1493                                  offset, rev, common->name);
1494     }
1495     return rc;
1496 }
1497 
1498 static
KTocEntryInflateNodeFile(KToc * toc,const KTocEntryInflateCommon * common,const void ** ptr,uint64_t offset,uint64_t arcsize,const void * limit,bool rev)1499 rc_t KTocEntryInflateNodeFile (KToc * toc, const KTocEntryInflateCommon * common,
1500 			       const void ** ptr, uint64_t offset, uint64_t arcsize, const void * limit, bool rev)
1501 {
1502     rc_t rc;
1503     uint64_t size;
1504     uint64_t foffset;
1505 
1506     rc = read_u64 (ptr, limit, rev, &foffset);
1507     if (rc == 0)
1508     {
1509 	rc = read_u64 (ptr, limit, rev, &size);
1510 	if (rc == 0)
1511 	{
1512 /*             KOutMsg ("%s %s %lu %lu %lu\n", __func__, common->name, size, offset + foffset, arcsize); */
1513             if (arcsize >= offset + foffset + size )
1514 
1515                 rc = KTocCreateFile (toc,
1516                                  offset + foffset,
1517                                  size,
1518                                  common->mtime,
1519                                  common->access,
1520                                  (KCreateMode)(kcmInit|kcmParents),
1521                                  common->name);
1522             else
1523 /*                 KOutMsg ("ZOMBIE: %s\n", common->name), */
1524 
1525                 rc = KTocCreateZombieFile (toc,
1526                                            offset + foffset,
1527                                            size,
1528                                            common->mtime,
1529                                            common->access,
1530                                            (KCreateMode)(kcmInit|kcmParents),
1531                                            common->name);
1532 	}
1533     }
1534     return rc;
1535 }
1536 
1537 static
KTocEntryInflateNodeEmptyFile(KToc * toc,const KTocEntryInflateCommon * common,const void ** ptr,uint64_t offset,const void * limit,bool rev)1538 rc_t KTocEntryInflateNodeEmptyFile (KToc * toc, const KTocEntryInflateCommon * common,
1539                                     const void ** ptr, uint64_t offset, const void * limit, bool rev)
1540 {
1541     rc_t rc;
1542 
1543     rc = KTocCreateFile (toc,
1544                          0,
1545                          0,
1546                          common->mtime,
1547                          common->access,
1548                          (KCreateMode)(kcmInit|kcmParents),
1549                          common->name);
1550     return rc;
1551 }
1552 
1553 static
KTocEntryInflateNodeChunked(KToc * toc,const KTocEntryInflateCommon * common,const void ** ptr,uint64_t offset,const void * limit,bool rev)1554 rc_t KTocEntryInflateNodeChunked (KToc * toc, const KTocEntryInflateCommon * common,
1555 				  const void ** ptr, uint64_t offset, const void * limit, bool rev)
1556 {
1557     rc_t rc;
1558     uint64_t size;
1559     uint32_t count;
1560     KTocChunk * chunks;
1561 
1562     rc = read_u64 (ptr, limit, rev, &size);
1563     if (rc == 0)
1564     {
1565 	rc = read_u32 (ptr, limit, rev, &count);
1566 	if (rc == 0)
1567 	{
1568 	    chunks = malloc (sizeof (KTocChunk) * count);
1569 	    if (chunks == NULL)
1570 		rc = RC (rcFS, rcTocEntry, rcParsing, rcMemory, rcExhausted);
1571 	    else
1572 	    {
1573 		uint32_t ix;
1574 		for (ix = 0; (rc == 0) && (ix < count); ++ix)
1575 		{
1576 		    if (rc == 0)
1577 			rc = read_u64 (ptr, limit, rev, &chunks[ix].logical_position);
1578 		    if (rc == 0)
1579 		    {
1580 			rc = read_u64 (ptr, limit, rev, &chunks[ix].source_position);
1581 			chunks[ix].source_position += offset;
1582 		    }
1583 		    if (rc == 0)
1584 			rc = read_u64 (ptr, limit, rev, &chunks[ix].size);
1585 		}
1586 		if (rc == 0)
1587 		    rc = KTocCreateChunkedFile (toc,
1588 						size,
1589 						common->mtime,
1590 						common->access,
1591 						count,
1592 						chunks,
1593 						(KCreateMode)(kcmInit|kcmParents),
1594 						common->name);
1595 		free (chunks);
1596 	    }
1597 	}
1598     }
1599     return rc;
1600 }
1601 
1602 static
KTocEntryInflateNodeHardLink(KToc * toc,const KTocEntryInflateCommon * common,const void ** ptr,uint64_t offset,const void * limit,bool rev)1603 rc_t KTocEntryInflateNodeHardLink (KToc * toc, const KTocEntryInflateCommon * common,
1604 				   const void ** ptr, uint64_t offset, const void * limit, bool rev)
1605 {
1606     rc_t rc;
1607     uint16_t llen;
1608     char * link;
1609 
1610     rc = read_u16 (ptr, limit, rev, &llen);
1611     if (rc)
1612 	return rc;
1613 
1614     if (check_limit (*ptr, limit, llen))
1615 	return RC (rcFS, rcTocEntry, rcParsing, rcBuffer, rcTooShort);;
1616 
1617     link = malloc (llen + 1);
1618     if (link == NULL)
1619 	return RC (rcFS, rcTocEntry, rcParsing, rcMemory, rcExhausted);
1620 
1621     memmove (link, ptr, llen);
1622     link[llen] = '\0';
1623 
1624     rc = KTocCreateHardLink (toc,
1625 			     common->mtime,
1626 			     common->access,
1627 			     (KCreateMode)(kcmInit|kcmParents),
1628 			     link,
1629 			     common->name);
1630 
1631     free (link);
1632     return rc;
1633 }
1634 
1635 static
KTocEntryInflateNodeSoftLink(KToc * toc,const KTocEntryInflateCommon * common,const void ** ptr,uint64_t offset,const void * limit,bool rev)1636 rc_t KTocEntryInflateNodeSoftLink (KToc * toc, const KTocEntryInflateCommon * common,
1637 				  const void ** ptr, uint64_t offset, const void * limit, bool rev)
1638 {
1639     rc_t rc;
1640     uint16_t llen;
1641     char * link;
1642 
1643     rc = read_u16 (ptr, limit, rev, &llen);
1644     if (rc)
1645 	return rc;
1646 
1647     if (check_limit (*ptr, limit, llen))
1648 	return RC (rcFS, rcTocEntry, rcParsing, rcBuffer, rcTooShort);;
1649 
1650     link = malloc (llen + 1);
1651     if (link == NULL)
1652 	return RC (rcFS, rcTocEntry, rcParsing, rcMemory, rcExhausted);
1653 
1654     memmove (link, *ptr, llen);
1655     link[llen] = '\0';
1656 
1657     rc = KTocCreateSoftLink (toc,
1658 			     common->mtime,
1659 			     common->access,
1660 			     (KCreateMode)(kcmInit|kcmParents),
1661 			     link,
1662 			     common->name);
1663 
1664     free (link);
1665     return rc;
1666 }
1667 
1668 static
KTocEntryInflate(PBSTNode * n,void * _data)1669 void CC KTocEntryInflate (PBSTNode * n, void * _data)
1670 {
1671     KTocEntryInflateData * data;
1672     const void * ptr;
1673     const void * limit;
1674     KTocEntryInflateCommon common;
1675     rc_t rc;
1676 
1677     data = _data;
1678     if (data->rc != 0)
1679 	return;
1680     ptr = n->data.addr;
1681     limit = (uint8_t*)ptr + n->data.size;
1682     rc = KTocEntryInflateNodeCommon (&ptr, limit, &common, data->path, data->rev);
1683     if (rc == 0)
1684     {
1685 	switch (common.type)
1686 	{
1687 	default:
1688 	case ktocentrytype_unknown:
1689 	case ktocentrytype_notfound:
1690 	    rc = RC (rcFS, rcTocEntry, rcParsing, rcFile, rcCorrupt);
1691 	    break;
1692 	case ktocentrytype_dir:
1693 	    rc = KTocEntryInflateNodeDir (data->toc, &common, &ptr, data->offset,
1694                                           data->arcsize, limit, data->rev);
1695 	    break;
1696 	case ktocentrytype_file:
1697             rc = KTocEntryInflateNodeFile (data->toc, &common, &ptr, data->offset,
1698                                            data->arcsize, limit, data->rev);
1699 	    break;
1700 	case ktocentrytype_emptyfile:
1701 	    rc = KTocEntryInflateNodeEmptyFile (data->toc, &common, &ptr, data->offset,
1702                                                 limit, data->rev);
1703 	    break;
1704 	case ktocentrytype_chunked:
1705 	    rc = KTocEntryInflateNodeChunked (data->toc, &common, &ptr, data->offset, limit, data->rev);
1706 	    break;
1707 	case ktocentrytype_softlink:
1708 	    rc = KTocEntryInflateNodeSoftLink (data->toc, &common, &ptr, data->offset, limit, data->rev);
1709 	    break;
1710 	case ktocentrytype_hardlink:
1711 	    rc = KTocEntryInflateNodeHardLink (data->toc, &common, &ptr, data->offset, limit, data->rev);
1712 	    break;
1713 	}
1714 	free (common.name);
1715     }
1716     data->rc = rc; /* return */
1717 }
1718 
KTocInflatePBSTree(KToc * self,uint64_t arcsize,const void * treestart,uint32_t maxsize,uint64_t offset,bool rev,const char * path)1719 rc_t KTocInflatePBSTree ( KToc * self, uint64_t arcsize, const void * treestart, uint32_t maxsize,
1720 			 uint64_t offset, bool rev, const char * path )
1721 {
1722     rc_t rc;
1723     PBSTree * pbst;
1724 
1725     rc = PBSTreeMake (&pbst, treestart, maxsize, rev);
1726     if (rc == 0)
1727     {
1728         KTocEntryInflateData data;
1729 
1730         data.toc = self;
1731         data.path = path;
1732         data.arcsize = arcsize;
1733         data.rc = 0;
1734         data.rev = rev;
1735         data.offset = offset;
1736 
1737         PBSTreeForEach (pbst, false, KTocEntryInflate, &data);
1738 
1739         rc = data.rc;
1740 
1741         PBSTreeWhack (pbst);
1742     }
1743     return rc;
1744 }
1745 
1746 
1747 /* end of file tocentry.c */
1748 
1749