PageRenderTime 52ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 0ms

/package/utils/oseama/src/oseama.c

https://gitlab.com/lede/lede-noltari-staging
C | 556 lines | 448 code | 86 blank | 22 comment | 88 complexity | 8e48be146b036d3bba4699e8d53db28f MD5 | raw file
  1. /*
  2. * oseama
  3. *
  4. * Copyright (C) 2016 Rafał Miłecki <zajec5@gmail.com>
  5. *
  6. * This program is free software; you can redistribute it and/or modify it
  7. * under the terms of the GNU General Public License as published by the Free
  8. * Software Foundation; either version 2 of the License, or (at your option)
  9. * any later version.
  10. */
  11. #include <byteswap.h>
  12. #include <endian.h>
  13. #include <errno.h>
  14. #include <stdint.h>
  15. #include <stdio.h>
  16. #include <stdlib.h>
  17. #include <string.h>
  18. #include <unistd.h>
  19. #include "md5.h"
  20. #if !defined(__BYTE_ORDER)
  21. #error "Unknown byte order"
  22. #endif
  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)
  33. #else
  34. #error "Unsupported endianness"
  35. #endif
  36. #define SEAMA_MAGIC 0x5ea3a417
  37. struct seama_seal_header {
  38. uint32_t magic;
  39. uint16_t reserved;
  40. uint16_t metasize;
  41. uint32_t imagesize;
  42. } __attribute__ ((packed));
  43. struct seama_entity_header {
  44. uint32_t magic;
  45. uint16_t reserved;
  46. uint16_t metasize;
  47. uint32_t imagesize;
  48. uint8_t md5[16];
  49. } __attribute__ ((packed));
  50. char *seama_path;
  51. int entity_idx = -1;
  52. char *out_path;
  53. static inline size_t oseama_min(size_t x, size_t y) {
  54. return x < y ? x : y;
  55. }
  56. /**************************************************
  57. * Info
  58. **************************************************/
  59. static void oseama_info_parse_options(int argc, char **argv) {
  60. int c;
  61. while ((c = getopt(argc, argv, "e:")) != -1) {
  62. switch (c) {
  63. case 'e':
  64. entity_idx = atoi(optarg);
  65. break;
  66. }
  67. }
  68. }
  69. static int oseama_info_entities(FILE *seama) {
  70. struct seama_entity_header hdr;
  71. size_t bytes, metasize, imagesize;
  72. uint8_t buf[1024];
  73. char *end, *tmp;
  74. int i = 0;
  75. int err = 0;
  76. while ((bytes = fread(&hdr, 1, sizeof(hdr), seama)) == sizeof(hdr)) {
  77. if (be32_to_cpu(hdr.magic) != SEAMA_MAGIC) {
  78. fprintf(stderr, "Invalid Seama magic: 0x%08x\n", be32_to_cpu(hdr.magic));
  79. err = -EINVAL;
  80. goto err_out;
  81. }
  82. metasize = be16_to_cpu(hdr.metasize);
  83. imagesize = be32_to_cpu(hdr.imagesize);
  84. if (entity_idx >= 0 && i != entity_idx) {
  85. fseek(seama, metasize + imagesize, SEEK_CUR);
  86. i++;
  87. continue;
  88. }
  89. if (metasize >= sizeof(buf)) {
  90. fprintf(stderr, "Too small buffer (%zu B) to read all meta info (%zd B)\n", sizeof(buf), metasize);
  91. err = -EINVAL;
  92. goto err_out;
  93. }
  94. if (entity_idx < 0)
  95. printf("\n");
  96. printf("Entity offset:\t%ld\n", ftell(seama) - sizeof(hdr));
  97. printf("Entity size:\t%zd\n", sizeof(hdr) + metasize + imagesize);
  98. printf("Meta size:\t%zd\n", metasize);
  99. printf("Image size:\t%zd\n", imagesize);
  100. bytes = fread(buf, 1, metasize, seama);
  101. if (bytes != metasize) {
  102. fprintf(stderr, "Couldn't read %zd B of meta\n", metasize);
  103. err = -EIO;
  104. goto err_out;
  105. }
  106. end = (char *)&buf[metasize - 1];
  107. *end = '\0';
  108. for (tmp = (char *)buf; tmp < end && strlen(tmp); tmp += strlen(tmp) + 1) {
  109. printf("Meta entry:\t%s\n", tmp);
  110. }
  111. fseek(seama, imagesize, SEEK_CUR);
  112. i++;
  113. }
  114. err_out:
  115. return err;
  116. }
  117. static int oseama_info(int argc, char **argv) {
  118. FILE *seama;
  119. struct seama_seal_header hdr;
  120. size_t bytes;
  121. uint16_t metasize;
  122. uint32_t imagesize;
  123. uint8_t buf[1024];
  124. int err = 0;
  125. if (argc < 3) {
  126. fprintf(stderr, "No Seama file passed\n");
  127. err = -EINVAL;
  128. goto out;
  129. }
  130. seama_path = argv[2];
  131. optind = 3;
  132. oseama_info_parse_options(argc, argv);
  133. seama = fopen(seama_path, "r");
  134. if (!seama) {
  135. fprintf(stderr, "Couldn't open %s\n", seama_path);
  136. err = -EACCES;
  137. goto out;
  138. }
  139. bytes = fread(&hdr, 1, sizeof(hdr), seama);
  140. if (bytes != sizeof(hdr)) {
  141. fprintf(stderr, "Couldn't read %s header\n", seama_path);
  142. err = -EIO;
  143. goto err_close;
  144. }
  145. metasize = be16_to_cpu(hdr.metasize);
  146. imagesize = be32_to_cpu(hdr.imagesize);
  147. if (be32_to_cpu(hdr.magic) != SEAMA_MAGIC) {
  148. fprintf(stderr, "Invalid Seama magic: 0x%08x\n", be32_to_cpu(hdr.magic));
  149. err = -EINVAL;
  150. goto err_close;
  151. }
  152. if (metasize >= sizeof(buf)) {
  153. fprintf(stderr, "Too small buffer (%zu B) to read all meta info (%d B)\n", sizeof(buf), metasize);
  154. err = -EINVAL;
  155. goto err_close;
  156. }
  157. if (imagesize) {
  158. fprintf(stderr, "Invalid Seama image size: 0x%08x (should be 0)\n", imagesize);
  159. err = -EINVAL;
  160. goto err_close;
  161. }
  162. bytes = fread(buf, 1, metasize, seama);
  163. if (bytes != metasize) {
  164. fprintf(stderr, "Couldn't read %d B of meta\n", metasize);
  165. err = -EIO;
  166. goto err_close;
  167. }
  168. if (entity_idx < 0) {
  169. char *end, *tmp;
  170. printf("Meta size:\t%d\n", metasize);
  171. printf("Image size:\t%d\n", imagesize);
  172. end = (char *)&buf[metasize - 1];
  173. *end = '\0';
  174. for (tmp = (char *)buf; tmp < end && strlen(tmp); tmp += strlen(tmp) + 1) {
  175. printf("Meta entry:\t%s\n", tmp);
  176. }
  177. }
  178. oseama_info_entities(seama);
  179. err_close:
  180. fclose(seama);
  181. out:
  182. return err;
  183. }
  184. /**************************************************
  185. * Create
  186. **************************************************/
  187. static ssize_t oseama_entity_append_file(FILE *seama, const char *in_path) {
  188. FILE *in;
  189. size_t bytes;
  190. ssize_t length = 0;
  191. uint8_t buf[128];
  192. in = fopen(in_path, "r");
  193. if (!in) {
  194. fprintf(stderr, "Couldn't open %s\n", in_path);
  195. return -EACCES;
  196. }
  197. while ((bytes = fread(buf, 1, sizeof(buf), in)) > 0) {
  198. if (fwrite(buf, 1, bytes, seama) != bytes) {
  199. fprintf(stderr, "Couldn't write %zu B to %s\n", bytes, seama_path);
  200. length = -EIO;
  201. break;
  202. }
  203. length += bytes;
  204. }
  205. fclose(in);
  206. return length;
  207. }
  208. static ssize_t oseama_entity_append_zeros(FILE *seama, size_t length) {
  209. uint8_t *buf;
  210. buf = malloc(length);
  211. if (!buf)
  212. return -ENOMEM;
  213. memset(buf, 0, length);
  214. if (fwrite(buf, 1, length, seama) != length) {
  215. fprintf(stderr, "Couldn't write %zu B to %s\n", length, seama_path);
  216. return -EIO;
  217. }
  218. return length;
  219. }
  220. static ssize_t oseama_entity_align(FILE *seama, size_t curr_offset, size_t alignment) {
  221. if (curr_offset & (alignment - 1)) {
  222. size_t length = alignment - (curr_offset % alignment);
  223. return oseama_entity_append_zeros(seama, length);
  224. }
  225. return 0;
  226. }
  227. static int oseama_entity_write_hdr(FILE *seama, size_t metasize, size_t imagesize) {
  228. struct seama_entity_header hdr = {};
  229. uint8_t buf[128];
  230. size_t length = imagesize;
  231. size_t bytes;
  232. MD5_CTX ctx;
  233. fseek(seama, sizeof(hdr) + metasize, SEEK_SET);
  234. MD5_Init(&ctx);
  235. while ((bytes = fread(buf, 1, oseama_min(sizeof(buf), length), seama)) > 0) {
  236. MD5_Update(&ctx, buf, bytes);
  237. length -= bytes;
  238. }
  239. MD5_Final(hdr.md5, &ctx);
  240. hdr.magic = cpu_to_be32(SEAMA_MAGIC);
  241. hdr.metasize = cpu_to_be16(metasize);
  242. hdr.imagesize = cpu_to_be32(imagesize);
  243. fseek(seama, 0, SEEK_SET);
  244. bytes = fwrite(&hdr, 1, sizeof(hdr), seama);
  245. if (bytes != sizeof(hdr)) {
  246. fprintf(stderr, "Couldn't write Seama entity header to %s\n", seama_path);
  247. return -EIO;
  248. }
  249. return 0;
  250. }
  251. static int oseama_entity(int argc, char **argv) {
  252. FILE *seama;
  253. ssize_t sbytes;
  254. size_t curr_offset = sizeof(struct seama_entity_header);
  255. size_t metasize = 0, imagesize = 0;
  256. int c;
  257. int err = 0;
  258. if (argc < 3) {
  259. fprintf(stderr, "No Seama file passed\n");
  260. err = -EINVAL;
  261. goto out;
  262. }
  263. seama_path = argv[2];
  264. seama = fopen(seama_path, "w+");
  265. if (!seama) {
  266. fprintf(stderr, "Couldn't open %s\n", seama_path);
  267. err = -EACCES;
  268. goto out;
  269. }
  270. fseek(seama, curr_offset, SEEK_SET);
  271. optind = 3;
  272. while ((c = getopt(argc, argv, "m:f:b:")) != -1) {
  273. switch (c) {
  274. case 'm':
  275. sbytes = fwrite(optarg, 1, strlen(optarg) + 1, seama);
  276. if (sbytes < 0) {
  277. fprintf(stderr, "Failed to write meta %s\n", optarg);
  278. } else {
  279. curr_offset += sbytes;
  280. metasize += sbytes;
  281. }
  282. sbytes = oseama_entity_align(seama, curr_offset, 4);
  283. if (sbytes < 0) {
  284. fprintf(stderr, "Failed to append zeros\n");
  285. } else {
  286. curr_offset += sbytes;
  287. metasize += sbytes;
  288. }
  289. break;
  290. case 'f':
  291. case 'b':
  292. break;
  293. }
  294. }
  295. optind = 3;
  296. while ((c = getopt(argc, argv, "m:f:b:")) != -1) {
  297. switch (c) {
  298. case 'm':
  299. break;
  300. case 'f':
  301. sbytes = oseama_entity_append_file(seama, optarg);
  302. if (sbytes < 0) {
  303. fprintf(stderr, "Failed to append file %s\n", optarg);
  304. } else {
  305. curr_offset += sbytes;
  306. imagesize += sbytes;
  307. }
  308. break;
  309. case 'b':
  310. sbytes = strtol(optarg, NULL, 0) - curr_offset;
  311. if (sbytes < 0) {
  312. 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));
  313. } else {
  314. sbytes = oseama_entity_append_zeros(seama, sbytes);
  315. if (sbytes < 0) {
  316. fprintf(stderr, "Failed to append zeros\n");
  317. } else {
  318. curr_offset += sbytes;
  319. imagesize += sbytes;
  320. }
  321. }
  322. break;
  323. }
  324. if (err)
  325. break;
  326. }
  327. oseama_entity_write_hdr(seama, metasize, imagesize);
  328. fclose(seama);
  329. out:
  330. return err;
  331. }
  332. /**************************************************
  333. * Extract
  334. **************************************************/
  335. static void oseama_extract_parse_options(int argc, char **argv) {
  336. int c;
  337. while ((c = getopt(argc, argv, "e:o:")) != -1) {
  338. switch (c) {
  339. case 'e':
  340. entity_idx = atoi(optarg);
  341. break;
  342. case 'o':
  343. out_path = optarg;
  344. break;
  345. }
  346. }
  347. }
  348. static int oseama_extract_entity(FILE *seama, FILE *out) {
  349. struct seama_entity_header hdr;
  350. size_t bytes, metasize, imagesize, length;
  351. uint8_t buf[1024];
  352. int i = 0;
  353. int err = 0;
  354. while ((bytes = fread(&hdr, 1, sizeof(hdr), seama)) == sizeof(hdr)) {
  355. if (be32_to_cpu(hdr.magic) != SEAMA_MAGIC) {
  356. fprintf(stderr, "Invalid Seama magic: 0x%08x\n", be32_to_cpu(hdr.magic));
  357. err = -EINVAL;
  358. break;
  359. }
  360. metasize = be16_to_cpu(hdr.metasize);
  361. imagesize = be32_to_cpu(hdr.imagesize);
  362. if (i != entity_idx) {
  363. fseek(seama, metasize + imagesize, SEEK_CUR);
  364. i++;
  365. continue;
  366. }
  367. fseek(seama, -sizeof(hdr), SEEK_CUR);
  368. length = sizeof(hdr) + metasize + imagesize;
  369. while ((bytes = fread(buf, 1, oseama_min(sizeof(buf), length), seama)) > 0) {
  370. if (fwrite(buf, 1, bytes, out) != bytes) {
  371. fprintf(stderr, "Couldn't write %zu B to %s\n", bytes, out_path);
  372. err = -EIO;
  373. break;
  374. }
  375. length -= bytes;
  376. }
  377. if (length) {
  378. fprintf(stderr, "Couldn't extract whole entity %d from %s (%zu B left)\n", entity_idx, seama_path, length);
  379. err = -EIO;
  380. break;
  381. }
  382. break;
  383. }
  384. return err;
  385. }
  386. static int oseama_extract(int argc, char **argv) {
  387. FILE *seama;
  388. FILE *out;
  389. struct seama_seal_header hdr;
  390. size_t bytes;
  391. uint16_t metasize;
  392. int err = 0;
  393. if (argc < 3) {
  394. fprintf(stderr, "No Seama file passed\n");
  395. err = -EINVAL;
  396. goto out;
  397. }
  398. seama_path = argv[2];
  399. optind = 3;
  400. oseama_extract_parse_options(argc, argv);
  401. if (entity_idx < 0) {
  402. fprintf(stderr, "No entity specified\n");
  403. err = -EINVAL;
  404. goto out;
  405. } else if (!out_path) {
  406. fprintf(stderr, "No output file specified\n");
  407. err = -EINVAL;
  408. goto out;
  409. }
  410. seama = fopen(seama_path, "r");
  411. if (!seama) {
  412. fprintf(stderr, "Couldn't open %s\n", seama_path);
  413. err = -EACCES;
  414. goto out;
  415. }
  416. out = fopen(out_path, "w");
  417. if (!out) {
  418. fprintf(stderr, "Couldn't open %s\n", out_path);
  419. err = -EACCES;
  420. goto err_close_seama;
  421. }
  422. bytes = fread(&hdr, 1, sizeof(hdr), seama);
  423. if (bytes != sizeof(hdr)) {
  424. fprintf(stderr, "Couldn't read %s header\n", seama_path);
  425. err = -EIO;
  426. goto err_close_out;
  427. }
  428. metasize = be16_to_cpu(hdr.metasize);
  429. fseek(seama, metasize, SEEK_CUR);
  430. oseama_extract_entity(seama, out);
  431. err_close_out:
  432. fclose(out);
  433. err_close_seama:
  434. fclose(seama);
  435. out:
  436. return err;
  437. }
  438. /**************************************************
  439. * Start
  440. **************************************************/
  441. static void usage() {
  442. printf("Usage:\n");
  443. printf("\n");
  444. printf("Info about Seama seal (container):\n");
  445. printf("\toseama info <file> [options]\n");
  446. printf("\t-e\t\t\t\tprint info about specified entity only\n");
  447. printf("\n");
  448. printf("Create Seama entity:\n");
  449. printf("\toseama entity <file> [options]\n");
  450. printf("\t-m meta\t\t\t\tmeta into to put in header\n");
  451. printf("\t-f file\t\t\t\tappend content from file\n");
  452. printf("\t-b offset\t\t\tappend zeros till reaching absolute offset\n");
  453. printf("\n");
  454. printf("Extract from Seama seal (container):\n");
  455. printf("\toseama extract <file> [options]\n");
  456. printf("\t-e\t\t\t\tindex of entity to extract\n");
  457. printf("\t-o file\t\t\t\toutput file\n");
  458. }
  459. int main(int argc, char **argv) {
  460. if (argc > 1) {
  461. if (!strcmp(argv[1], "info"))
  462. return oseama_info(argc, argv);
  463. else if (!strcmp(argv[1], "entity"))
  464. return oseama_entity(argc, argv);
  465. else if (!strcmp(argv[1], "extract"))
  466. return oseama_extract(argc, argv);
  467. }
  468. usage();
  469. return 0;
  470. }