1 /*
2 ** Copyright (C) 2006-2020 by Carnegie Mellon University.
3 **
4 ** @OPENSOURCE_LICENSE_START@
5 ** See license information in ../../LICENSE.txt
6 ** @OPENSOURCE_LICENSE_END@
7 */
8 
9 /*
10 **  skheader.c
11 **
12 **    Routines to read, write, and manipulate the header of a SiLK file
13 **
14 **    Mark Thomas
15 **    November 2006
16 **
17 */
18 
19 /* Defining SKHEADER_SOURCE ensures we do not define a version of
20  * sk_hentry_packedfile_t that is needed for compatibility by code
21  * that uses libsilk from SiLK-3.16.0 and earlier. */
22 #define  SKHEADER_SOURCE    1
23 #include <silk/silk.h>
24 
25 RCSIDENT("$SiLK: skheader.c ef14e54179be 2020-04-14 21:57:45Z mthomas $");
26 
27 #include "skheader_priv.h"
28 #include "skstream_priv.h"
29 
30 /* TYPDEFS AND DEFINES */
31 
32 /*
33  *    The 0xdeadbeef magic number that appears at the start of all
34  *    binary SiLK files.  The number is defined as 4 single bytes.
35  */
36 #define SKHDR_MAGIC1    0xDE
37 #define SKHDR_MAGIC2    0xAD
38 #define SKHDR_MAGIC3    0xBE
39 #define SKHDR_MAGIC4    0xEF
40 
41 /*
42  *    Number of bytes of header to read initially to determine the
43  *    version of the file.
44  *
45  *    This value handles files that were created in the days when we
46  *    only had the "genericHeader".
47  */
48 #define SKHDR_INITIAL_READLEN   8
49 
50 /*
51  *    Initial size to allocate for a header-entry; this can grow as
52  *    required.
53  */
54 #define HENTRY_INIT_BUFSIZE 512
55 
56 
57 /*
58  *  end_of_headers = HENTRY_SPEC_EOH(header_entry);
59  *
60  *    Return a TRUE value if 'header_entry' is the final header entry.
61  *    False otherwise.
62  */
63 #define HENTRY_SPEC_EOH(he)                                     \
64     (skHeaderEntryGetTypeId((sk_header_entry_t*)(he)) == 0)
65 
66 
67 /*
68  *  SK_HENTRY_SPEC_UNPACK(header_entry_spec, raw_bytes);
69  *
70  *    Copy the octet array 'raw_bytes' that contains the header entry
71  *    spec into 'header_entry_spec'.  'raw_bytes' should be in network
72  *    byte order, and 'header_entry_spec' will be in native byte
73  *    order.
74  */
75 #define SK_HENTRY_SPEC_UNPACK(new_spec, raw_bytes)                      \
76     {                                                                   \
77         memcpy((new_spec),(raw_bytes),sizeof(sk_header_entry_spec_t));  \
78         (new_spec)->hes_id = ntohl((new_spec)->hes_id);                 \
79         (new_spec)->hes_len = ntohl((new_spec)->hes_len);               \
80     }
81 
82 
83 /*
84  *  SK_HENTRY_SPEC_PACK(raw_bytes, header_entry_spec);
85  *
86  *    Copy the header entry spec 'header_entry_spec' into the octet
87  *    array 'raw_bytes'.  'header_entry_spec' should be in native byte
88  *    order, and 'raw_bytes' will be in network byte order.
89  */
90 #define SK_HENTRY_SPEC_PACK(raw_bytes, old_spec)                        \
91     {                                                                   \
92         sk_header_entry_spec_t _spec;                                   \
93         _spec.hes_id = htonl((old_spec)->hes_id);                       \
94         _spec.hes_len = htonl((old_spec)->hes_len);                     \
95         memcpy((raw_bytes),(&_spec), sizeof(sk_header_entry_spec_t));   \
96     }
97 
98 
99 /* LOCAL VARIABLES */
100 
101 /* A linked list of all registered header types */
102 static sk_hentry_type_t *hentry_type_list = NULL;
103 
104 
105 
106 /* LOCAL FUNCTION PROTOTYPES */
107 
108 static sk_header_entry_t *
109 skHentryDefaultCopy(
110     const sk_header_entry_t    *hentry);
111 
112 static void
113 skHentryDefaultFree(
114     sk_header_entry_t  *hentry);
115 
116 static ssize_t
117 skHentryDefaultPacker(
118     const sk_header_entry_t    *in_hentry,
119     uint8_t                    *out_packed,
120     size_t                      bufsize);
121 
122 static void
123 skHentryDefaultPrint(
124     const sk_header_entry_t    *hentry,
125     FILE                       *fh);
126 
127 static sk_header_entry_t *
128 skHentryDefaultUnpacker(
129     uint8_t            *in_packed);
130 
131 static int hentryRegisterAnnotation(sk_hentry_type_id_t hentry_id);
132 static int hentryRegisterInvocation(sk_hentry_type_id_t hentry_id);
133 static int hentryRegisterPackedfile(sk_hentry_type_id_t hentry_id);
134 static int hentryRegisterProbename(sk_hentry_type_id_t hentry_id);
135 static int hentryRegisterTombstone(sk_hentry_type_id_t hentry_id);
136 
137 
138 /* FUNCTION DEFINITIONS */
139 
140 
141 int
skHeaderAddEntry(sk_file_header_t * hdr,sk_header_entry_t * hentry)142 skHeaderAddEntry(
143     sk_file_header_t   *hdr,
144     sk_header_entry_t  *hentry)
145 {
146     sk_hentry_node_t *new_node;
147 
148     if (NULL == hdr || NULL == hentry) {
149         return SKHEADER_ERR_NULL_ARGUMENT;
150     }
151     if (hdr->header_lock == SKHDR_LOCK_FIXED) {
152         return SKHEADER_ERR_IS_LOCKED;
153     }
154     if (HENTRY_SPEC_EOH(hentry)) {
155         return SKHEADER_ERR_INVALID_ID;
156     }
157 
158     /* create a new node to hold the entry */
159     new_node = (sk_hentry_node_t*)calloc(1, sizeof(sk_hentry_node_t));
160     if (NULL == new_node) {
161         return SKHEADER_ERR_ALLOC;
162     }
163     new_node->hen_entry = hentry;
164     new_node->hen_type = skHentryTypeLookup(skHeaderEntryGetTypeId(hentry));
165 
166     /* the new entry's node goes just before the end-of-header
167      * marker, which is the root node */
168     new_node->hen_prev = (hdr->fh_rootnode)->hen_prev;
169     new_node->hen_next = (hdr->fh_rootnode);
170     new_node->hen_prev->hen_next = new_node;
171     new_node->hen_next->hen_prev = new_node;
172 
173     return SKHEADER_OK;
174 }
175 
176 
177 int
skHeaderCopy(sk_file_header_t * dst_hdr,const sk_file_header_t * src_hdr,uint32_t copy_flags)178 skHeaderCopy(
179     sk_file_header_t       *dst_hdr,
180     const sk_file_header_t *src_hdr,
181     uint32_t                copy_flags)
182 {
183     sk_header_start_t *dst_start = &(dst_hdr->fh_start);
184     const sk_header_start_t *src_start = &(src_hdr->fh_start);
185     sk_hentry_node_t *hnode;
186     sk_hentry_type_t *htype;
187     sk_header_entry_t *dst_hentry;
188     sk_header_entry_t *src_hentry;
189     int rv = SKHEADER_OK;
190 
191     if (NULL == dst_hdr || NULL == src_hdr) {
192         return SKHEADER_ERR_NULL_ARGUMENT;
193     }
194     if (dst_hdr->header_lock == SKHDR_LOCK_FIXED) {
195         return SKHEADER_ERR_IS_LOCKED;
196     }
197     if ((dst_hdr->header_lock == SKHDR_LOCK_ENTRY_OK)
198         && (copy_flags != SKHDR_CP_ENTRIES))
199     {
200         return SKHEADER_ERR_IS_LOCKED;
201     }
202 
203     /* do not copy the file version if it is older than the minimum we
204      * support */
205     if (src_start->file_version < SKHDR_EXPANDED_INIT_VERS) {
206         copy_flags &= ~SKHDR_CP_FILE_VERS;
207     }
208 
209     if ((copy_flags & SKHDR_CP_START) == SKHDR_CP_START) {
210         /* copy the entire header_start except silk_version */
211         uint32_t silk_vers = dst_start->silk_version;
212         memcpy(dst_start, src_start, sizeof(sk_header_start_t));
213         dst_start->silk_version = silk_vers;
214     } else if (copy_flags & SKHDR_CP_START) {
215         /* copy parts of header_start */
216         if (copy_flags & SKHDR_CP_FORMAT) {
217             dst_start->file_format = src_start->file_format;
218             /* Always set the record size to 0 */
219             dst_start->rec_size = 0;
220         }
221         if (copy_flags & SKHDR_CP_FILE_VERS) {
222             dst_start->file_version = src_start->file_version;
223         }
224         if (copy_flags & SKHDR_CP_COMPMETHOD) {
225             dst_start->comp_method = src_start->comp_method;
226         }
227         if (copy_flags & SKHDR_CP_REC_LEN) {
228             /* Always set the record size to 0 */
229             dst_start->rec_size = 0;
230         }
231         if (copy_flags & SKHDR_CP_REC_VERS) {
232             dst_start->rec_version = src_start->rec_version;
233         }
234         if ((copy_flags & SKHDR_CP_FILE_FLAGS) == SKHDR_CP_FILE_FLAGS) {
235             dst_start->file_flags = src_start->file_flags;
236         } else if (copy_flags & SKHDR_CP_FILE_FLAGS) {
237             int i;
238             for (i = 0; i < 8; ++i) {
239                 if (copy_flags & (1 << i)) {
240                     dst_start->file_flags
241                         = ((dst_start->file_flags & (uint8_t)~(1 << i))
242                            | (src_start->file_flags & (uint8_t)(1 << i)));
243                 }
244             }
245         }
246     }
247 
248     if (copy_flags & SKHDR_CP_ENTRIES) {
249         /* we have a circular linked list; where the rootnode always
250          * exists---it is the end-of-header marker */
251         hnode = src_hdr->fh_rootnode->hen_next;
252         src_hentry = hnode->hen_entry;
253         while (!HENTRY_SPEC_EOH(src_hentry)) {
254             /* call the appropriate function to copy the header_entry */
255             htype = skHentryTypeLookup(skHeaderEntryGetTypeId(src_hentry));
256 
257             if (htype && htype->het_copy) {
258                 dst_hentry = htype->het_copy(src_hentry);
259             } else {
260                 dst_hentry = skHentryDefaultCopy(src_hentry);
261             }
262 
263             if (dst_hentry == NULL) {
264                 rv = SKHEADER_ERR_ALLOC;
265                 break;
266             }
267 
268             rv = skHeaderAddEntry(dst_hdr, dst_hentry);
269             if (rv) {
270                 sk_hentry_callback_fn_t free_fn;
271                 free_fn = ((htype && htype->het_free)
272                            ? htype->het_free
273                            : &skHentryDefaultFree);
274                 free_fn(dst_hentry);
275                 break;
276             }
277 
278             hnode = hnode->hen_next;
279             src_hentry = hnode->hen_entry;
280         }
281     }
282 
283     return rv;
284 }
285 
286 
287 int
skHeaderCopyEntries(sk_file_header_t * dst_hdr,const sk_file_header_t * src_hdr,sk_hentry_type_id_t entry_id)288 skHeaderCopyEntries(
289     sk_file_header_t       *dst_hdr,
290     const sk_file_header_t *src_hdr,
291     sk_hentry_type_id_t     entry_id)
292 {
293     sk_hentry_node_t *hnode;
294     sk_hentry_type_t *htype;
295     sk_header_entry_t *dst_hentry;
296     sk_header_entry_t *src_hentry;
297     sk_hentry_copy_fn_t copy_fn;
298     int rv = SKHEADER_OK;
299 
300     if (NULL == dst_hdr || NULL == src_hdr) {
301         return SKHEADER_ERR_NULL_ARGUMENT;
302     }
303     if (dst_hdr->header_lock == SKHDR_LOCK_FIXED) {
304         return SKHEADER_ERR_IS_LOCKED;
305     }
306 
307     /* get a handle to the copy function */
308     htype = skHentryTypeLookup(entry_id);
309     if (htype && htype->het_copy) {
310         copy_fn = htype->het_copy;
311     } else {
312         copy_fn = &skHentryDefaultCopy;
313     }
314 
315     /* we have a circular linked list; where the rootnode always
316      * exists---it is the end-of-header marker */
317     hnode = src_hdr->fh_rootnode;
318     do {
319         hnode = hnode->hen_next;
320         src_hentry = hnode->hen_entry;
321 
322         if (entry_id != skHeaderEntryGetTypeId(src_hentry)) {
323             continue;
324         }
325 
326         dst_hentry = copy_fn(src_hentry);
327         if (dst_hentry == NULL) {
328             rv = SKHEADER_ERR_ALLOC;
329             break;
330         }
331 
332         rv = skHeaderAddEntry(dst_hdr, dst_hentry);
333         if (rv) {
334             sk_hentry_callback_fn_t free_fn;
335             free_fn = ((htype && htype->het_free)
336                        ? htype->het_free
337                        : &skHentryDefaultFree);
338             free_fn(dst_hentry);
339             break;
340         }
341     } while (!HENTRY_SPEC_EOH(src_hentry));
342 
343     return rv;
344 }
345 
346 
347 int
skHeaderCreate(sk_file_header_t ** hdr)348 skHeaderCreate(
349     sk_file_header_t  **hdr)
350 {
351     sk_file_header_t *new_hdr;
352     char *envar;
353     int rv = SKHEADER_ERR_ALLOC;
354 
355     if (NULL == hdr) {
356         return SKHEADER_ERR_NULL_ARGUMENT;
357     }
358 
359     new_hdr = (sk_file_header_t*)calloc(1, sizeof(sk_file_header_t));
360     if (NULL == new_hdr) {
361         goto END;
362     }
363 
364     /* fill out the sk_header_start_t */
365     new_hdr->fh_start.magic1 = SKHDR_MAGIC1;
366     new_hdr->fh_start.magic2 = SKHDR_MAGIC2;
367     new_hdr->fh_start.magic3 = SKHDR_MAGIC3;
368     new_hdr->fh_start.magic4 = SKHDR_MAGIC4;
369 #if SK_LITTLE_ENDIAN
370     new_hdr->fh_start.file_flags = 0;
371 #else
372     new_hdr->fh_start.file_flags = 1;
373 #endif
374     new_hdr->fh_start.file_format = UINT8_MAX;
375     new_hdr->fh_start.file_version = SK_FILE_VERSION_DEFAULT;
376     new_hdr->fh_start.comp_method = SK_COMPMETHOD_DEFAULT;
377     new_hdr->fh_start.rec_size = 0;
378     new_hdr->fh_start.rec_version = SK_RECORD_VERSION_ANY;
379 
380 #ifdef SILK_HEADER_NOVERSION_ENV
381     envar = getenv(SILK_HEADER_NOVERSION_ENV);
382 #else
383     envar = NULL;
384 #endif
385     if (envar && envar[0]) {
386         new_hdr->fh_start.silk_version = 0;
387     } else {
388         new_hdr->fh_start.silk_version = SK_VERSION_INTEGER;
389     }
390 
391     /* create the node to hold the end-of-header marker.  This is a
392      * circular, doubly-linked list. */
393     new_hdr->fh_rootnode
394         = (sk_hentry_node_t*)calloc(1, sizeof(sk_hentry_node_t));
395     if (NULL == new_hdr->fh_rootnode) {
396         goto END;
397     }
398     new_hdr->fh_rootnode->hen_next = new_hdr->fh_rootnode;
399     new_hdr->fh_rootnode->hen_prev = new_hdr->fh_rootnode;
400     new_hdr->fh_rootnode->hen_type = NULL;
401 
402     /* create the entry */
403     new_hdr->fh_rootnode->hen_entry
404         = (sk_header_entry_t*)calloc(1, sizeof(sk_header_entry_t));
405     if (NULL == new_hdr->fh_rootnode->hen_entry) {
406         goto END;
407     }
408     new_hdr->fh_rootnode->hen_entry->he_spec.hes_id = 0;
409     new_hdr->fh_rootnode->hen_entry->he_spec.hes_len
410         = sizeof(sk_header_entry_spec_t);
411 
412     /* Success */
413     rv = SKHEADER_OK;
414 
415   END:
416     if (SKHEADER_OK == rv) {
417         *hdr = new_hdr;
418     } else {
419         if (new_hdr) {
420             if (new_hdr->fh_rootnode) {
421                 if (new_hdr->fh_rootnode->hen_entry) {
422                     free(new_hdr->fh_rootnode->hen_entry);
423                 }
424                 free(new_hdr->fh_rootnode);
425             }
426             free(new_hdr);
427         }
428     }
429     return rv;
430 }
431 
432 
433 int
skHeaderDestroy(sk_file_header_t ** hdr)434 skHeaderDestroy(
435     sk_file_header_t  **hdr)
436 {
437     sk_hentry_node_t *hnode;
438     sk_header_entry_t *hentry;
439     sk_hentry_type_t *htype;
440 
441     if (NULL == hdr || NULL == *hdr) {
442         return SKHEADER_OK;
443     }
444 
445     /* we have a circular linked list; where the rootnode always
446      * exists---it is the end-of-header marker */
447     hnode = (*hdr)->fh_rootnode->hen_next;
448     while ( !HENTRY_SPEC_EOH(hnode->hen_entry)) {
449         hentry = hnode->hen_entry;
450 
451         /* call the appropriate function to destroy the header_entry */
452         htype = skHentryTypeLookup(skHeaderEntryGetTypeId(hentry));
453         if (htype && htype->het_free) {
454             htype->het_free(hentry);
455         } else {
456             skHentryDefaultFree(hentry);
457         }
458         hnode->hen_entry = NULL;
459         /* now destroy the node */
460         assert(hnode == hnode->hen_next->hen_prev);
461         hnode = hnode->hen_next;
462         free(hnode->hen_prev);
463     }
464 
465     /* destroy the root node */
466     assert(hnode == (*hdr)->fh_rootnode);
467     hentry = hnode->hen_entry;
468     free(hentry);
469     free(hnode);
470     (*hdr)->fh_rootnode = NULL;
471 
472     /* destroy the header */
473     free(*hdr);
474     *hdr = NULL;
475 
476     return SKHEADER_OK;
477 }
478 
479 
480 sk_header_entry_t *
skHeaderEntryCopy(const sk_header_entry_t * src_hentry)481 skHeaderEntryCopy(
482     const sk_header_entry_t    *src_hentry)
483 {
484     sk_hentry_type_t *htype;
485     sk_header_entry_t *dst_hentry = NULL;
486 
487     if (NULL == src_hentry || HENTRY_SPEC_EOH(src_hentry)) {
488         return NULL;
489     }
490 
491     /* call the appropriate function to copy the header_entry */
492     htype = skHentryTypeLookup(skHeaderEntryGetTypeId(src_hentry));
493 
494     if (htype && htype->het_copy) {
495         dst_hentry = htype->het_copy(src_hentry);
496     } else {
497         dst_hentry = skHentryDefaultCopy(src_hentry);
498     }
499 
500     return dst_hentry;
501 }
502 
503 
504 void
skHeaderEntryPrint(const sk_header_entry_t * hentry,FILE * fp)505 skHeaderEntryPrint(
506     const sk_header_entry_t  *hentry,
507     FILE               *fp)
508 {
509     sk_hentry_type_t *htype;
510 
511     if (NULL == hentry || NULL == fp) {
512         return;
513     }
514 
515     htype = skHentryTypeLookup(skHeaderEntryGetTypeId(hentry));
516     if (htype && htype->het_print) {
517         htype->het_print(hentry, fp);
518     } else {
519         skHentryDefaultPrint(hentry, fp);
520     }
521 }
522 
523 
524 size_t
skHeaderEntrySpecPack(const sk_header_entry_spec_t * he_spec,uint8_t * out_packed,size_t bufsize)525 skHeaderEntrySpecPack(
526     const sk_header_entry_spec_t   *he_spec,
527     uint8_t                        *out_packed,
528     size_t                          bufsize)
529 {
530     if (bufsize >= sizeof(sk_header_entry_spec_t)) {
531         SK_HENTRY_SPEC_PACK(out_packed, he_spec);
532     }
533     return sizeof(sk_header_entry_spec_t);
534 }
535 
536 
537 void
skHeaderEntrySpecUnpack(sk_header_entry_spec_t * he_spec,const uint8_t * in_packed)538 skHeaderEntrySpecUnpack(
539     sk_header_entry_spec_t *he_spec,
540     const uint8_t          *in_packed)
541 {
542     SK_HENTRY_SPEC_UNPACK(he_spec, in_packed);
543     assert(he_spec->hes_len >= sizeof(sk_header_entry_spec_t));
544 }
545 
546 
547 sk_compmethod_t
skHeaderGetCompressionMethod(const sk_file_header_t * hdr)548 skHeaderGetCompressionMethod(
549     const sk_file_header_t *hdr)
550 {
551     if (NULL == hdr) {
552         return SK_COMPMETHOD_DEFAULT;
553     }
554     return hdr->fh_start.comp_method;
555 }
556 
557 
558 silk_endian_t
skHeaderGetByteOrder(const sk_file_header_t * hdr)559 skHeaderGetByteOrder(
560     const sk_file_header_t *hdr)
561 {
562     if (NULL == hdr) {
563         return SILK_ENDIAN_ANY;
564     }
565     return ((hdr->fh_start.file_flags & 0x01)
566             ? SILK_ENDIAN_BIG
567             : SILK_ENDIAN_LITTLE);
568 }
569 
570 
571 sk_file_format_t
skHeaderGetFileFormat(const sk_file_header_t * hdr)572 skHeaderGetFileFormat(
573     const sk_file_header_t *hdr)
574 {
575     if (NULL == hdr) {
576         return SK_INVALID_FILE_FORMAT;
577     }
578     return hdr->fh_start.file_format;
579 }
580 
581 
582 sk_file_version_t
skHeaderGetFileVersion(const sk_file_header_t * hdr)583 skHeaderGetFileVersion(
584     const sk_file_header_t *hdr)
585 {
586     if (NULL == hdr) {
587         return 0;
588     }
589     return hdr->fh_start.file_version;
590 }
591 
592 
593 sk_header_entry_t *
skHeaderGetFirstMatch(const sk_file_header_t * hdr,sk_hentry_type_id_t entry_id)594 skHeaderGetFirstMatch(
595     const sk_file_header_t *hdr,
596     sk_hentry_type_id_t     entry_id)
597 {
598     sk_hentry_node_t *hnode;
599     sk_header_entry_t *hentry;
600 
601     if (NULL == hdr) {
602         return NULL;
603     }
604 
605     /* we have a circular linked list; where the rootnode always
606      * exists---it is the end-of-header marker */
607     hnode = hdr->fh_rootnode;
608     do {
609         hnode = hnode->hen_next;
610         hentry = hnode->hen_entry;
611         if (skHeaderEntryGetTypeId(hentry) == entry_id) {
612             return hentry;
613         }
614     } while (!HENTRY_SPEC_EOH(hentry));
615 
616     return NULL;
617 }
618 
619 
620 size_t
skHeaderGetLength(const sk_file_header_t * hdr)621 skHeaderGetLength(
622     const sk_file_header_t *hdr)
623 {
624     if (NULL == hdr) {
625         return 0;
626     }
627     return hdr->header_length;
628 }
629 
630 
631 sk_header_lock_t
skHeaderGetLockStatus(const sk_file_header_t * hdr)632 skHeaderGetLockStatus(
633     const sk_file_header_t *hdr)
634 {
635     if (NULL == hdr) {
636         return SKHDR_LOCK_FIXED;
637     }
638     return hdr->header_lock;
639 }
640 
641 
642 size_t
skHeaderGetRecordLength(const sk_file_header_t * hdr)643 skHeaderGetRecordLength(
644     const sk_file_header_t *hdr)
645 {
646     if (NULL == hdr) {
647         return 0;
648     }
649     return hdr->fh_start.rec_size;
650 }
651 
652 
653 sk_file_version_t
skHeaderGetRecordVersion(const sk_file_header_t * hdr)654 skHeaderGetRecordVersion(
655     const sk_file_header_t *hdr)
656 {
657     if (NULL == hdr) {
658         return 0;
659     }
660     return hdr->fh_start.rec_version;
661 }
662 
663 
664 uint32_t
skHeaderGetSilkVersion(const sk_file_header_t * hdr)665 skHeaderGetSilkVersion(
666     const sk_file_header_t *hdr)
667 {
668     if (NULL == hdr) {
669         return 0;
670     }
671     return hdr->fh_start.silk_version;
672 }
673 
674 
675 int
skHeaderIsNativeByteOrder(const sk_file_header_t * hdr)676 skHeaderIsNativeByteOrder(
677     const sk_file_header_t *hdr)
678 {
679     if (NULL == hdr) {
680         return 1;
681     }
682     return ((hdr->fh_start.file_flags & 0x01) == (SK_BIG_ENDIAN));
683 }
684 
685 
686 void
skHeaderIteratorBind(sk_hentry_iterator_t * iter,const sk_file_header_t * hdr)687 skHeaderIteratorBind(
688     sk_hentry_iterator_t   *iter,
689     const sk_file_header_t *hdr)
690 {
691     if (NULL == hdr || NULL == iter) {
692         return;
693     }
694 
695     iter->hdr = hdr;
696     iter->node = hdr->fh_rootnode;
697     iter->htype_filter = 0;
698 }
699 
700 
701 void
skHeaderIteratorBindType(sk_hentry_iterator_t * iter,const sk_file_header_t * hdr,sk_hentry_type_id_t htype)702 skHeaderIteratorBindType(
703     sk_hentry_iterator_t   *iter,
704     const sk_file_header_t *hdr,
705     sk_hentry_type_id_t     htype)
706 {
707     if (NULL == hdr || NULL == iter) {
708         return;
709     }
710 
711     skHeaderIteratorBind(iter, hdr);
712     iter->htype_filter = htype;
713 }
714 
715 
716 sk_header_entry_t *
skHeaderIteratorNext(sk_hentry_iterator_t * iter)717 skHeaderIteratorNext(
718     sk_hentry_iterator_t   *iter)
719 {
720     if (NULL == iter) {
721         return NULL;
722     }
723     do {
724         iter->node = iter->node->hen_next;
725         if (HENTRY_SPEC_EOH(iter->node->hen_entry)) {
726             return NULL;
727         }
728     } while (iter->htype_filter
729              != skHeaderEntryGetTypeId(iter->node->hen_entry));
730 
731     return iter->node->hen_entry;
732 }
733 
734 
735 int
skHeaderInitialize(void)736 skHeaderInitialize(
737     void)
738 {
739     static int initialized = 0;
740     int rv = SKHEADER_OK;
741 
742     if (initialized) {
743         return rv;
744     }
745     initialized = 1;
746 
747     /* defined below */
748     rv |= hentryRegisterPackedfile(SK_HENTRY_PACKEDFILE_ID);
749     /* defined below */
750     rv |= hentryRegisterInvocation(SK_HENTRY_INVOCATION_ID);
751     /* defined below  -- FIXME: Move to skoptions-notes.c */
752     rv |= hentryRegisterAnnotation(SK_HENTRY_ANNOTATION_ID);
753     /* defined below */
754     rv |= hentryRegisterProbename(SK_HENTRY_PROBENAME_ID);
755     /* defined below */
756     rv |= hentryRegisterTombstone(SK_HENTRY_TOMBSTONE_ID);
757     /* defined in skprefixmap.c */
758     rv |= skPrefixMapRegisterHeaderEntry(SK_HENTRY_PREFIXMAP_ID);
759     /* defined in skbag.c */
760     rv |= skBagRegisterHeaderEntry(SK_HENTRY_BAG_ID);
761     /* defined in skipset.c */
762     rv |= skIPSetRegisterHeaderEntry(SK_HENTRY_IPSET_ID);
763     /* defined in skaggbag.c */
764     rv |= skAggBagRegisterHeaderEntry(SK_HENTRY_AGGBAG_ID);
765 
766     rv |= skHeaderLegacyInitialize();
767 
768     return rv;
769 }
770 
771 
772 int
skHeaderReadEntries(skstream_t * stream,sk_file_header_t * hdr)773 skHeaderReadEntries(
774     skstream_t         *stream,
775     sk_file_header_t   *hdr)
776 {
777     sk_header_entry_spec_t *spec;
778     sk_header_entry_t *hentry;
779     int rv = SKHEADER_OK;
780     uint32_t len;
781     ssize_t saw;
782     size_t bufsize;
783     sk_hentry_type_t *htype;
784 
785     if (NULL == hdr || NULL == stream) {
786         return SKHEADER_ERR_NULL_ARGUMENT;
787     }
788     if (hdr->fh_start.file_version < SKHDR_EXPANDED_INIT_VERS) {
789         return skHeaderLegacyDispatch(stream, hdr);
790     }
791 
792     /* create a buffer that we read the headers into; assign it to a
793      * sk_header_entry_spec_t* since that is how we read the first few
794      * bytes, but it is really just a buffer of uint8_t's. */
795     bufsize = HENTRY_INIT_BUFSIZE;
796     spec = (sk_header_entry_spec_t*)malloc(bufsize);
797     if (NULL == spec) {
798         rv = SKHEADER_ERR_ALLOC;
799         goto END;
800     }
801 
802     for (;;) {
803         /* read the header_entry_spec */
804         saw = skStreamRead(stream, spec, sizeof(sk_header_entry_spec_t));
805         if (saw < 0) {
806             rv = -1;
807             goto END;
808         }
809         hdr->header_length += saw;
810         if (saw < (ssize_t)sizeof(sk_header_entry_spec_t)) {
811             /* header claims to be smaller than the amount of data
812              * we've already read */
813             rv = SKHEADER_ERR_ENTRY_READ;
814             goto END;
815         }
816 
817         /* length of header_entry */
818         len = ntohl(spec->hes_len);
819         if (len < (uint32_t)saw) {
820             /* header claims to be smaller than the amount of data
821              * we've already read */
822             rv = SKHEADER_ERR_ENTRY_READ;
823             goto END;
824         }
825 
826         /* if buffer is too small, grow it to hold the complete
827          * header_entry */
828         if (bufsize < len) {
829             sk_header_entry_spec_t *old_spec = spec;
830             spec = (sk_header_entry_spec_t*)realloc(spec, len);
831             if (!spec) {
832                 spec = old_spec;
833                 rv = SKHEADER_ERR_ALLOC;
834                 goto END;
835             }
836             bufsize = len;
837         }
838 
839         /* read the bytes into the buffer */
840         if (len > (uint32_t)saw) {
841             len -= saw;
842             saw = skStreamRead(stream, &(((uint8_t*)spec)[saw]), len);
843             if (saw < 0) {
844                 rv = -1;
845                 goto END;
846             }
847             hdr->header_length += saw;
848             if (saw < (ssize_t)len) {
849                 /* short read */
850                 rv = SKHEADER_ERR_SHORTREAD;
851                 goto END;
852             }
853         }
854 
855         if (spec->hes_id == 0) {
856             /* stop if this is the end-of-header marker */
857             break;
858         }
859 
860         /* call the appropriate function to unpack the header_entry */
861         htype = skHentryTypeLookup(ntohl(spec->hes_id));
862         if (htype && htype->het_unpacker) {
863             hentry = htype->het_unpacker((uint8_t*)spec);
864         } else {
865             hentry = skHentryDefaultUnpacker((uint8_t*)spec);
866         }
867         if (NULL == hentry) {
868             rv = SKHEADER_ERR_ENTRY_UNPACK;
869             goto END;
870         }
871 
872         /* and add the header_entry to the list of headers */
873         rv = skHeaderAddEntry(hdr, hentry);
874         if (rv) {
875             goto END;
876         }
877     }
878 
879   END:
880     if (spec) {
881         free(spec);
882     }
883     return rv;
884 }
885 
886 
887 int
skHeaderReadStart(skstream_t * stream,sk_file_header_t * hdr)888 skHeaderReadStart(
889     skstream_t         *stream,
890     sk_file_header_t   *hdr)
891 {
892     size_t len;
893     ssize_t saw;
894 
895     if (NULL == hdr || NULL == stream) {
896         return SKHEADER_ERR_NULL_ARGUMENT;
897     }
898     if (hdr->header_lock) {
899         return SKHEADER_ERR_IS_LOCKED;
900     }
901 
902     /* read the traditional "genericHeader" */
903     if (hdr->header_length < SKHDR_INITIAL_READLEN) {
904         len = SKHDR_INITIAL_READLEN - hdr->header_length;
905         saw = skStreamRead(
906             stream, ((uint8_t*)&hdr->fh_start) + hdr->header_length, len);
907         if (saw == -1) {
908             return SKSTREAM_ERR_READ;
909         }
910         hdr->header_length += saw;
911         if (hdr->header_length < SKHDR_INITIAL_READLEN) {
912             return SKHEADER_ERR_SHORTREAD;
913         }
914     }
915 
916     /* verify this is a SiLK file */
917     if (hdr->fh_start.magic1 != SKHDR_MAGIC1
918         || hdr->fh_start.magic2 != SKHDR_MAGIC2
919         || hdr->fh_start.magic3 != SKHDR_MAGIC3
920         || hdr->fh_start.magic4 != SKHDR_MAGIC4)
921     {
922         return SKSTREAM_ERR_BAD_MAGIC;
923     }
924 
925     /* if this file's version indicates it was written when we only
926      * had the generic header, return */
927     if (hdr->fh_start.file_version < SKHDR_EXPANDED_INIT_VERS) {
928         if (hdr->header_length > SKHDR_INITIAL_READLEN) {
929             skAppPrintErr("Header length (%" PRIu32 ") is greater than"
930                           " genericHeader for old SiLK file",
931                           hdr->header_length);
932             skAbort();
933             /* return SKHEADER_ERR_TOOLONG; */
934         }
935         return SKSTREAM_OK;
936     }
937 
938     /* read the remainder of the sk_header_start_t */
939     if (hdr->header_length < sizeof(sk_header_start_t)) {
940         len = sizeof(sk_header_start_t) - hdr->header_length;
941         saw = skStreamRead(
942             stream, ((uint8_t*)&hdr->fh_start) + hdr->header_length, len);
943         if (saw == -1) {
944             return SKSTREAM_ERR_READ;
945         }
946         hdr->header_length += saw;
947         if (hdr->header_length < sizeof(sk_header_start_t)) {
948             return SKHEADER_ERR_SHORTREAD;
949         }
950     }
951     hdr->fh_start.silk_version = ntohl(hdr->fh_start.silk_version);
952     hdr->fh_start.rec_size = ntohs(hdr->fh_start.rec_size);
953     hdr->fh_start.rec_version = ntohs(hdr->fh_start.rec_version);
954 
955     return SKHEADER_OK;
956 }
957 
958 
959 int
skHeaderRemoveAllMatching(sk_file_header_t * hdr,sk_hentry_type_id_t entry_id)960 skHeaderRemoveAllMatching(
961     sk_file_header_t       *hdr,
962     sk_hentry_type_id_t     entry_id)
963 {
964     sk_hentry_node_t *hnode;
965     sk_hentry_node_t *hnode_next;
966     sk_header_entry_t *hentry;
967     sk_hentry_type_t *htype;
968 
969     if (NULL == hdr) {
970         return SKHEADER_ERR_NULL_ARGUMENT;
971     }
972     if (0 == entry_id) {
973         return SKHEADER_ERR_INVALID_ID;
974     }
975 
976     /* Do not modify a locked header */
977     if (hdr->header_lock) {
978         return SKHEADER_ERR_IS_LOCKED;
979     }
980 
981     htype = skHentryTypeLookup(entry_id);
982 
983     /* we have a circular linked list; where the rootnode always
984      * exists---it is the end-of-header marker */
985     hnode = hdr->fh_rootnode->hen_next;
986     hentry = hnode->hen_entry;
987     while (!HENTRY_SPEC_EOH(hentry)) {
988         hnode_next = hnode->hen_next;
989         if (skHeaderEntryGetTypeId(hentry) == entry_id) {
990             /* fix linked lists */
991             hnode->hen_prev->hen_next = hnode_next;
992             hnode_next->hen_prev = hnode->hen_prev;
993             /* free the header entry and the node */
994             if (htype && htype->het_free) {
995                 htype->het_free(hentry);
996             } else {
997                 skHentryDefaultFree(hentry);
998             }
999             hnode->hen_entry = NULL;
1000             free(hnode);
1001         }
1002         hnode = hnode_next;
1003         hentry = hnode->hen_entry;
1004     }
1005 
1006     return SKHEADER_OK;
1007 }
1008 
1009 
1010 #if 0
1011 /**
1012  *    On the File Header 'hdr', replace the Header Entry 'old_entry'
1013  *    with the Entry 'new_entry'.
1014  *
1015  *    If 'new_entry' is NULL, 'old_entry' will be removed.
1016  *
1017  *    If 'hentry_cb' is specified, it will be called with value of
1018  *    'old_entry' so that any cleanup can be performed.
1019  *
1020  *    Returns SKHEADER_OK if 'old_entry' was found.  Return
1021  *    SKHEADER_ERR_ENTRY_NOTFOUND if 'old_entry' was not found.
1022  *    Return SKHEADER_ERR_INVALID_ID if 'old_entry' or 'new_entry'
1023  *    have a restricted ID.  Return SKHEADER_ERR_IS_LOCKED is 'hdr' is
1024  *    locked.
1025  */
1026 int
1027 skHeaderReplaceEntry(
1028     sk_file_header_t           *hdr,
1029     sk_header_entry_t          *old_entry,
1030     sk_header_entry_t          *new_entry,
1031     sk_hentry_callback_fn_t     hentry_cb);
1032 
1033 int
1034 skHeaderReplaceEntry(
1035     sk_file_header_t           *hdr,
1036     sk_header_entry_t          *old_entry,
1037     sk_header_entry_t          *new_entry,
1038     sk_hentry_callback_fn_t     hentry_cb)
1039 {
1040     sk_hentry_node_t *hnode;
1041     sk_header_entry_t *hentry;
1042     int found = 0;
1043 
1044     if (NULL == hdr) {
1045         return SKHEADER_ERR_NULL_ARGUMENT;
1046     }
1047     assert(old_entry);
1048 
1049     /* Cannot replace the end of header marker */
1050     if (HENTRY_SPEC_EOH(old_entry)) {
1051         return SKHEADER_ERR_INVALID_ID;
1052     }
1053     if (new_entry && HENTRY_SPEC_EOH(new_entry)) {
1054         return SKHEADER_ERR_INVALID_ID;
1055     }
1056     /* Do not modify a locked header */
1057     if (hdr->header_lock) {
1058         return SKHEADER_ERR_IS_LOCKED;
1059     }
1060 
1061     hnode = hdr->fh_rootnode;
1062     do {
1063         hnode = hnode->hen_next;
1064         hentry = hnode->hen_entry;
1065         if (hentry == old_entry) {
1066             found = 1;
1067             if (hentry_cb) {
1068                 hentry_cb(old_entry);
1069             }
1070             if (new_entry) {
1071                 hnode->hen_entry = new_entry;
1072             } else {
1073                 hnode->hen_prev->hen_next = hnode->hen_next;
1074                 hnode->hen_next->hen_prev = hnode->hen_prev;
1075                 hnode->hen_entry = NULL;
1076                 free(hnode);
1077             }
1078             break;
1079         }
1080     } while (!HENTRY_SPEC_EOH(hnode->hen_entry));
1081 
1082     if (!found) {
1083         return SKHEADER_ERR_ENTRY_NOTFOUND;
1084     }
1085 
1086     return SKHEADER_OK;
1087 }
1088 #endif  /* 0 */
1089 
1090 
1091 int
skHeaderSetByteOrder(sk_file_header_t * hdr,silk_endian_t byte_order)1092 skHeaderSetByteOrder(
1093     sk_file_header_t   *hdr,
1094     silk_endian_t       byte_order)
1095 {
1096     if (hdr == NULL) {
1097         return SKHEADER_ERR_NULL_ARGUMENT;
1098     }
1099 
1100     /* Do not modify a locked header */
1101     if (hdr->header_lock) {
1102         return SKHEADER_ERR_IS_LOCKED;
1103     }
1104 
1105     switch (byte_order) {
1106       case SILK_ENDIAN_BIG:
1107         hdr->fh_start.file_flags = (hdr->fh_start.file_flags | 0x01);
1108         break;
1109       case SILK_ENDIAN_LITTLE:
1110         hdr->fh_start.file_flags = (hdr->fh_start.file_flags & 0xFE);
1111         break;
1112       case SILK_ENDIAN_NATIVE:
1113       case SILK_ENDIAN_ANY:
1114 #if SK_LITTLE_ENDIAN
1115         hdr->fh_start.file_flags = (hdr->fh_start.file_flags & 0xFE);
1116 #else
1117         hdr->fh_start.file_flags = (hdr->fh_start.file_flags | 0x01);
1118 #endif
1119         break;
1120     }
1121 
1122     return SKHEADER_OK;
1123 }
1124 
1125 
1126 int
skHeaderSetCompressionMethod(sk_file_header_t * hdr,uint8_t comp_method)1127 skHeaderSetCompressionMethod(
1128     sk_file_header_t   *hdr,
1129     uint8_t             comp_method)
1130 {
1131     if (hdr == NULL) {
1132         return SKHEADER_ERR_NULL_ARGUMENT;
1133     }
1134 
1135     /* Do not modify a locked header */
1136     if (hdr->header_lock) {
1137         return SKHEADER_ERR_IS_LOCKED;
1138     }
1139 
1140     switch (skCompMethodCheck(comp_method)) {
1141       case SK_COMPMETHOD_IS_AVAIL:
1142       case SK_COMPMETHOD_IS_KNOWN:
1143         /* known, valid, and available, or undecided which will
1144          * eventually be available */
1145         hdr->fh_start.comp_method = comp_method;
1146         break;
1147       case SK_COMPMETHOD_IS_VALID:
1148         /* method is not available--missing library at configure */
1149         return SKSTREAM_ERR_COMPRESS_UNAVAILABLE;
1150       default:
1151         /* value is completely unknown */
1152         return SKSTREAM_ERR_COMPRESS_INVALID;
1153     }
1154 
1155     return SKHEADER_OK;
1156 }
1157 
1158 
1159 int
skHeaderSetFileFormat(sk_file_header_t * hdr,sk_file_format_t file_format)1160 skHeaderSetFileFormat(
1161     sk_file_header_t   *hdr,
1162     sk_file_format_t    file_format)
1163 {
1164     if (hdr == NULL) {
1165         return SKHEADER_ERR_NULL_ARGUMENT;
1166     }
1167 
1168     /* Do not modify a locked header */
1169     if (hdr->header_lock) {
1170         return SKHEADER_ERR_IS_LOCKED;
1171     }
1172 
1173     if (skFileFormatIsValid(file_format)) {
1174         hdr->fh_start.file_format = file_format;
1175     } else {
1176         return SKSTREAM_ERR_INVALID_INPUT;
1177     }
1178 
1179     return SKHEADER_OK;
1180 }
1181 
1182 
1183 int
skHeaderSetFileVersion(sk_file_header_t * hdr,sk_file_version_t file_version)1184 skHeaderSetFileVersion(
1185     sk_file_header_t   *hdr,
1186     sk_file_version_t   file_version)
1187 {
1188     if (hdr == NULL) {
1189         return SKHEADER_ERR_NULL_ARGUMENT;
1190     }
1191 
1192     /* Do not modify a locked header */
1193     if (hdr->header_lock) {
1194         return SKHEADER_ERR_IS_LOCKED;
1195     }
1196     if (file_version < SK_FILE_VERSION_MINIMUM
1197         || file_version > SK_FILE_VERSION_MAXIMUM)
1198     {
1199         return SKHEADER_ERR_BAD_VERSION;
1200     }
1201     hdr->fh_start.file_version = file_version;
1202     return SKHEADER_OK;
1203 }
1204 
1205 
1206 int
skHeaderSetLock(sk_file_header_t * hdr,sk_header_lock_t lock)1207 skHeaderSetLock(
1208     sk_file_header_t   *hdr,
1209     sk_header_lock_t    lock)
1210 {
1211     if (hdr == NULL) {
1212         return SKHEADER_ERR_NULL_ARGUMENT;
1213     }
1214 
1215     hdr->header_lock = lock;
1216     return SKHEADER_OK;
1217 }
1218 
1219 
1220 int
skHeaderSetPaddingModulus(sk_file_header_t * hdr,uint32_t mod)1221 skHeaderSetPaddingModulus(
1222     sk_file_header_t   *hdr,
1223     uint32_t            mod)
1224 {
1225     if (hdr == NULL) {
1226         return SKHEADER_ERR_NULL_ARGUMENT;
1227     }
1228 
1229     /* Do not modify a locked header */
1230     if (hdr->header_lock) {
1231         return SKHEADER_ERR_IS_LOCKED;
1232     }
1233 
1234     hdr->padding_modulus = mod;
1235     return SKHEADER_OK;
1236 }
1237 
1238 
1239 int
skHeaderSetRecordLength(sk_file_header_t * hdr,size_t rec_len)1240 skHeaderSetRecordLength(
1241     sk_file_header_t   *hdr,
1242     size_t              rec_len)
1243 {
1244     if (hdr == NULL) {
1245         return SKHEADER_ERR_NULL_ARGUMENT;
1246     }
1247 
1248     /* Do not modify a locked header */
1249     if (hdr->header_lock) {
1250         return SKHEADER_ERR_IS_LOCKED;
1251     }
1252 
1253     hdr->fh_start.rec_size = rec_len;
1254     return SKHEADER_OK;
1255 }
1256 
1257 
1258 int
skHeaderSetRecordVersion(sk_file_header_t * hdr,sk_file_version_t version)1259 skHeaderSetRecordVersion(
1260     sk_file_header_t   *hdr,
1261     sk_file_version_t   version)
1262 {
1263     if (hdr == NULL) {
1264         return SKHEADER_ERR_NULL_ARGUMENT;
1265     }
1266 
1267     /* Do not modify a locked header */
1268     if (hdr->header_lock) {
1269         return SKHEADER_ERR_IS_LOCKED;
1270     }
1271 
1272     hdr->fh_start.rec_version = version;
1273     return SKHEADER_OK;
1274 }
1275 
1276 
1277 #if 0
1278 /**
1279  *    Read each hentry block until the end of the file header is
1280  *    reached, but do not populate the data structures to hold the
1281  *    header entries.
1282  */
1283 int
1284 skHeaderSkipEntries(
1285     skstream_t         *stream,
1286     sk_file_header_t   *hdr);
1287 
1288 int
1289 skHeaderSkipEntries(
1290     skstream_t         *stream,
1291     sk_file_header_t   *hdr)
1292 {
1293     char buf[HENTRY_INIT_BUFSIZE];
1294     sk_header_entry_spec_t *spec;
1295     uint32_t len;
1296     ssize_t saw;
1297     size_t to_read;
1298 
1299     for (;;) {
1300         saw = skStreamRead(stream, buf, sizeof(sk_header_entry_spec_t));
1301         if (saw == -1) {
1302             /* error */
1303             return -1;
1304         }
1305         hdr->header_length += saw;
1306         if ((size_t)saw < sizeof(sk_header_entry_spec_t)) {
1307             /* short read */
1308             return SKHEADER_ERR_SHORTREAD;
1309         }
1310 
1311         spec = (sk_header_entry_spec_t*)buf;
1312         len = ntohl(spec->hes_len);
1313 
1314         if (len < sizeof(sk_header_entry_spec_t)) {
1315             /* header claims to be smaller than the amount of data
1316              * we've already read */
1317             return SKHEADER_ERR_ENTRY_READ;
1318         }
1319 
1320         /* read the data into 'buf' and ignore it */
1321         len -= saw;
1322         while (len > 0) {
1323             to_read = ((len < sizeof(buf)) ? len : sizeof(buf));
1324             saw = skStreamRead(stream, buf, to_read);
1325             if (saw < 0) {
1326                 return -1;
1327             }
1328             if (saw == 0) {
1329                 return SKHEADER_ERR_SHORTREAD;
1330             }
1331             len -= saw;
1332             hdr->header_length += saw;
1333         }
1334 
1335         if (spec->hes_id == 0) {
1336             break;
1337         }
1338     }
1339 
1340     return SKHEADER_OK;
1341 }
1342 #endif  /* 0 */
1343 
1344 
1345 const char *
skHeaderStrerror(ssize_t err_code)1346 skHeaderStrerror(
1347     ssize_t             err_code)
1348 {
1349     static char buf[128];
1350 
1351     switch ((skHeaderErrorCodes_t)err_code) {
1352       case SKHEADER_OK:
1353         return "Command completed successfully";
1354 
1355       case SKHEADER_ERR_ALLOC:
1356         return "Memory allocation failed";
1357 
1358       case SKHEADER_ERR_NULL_ARGUMENT:
1359         return "NULL passed as argument to function";
1360 
1361       case SKHEADER_ERR_BAD_FORMAT:
1362         return "The file format is not supported";
1363 
1364       case SKHEADER_ERR_BAD_VERSION:
1365         return "The file version is not supported";
1366 
1367       case SKHEADER_ERR_ENTRY_NOTFOUND:
1368         return "Attempt to replace a header entry that does not exist";
1369 
1370       case SKHEADER_ERR_ENTRY_PACK:
1371         return "Error in packing a header entry";
1372 
1373       case SKHEADER_ERR_ENTRY_READ:
1374         return "Error in reading a header entry from disk";
1375 
1376       case SKHEADER_ERR_ENTRY_UNPACK:
1377         return "Error in unpacking a header entry";
1378 
1379       case SKHEADER_ERR_INVALID_ID:
1380         return "The entry ID is invalid";
1381 
1382       case SKHEADER_ERR_IS_LOCKED:
1383         return "Attempt to modify a locked header";
1384 
1385       case SKHEADER_ERR_LEGACY:
1386         return "Error handling a legacy header";
1387 
1388       case SKHEADER_ERR_BAD_COMPRESSION:
1389         return "The compression value is invalid";
1390 
1391       case SKHEADER_ERR_SHORTREAD:
1392         return "Unexpected end of file while reading header";
1393 
1394       case SKHEADER_ERR_TOOLONG:
1395         return "Header length is longer than expected";
1396     }
1397 
1398     snprintf(buf, sizeof(buf), "Unrecognized skHeader error code %" SK_PRIdZ,
1399              err_code);
1400     return buf;
1401 }
1402 
1403 
1404 void
skHeaderTeardown(void)1405 skHeaderTeardown(
1406     void)
1407 {
1408     sk_hentry_type_t *htype;
1409     sk_hentry_type_t *next_htype;
1410 
1411     for (htype = hentry_type_list; htype != NULL; htype = next_htype) {
1412         next_htype = htype->het_next;
1413         free(htype);
1414     }
1415     hentry_type_list = NULL;
1416 
1417     skHeaderLegacyTeardown();
1418 }
1419 
1420 
1421 int
skHeaderWrite(skstream_t * stream,sk_file_header_t * hdr)1422 skHeaderWrite(
1423     skstream_t         *stream,
1424     sk_file_header_t   *hdr)
1425 {
1426     sk_header_start_t *hstart;
1427     sk_header_entry_t *hentry;
1428     sk_hentry_node_t *hnode;
1429     sk_hentry_type_t *htype;
1430     int rv = SKHEADER_OK;
1431     ssize_t sz;
1432     ssize_t said;
1433     size_t len;
1434     size_t bufsize;
1435     uint8_t *buf;
1436     int i;
1437     uint32_t tmp32;
1438     uint16_t tmp16;
1439     uint32_t pad_len;
1440     uint8_t *pos;
1441 
1442     if (NULL == hdr || NULL == stream) {
1443         return SKHEADER_ERR_NULL_ARGUMENT;
1444     }
1445 
1446     /* create a buffer that the header will be packed into */
1447     bufsize = HENTRY_INIT_BUFSIZE;
1448     buf = (uint8_t*)malloc(bufsize);
1449     if (NULL == buf) {
1450         rv = SKHEADER_ERR_ALLOC;
1451         goto END;
1452     }
1453 
1454     hdr->header_length = 0;
1455 
1456     hstart = &(hdr->fh_start);
1457 
1458     /* make certain file format is valid */
1459     if (!skFileFormatIsValid(hstart->file_format)) {
1460         rv = SKHEADER_ERR_BAD_FORMAT;
1461         goto END;
1462     }
1463     /* make certain compression is available */
1464     if (SK_COMPMETHOD_IS_AVAIL != skCompMethodCheck(hstart->comp_method)) {
1465         rv = SKHEADER_ERR_BAD_COMPRESSION;
1466     }
1467 
1468     /* we cannot write old versions of the headers */
1469     if (hstart->file_version < SK_FILE_VERSION_MINIMUM) {
1470         rv = SKHEADER_ERR_BAD_VERSION;
1471         skAppPrintErr("Cannot write header version %u",
1472                       (unsigned)hstart->file_version);
1473         goto END;
1474     }
1475     if (hstart->file_version > SK_FILE_VERSION_MAXIMUM) {
1476         skAbort();
1477     }
1478 
1479     /* check for valid record size */
1480     if (hstart->rec_size == 0) {
1481         hstart->rec_size = 1;
1482     }
1483 
1484     /* Padding modulus of 0 is the record size */
1485     if (hdr->padding_modulus == 0) {
1486         hdr->padding_modulus = hstart->rec_size;
1487     }
1488 
1489     /* pack the header_start into 'buf' */
1490     memcpy(buf, hstart, 8);
1491     tmp32 = htonl(hstart->silk_version);
1492     memcpy(&(buf[8]), &tmp32, 4);
1493     tmp16 = htons(hstart->rec_size);
1494     memcpy(&(buf[12]), &tmp16, 2);
1495     tmp16 = htons(hstart->rec_version);
1496     memcpy(&(buf[14]), &tmp16, 2);
1497 
1498     len = sizeof(sk_header_start_t);
1499     said = skStreamWrite(stream, buf, len);
1500     if (said != (ssize_t)len) {
1501         rv = -1;
1502         goto END;
1503     }
1504     hdr->header_length += len;
1505 
1506     /* we have a circular linked list; where the rootnode always
1507      * exists---it is the end-of-header marker */
1508     hnode = hdr->fh_rootnode;
1509     do {
1510         hnode = hnode->hen_next;
1511         hentry = hnode->hen_entry;
1512 
1513         /* call the appropriate function to pack the header_entry */
1514         htype = skHentryTypeLookup(skHeaderEntryGetTypeId(hentry));
1515 
1516         /* potentially loop twice; first time may fail if the buffer
1517          * is too small */
1518         for (i = 0; i < 2; ++i) {
1519             memset(buf, 0, bufsize);
1520 
1521             if (HENTRY_SPEC_EOH(hentry)) {
1522                 /* handle final entry */
1523                 sz = sizeof(sk_header_entry_spec_t);
1524                 if (hdr->padding_modulus > 1) {
1525                     pad_len = hdr->padding_modulus - ((hdr->header_length + sz)
1526                                                       % hdr->padding_modulus);
1527                     if (pad_len != hdr->padding_modulus) {
1528                         sz += pad_len;
1529                     }
1530                 }
1531                 if (sz < (int)bufsize) {
1532                     tmp32 = htonl(sz);
1533                     memcpy(&buf[4], &tmp32, 4);
1534                 }
1535             } else if (htype && htype->het_packer) {
1536                 sz = htype->het_packer(hentry, buf, bufsize);
1537             } else {
1538                 sz = skHentryDefaultPacker(hentry, buf, bufsize);
1539             }
1540 
1541             if (sz < 0) {
1542                 rv = SKHEADER_ERR_ENTRY_PACK;
1543                 break;
1544             }
1545 
1546             len = (size_t)sz;
1547             if (len <= bufsize) {
1548                 /* packing was successful */
1549                 break;
1550             }
1551 
1552             /* buffer is too small; grow it to 'len' and try again */
1553             pos = buf;
1554             buf = (uint8_t*)realloc(buf, len);
1555             if (!buf) {
1556                 buf = pos;
1557                 rv = SKHEADER_ERR_ALLOC;
1558                 goto END;
1559             }
1560             bufsize = len;
1561         }
1562 
1563         if (rv != SKHEADER_OK) {
1564             /* error */
1565             goto END;
1566         }
1567 
1568         /* write the bytes from buffer */
1569         pos = buf;
1570         while (len > 0) {
1571             said = skStreamWrite(stream, pos, len);
1572             if (said <= 0) {
1573                 rv = -1;
1574                 goto END;
1575             }
1576             len -= said;
1577             pos += said;
1578             hdr->header_length += said;
1579         }
1580     } while (!HENTRY_SPEC_EOH(hnode->hen_entry));
1581 
1582   END:
1583     if (buf) {
1584         free(buf);
1585     }
1586     return rv;
1587 }
1588 
1589 
1590 /*  Header Entry Types */
1591 
1592 
1593 /* Register a header type */
1594 int
skHentryTypeRegister(sk_hentry_type_id_t entry_id,sk_hentry_pack_fn_t pack_fn,sk_hentry_unpack_fn_t unpack_fn,sk_hentry_copy_fn_t copy_fn,sk_hentry_callback_fn_t free_fn,sk_hentry_print_fn_t print_fn)1595 skHentryTypeRegister(
1596     sk_hentry_type_id_t     entry_id,
1597     sk_hentry_pack_fn_t     pack_fn,
1598     sk_hentry_unpack_fn_t   unpack_fn,
1599     sk_hentry_copy_fn_t     copy_fn,
1600     sk_hentry_callback_fn_t free_fn,
1601     sk_hentry_print_fn_t    print_fn)
1602 {
1603     sk_hentry_type_t *new_reg;
1604 
1605     if (0 == entry_id) {
1606         return SKHEADER_ERR_INVALID_ID;
1607     }
1608     if (skHentryTypeLookup(entry_id)) {
1609         return SKHEADER_ERR_INVALID_ID;
1610     }
1611 
1612     new_reg = (sk_hentry_type_t*)calloc(1, sizeof(sk_hentry_type_t));
1613     if (NULL == new_reg) {
1614         return SKHEADER_ERR_ALLOC;
1615     }
1616     new_reg->het_id = entry_id;
1617     new_reg->het_packer = pack_fn;
1618     new_reg->het_unpacker = unpack_fn;
1619     new_reg->het_copy = copy_fn;
1620     new_reg->het_free = free_fn;
1621     new_reg->het_print = print_fn;
1622     new_reg->het_next = hentry_type_list;
1623     hentry_type_list = new_reg;
1624 
1625     return SKHEADER_OK;
1626 }
1627 
1628 
1629 sk_hentry_type_t *
skHentryTypeLookup(sk_hentry_type_id_t entry_id)1630 skHentryTypeLookup(
1631     sk_hentry_type_id_t entry_id)
1632 {
1633     sk_hentry_type_t *htype = NULL;
1634 
1635     for (htype = hentry_type_list; htype != NULL; htype = htype->het_next) {
1636         if (htype->het_id == entry_id) {
1637             break;
1638         }
1639     }
1640 
1641     return htype;
1642 }
1643 
1644 
1645 /*  Default pack/unpack rules */
1646 
1647 
1648 static sk_header_entry_t *
skHentryDefaultCopy(const sk_header_entry_t * hentry)1649 skHentryDefaultCopy(
1650     const sk_header_entry_t    *hentry)
1651 {
1652     sk_header_entry_t *new_hentry;
1653     uint32_t len;
1654 
1655     if (NULL == hentry) {
1656         return NULL;
1657     }
1658 
1659     /* create space for new header */
1660     new_hentry = (sk_header_entry_t*)calloc(1, sizeof(sk_header_entry_t));
1661     if (NULL == new_hentry) {
1662         return NULL;
1663     }
1664 
1665     /* copy the spec */
1666     memcpy(&(new_hentry->he_spec), &(hentry->he_spec),
1667            sizeof(sk_header_entry_spec_t));
1668 
1669     /* create byte array to hold rest of data */
1670     len = hentry->he_spec.hes_len;
1671     if (len < sizeof(sk_header_entry_spec_t)) {
1672         free(new_hentry);
1673         return NULL;
1674     }
1675     len -= sizeof(sk_header_entry_spec_t);
1676     if (len == 0) {
1677         new_hentry->he_data = NULL;
1678     } else {
1679         new_hentry->he_data = malloc(len);
1680         if (NULL == new_hentry->he_data) {
1681             free(new_hentry);
1682             return NULL;
1683         }
1684         memcpy(new_hentry->he_data, hentry->he_data, len);
1685     }
1686 
1687     return new_hentry;
1688 }
1689 
1690 
1691 /*
1692  *  skHentryDefaultFree(hentry);
1693  *
1694  *    Free the memory associated with the header entry 'hentry.'
1695  */
1696 static void
skHentryDefaultFree(sk_header_entry_t * hentry)1697 skHentryDefaultFree(
1698     sk_header_entry_t  *hentry)
1699 {
1700     if (hentry == NULL) {
1701         return;
1702     }
1703 
1704     if (hentry->he_data) {
1705         free(hentry->he_data);
1706         hentry->he_data = NULL;
1707     }
1708     hentry->he_spec.hes_id = UINT32_MAX;
1709     free(hentry);
1710 }
1711 
1712 
1713 /*
1714  *  size = skHentryDefaultPacker(in_hentry, out_packed, bufsize);
1715  *
1716  *    Copies the data from 'in_hentry' to 'out_packed', converting the
1717  *    header entry spec portion of the header to network byte order.
1718  *    The data section of the header entry is copied as-is.  The
1719  *    caller should specify 'bufsize' as the size of 'out_packed'; the
1720  *    return value is the number of bytes written to 'out_packed'.  If
1721  *    the return value is larger than 'bufsize', 'out_packed' was too
1722  *    small to hold the header.
1723  */
1724 static ssize_t
skHentryDefaultPacker(const sk_header_entry_t * in_hentry,uint8_t * out_packed,size_t bufsize)1725 skHentryDefaultPacker(
1726     const sk_header_entry_t    *in_hentry,
1727     uint8_t                    *out_packed,
1728     size_t                      bufsize)
1729 
1730 {
1731     const sk_header_entry_spec_t *spec;
1732     uint32_t tmp;
1733 
1734     spec = &(in_hentry->he_spec);
1735     tmp = spec->hes_len;
1736     if (bufsize < tmp) {
1737         return tmp;
1738     }
1739 
1740     /* copy the data */
1741     memcpy(&(out_packed[8]), in_hentry->he_data, tmp);
1742 
1743     /* copy the length */
1744     tmp = htonl(tmp);
1745     memcpy(&(out_packed[4]), &tmp, 4);
1746 
1747     /* copy the ID */
1748     tmp = htonl(spec->hes_id);
1749     memcpy(&(out_packed[0]), &tmp, 4);
1750 
1751     return spec->hes_len;
1752 }
1753 
1754 
1755 /*
1756  *  skHentryDefaultPrint(hentry, fh);
1757  *
1758  *    Print the header entry 'hentry' as human readable text to the
1759  *    file handle 'fh'.
1760  */
1761 static void
skHentryDefaultPrint(const sk_header_entry_t * hentry,FILE * fh)1762 skHentryDefaultPrint(
1763     const sk_header_entry_t    *hentry,
1764     FILE                       *fh)
1765 {
1766     fprintf(fh, ("unknown; length %" PRIu32), hentry->he_spec.hes_len);
1767 }
1768 
1769 
1770 /*
1771  *  hentry = skHentryDefaultUnacker(in_packed);
1772  *
1773  *    Creates a new header entry, copies the data from 'in_packed'
1774  *    into the new header entry, and returns the new header entry.
1775  *    The header entry spec will be in native byte order.  The data
1776  *    section of the header entry is copied as-is into newly allocated
1777  *    memory.  The function returns NULL if memory allocation fails or
1778  *    if the header entry's size is less then the mimimum.
1779  */
1780 static sk_header_entry_t *
skHentryDefaultUnpacker(uint8_t * in_packed)1781 skHentryDefaultUnpacker(
1782     uint8_t            *in_packed)
1783 {
1784     sk_header_entry_t *hentry;
1785     uint32_t len;
1786 
1787     assert(in_packed);
1788 
1789     /* create space for new header */
1790     hentry = (sk_header_entry_t*)calloc(1, sizeof(sk_header_entry_t));
1791     if (NULL == hentry) {
1792         return NULL;
1793     }
1794 
1795     /* copy the spec */
1796     SK_HENTRY_SPEC_UNPACK(&(hentry->he_spec), in_packed);
1797 
1798     /* create byte array to hold rest of data */
1799     len = hentry->he_spec.hes_len;
1800     if (len < sizeof(sk_header_entry_spec_t)) {
1801         free(hentry);
1802         return NULL;
1803     }
1804     len -= sizeof(sk_header_entry_spec_t);
1805     if (len == 0) {
1806         hentry->he_data = NULL;
1807     } else {
1808         hentry->he_data = malloc(len);
1809         if (NULL == hentry->he_data) {
1810             free(hentry);
1811             return NULL;
1812         }
1813         memcpy(hentry->he_data, &(in_packed[sizeof(sk_header_entry_spec_t)]),
1814                len);
1815     }
1816 
1817     return hentry;
1818 }
1819 
1820 
1821 /*
1822  *    **********************************************************************
1823  *
1824  *    Packed File Headers
1825  *
1826  */
1827 
1828 typedef struct sk_hentry_packedfile_st {
1829     sk_header_entry_spec_t  he_spec;
1830     int64_t                 start_time;
1831     uint32_t                flowtype_id;
1832     uint32_t                sensor_id;
1833 } sk_hentry_packedfile_t;
1834 
1835 /* forward declaration */
1836 static sk_header_entry_t *
1837 packedfileCreate(
1838     sktime_t            start_time,
1839     sk_flowtype_id_t    flowtype_id,
1840     sk_sensor_id_t      sensor_id);
1841 
1842 static sk_header_entry_t *
packedfileCopy(const sk_header_entry_t * hentry)1843 packedfileCopy(
1844     const sk_header_entry_t    *hentry)
1845 {
1846     const sk_hentry_packedfile_t *pf_hdr = (sk_hentry_packedfile_t*)hentry;
1847 
1848     assert(hentry);
1849     assert(SK_HENTRY_PACKEDFILE_ID == skHeaderEntryGetTypeId(pf_hdr));
1850 
1851     return packedfileCreate(pf_hdr->start_time, pf_hdr->flowtype_id,
1852                                     pf_hdr->sensor_id);
1853 }
1854 
1855 static sk_header_entry_t *
packedfileCreate(sktime_t start_time,sk_flowtype_id_t flowtype_id,sk_sensor_id_t sensor_id)1856 packedfileCreate(
1857     sktime_t            start_time,
1858     sk_flowtype_id_t    flowtype_id,
1859     sk_sensor_id_t      sensor_id)
1860 {
1861     sk_hentry_packedfile_t *pf_hdr;
1862 
1863     pf_hdr = (sk_hentry_packedfile_t*)calloc(1, sizeof(sk_hentry_packedfile_t));
1864     if (NULL == pf_hdr) {
1865         return NULL;
1866     }
1867 
1868     pf_hdr->he_spec.hes_id   = SK_HENTRY_PACKEDFILE_ID;
1869     pf_hdr->he_spec.hes_len  = sizeof(sk_hentry_packedfile_t);
1870     pf_hdr->start_time       = start_time - (start_time % 3600000);
1871     pf_hdr->flowtype_id      = flowtype_id;
1872     pf_hdr->sensor_id        = sensor_id;
1873 
1874     return (sk_header_entry_t*)pf_hdr;
1875 }
1876 
1877 static void
packedfileFree(sk_header_entry_t * hentry)1878 packedfileFree(
1879     sk_header_entry_t  *hentry)
1880 {
1881     /* allocated in a single block */
1882     if (hentry) {
1883         assert(skHeaderEntryGetTypeId(hentry) == SK_HENTRY_PACKEDFILE_ID);
1884         hentry->he_spec.hes_id = UINT32_MAX;
1885         free(hentry);
1886     }
1887 }
1888 
1889 static ssize_t
packedfilePacker(const sk_header_entry_t * in_hentry,uint8_t * out_packed,size_t bufsize)1890 packedfilePacker(
1891     const sk_header_entry_t    *in_hentry,
1892     uint8_t                    *out_packed,
1893     size_t                      bufsize)
1894 {
1895     const sk_hentry_packedfile_t *pf_hdr = (sk_hentry_packedfile_t*)in_hentry;
1896     sk_hentry_packedfile_t tmp_hdr;
1897 
1898     assert(pf_hdr);
1899     assert(out_packed);
1900     assert(SK_HENTRY_PACKEDFILE_ID == skHeaderEntryGetTypeId(pf_hdr));
1901 
1902     if (bufsize >= sizeof(sk_hentry_packedfile_t)) {
1903         SK_HENTRY_SPEC_PACK(&tmp_hdr, &(pf_hdr->he_spec));
1904         tmp_hdr.start_time   = hton64(pf_hdr->start_time);
1905         tmp_hdr.flowtype_id  = htonl(pf_hdr->flowtype_id);
1906         tmp_hdr.sensor_id    = htonl(pf_hdr->sensor_id);
1907 
1908         memcpy(out_packed, &tmp_hdr, sizeof(sk_hentry_packedfile_t));
1909     }
1910 
1911     return sizeof(sk_hentry_packedfile_t);
1912 }
1913 
1914 static void
packedfilePrint(const sk_header_entry_t * hentry,FILE * fh)1915 packedfilePrint(
1916     const sk_header_entry_t    *hentry,
1917     FILE                       *fh)
1918 {
1919     char buf[512];
1920 
1921     assert(SK_HENTRY_PACKEDFILE_ID == skHeaderEntryGetTypeId(hentry));
1922     fprintf(fh, "%sZ ",
1923             sktimestamp_r(buf, skHentryPackedfileGetStartTime(hentry),
1924                           SKTIMESTAMP_NOMSEC | SKTIMESTAMP_UTC));
1925 
1926     sksiteFlowtypeGetName(buf, sizeof(buf),
1927                           skHentryPackedfileGetFlowtypeID(hentry));
1928     fprintf(fh, "%s ", buf);
1929 
1930     sksiteSensorGetName(buf, sizeof(buf),
1931                         skHentryPackedfileGetSensorID(hentry));
1932     fprintf(fh, "%s", buf);
1933 }
1934 
1935 static sk_header_entry_t *
packedfileUnpacker(uint8_t * in_packed)1936 packedfileUnpacker(
1937     uint8_t            *in_packed)
1938 {
1939     sk_hentry_packedfile_t *pf_hdr;
1940 
1941     assert(in_packed);
1942 
1943     /* create space for new header */
1944     pf_hdr = (sk_hentry_packedfile_t*)calloc(1, sizeof(sk_hentry_packedfile_t));
1945     if (NULL == pf_hdr) {
1946         return NULL;
1947     }
1948 
1949     /* copy the spec */
1950     SK_HENTRY_SPEC_UNPACK(&(pf_hdr->he_spec), in_packed);
1951     assert(skHeaderEntryGetTypeId(pf_hdr) == SK_HENTRY_PACKEDFILE_ID);
1952 
1953     /* copy the data */
1954     if (pf_hdr->he_spec.hes_len != sizeof(sk_hentry_packedfile_t)) {
1955         free(pf_hdr);
1956         return NULL;
1957     }
1958     memcpy(&(pf_hdr->start_time), &(in_packed[sizeof(sk_header_entry_spec_t)]),
1959            sizeof(sk_hentry_packedfile_t)-sizeof(sk_header_entry_spec_t));
1960     pf_hdr->start_time   = ntoh64(pf_hdr->start_time);
1961     pf_hdr->flowtype_id  = ntohl(pf_hdr->flowtype_id);
1962     pf_hdr->sensor_id    = ntohl(pf_hdr->sensor_id);
1963 
1964     return (sk_header_entry_t*)pf_hdr;
1965 }
1966 
1967 /*  Called by skHeaderInitialize to register the header type */
1968 static int
hentryRegisterPackedfile(sk_hentry_type_id_t hentry_id)1969 hentryRegisterPackedfile(
1970     sk_hentry_type_id_t hentry_id)
1971 {
1972     assert(hentry_id == SK_HENTRY_PACKEDFILE_ID);
1973     return (skHentryTypeRegister(
1974                 hentry_id, &packedfilePacker, &packedfileUnpacker,
1975                 &packedfileCopy, &packedfileFree, &packedfilePrint));
1976 }
1977 
1978 int
skHeaderAddPackedfile(sk_file_header_t * hdr,sktime_t start_time,sk_flowtype_id_t flowtype_id,sk_sensor_id_t sensor_id)1979 skHeaderAddPackedfile(
1980     sk_file_header_t   *hdr,
1981     sktime_t            start_time,
1982     sk_flowtype_id_t    flowtype_id,
1983     sk_sensor_id_t      sensor_id)
1984 {
1985     int rv;
1986     sk_header_entry_t *pfh;
1987 
1988     pfh = packedfileCreate(start_time, flowtype_id, sensor_id);
1989     if (pfh == NULL) {
1990         return SKHEADER_ERR_ALLOC;
1991     }
1992     rv = skHeaderAddEntry(hdr, pfh);
1993     if (rv) {
1994         packedfileFree(pfh);
1995     }
1996     return rv;
1997 }
1998 
1999 sktime_t
skHentryPackedfileGetStartTime(const sk_header_entry_t * hentry)2000 skHentryPackedfileGetStartTime(
2001     const sk_header_entry_t    *hentry)
2002 {
2003     const sk_hentry_packedfile_t *pf_hdr = (sk_hentry_packedfile_t*)hentry;
2004 
2005     assert(hentry);
2006     if (skHeaderEntryGetTypeId(pf_hdr) != SK_HENTRY_PACKEDFILE_ID) {
2007         return sktimeCreate(0, 0);
2008     }
2009     return (sktime_t)pf_hdr->start_time;
2010 }
2011 
2012 sk_sensor_id_t
skHentryPackedfileGetSensorID(const sk_header_entry_t * hentry)2013 skHentryPackedfileGetSensorID(
2014     const sk_header_entry_t    *hentry)
2015 {
2016     const sk_hentry_packedfile_t *pf_hdr = (sk_hentry_packedfile_t*)hentry;
2017 
2018     assert(hentry);
2019     if (skHeaderEntryGetTypeId(pf_hdr) != SK_HENTRY_PACKEDFILE_ID) {
2020         return SK_INVALID_SENSOR;
2021     }
2022     return (sk_sensor_id_t)pf_hdr->sensor_id;
2023 }
2024 
2025 sk_flowtype_id_t
skHentryPackedfileGetFlowtypeID(const sk_header_entry_t * hentry)2026 skHentryPackedfileGetFlowtypeID(
2027     const sk_header_entry_t    *hentry)
2028 {
2029     const sk_hentry_packedfile_t *pf_hdr = (sk_hentry_packedfile_t*)hentry;
2030 
2031     assert(hentry);
2032     if (skHeaderEntryGetTypeId(pf_hdr) != SK_HENTRY_PACKEDFILE_ID) {
2033         return SK_INVALID_FLOWTYPE;
2034     }
2035     return (sk_flowtype_id_t)pf_hdr->flowtype_id;
2036 }
2037 
2038 
2039 
2040 
2041 /*
2042  *    **********************************************************************
2043  *
2044  *    Invocation (Command Line) History
2045  *
2046  */
2047 
2048 typedef struct sk_hentry_invocation_st {
2049     sk_header_entry_spec_t  he_spec;
2050     char                   *command_line;
2051 } sk_hentry_invocation_t;
2052 
2053 /* forward declaration */
2054 static sk_header_entry_t *
2055 invocationCreate(
2056     int                 strip_path,
2057     int                 argc,
2058     char              **argv);
2059 
2060 static sk_header_entry_t *
invocationCopy(const sk_header_entry_t * hentry)2061 invocationCopy(
2062     const sk_header_entry_t    *hentry)
2063 {
2064     const sk_hentry_invocation_t *ci_hdr = (sk_hentry_invocation_t*)hentry;
2065 
2066     assert(SK_HENTRY_INVOCATION_ID == skHeaderEntryGetTypeId(ci_hdr));
2067     return invocationCreate(0, 1, (char**)&(ci_hdr->command_line));
2068 }
2069 
2070 static sk_header_entry_t *
invocationCreate(int strip_path,int argc,char ** argv)2071 invocationCreate(
2072     int                 strip_path,
2073     int                 argc,
2074     char              **argv)
2075 {
2076     const char *libtool_prefix = "lt-";
2077     sk_hentry_invocation_t *ci_hdr;
2078     int len = 0;
2079     int sz;
2080     char *cp;
2081     char *appname = argv[0];
2082     int i;
2083 
2084     if (strip_path) {
2085         /* remove pathname from the application */
2086         cp = strrchr(appname, '/');
2087         if (cp) {
2088             appname = cp + 1;
2089             if (*appname == '\0') {
2090                 return NULL;
2091             }
2092         }
2093         /* handle libtool's "lt-" prefix */
2094         if ((strlen(appname) > strlen(libtool_prefix))
2095             && (0 == strncmp(appname, libtool_prefix, strlen(libtool_prefix))))
2096         {
2097             appname += 3;
2098         }
2099     }
2100 
2101     /* get length of header */
2102     len = strlen(appname) + 1;
2103     for (i = 1; i < argc; ++i) {
2104         len += strlen(argv[i]) + 1;
2105     }
2106 
2107     /* create the header */
2108     ci_hdr = (sk_hentry_invocation_t*)calloc(1, sizeof(sk_hentry_invocation_t));
2109     if (NULL == ci_hdr) {
2110         return NULL;
2111     }
2112     ci_hdr->he_spec.hes_id   = SK_HENTRY_INVOCATION_ID;
2113     ci_hdr->he_spec.hes_len  = sizeof(sk_header_entry_spec_t) + len;
2114 
2115     /* allocate the buffer for command line */
2116     ci_hdr->command_line = (char*)calloc(len, sizeof(char));
2117     if (NULL == ci_hdr->command_line) {
2118         free(ci_hdr);
2119         return NULL;
2120     }
2121 
2122     /* copy the command line into place */
2123     cp = ci_hdr->command_line;
2124     sz = strlen(appname);
2125     strncpy(cp, appname, len);
2126     cp += sz;
2127     len -= sz;
2128     for (i = 1; i < argc; ++i) {
2129         *cp = ' ';
2130         ++cp;
2131         --len;
2132         sz = strlen(argv[i]);
2133         strncpy(cp, argv[i], len);
2134         cp += sz;
2135         len -= sz;
2136     }
2137 
2138     return (sk_header_entry_t*)ci_hdr;
2139 }
2140 
2141 static void
invocationFree(sk_header_entry_t * hentry)2142 invocationFree(
2143     sk_header_entry_t  *hentry)
2144 {
2145     sk_hentry_invocation_t *ci_hdr = (sk_hentry_invocation_t*)hentry;
2146 
2147     if (ci_hdr) {
2148         assert(skHeaderEntryGetTypeId(ci_hdr) == SK_HENTRY_INVOCATION_ID);
2149         ci_hdr->he_spec.hes_id = UINT32_MAX;
2150         if (ci_hdr->command_line) {
2151             free(ci_hdr->command_line);
2152             ci_hdr->command_line = NULL;
2153         }
2154         free(ci_hdr);
2155     }
2156 }
2157 
2158 static ssize_t
invocationPacker(const sk_header_entry_t * in_hentry,uint8_t * out_packed,size_t bufsize)2159 invocationPacker(
2160     const sk_header_entry_t    *in_hentry,
2161     uint8_t                    *out_packed,
2162     size_t                      bufsize)
2163 {
2164     sk_hentry_invocation_t *ci_hdr = (sk_hentry_invocation_t*)in_hentry;
2165     uint32_t check_len;
2166 
2167     assert(in_hentry);
2168     assert(out_packed);
2169     assert(skHeaderEntryGetTypeId(ci_hdr) == SK_HENTRY_INVOCATION_ID);
2170 
2171     /* adjust the length recorded in the header it if it too small */
2172     check_len = (1 + strlen(ci_hdr->command_line)
2173                  + sizeof(sk_header_entry_spec_t));
2174     if (check_len > ci_hdr->he_spec.hes_len) {
2175         ci_hdr->he_spec.hes_len = check_len;
2176     }
2177 
2178     if (bufsize >= ci_hdr->he_spec.hes_len) {
2179         SK_HENTRY_SPEC_PACK(out_packed, &(ci_hdr->he_spec));
2180         memcpy(&(out_packed[sizeof(sk_header_entry_spec_t)]),
2181                ci_hdr->command_line,
2182                (ci_hdr->he_spec.hes_len - sizeof(sk_header_entry_spec_t)));
2183     }
2184 
2185     return ci_hdr->he_spec.hes_len;
2186 }
2187 
2188 static void
invocationPrint(const sk_header_entry_t * hentry,FILE * fh)2189 invocationPrint(
2190     const sk_header_entry_t    *hentry,
2191     FILE                       *fh)
2192 {
2193     const sk_hentry_invocation_t *ci_hdr = (sk_hentry_invocation_t*)hentry;
2194 
2195     assert(skHeaderEntryGetTypeId(ci_hdr) == SK_HENTRY_INVOCATION_ID);
2196     fprintf(fh, "%s", ci_hdr->command_line);
2197 }
2198 
2199 static sk_header_entry_t *
invocationUnpacker(uint8_t * in_packed)2200 invocationUnpacker(
2201     uint8_t            *in_packed)
2202 {
2203     sk_hentry_invocation_t *ci_hdr;
2204     uint32_t len;
2205 
2206     assert(in_packed);
2207 
2208     /* create space for new header */
2209     ci_hdr = (sk_hentry_invocation_t*)calloc(1, sizeof(sk_hentry_invocation_t));
2210     if (NULL == ci_hdr) {
2211         return NULL;
2212     }
2213 
2214     /* copy the spec */
2215     SK_HENTRY_SPEC_UNPACK(&(ci_hdr->he_spec), in_packed);
2216     assert(skHeaderEntryGetTypeId(ci_hdr) == SK_HENTRY_INVOCATION_ID);
2217 
2218     /* copy the data */
2219     len = ci_hdr->he_spec.hes_len;
2220     if (len < sizeof(sk_header_entry_spec_t)) {
2221         free(ci_hdr);
2222         return NULL;
2223     }
2224     len -= sizeof(sk_header_entry_spec_t);
2225     ci_hdr->command_line = (char*)calloc(len, sizeof(char));
2226     if (NULL == ci_hdr->command_line) {
2227         free(ci_hdr);
2228         return NULL;
2229     }
2230     memcpy(ci_hdr->command_line, &(in_packed[sizeof(sk_header_entry_spec_t)]),
2231            len);
2232 
2233     return (sk_header_entry_t*)ci_hdr;
2234 }
2235 
2236 /*  Called by skHeaderInitialize to register the header type */
2237 static int
hentryRegisterInvocation(sk_hentry_type_id_t hentry_id)2238 hentryRegisterInvocation(
2239     sk_hentry_type_id_t hentry_id)
2240 {
2241     assert(SK_HENTRY_INVOCATION_ID == hentry_id);
2242     return (skHentryTypeRegister(
2243                 hentry_id, &invocationPacker, &invocationUnpacker,
2244                 &invocationCopy, &invocationFree, &invocationPrint));
2245 }
2246 
2247 int
skHeaderAddInvocation(sk_file_header_t * hdr,int strip_path,int argc,char ** argv)2248 skHeaderAddInvocation(
2249     sk_file_header_t   *hdr,
2250     int                 strip_path,
2251     int                 argc,
2252     char              **argv)
2253 {
2254     int rv;
2255     sk_header_entry_t *ci_hdr;
2256 
2257     ci_hdr = invocationCreate(strip_path, argc, argv);
2258     if (ci_hdr == NULL) {
2259         return SKHEADER_ERR_ALLOC;
2260     }
2261     rv = skHeaderAddEntry(hdr, ci_hdr);
2262     if (rv) {
2263         invocationFree(ci_hdr);
2264     }
2265     return rv;
2266 }
2267 
2268 const char *
skHentryInvocationGetInvocation(const sk_header_entry_t * hentry)2269 skHentryInvocationGetInvocation(
2270     const sk_header_entry_t    *hentry)
2271 {
2272     const sk_hentry_invocation_t *ci_hdr = (sk_hentry_invocation_t*)hentry;
2273 
2274     if (skHeaderEntryGetTypeId(ci_hdr) != SK_HENTRY_INVOCATION_ID) {
2275         return NULL;
2276     }
2277     return ci_hdr->command_line;
2278 }
2279 
2280 
2281 
2282 /*
2283  *    **********************************************************************
2284  *
2285  *    Annotation
2286  *
2287  */
2288 
2289 typedef struct sk_hentry_annotation_st {
2290     sk_header_entry_spec_t  he_spec;
2291     char                   *annotation;
2292 } sk_hentry_annotation_t;
2293 
2294 /* forward declaration */
2295 static sk_header_entry_t *annotationCreate(const char *annotation);
2296 
2297 static sk_header_entry_t *
annotationCopy(const sk_header_entry_t * hentry)2298 annotationCopy(
2299     const sk_header_entry_t    *hentry)
2300 {
2301     const sk_hentry_annotation_t *an_hdr = (sk_hentry_annotation_t*)hentry;
2302 
2303     return annotationCreate(an_hdr->annotation);
2304 }
2305 
2306 static sk_header_entry_t *
annotationCreate(const char * annotation)2307 annotationCreate(
2308     const char         *annotation)
2309 {
2310     sk_hentry_annotation_t *an_hdr;
2311     int len;
2312 
2313     if (!annotation) {
2314         /* always provide an annotation string */
2315         annotation = "";
2316     }
2317     len = 1 + strlen(annotation);
2318 
2319     an_hdr = (sk_hentry_annotation_t*)calloc(1, sizeof(sk_hentry_annotation_t));
2320     if (NULL == an_hdr) {
2321         return NULL;
2322     }
2323     an_hdr->he_spec.hes_id   = SK_HENTRY_ANNOTATION_ID;
2324     an_hdr->he_spec.hes_len  = sizeof(sk_header_entry_spec_t) + len;
2325 
2326     an_hdr->annotation = strdup(annotation);
2327     if (NULL == an_hdr->annotation) {
2328         free(an_hdr);
2329         return NULL;
2330     }
2331 
2332     return (sk_header_entry_t*)an_hdr;
2333 }
2334 
2335 static sk_header_entry_t *
annotationCreateFromFile(const char * pathname)2336 annotationCreateFromFile(
2337     const char         *pathname)
2338 {
2339     sk_hentry_annotation_t *an_hdr = NULL;
2340     skstream_t *stream = NULL;
2341     char *content = NULL;
2342     char *pos = NULL;
2343     size_t bufsize = HENTRY_INIT_BUFSIZE;
2344     ssize_t wanted;
2345     ssize_t saw;
2346     int len = 0;
2347 
2348     if (!pathname || !pathname[0]) {
2349         return NULL;
2350     }
2351 
2352     /* open the stream */
2353     if (skStreamCreate(&stream, SK_IO_READ, SK_CONTENT_TEXT)
2354         || skStreamBind(stream, pathname)
2355         || skStreamOpen(stream))
2356     {
2357         goto END;
2358     }
2359 
2360     /* create buffer to hold the stream's content */
2361     content = (char*)malloc(bufsize);
2362     if (content == NULL) {
2363         goto END;
2364     }
2365 
2366     /* read from the stream until we read the end of file or an error.
2367      * grow the content buffer as needed. */
2368     for (;;) {
2369         pos = &content[len];
2370         wanted = bufsize - len - 1;
2371         saw = skStreamRead(stream, pos, wanted);
2372         if (saw == -1) {
2373             /* error */
2374             goto END;
2375         }
2376         if (saw == 0) {
2377             /* assume end of file */
2378             break;
2379         }
2380         if (saw == wanted) {
2381             /* buffer is full, grow it */
2382             bufsize = 2 * bufsize;
2383             pos = content;
2384             content = (char*)realloc(content, bufsize);
2385             if (content == NULL) {
2386                 free(pos);
2387                 goto END;
2388             }
2389         }
2390         len += saw;
2391     }
2392     content[len] = '\0';
2393     ++len;
2394 
2395     skStreamDestroy(&stream);
2396 
2397     /* shink the buffer */
2398     pos = content;
2399     content = (char*)realloc(content, len);
2400     if (content == NULL) {
2401         free(pos);
2402         goto END;
2403     }
2404 
2405     /* create the annotion object */
2406     an_hdr = (sk_hentry_annotation_t*)calloc(1, sizeof(sk_hentry_annotation_t));
2407     if (NULL == an_hdr) {
2408         free(content);
2409         return NULL;
2410     }
2411     an_hdr->he_spec.hes_id   = SK_HENTRY_ANNOTATION_ID;
2412     an_hdr->he_spec.hes_len  = sizeof(sk_header_entry_spec_t) + len;
2413     an_hdr->annotation = content;
2414 
2415   END:
2416     skStreamDestroy(&stream);
2417     return (sk_header_entry_t*)an_hdr;
2418 }
2419 
2420 static void
annotationFree(sk_header_entry_t * hentry)2421 annotationFree(
2422     sk_header_entry_t  *hentry)
2423 {
2424     sk_hentry_annotation_t *an_hdr = (sk_hentry_annotation_t*)hentry;
2425 
2426     if (an_hdr) {
2427         assert(skHeaderEntryGetTypeId(an_hdr) == SK_HENTRY_ANNOTATION_ID);
2428         an_hdr->he_spec.hes_id = UINT32_MAX;
2429         if (an_hdr->annotation) {
2430             free(an_hdr->annotation);
2431             an_hdr->annotation = NULL;
2432         }
2433         free(an_hdr);
2434     }
2435 }
2436 
2437 static ssize_t
annotationPacker(const sk_header_entry_t * in_hentry,uint8_t * out_packed,size_t bufsize)2438 annotationPacker(
2439     const sk_header_entry_t    *in_hentry,
2440     uint8_t                    *out_packed,
2441     size_t                      bufsize)
2442 {
2443     sk_hentry_annotation_t *an_hdr = (sk_hentry_annotation_t*)in_hentry;
2444     uint32_t check_len;
2445 
2446     assert(in_hentry);
2447     assert(out_packed);
2448     assert(skHeaderEntryGetTypeId(an_hdr) == SK_HENTRY_ANNOTATION_ID);
2449 
2450     /* adjust the length recorded in the header it if it too small */
2451     check_len = (1 + strlen(an_hdr->annotation)
2452                  + sizeof(sk_header_entry_spec_t));
2453     if (check_len > an_hdr->he_spec.hes_len) {
2454         an_hdr->he_spec.hes_len = check_len;
2455     }
2456 
2457     if (bufsize >= an_hdr->he_spec.hes_len) {
2458         SK_HENTRY_SPEC_PACK(out_packed, &(an_hdr->he_spec));
2459         memcpy(&(out_packed[sizeof(sk_header_entry_spec_t)]),
2460                an_hdr->annotation,
2461                (an_hdr->he_spec.hes_len - sizeof(sk_header_entry_spec_t)));
2462     }
2463 
2464     return an_hdr->he_spec.hes_len;
2465 }
2466 
2467 static void
annotationPrint(const sk_header_entry_t * hentry,FILE * fh)2468 annotationPrint(
2469     const sk_header_entry_t    *hentry,
2470     FILE                       *fh)
2471 {
2472     const sk_hentry_annotation_t *an_hdr = (sk_hentry_annotation_t*)hentry;
2473 
2474     assert(skHeaderEntryGetTypeId(an_hdr) == SK_HENTRY_ANNOTATION_ID);
2475     fprintf(fh, "%s", an_hdr->annotation);
2476 }
2477 
2478 static sk_header_entry_t *
annotationUnpacker(uint8_t * in_packed)2479 annotationUnpacker(
2480     uint8_t            *in_packed)
2481 {
2482     sk_hentry_annotation_t *an_hdr;
2483     uint32_t len;
2484 
2485     assert(in_packed);
2486 
2487     /* create space for new header */
2488     an_hdr = (sk_hentry_annotation_t*)calloc(1, sizeof(sk_hentry_annotation_t));
2489     if (NULL == an_hdr) {
2490         return NULL;
2491     }
2492 
2493     /* copy the spec */
2494     SK_HENTRY_SPEC_UNPACK(&(an_hdr->he_spec), in_packed);
2495     assert(skHeaderEntryGetTypeId(an_hdr) == SK_HENTRY_ANNOTATION_ID);
2496 
2497     /* copy the data */
2498     len = an_hdr->he_spec.hes_len;
2499     if (len < sizeof(sk_header_entry_spec_t)) {
2500         free(an_hdr);
2501         return NULL;
2502     }
2503     len -= sizeof(sk_header_entry_spec_t);
2504     an_hdr->annotation = (char*)calloc(len, sizeof(char));
2505     if (NULL == an_hdr->annotation) {
2506         free(an_hdr);
2507         return NULL;
2508     }
2509     memcpy(an_hdr->annotation, &(in_packed[sizeof(sk_header_entry_spec_t)]),
2510            len);
2511 
2512     return (sk_header_entry_t*)an_hdr;
2513 }
2514 
2515 /*  Called by skHeaderInitialize to register the header type */
2516 static int
hentryRegisterAnnotation(sk_hentry_type_id_t hentry_id)2517 hentryRegisterAnnotation(
2518     sk_hentry_type_id_t hentry_id)
2519 {
2520     assert(SK_HENTRY_ANNOTATION_ID == hentry_id);
2521     return (skHentryTypeRegister(
2522                 hentry_id, &annotationPacker, &annotationUnpacker,
2523                 &annotationCopy, &annotationFree, &annotationPrint));
2524 }
2525 
2526 int
skHeaderAddAnnotation(sk_file_header_t * hdr,const char * annotation)2527 skHeaderAddAnnotation(
2528     sk_file_header_t   *hdr,
2529     const char         *annotation)
2530 {
2531     int rv;
2532     sk_header_entry_t *an_hdr;
2533 
2534     an_hdr = annotationCreate(annotation);
2535     if (an_hdr == NULL) {
2536         return SKHEADER_ERR_ALLOC;
2537     }
2538     rv = skHeaderAddEntry(hdr, an_hdr);
2539     if (rv) {
2540         annotationFree(an_hdr);
2541     }
2542     return rv;
2543 }
2544 
2545 int
skHeaderAddAnnotationFromFile(sk_file_header_t * hdr,const char * pathname)2546 skHeaderAddAnnotationFromFile(
2547     sk_file_header_t   *hdr,
2548     const char         *pathname)
2549 {
2550     int rv;
2551     sk_header_entry_t *an_hdr;
2552 
2553     an_hdr = annotationCreateFromFile(pathname);
2554     if (an_hdr == NULL) {
2555         return SKHEADER_ERR_ALLOC;
2556     }
2557     rv = skHeaderAddEntry(hdr, an_hdr);
2558     if (rv) {
2559         annotationFree(an_hdr);
2560     }
2561     return rv;
2562 }
2563 
2564 const char *
skHentryAnnotationGetNote(const sk_header_entry_t * hentry)2565 skHentryAnnotationGetNote(
2566     const sk_header_entry_t    *hentry)
2567 {
2568     const sk_hentry_annotation_t *an_hdr = (sk_hentry_annotation_t*)hentry;
2569 
2570     if (skHeaderEntryGetTypeId(an_hdr) != SK_HENTRY_ANNOTATION_ID) {
2571         return NULL;
2572     }
2573     return an_hdr->annotation;
2574 }
2575 
2576 
2577 
2578 /*
2579  *    **********************************************************************
2580  *
2581  *    Probename
2582  *
2583  */
2584 
2585 typedef struct sk_hentry_probename_st {
2586     sk_header_entry_spec_t  he_spec;
2587     char                   *probe_name;
2588 } sk_hentry_probename_t;
2589 
2590 /* forward declaration */
2591 static sk_header_entry_t *probenameCreate(const char *probe_name);
2592 
2593 static sk_header_entry_t *
probenameCopy(const sk_header_entry_t * hentry)2594 probenameCopy(
2595     const sk_header_entry_t    *hentry)
2596 {
2597     const sk_hentry_probename_t *pn_hdr = (sk_hentry_probename_t*)hentry;
2598 
2599     return probenameCreate(pn_hdr->probe_name);
2600 }
2601 
2602 static sk_header_entry_t *
probenameCreate(const char * probe_name)2603 probenameCreate(
2604     const char         *probe_name)
2605 {
2606     sk_hentry_probename_t *pn_hdr;
2607     int len;
2608 
2609     /* verify name is specified */
2610     if (probe_name == NULL || probe_name[0] == '\0') {
2611         return NULL;
2612     }
2613     len = 1 + strlen(probe_name);
2614 
2615     pn_hdr = (sk_hentry_probename_t*)calloc(1, sizeof(sk_hentry_probename_t));
2616     if (NULL == pn_hdr) {
2617         return NULL;
2618     }
2619     pn_hdr->he_spec.hes_id  = SK_HENTRY_PROBENAME_ID;
2620     pn_hdr->he_spec.hes_len = sizeof(sk_header_entry_spec_t) + len;
2621 
2622     pn_hdr->probe_name = strdup(probe_name);
2623     if (NULL == pn_hdr->probe_name) {
2624         free(pn_hdr);
2625         return NULL;
2626     }
2627 
2628     return (sk_header_entry_t*)pn_hdr;
2629 }
2630 
2631 static void
probenameFree(sk_header_entry_t * hentry)2632 probenameFree(
2633     sk_header_entry_t  *hentry)
2634 {
2635     sk_hentry_probename_t *pn_hdr = (sk_hentry_probename_t*)hentry;
2636 
2637     if (pn_hdr) {
2638         assert(skHeaderEntryGetTypeId(pn_hdr) == SK_HENTRY_PROBENAME_ID);
2639         pn_hdr->he_spec.hes_id = UINT32_MAX;
2640         if (pn_hdr->probe_name) {
2641             free(pn_hdr->probe_name);
2642             pn_hdr->probe_name = NULL;
2643         }
2644         free(pn_hdr);
2645     }
2646 }
2647 
2648 static ssize_t
probenamePacker(const sk_header_entry_t * in_hentry,uint8_t * out_packed,size_t bufsize)2649 probenamePacker(
2650     const sk_header_entry_t    *in_hentry,
2651     uint8_t                    *out_packed,
2652     size_t                      bufsize)
2653 {
2654     sk_hentry_probename_t *pn_hdr = (sk_hentry_probename_t*)in_hentry;
2655     uint32_t check_len;
2656     uint32_t probe_name_len;
2657 
2658     assert(in_hentry);
2659     assert(out_packed);
2660     assert(skHeaderEntryGetTypeId(pn_hdr) == SK_HENTRY_PROBENAME_ID);
2661 
2662     /* adjust the length recorded in the header it if it too small */
2663     probe_name_len = 1 + strlen(pn_hdr->probe_name);
2664     check_len = probe_name_len + sizeof(sk_header_entry_spec_t);
2665     if (check_len > pn_hdr->he_spec.hes_len) {
2666         pn_hdr->he_spec.hes_len = check_len;
2667     }
2668 
2669     if (bufsize >= pn_hdr->he_spec.hes_len) {
2670         SK_HENTRY_SPEC_PACK(out_packed, &(pn_hdr->he_spec));
2671         memcpy(&(out_packed[sizeof(sk_header_entry_spec_t)]),
2672                pn_hdr->probe_name, probe_name_len);
2673     }
2674 
2675     return pn_hdr->he_spec.hes_len;
2676 }
2677 
2678 static void
probenamePrint(const sk_header_entry_t * hentry,FILE * fh)2679 probenamePrint(
2680     const sk_header_entry_t    *hentry,
2681     FILE                       *fh)
2682 {
2683     sk_hentry_probename_t *pn_hdr = (sk_hentry_probename_t*)hentry;
2684 
2685     assert(skHeaderEntryGetTypeId(pn_hdr) == SK_HENTRY_PROBENAME_ID);
2686     fprintf(fh, "%s",
2687             (pn_hdr->probe_name ? pn_hdr->probe_name : "NULL"));
2688 }
2689 
2690 static sk_header_entry_t *
probenameUnpacker(uint8_t * in_packed)2691 probenameUnpacker(
2692     uint8_t            *in_packed)
2693 {
2694     sk_hentry_probename_t *pn_hdr;
2695     uint32_t len;
2696 
2697     assert(in_packed);
2698 
2699     /* create space for new header */
2700     pn_hdr = (sk_hentry_probename_t*)calloc(1, sizeof(sk_hentry_probename_t));
2701     if (NULL == pn_hdr) {
2702         return NULL;
2703     }
2704 
2705     /* copy the spec */
2706     SK_HENTRY_SPEC_UNPACK(&(pn_hdr->he_spec), in_packed);
2707     assert(skHeaderEntryGetTypeId(pn_hdr) == SK_HENTRY_PROBENAME_ID);
2708 
2709     /* copy the data */
2710     len = pn_hdr->he_spec.hes_len;
2711     if (len < sizeof(sk_header_entry_spec_t)) {
2712         free(pn_hdr);
2713         return NULL;
2714     }
2715     len -= sizeof(sk_header_entry_spec_t);
2716     pn_hdr->probe_name = (char*)calloc(len, sizeof(char));
2717     if (NULL == pn_hdr->probe_name) {
2718         free(pn_hdr);
2719         return NULL;
2720     }
2721     memcpy(pn_hdr->probe_name, &(in_packed[sizeof(sk_header_entry_spec_t)]),
2722            len);
2723 
2724     return (sk_header_entry_t*)pn_hdr;
2725 }
2726 
2727 /*  Called by skHeaderInitialize to register the header type */
2728 static int
hentryRegisterProbename(sk_hentry_type_id_t hentry_id)2729 hentryRegisterProbename(
2730     sk_hentry_type_id_t hentry_id)
2731 {
2732     assert(SK_HENTRY_PROBENAME_ID == hentry_id);
2733     return skHentryTypeRegister(hentry_id,&probenamePacker,&probenameUnpacker,
2734                                 &probenameCopy,&probenameFree,&probenamePrint);
2735 }
2736 
2737 
2738 int
skHeaderAddProbename(sk_file_header_t * hdr,const char * probe_name)2739 skHeaderAddProbename(
2740     sk_file_header_t   *hdr,
2741     const char         *probe_name)
2742 {
2743     int rv;
2744     sk_header_entry_t *pn_hdr;
2745 
2746     pn_hdr = probenameCreate(probe_name);
2747     if (pn_hdr == NULL) {
2748         return SKHEADER_ERR_ALLOC;
2749     }
2750     rv = skHeaderAddEntry(hdr, pn_hdr);
2751     if (rv) {
2752         probenameFree(pn_hdr);
2753     }
2754     return rv;
2755 }
2756 
2757 const char *
skHentryProbenameGetProbeName(const sk_header_entry_t * hentry)2758 skHentryProbenameGetProbeName(
2759     const sk_header_entry_t    *hentry)
2760 {
2761     const sk_hentry_probename_t *pn_hdr = (sk_hentry_probename_t*)hentry;
2762 
2763     if (skHeaderEntryGetTypeId(pn_hdr) != SK_HENTRY_PROBENAME_ID) {
2764         return NULL;
2765     }
2766     return pn_hdr->probe_name;
2767 }
2768 
2769 
2770 /*
2771  *    **********************************************************************
2772  *
2773  *    Tombstone
2774  *
2775  */
2776 
2777 /*
2778  *    sk_hentry_tombstone_t is the current definition of the tombstone
2779  *    header.
2780  */
2781 typedef struct sk_hentry_tombstone_st {
2782     sk_header_entry_spec_t  he_spec;
2783     uint32_t                ts_version;
2784     uint32_t                ts_counter;
2785 } sk_hentry_tombstone_t;
2786 
2787 /*
2788  *    tombstone_zero_t is the structure used for tombstone records
2789  *    that have a version that is not supported by this release
2790  */
2791 typedef struct tombstone_zero_st {
2792     sk_header_entry_spec_t  he_spec;
2793     uint32_t                ts_version;
2794     uint32_t                ts_dummy;
2795 } tombstone_zero_t;
2796 
2797 /* Forward declaration */
2798 static sk_header_entry_t *tombstoneCreate(uint32_t tombstone_count);
2799 static sk_header_entry_t *tombstoneZero(void);
2800 
2801 static sk_header_entry_t *
tombstoneCopy(const sk_header_entry_t * hentry)2802 tombstoneCopy(
2803     const sk_header_entry_t    *hentry)
2804 {
2805     const sk_hentry_tombstone_t *ts_hdr = (sk_hentry_tombstone_t*)hentry;
2806 
2807     assert(skHeaderEntryGetTypeId(ts_hdr) == SK_HENTRY_TOMBSTONE_ID);
2808 
2809     if (1 != ts_hdr->ts_version) {
2810         return tombstoneZero();
2811     }
2812     return tombstoneCreate(ts_hdr->ts_counter);
2813 }
2814 
2815 static sk_header_entry_t *
tombstoneCreate(uint32_t tombstone_count)2816 tombstoneCreate(
2817     uint32_t            tombstone_count)
2818 {
2819     sk_hentry_tombstone_t *ts_hdr;
2820 
2821     ts_hdr = (sk_hentry_tombstone_t*)calloc(1, sizeof(sk_hentry_tombstone_t));
2822     if (NULL == ts_hdr) {
2823         return NULL;
2824     }
2825     ts_hdr->he_spec.hes_id  = SK_HENTRY_TOMBSTONE_ID;
2826     ts_hdr->he_spec.hes_len = sizeof(sk_hentry_tombstone_t);
2827     ts_hdr->ts_version = 1;
2828     ts_hdr->ts_counter = tombstone_count;
2829 
2830     return (sk_header_entry_t *)ts_hdr;
2831 }
2832 
2833 static void
tombstoneFree(sk_header_entry_t * hentry)2834 tombstoneFree(
2835     sk_header_entry_t  *hentry)
2836 {
2837     sk_hentry_tombstone_t *ts_hdr = (sk_hentry_tombstone_t*)hentry;
2838 
2839     if (ts_hdr) {
2840         assert(skHeaderEntryGetTypeId(ts_hdr) == SK_HENTRY_TOMBSTONE_ID);
2841         ts_hdr->he_spec.hes_id = UINT32_MAX;
2842         free(ts_hdr);
2843     }
2844 }
2845 
2846 static ssize_t
tombstonePacker(const sk_header_entry_t * in_hentry,uint8_t * out_packed,size_t bufsize)2847 tombstonePacker(
2848     const sk_header_entry_t    *in_hentry,
2849     uint8_t                    *out_packed,
2850     size_t                      bufsize)
2851 {
2852     const sk_hentry_tombstone_t *ts_hdr = (sk_hentry_tombstone_t*)in_hentry;
2853 
2854     assert(in_hentry);
2855     assert(out_packed);
2856     assert(skHeaderEntryGetTypeId(ts_hdr) == SK_HENTRY_TOMBSTONE_ID);
2857 
2858     if (1 != ts_hdr->ts_version) {
2859         tombstone_zero_t zero;
2860         if (bufsize >= sizeof(zero)) {
2861             memset(&zero, 0, sizeof(zero));
2862             zero.he_spec.hes_id  = SK_HENTRY_TOMBSTONE_ID;
2863             zero.he_spec.hes_len = sizeof(tombstone_zero_t);
2864             SK_HENTRY_SPEC_PACK(out_packed, &zero.he_spec);
2865             memset(out_packed, 0,
2866                    sizeof(zero) - sizeof(sk_header_entry_spec_t));
2867         }
2868         return sizeof(zero);
2869     }
2870 
2871     if (bufsize >= sizeof(sk_hentry_tombstone_t)) {
2872         sk_hentry_tombstone_t tmp_hdr;
2873         SK_HENTRY_SPEC_PACK(&tmp_hdr, &ts_hdr->he_spec);
2874         tmp_hdr.ts_version = htonl(ts_hdr->ts_version);
2875         tmp_hdr.ts_counter = htonl(ts_hdr->ts_counter);
2876 
2877         memcpy(out_packed, &tmp_hdr, sizeof(tmp_hdr));
2878     }
2879 
2880     return sizeof(sk_hentry_tombstone_t);
2881 }
2882 
2883 static void
tombstonePrint(const sk_header_entry_t * hentry,FILE * fh)2884 tombstonePrint(
2885     const sk_header_entry_t    *hentry,
2886     FILE                       *fh)
2887 {
2888     const sk_hentry_tombstone_t *ts_hdr = (sk_hentry_tombstone_t*)hentry;
2889 
2890     assert(skHeaderEntryGetTypeId(ts_hdr) == SK_HENTRY_TOMBSTONE_ID);
2891     switch (ts_hdr->ts_version) {
2892       case 1:
2893         fprintf(fh, "v1, id = %" PRIu32, ts_hdr->ts_counter);
2894         break;
2895       default:
2896         fprintf(fh, "v%u, unsupported", ts_hdr->ts_version);
2897         break;
2898     }
2899 }
2900 
2901 static sk_header_entry_t *
tombstoneUnpacker(uint8_t * in_packed)2902 tombstoneUnpacker(
2903     uint8_t            *in_packed)
2904 {
2905     sk_hentry_tombstone_t *ts_hdr;
2906     size_t offset;
2907 
2908     assert(in_packed);
2909 
2910     /* create space for new header */
2911     ts_hdr = (sk_hentry_tombstone_t*)calloc(1, sizeof(sk_hentry_tombstone_t));
2912     if (NULL == ts_hdr) {
2913         return NULL;
2914     }
2915 
2916     /* copy the spec */
2917     SK_HENTRY_SPEC_UNPACK(&(ts_hdr->he_spec), in_packed);
2918     assert(skHeaderEntryGetTypeId(ts_hdr) == SK_HENTRY_TOMBSTONE_ID);
2919 
2920     offset = sizeof(sk_header_entry_spec_t);
2921 
2922     /* get the version number */
2923     if (ts_hdr->he_spec.hes_len < offset + sizeof(uint32_t)) {
2924         free(ts_hdr);
2925         return NULL;
2926     }
2927     memcpy(&ts_hdr->ts_version, &in_packed[offset],sizeof(ts_hdr->ts_version));
2928     ts_hdr->ts_version = ntohl(ts_hdr->ts_version);
2929     if (1 != ts_hdr->ts_version) {
2930         return tombstoneZero();
2931     }
2932     offset += sizeof(uint32_t);
2933 
2934     if (ts_hdr->he_spec.hes_len != sizeof(sk_hentry_tombstone_t)) {
2935         free(ts_hdr);
2936         return NULL;
2937     }
2938 
2939     /* handle the count */
2940     memcpy(&ts_hdr->ts_counter, &in_packed[offset],sizeof(ts_hdr->ts_counter));
2941     ts_hdr->ts_counter = ntohl(ts_hdr->ts_counter);
2942 
2943     return (sk_header_entry_t*)ts_hdr;
2944 }
2945 
2946 /*
2947  *    Return a tombstone header entry whose version is 0.  Used when
2948  *    an attempt to make to access a tombstone record that is unknown
2949  *    by this release of SiLK.
2950  */
2951 static sk_header_entry_t *
tombstoneZero(void)2952 tombstoneZero(
2953     void)
2954 {
2955     tombstone_zero_t *ts_hdr;
2956 
2957     ts_hdr = (tombstone_zero_t *)calloc(1, sizeof(tombstone_zero_t));
2958     if (NULL == ts_hdr) {
2959         return NULL;
2960     }
2961     ts_hdr->he_spec.hes_id  = SK_HENTRY_TOMBSTONE_ID;
2962     ts_hdr->he_spec.hes_len = sizeof(tombstone_zero_t);
2963 
2964     return (sk_header_entry_t *)ts_hdr;
2965 }
2966 
2967 /*  Called by skHeaderInitialize to register the header type */
2968 static int
hentryRegisterTombstone(sk_hentry_type_id_t hentry_id)2969 hentryRegisterTombstone(
2970     sk_hentry_type_id_t hentry_id)
2971 {
2972     assert(SK_HENTRY_TOMBSTONE_ID == hentry_id);
2973     return skHentryTypeRegister(hentry_id, &tombstonePacker,&tombstoneUnpacker,
2974                                 &tombstoneCopy,&tombstoneFree,&tombstonePrint);
2975 }
2976 
2977 int
skHeaderAddTombstone(sk_file_header_t * hdr,uint32_t tombstone_count)2978 skHeaderAddTombstone(
2979     sk_file_header_t   *hdr,
2980     uint32_t            tombstone_count)
2981 {
2982     int rv;
2983     sk_header_entry_t *ts_hdr;
2984 
2985     ts_hdr = tombstoneCreate(tombstone_count);
2986     if (ts_hdr == NULL) {
2987         return SKHEADER_ERR_ALLOC;
2988     }
2989     rv = skHeaderAddEntry(hdr, ts_hdr);
2990     if (rv) {
2991         tombstoneFree(ts_hdr);
2992     }
2993     return rv;
2994 }
2995 
2996 uint32_t
skHentryTombstoneGetCount(const sk_header_entry_t * hentry)2997 skHentryTombstoneGetCount(
2998     const sk_header_entry_t    *hentry)
2999 {
3000     const sk_hentry_tombstone_t *ts_hdr = (sk_hentry_tombstone_t*)hentry;
3001 
3002     assert(skHeaderEntryGetTypeId(ts_hdr) == SK_HENTRY_TOMBSTONE_ID);
3003     if (ts_hdr->ts_version != 1) {
3004         return UINT32_MAX;
3005     }
3006     return ts_hdr->ts_counter;
3007 }
3008 
3009 
3010 /*
3011 ** Local Variables:
3012 ** mode:c
3013 ** indent-tabs-mode:nil
3014 ** c-basic-offset:4
3015 ** End:
3016 */
3017