diff mbox

[10/13] tools: added support to sloffs to read from /dev/slof_flash

Message ID 1465979400-2964-11-git-send-email-adrian@lisas.de
State Accepted
Headers show

Commit Message

Adrian Reber June 15, 2016, 8:29 a.m. UTC
Rewrote all code accessing the input file to not mmap it anymore,
because the crappy slof_flash driver does not support mmap but
only read/lseek.
Using read/lseek sloffs can now operate on a flash file image or
directly use the slof_flash device using the same code.

(cherry picked from commit 23fa80154b22b14147467160bd33ebc23b9275d1)

Cherry picked from https://lisas.de/~adrian/slof/slof.git/

Signed-off-by: Adrian Reber <adrian@lisas.de>
---
 tools/sloffs.c | 264 ++++++++++++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 216 insertions(+), 48 deletions(-)
diff mbox

Patch

diff --git a/tools/sloffs.c b/tools/sloffs.c
index 4db5cfe..b8faaae 100644
--- a/tools/sloffs.c
+++ b/tools/sloffs.c
@@ -66,14 +66,55 @@  struct sloffs {
 #define ALIGN64(x) (((x) + 7) & ~7)
 
 static struct sloffs *
-next_file(struct sloffs *sloffs)
+next_file_mm(struct sloffs *sloffs)
 {
 	return (struct sloffs *)((unsigned char *)sloffs +
 				 be64_to_cpu(sloffs->next));
 }
 
+static int
+next_file(const int fd, struct sloffs *sloffs)
+{
+	int ret;
+	uint64_t size;
+	uint64_t offset;
+	char *name;
+
+	offset = 0;
+
+	/* if sloffs is not all NULL we want the next file
+	 * else we just take the first file */
+	if (sloffs->name && sloffs->len && sloffs->data) {
+		offset = be64_to_cpu(sloffs->next);
+		/* we already read over the header; skip it in the seek */
+		offset -= be64_to_cpu(sloffs->data);
+		free(sloffs->name);
+		sloffs->name = NULL;
+		lseek(fd, offset, SEEK_CUR);
+	} else {
+		lseek(fd, offset, SEEK_SET);
+	}
+
+	ret = read(fd, sloffs, SLOFFS_META);
+	if (ret == -1)
+		return -1;
+	/* read the size of the header */
+	size = be64_to_cpu(sloffs->data);
+	/* get the size of the filename */
+	size -= SLOFFS_META;
+	name = malloc(size);
+
+	ret = read(fd, name, size);
+	if (ret == -1) {
+		free(name);
+		return -1;
+	}
+	sloffs->name = name;
+	return 0;
+}
+
 static struct sloffs *
-find_file(const void *data, const char *name)
+find_file_mm(const void *data, const char *name)
 {
 	struct sloffs *sloffs = (struct sloffs *)data;
 
@@ -83,20 +124,42 @@  find_file(const void *data, const char *name)
 
 		if (be64_to_cpu(sloffs->next) == 0)
 			break;
-		sloffs = next_file(sloffs);
+		sloffs = next_file_mm(sloffs);
 	}
 	return NULL;
 }
 
+static struct sloffs *
+find_file(const int fd, const char *name, struct sloffs *sloffs)
+{
+	memset(sloffs, 0, sizeof(struct sloffs));
+
+	if (next_file(fd, sloffs))
+		return NULL;
+
+	for (;;) {
+		if (!strcmp(sloffs->name, name))
+			return sloffs;
+
+		if (be64_to_cpu(sloffs->next) == 0)
+			break;
+		if (next_file(fd, sloffs))
+			return NULL;
+	}
+
+	free(sloffs->name);
+	return NULL;
+}
+
 static struct stH *
