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