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