-sloffs_header(const void *data)
+sloffs_header_mm(const void *data)
 {
 	struct sloffs *sloffs;
 	struct stH *header;
 
 	/* find the "header" file with all the information about
 	 * the flash image */
-	sloffs = find_file(data, "header");
+	sloffs = find_file_mm(data, "header");
 	if (!sloffs) {
 		printf("sloffs file \"header\" not found. aborting...\n");
 		return NULL;
@@ -107,14 +170,36 @@  sloffs_header(const void *data)
 	return header;
 }
 
+static struct stH *
+sloffs_header(const int fd)
+{
+	struct sloffs file;
+	struct sloffs *sloffs;
+	struct stH *header;
+
+	header = (struct stH *)malloc(sizeof(struct stH));
+
+	/* find the "header" file with all the information about
+	 * the flash image */
+	sloffs = find_file(fd, "header", &file);
+	if (!sloffs) {
+		printf("sloffs file \"header\" not found. aborting...\n");
+		return NULL;
+	}
+
+	read(fd, header, sizeof(struct stH));
+	free(sloffs->name);
+	return header;
+}
+
 static uint64_t
-header_length(const void *data)
+header_length_mm(const void *data)
 {
 	struct sloffs *sloffs;
 
 	/* find the "header" file with all the information about
 	 * the flash image */
-	sloffs = find_file(data, "header");
+	sloffs = find_file_mm(data, "header");
 	if (!sloffs) {
 		printf("sloffs file \"header\" not found. aborting...\n");
 		return 0;
@@ -122,6 +207,23 @@  header_length(const void *data)
 	return be64_to_cpu(sloffs->len);
 }
 
+static uint64_t
+header_length(const int fd)
+{
+	struct sloffs file;
+	struct sloffs *sloffs;
+
+	/* find the "header" file with all the information about
+	 * the flash image */
+	sloffs = find_file(fd, "header", &file);
+	if (!sloffs) {
+		printf("sloffs file \"header\" not found. aborting...\n");
+		return 0;
+	}
+
+	free(sloffs->name);
+	return be64_to_cpu(sloffs->len);
+}
 
 static void
 update_modification_time(struct stH *header)
@@ -146,20 +248,40 @@  static void
 update_crc(void *data)
 {
 	uint64_t crc;
-	struct stH *header = sloffs_header(data);
+	struct stH *header = sloffs_header_mm(data);
 	uint64_t len = be64_to_cpu(header->flashlen);
 
 	/* calculate header CRC */
 	header->ui64CRC = 0;
-	crc = checkCRC(data, header_length(data), 0);
+	crc = checkCRC(data, header_length_mm(data), 0);
 	header->ui64CRC = cpu_to_be64(crc);
 	/* calculate flash image CRC */
 	crc = checkCRC(data, len, 0);
 	*(uint64_t *)(data + len - 8) = cpu_to_be64(crc);
 }
 
+static uint64_t
+check_image_crc(const int fd, uint64_t len)
+{
+	uint64_t crc;
+	uint64_t i;
+	uint64_t read_bytes;
+	unsigned char buffer[4096];
+
+	lseek(fd, 0, SEEK_SET);
+	crc = 0;
+	read_bytes = 0;
+	while (read_bytes < len) {
+		i = read(fd, buffer, 4096);
+		read_bytes += i;
+		if (read_bytes > len)
+			i -= read_bytes - len;
+		crc = calCRCword(buffer, i, cpu_to_be64(crc));
+	}
+	return crc;
+}
 static void
-sloffs_append(const void *data, const char *name, const char *dest)
+sloffs_append(const int file, const char *name, const char *dest)
 {
 	void *append;
 	unsigned char *write_data;
@@ -171,6 +293,8 @@  sloffs_append(const void *data, const char *name, const char *dest)
 	uint64_t new_len;
 	struct sloffs *sloffs;
 	struct sloffs new_file;
+	uint64_t read_len;
+	int i;
 
 	fd = open(name, O_RDONLY);
 
@@ -181,7 +305,7 @@  sloffs_append(const void *data, const char *name, const char *dest)
 
 	fstat(fd, &stat);
 	append = mmap(NULL, stat.st_size, PROT_READ, MAP_SHARED, fd, 0);
-	header = sloffs_header(data);
+	header = sloffs_header(file);
 
 	if (!header)
 		return;
@@ -216,9 +340,22 @@  sloffs_append(const void *data, const char *name, const char *dest)
 		exit(1);
 	}
 
-	write_data = memcpy(write_start, data, be64_to_cpu(header->flashlen));
+	lseek(file, 0, SEEK_SET);
+	write_data = write_start;
+	read_len = be64_to_cpu(header->flashlen);
+	for (;;) {
+		i = read(file, write_data, read_len);
+		if (i < 0) {
+			perror("read");
+			exit(1);
+		}
+		if (i == 0)
+			break;
+		write_data += i;
+		read_len -= i;
+	}
 	/* -8: overwrite old CRC */
-	write_data += be64_to_cpu(header->flashlen) - 8;
+	write_data = write_start + be64_to_cpu(header->flashlen) - 8;
 	memcpy(write_data, &new_file, SLOFFS_META);
 	write_data += SLOFFS_META;
 	/* write the filename */
@@ -233,7 +370,7 @@  sloffs_append(const void *data, const char *name, const char *dest)
 	for (;;) {
 		if (be64_to_cpu(sloffs->next) == 0)
 			break;
-		sloffs = next_file(sloffs);
+		sloffs = next_file_mm(sloffs);
 	}
 	/* get the distance to the next file */
 	sloffs->next = ALIGN64(be64_to_cpu(sloffs->len));
@@ -250,8 +387,9 @@  sloffs_append(const void *data, const char *name, const char *dest)
 
 	sloffs->next = cpu_to_be64(sloffs->next);
 
+	free(header);
 	/* update new length of flash image */
-	header = sloffs_header(write_start);
+	header = sloffs_header_mm(write_start);
 	header->flashlen = cpu_to_be64(new_len);
 
 	update_modification_time(header);
@@ -265,14 +403,16 @@  sloffs_append(const void *data, const char *name, const char *dest)
 }
 
 static void
-sloffs_dump(const void *data)
+sloffs_dump(const int fd)
 {
+	void *data;
 	struct stH *header;
-	struct sloffs *sloffs;
+	struct sloffs file;
 	int i;
 	uint64_t crc;
+	uint64_t header_len;
 
-	header = sloffs_header(data);
+	header = sloffs_header(fd);
 
 	if (!header)
 		return;
@@ -319,7 +459,13 @@  sloffs_dump(const void *data)
 	 * which could be easily obtained with sizeof(struct stH);
 	 * the actual size can only be obtained from the filesystem
 	 * meta information */
-	crc = calCRCword((unsigned char *)data, header_length(data), 0);
+	header_len = header_length(fd);
+	/* no copy the header to memory to crc test it */
+	data = malloc(header_len);
+	lseek(fd, 0, SEEK_SET);
+	read(fd, data, header_len);
+	crc = calCRCword((unsigned char *)data, header_length(fd), 0);
+	free(data);
 	if (!crc)
 		printf("[OK]");
 	else
@@ -327,10 +473,13 @@  sloffs_dump(const void *data)
 	printf("\n");
 
 	crc = be64_to_cpu(header->flashlen);
-	crc = *(uint64_t *)(unsigned char *)(data + crc - 8);
+	/* move to the CRC */
+	lseek(fd, crc - 8, SEEK_SET);
+	/* read it */
+	read(fd, &crc, 8);
 	crc = be64_to_cpu(crc);
 	printf("  Image CRC   : 0x%016llx CRC check: ", crc);
-	crc = calCRCword((unsigned char *)data, be64_to_cpu(header->flashlen), 0);
+	crc = check_image_crc(fd, be64_to_cpu(header->flashlen));
 	if (!crc)
 		printf("[OK]");
 	else
@@ -338,37 +487,53 @@  sloffs_dump(const void *data)
 	printf("\n");
 
 	/* count number of files */
-	sloffs = (struct sloffs *)data;
 	i = 0;
+	memset(&file, 0, sizeof(struct sloffs));
+	if (next_file(fd, &file))
+		return;
 	for (;;) {
 		i++;
-		if (be64_to_cpu(sloffs->next) == 0)
+
+		if (be64_to_cpu(file.next) == 0)
 			break;
-		sloffs = next_file(sloffs);
+		if (next_file(fd, &file))
+			return;
 	}
+	free(file.name);
 	printf("  Files       : %d\n", i);
+	free(header);
 }
 
 static void
-sloffs_list(const void *data)
+sloffs_list(const int fd)
 {
-	struct sloffs *sloffs = (struct sloffs *)data;
 	const char *name_header = "File Name";
 	unsigned int i;
 	unsigned int max;
 	unsigned int line;
+	struct sloffs file;
+	uint64_t offset = 0;
+
+	memset(&file, 0, sizeof(struct sloffs));
+
+	if (next_file(fd, &file))
+		return;
 
 	/* find largest name */
-	max = strlen(name_header);;
+	max = strlen(name_header);
 	for (;;) {
-		if (max < strlen((char *)&sloffs->name))
-			max = strlen((char *)&sloffs->name);
+		if (max < strlen((char *)file.name))
+			max = strlen((char *)file.name);
 
-		if (be64_to_cpu(sloffs->next) == 0)
+		if (be64_to_cpu(file.next) == 0)
 			break;
-		sloffs = next_file(sloffs);
+		if (next_file(fd, &file))
+			return;
 	}
 
+	free(file.name);
+
+
 	/* have at least two spaces between name and size column */
 	max += 2;
 
@@ -384,21 +549,28 @@  sloffs_list(const void *data)
 		printf("=");
 	printf("\n");
 
-	sloffs = (struct sloffs *)data;
+	memset(&file, 0, sizeof(struct sloffs));
+
+	if (next_file(fd, &file))
+		return;
+
 	for (;;) {
-		printf("   0x%08x", (void *)sloffs - (void *)data);
-		printf("  %s", (char *)&sloffs->name);
-		for (i = 0; i < max - strlen((char *)&sloffs->name); i++)
+		printf("   0x%08llx", offset);
+		offset += be64_to_cpu(file.next);
+		printf("  %s", file.name);
+		for (i = 0; i < max - strlen(file.name); i++)
 			printf(" ");
 
-		printf("%07lld ", be64_to_cpu(sloffs->len));
-		printf("(0x%06llx)", be64_to_cpu(sloffs->len));
-		printf("  0x%08llx\n", be64_to_cpu(sloffs->flags));
+		printf("%07lld ", be64_to_cpu(file.len));
+		printf("(0x%06llx)", be64_to_cpu(file.len));
+		printf("  0x%08llx\n", be64_to_cpu(file.flags));
 
-		if (be64_to_cpu(sloffs->next) == 0)
+		if (be64_to_cpu(file.next) == 0)
 			break;
-		sloffs = next_file(sloffs);
+		if (next_file(fd, &file))
+			return;
 	}
+	free(file.name);
 }
 
 static void
@@ -426,8 +598,6 @@  int
 main(int argc, char *argv[])
 {
 	int fd;
-	void *file;
-	struct stat stat;
 	const struct option loption[] = {
 		{ "help", 0, NULL, 'h' },
 		{ "list", 0, NULL, 'l' },
@@ -480,15 +650,14 @@  main(int argc, char *argv[])
 		exit(1);
 	}
 
-	fstat(fd, &stat);
-	file = mmap(NULL, stat.st_size, PROT_READ, MAP_SHARED, fd, 0);
+	lseek(fd, 0, SEEK_SET);
 
 	switch (mode) {
 	case 'l':
-		sloffs_list(file);
+		sloffs_list(fd);
 		break;
 	case 'd':
-		sloffs_dump(file);
+		sloffs_dump(fd);
 		break;
 	case 'a':
 		if (!output) {
@@ -496,13 +665,12 @@  main(int argc, char *argv[])
 				"sloffs requires -o, --output=FILENAME when in append mode\n\n");
 			usage();
 		}
-		sloffs_append(file, append, output);
+		sloffs_append(fd, append, output);
 		break;
 	}
 
 	free(append);
 	free(output);
-	munmap(file, stat.st_size);
 	close(fd);
 	return 0;
 }