1 // SPDX-License-Identifier: GPL-2.0-or-later
5 * Copyright (C) 2016 Rafał Miłecki <zajec5@gmail.com>
19 #if !defined(__BYTE_ORDER)
20 #error "Unknown byte order"
23 #if __BYTE_ORDER == __BIG_ENDIAN
24 #define cpu_to_be32(x) (x)
25 #define be32_to_cpu(x) (x)
26 #define cpu_to_be16(x) (x)
27 #define be16_to_cpu(x) (x)
28 #elif __BYTE_ORDER == __LITTLE_ENDIAN
29 #define cpu_to_be32(x) bswap_32(x)
30 #define be32_to_cpu(x) bswap_32(x)
31 #define cpu_to_be16(x) bswap_16(x)
32 #define be16_to_cpu(x) bswap_16(x)
34 #error "Unsupported endianness"
37 #define SEAMA_MAGIC 0x5ea3a417
39 struct seama_seal_header
{
44 } __attribute__ ((packed
));
46 struct seama_entity_header
{
52 } __attribute__ ((packed
));
58 static inline size_t oseama_min(size_t x
, size_t y
) {
62 /**************************************************
64 **************************************************/
66 static FILE *oseama_open(const char *pathname
, const char *mode
) {
67 if (strcmp(pathname
, "-"))
68 return fopen(pathname
, mode
);
70 if (isatty(fileno(stdin
))) {
71 fprintf(stderr
, "Reading from TTY stdin is unsupported\n");
78 static int oseama_skip(FILE *fp
, size_t length
)
80 if (fseek(fp
, length
, SEEK_CUR
)) {
85 bytes
= fread(buf
, 1, oseama_min(sizeof(buf
), length
), fp
);
95 static void oseama_close(FILE *fp
) {
100 /**************************************************
102 **************************************************/
104 static void oseama_info_parse_options(int argc
, char **argv
) {
107 while ((c
= getopt(argc
, argv
, "e:")) != -1) {
110 entity_idx
= atoi(optarg
);
116 static int oseama_info_entities(FILE *seama
, size_t *pos
) {
117 struct seama_entity_header hdr
;
118 size_t bytes
, metasize
, imagesize
;
124 while ((bytes
= fread(&hdr
, 1, sizeof(hdr
), seama
)) == sizeof(hdr
)) {
127 if (be32_to_cpu(hdr
.magic
) != SEAMA_MAGIC
) {
128 fprintf(stderr
, "Invalid Seama magic: 0x%08x\n", be32_to_cpu(hdr
.magic
));
132 metasize
= be16_to_cpu(hdr
.metasize
);
133 imagesize
= be32_to_cpu(hdr
.imagesize
);
135 if (entity_idx
>= 0 && i
!= entity_idx
) {
136 oseama_skip(seama
, metasize
+ imagesize
);
137 *pos
+= metasize
+ imagesize
;
142 if (metasize
>= sizeof(buf
)) {
143 fprintf(stderr
, "Too small buffer (%zu B) to read all meta info (%zd B)\n", sizeof(buf
), metasize
);
150 printf("Entity offset:\t%ld\n", *pos
- sizeof(hdr
));
151 printf("Entity size:\t%zd\n", sizeof(hdr
) + metasize
+ imagesize
);
152 printf("Meta size:\t%zd\n", metasize
);
153 printf("Image size:\t%zd\n", imagesize
);
155 bytes
= fread(buf
, 1, metasize
, seama
);
156 if (bytes
!= metasize
) {
157 fprintf(stderr
, "Couldn't read %zd B of meta\n", metasize
);
163 end
= (char *)&buf
[metasize
- 1];
165 for (tmp
= (char *)buf
; tmp
< end
&& strlen(tmp
); tmp
+= strlen(tmp
) + 1) {
166 printf("Meta entry:\t%s\n", tmp
);
169 oseama_skip(seama
, imagesize
);
178 static int oseama_info(int argc
, char **argv
) {
180 struct seama_seal_header hdr
;
189 fprintf(stderr
, "No Seama file passed\n");
193 seama_path
= argv
[2];
196 oseama_info_parse_options(argc
, argv
);
198 seama
= oseama_open(seama_path
, "r");
200 fprintf(stderr
, "Couldn't open %s\n", seama_path
);
205 bytes
= fread(&hdr
, 1, sizeof(hdr
), seama
);
206 if (bytes
!= sizeof(hdr
)) {
207 fprintf(stderr
, "Couldn't read %s header\n", seama_path
);
213 metasize
= be16_to_cpu(hdr
.metasize
);
214 imagesize
= be32_to_cpu(hdr
.imagesize
);
216 if (be32_to_cpu(hdr
.magic
) != SEAMA_MAGIC
) {
217 fprintf(stderr
, "Invalid Seama magic: 0x%08x\n", be32_to_cpu(hdr
.magic
));
222 if (metasize
>= sizeof(buf
)) {
223 fprintf(stderr
, "Too small buffer (%zu B) to read all meta info (%d B)\n", sizeof(buf
), metasize
);
229 fprintf(stderr
, "Invalid Seama image size: 0x%08x (should be 0)\n", imagesize
);
234 bytes
= fread(buf
, 1, metasize
, seama
);
235 if (bytes
!= metasize
) {
236 fprintf(stderr
, "Couldn't read %d B of meta\n", metasize
);
242 if (entity_idx
< 0) {
245 printf("Meta size:\t%d\n", metasize
);
246 printf("Image size:\t%d\n", imagesize
);
248 end
= (char *)&buf
[metasize
- 1];
250 for (tmp
= (char *)buf
; tmp
< end
&& strlen(tmp
); tmp
+= strlen(tmp
) + 1) {
251 printf("Meta entry:\t%s\n", tmp
);
255 oseama_info_entities(seama
, &pos
);
263 /**************************************************
265 **************************************************/
267 static ssize_t
oseama_entity_append_file(FILE *seama
, const char *in_path
) {
273 in
= fopen(in_path
, "r");
275 fprintf(stderr
, "Couldn't open %s\n", in_path
);
279 while ((bytes
= fread(buf
, 1, sizeof(buf
), in
)) > 0) {
280 if (fwrite(buf
, 1, bytes
, seama
) != bytes
) {
281 fprintf(stderr
, "Couldn't write %zu B to %s\n", bytes
, seama_path
);
293 static ssize_t
oseama_entity_append_zeros(FILE *seama
, size_t length
) {
296 buf
= malloc(length
);
299 memset(buf
, 0, length
);
301 if (fwrite(buf
, 1, length
, seama
) != length
) {
302 fprintf(stderr
, "Couldn't write %zu B to %s\n", length
, seama_path
);
309 static ssize_t
oseama_entity_align(FILE *seama
, size_t curr_offset
, size_t alignment
) {
310 if (curr_offset
& (alignment
- 1)) {
311 size_t length
= alignment
- (curr_offset
% alignment
);
313 return oseama_entity_append_zeros(seama
, length
);
319 static int oseama_entity_write_hdr(FILE *seama
, size_t metasize
, size_t imagesize
) {
320 struct seama_entity_header hdr
= {};
322 size_t length
= imagesize
;
326 fseek(seama
, sizeof(hdr
) + metasize
, SEEK_SET
);
328 while ((bytes
= fread(buf
, 1, oseama_min(sizeof(buf
), length
), seama
)) > 0) {
329 MD5_Update(&ctx
, buf
, bytes
);
332 MD5_Final(hdr
.md5
, &ctx
);
334 hdr
.magic
= cpu_to_be32(SEAMA_MAGIC
);
335 hdr
.metasize
= cpu_to_be16(metasize
);
336 hdr
.imagesize
= cpu_to_be32(imagesize
);
338 fseek(seama
, 0, SEEK_SET
);
339 bytes
= fwrite(&hdr
, 1, sizeof(hdr
), seama
);
340 if (bytes
!= sizeof(hdr
)) {
341 fprintf(stderr
, "Couldn't write Seama entity header to %s\n", seama_path
);
348 static int oseama_entity(int argc
, char **argv
) {
351 size_t curr_offset
= sizeof(struct seama_entity_header
);
352 size_t metasize
= 0, imagesize
= 0;
357 fprintf(stderr
, "No Seama file passed\n");
361 seama_path
= argv
[2];
363 seama
= fopen(seama_path
, "w+");
365 fprintf(stderr
, "Couldn't open %s\n", seama_path
);
369 fseek(seama
, curr_offset
, SEEK_SET
);
372 while ((c
= getopt(argc
, argv
, "m:f:b:")) != -1) {
375 sbytes
= fwrite(optarg
, 1, strlen(optarg
) + 1, seama
);
377 fprintf(stderr
, "Failed to write meta %s\n", optarg
);
379 curr_offset
+= sbytes
;
383 sbytes
= oseama_entity_align(seama
, curr_offset
, 4);
385 fprintf(stderr
, "Failed to append zeros\n");
387 curr_offset
+= sbytes
;
399 while ((c
= getopt(argc
, argv
, "m:f:b:")) != -1) {
404 sbytes
= oseama_entity_append_file(seama
, optarg
);
406 fprintf(stderr
, "Failed to append file %s\n", optarg
);
408 curr_offset
+= sbytes
;
413 sbytes
= strtol(optarg
, NULL
, 0) - curr_offset
;
415 fprintf(stderr
, "Current Seama entity length is 0x%zx, can't pad it with zeros to 0x%lx\n", curr_offset
, strtol(optarg
, NULL
, 0));
417 sbytes
= oseama_entity_append_zeros(seama
, sbytes
);
419 fprintf(stderr
, "Failed to append zeros\n");
421 curr_offset
+= sbytes
;
431 oseama_entity_write_hdr(seama
, metasize
, imagesize
);
438 /**************************************************
440 **************************************************/
442 static void oseama_extract_parse_options(int argc
, char **argv
) {
445 while ((c
= getopt(argc
, argv
, "e:o:")) != -1) {
448 entity_idx
= atoi(optarg
);
457 static int oseama_extract_entity(FILE *seama
, FILE *out
) {
458 struct seama_entity_header hdr
;
459 size_t bytes
, metasize
, imagesize
, length
;
464 while ((bytes
= fread(&hdr
, 1, sizeof(hdr
), seama
)) == sizeof(hdr
)) {
465 if (be32_to_cpu(hdr
.magic
) != SEAMA_MAGIC
) {
466 fprintf(stderr
, "Invalid Seama magic: 0x%08x\n", be32_to_cpu(hdr
.magic
));
470 metasize
= be16_to_cpu(hdr
.metasize
);
471 imagesize
= be32_to_cpu(hdr
.imagesize
);
473 if (i
!= entity_idx
) {
474 oseama_skip(seama
, metasize
+ imagesize
);
479 if (fwrite(&hdr
, 1, sizeof(hdr
), out
) != sizeof(hdr
)) {
480 fprintf(stderr
, "Couldn't write %zu B to %s\n", sizeof(hdr
), out_path
);
485 length
= metasize
+ imagesize
;
486 while ((bytes
= fread(buf
, 1, oseama_min(sizeof(buf
), length
), seama
)) > 0) {
487 if (fwrite(buf
, 1, bytes
, out
) != bytes
) {
488 fprintf(stderr
, "Couldn't write %zu B to %s\n", bytes
, out_path
);
496 fprintf(stderr
, "Couldn't extract whole entity %d from %s (%zu B left)\n", entity_idx
, seama_path
, length
);
507 static int oseama_extract(int argc
, char **argv
) {
510 struct seama_seal_header hdr
;
516 fprintf(stderr
, "No Seama file passed\n");
520 seama_path
= argv
[2];
523 oseama_extract_parse_options(argc
, argv
);
524 if (entity_idx
< 0) {
525 fprintf(stderr
, "No entity specified\n");
528 } else if (!out_path
) {
529 fprintf(stderr
, "No output file specified\n");
534 seama
= oseama_open(seama_path
, "r");
536 fprintf(stderr
, "Couldn't open %s\n", seama_path
);
541 out
= fopen(out_path
, "w");
543 fprintf(stderr
, "Couldn't open %s\n", out_path
);
545 goto err_close_seama
;
548 bytes
= fread(&hdr
, 1, sizeof(hdr
), seama
);
549 if (bytes
!= sizeof(hdr
)) {
550 fprintf(stderr
, "Couldn't read %s header\n", seama_path
);
554 metasize
= be16_to_cpu(hdr
.metasize
);
556 oseama_skip(seama
, metasize
);
558 oseama_extract_entity(seama
, out
);
568 /**************************************************
570 **************************************************/
572 static void usage() {
575 printf("Info about Seama seal (container):\n");
576 printf("\toseama info <file> [options]\n");
577 printf("\t-e\t\t\t\tprint info about specified entity only\n");
579 printf("Create Seama entity:\n");
580 printf("\toseama entity <file> [options]\n");
581 printf("\t-m meta\t\t\t\tmeta into to put in header\n");
582 printf("\t-f file\t\t\t\tappend content from file\n");
583 printf("\t-b offset\t\t\tappend zeros till reaching absolute offset\n");
585 printf("Extract from Seama seal (container):\n");
586 printf("\toseama extract <file> [options]\n");
587 printf("\t-e\t\t\t\tindex of entity to extract\n");
588 printf("\t-o file\t\t\t\toutput file\n");
591 int main(int argc
, char **argv
) {
593 if (!strcmp(argv
[1], "info"))
594 return oseama_info(argc
, argv
);
595 else if (!strcmp(argv
[1], "entity"))
596 return oseama_entity(argc
, argv
);
597 else if (!strcmp(argv
[1], "extract"))
598 return oseama_extract(argc
, argv
);