From ab6462dd56829f5c8344bc2f97ca448e2875e64d Mon Sep 17 00:00:00 2001
From: Rafał Miłecki <zajec5@gmail.com>
Date: Sun, 12 Apr 2015 11:46:11 +0000
Subject: otrx: support for extracting partitions
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Rafał Miłecki <zajec5@gmail.com>

SVN-Revision: 45390
---
 package/utils/otrx/src/otrx.c | 128 +++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 127 insertions(+), 1 deletion(-)

diff --git a/package/utils/otrx/src/otrx.c b/package/utils/otrx/src/otrx.c
index b3cfdfe55b..2f305cf484 100644
--- a/package/utils/otrx/src/otrx.c
+++ b/package/utils/otrx/src/otrx.c
@@ -27,6 +27,7 @@
 
 #define TRX_MAGIC			0x30524448
 #define TRX_FLAGS_OFFSET		12
+#define TRX_MAX_PARTS			3
 
 struct trx_header {
 	uint32_t magic;
@@ -40,12 +41,14 @@ struct trx_header {
 enum mode {
 	MODE_UNKNOWN,
 	MODE_CHECK,
+	MODE_EXTRACT,
 };
 
 enum mode mode = MODE_UNKNOWN;
 
 char *trx_path;
 size_t trx_offset = 0;
+char *partition[TRX_MAX_PARTS] = {};
 
 /**************************************************
  * CRC32
@@ -195,6 +198,107 @@ out:
 	return err;
 }
 
+/**************************************************
+ * Extract
+ **************************************************/
+
+static int otrx_extract_copy(FILE *trx, size_t offset, size_t length, char *out_path) {
+	FILE *out;
+	size_t bytes;
+	uint8_t *buf;
+	int err = 0;
+
+	out = fopen(out_path, "w");
+	if (!out) {
+		fprintf(stderr, "Couldn't open %s\n", out_path);
+		err = -EACCES;
+		goto out;
+	}
+
+	buf = malloc(length);
+	if (!buf) {
+		fprintf(stderr, "Couldn't alloc %zu B buffer\n", length);
+		err =  -ENOMEM;
+		goto err_close;
+	}
+
+	fseek(trx, offset, SEEK_SET);
+	bytes = fread(buf, 1, length, trx);
+	if (bytes != length) {
+		fprintf(stderr, "Couldn't read %zu B of data from %s\n", length, trx_path);
+		err =  -ENOMEM;
+		goto err_free_buf;
+	};
+
+	bytes = fwrite(buf, 1, length, out);
+	if (bytes != length) {
+		fprintf(stderr, "Couldn't write %zu B to %s\n", length, out_path);
+		err =  -ENOMEM;
+		goto err_free_buf;
+	}
+
+	printf("Extracted 0x%zx bytes into %s\n", length, out_path);
+
+err_free_buf:
+	free(buf);
+err_close:
+	fclose(out);
+out:
+	return err;
+}
+
+static int otrx_extract() {
+	FILE *trx;
+	struct trx_header hdr;
+	size_t bytes;
+	int i;
+	int err = 0;
+
+	trx = fopen(trx_path, "r");
+	if (!trx) {
+		fprintf(stderr, "Couldn't open %s\n", trx_path);
+		err = -EACCES;
+		goto out;
+	}
+
+	fseek(trx, trx_offset, SEEK_SET);
+	bytes = fread(&hdr, 1, sizeof(hdr), trx);
+	if (bytes != sizeof(hdr)) {
+		fprintf(stderr, "Couldn't read %s header\n", trx_path);
+		err =  -EIO;
+		goto err_close;
+	}
+
+	if (le32_to_cpu(hdr.magic) != TRX_MAGIC) {
+		fprintf(stderr, "Invalid TRX magic: 0x%08x\n", le32_to_cpu(hdr.magic));
+		err =  -EINVAL;
+		goto err_close;
+	}
+
+	for (i = 0; i < TRX_MAX_PARTS; i++) {
+		size_t length;
+
+		if (!partition[i])
+			continue;
+		if (!hdr.offset[i]) {
+			printf("TRX doesn't contain partition %d, can't extract %s\n", i + 1, partition[i]);
+			continue;
+		}
+
+		if (i + 1 >= TRX_MAX_PARTS || !hdr.offset[i + 1])
+			length = le32_to_cpu(hdr.length) - le32_to_cpu(hdr.offset[i]);
+		else
+			length = le32_to_cpu(hdr.offset[i + 1]) - le32_to_cpu(hdr.offset[i]);
+
+		otrx_extract_copy(trx, trx_offset + le32_to_cpu(hdr.offset[i]), length, partition[i]);
+	}
+
+err_close:
+	fclose(trx);
+out:
+	return err;
+}
+
 /**************************************************
  * Start
  **************************************************/
@@ -202,15 +306,28 @@ out:
 static void parse_options(int argc, char **argv) {
 	int c;
 
-	while ((c = getopt(argc, argv, "c:o:")) != -1) {
+	while ((c = getopt(argc, argv, "c:e:o:1:2:3:")) != -1) {
 		switch (c) {
 		case 'c':
 			mode = MODE_CHECK;
 			trx_path = optarg;
 			break;
+		case 'e':
+			mode = MODE_EXTRACT;
+			trx_path = optarg;
+			break;
 		case 'o':
 			trx_offset = atoi(optarg);
 			break;
+		case '1':
+			partition[0] = optarg;
+			break;
+		case '2':
+			partition[1] = optarg;
+			break;
+		case '3':
+			partition[2] = optarg;
+			break;
 		}
 	}
 }
@@ -221,6 +338,13 @@ static void usage() {
 	printf("Checking TRX file:\n");
 	printf("\t-c file\t\tcheck if file is a valid TRX\n");
 	printf("\t-o offset\toffset of TRX data in file (default: 0)\n");
+	printf("\n");
+	printf("Extracting from TRX file:\n");
+	printf("\t-e file\t\tfile with TRX to extract from\n");
+	printf("\t-o offset\toffset of TRX data in file (default: 0)\n");
+	printf("\t-1 file\t\tfile to extract 1st partition to (optional)\n");
+	printf("\t-2 file\t\tfile to extract 2nd partition to (optional)\n");
+	printf("\t-3 file\t\tfile to extract 3rd partition to (optional)\n");
 }
 
 int main(int argc, char **argv) {
@@ -229,6 +353,8 @@ int main(int argc, char **argv) {
 	switch (mode) {
 	case MODE_CHECK:
 		return otrx_check();
+	case MODE_EXTRACT:
+		return otrx_extract();
 	default:
 		usage();
 	}
-- 
cgit v1.2.3