diff mpffs/common.c @ 29:e96d6862cec0

mpffs-rdutils code started
author Michael Spacefalcon <msokolov@ivan.Harhan.ORG>
date Sun, 30 Jun 2013 05:16:23 +0000
parents
children 9c3c5a572b57
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mpffs/common.c	Sun Jun 30 05:16:23 2013 +0000
@@ -0,0 +1,264 @@
+/*
+ * This module contains the code that will be common between mpffs-cat,
+ * mpffs-ls and mpffs-xtr.
+ */
+
+#include <sys/types.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <endian.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "types.h"
+#include "struct.h"
+
+u8 mpffs_header[6] = {'F', 'f', 's', '#', 0x10, 0x02};
+
+char *imgfile;
+u32 eraseblk_size;
+int total_blocks;
+u32 total_ffs_size;
+u8 *image, *indexblk;
+int index_blk_num, root_node_no;
+int verbose;
+
+/*
+ * The following function is used to verify that the specified or computed
+ * flash erase block size is a power of 2.
+ */
+count_ones(word)
+	u32 word;
+{
+	int count;
+
+	for (count = 0; word; word >>= 1)
+		count += word & 1;
+	return count;
+}
+
+eraseblk_size_reasonable()
+{
+	if (count_ones(eraseblk_size) != 1 || eraseblk_size < 16384) {
+		fprintf(stderr, "0x%lx is an unreasonable erase block size\n",
+			(u_long) eraseblk_size);
+		exit(1);
+	}
+}
+
+read_img_file()
+{
+	int fd;
+	struct stat st;
+
+	fd = open(imgfile, O_RDONLY);
+	if (fd < 0) {
+		perror(imgfile);
+		exit(1);
+	}
+	fstat(fd, &st);
+	if (!S_ISREG(st.st_mode)) {
+		fprintf(stderr, "%s is not a regular file\n", imgfile);
+		exit(1);
+	}
+	if (!eraseblk_size && !total_blocks) {
+		switch (st.st_size) {
+		case 0x70000:
+			/* assume Closedmoko */
+			eraseblk_size = 0x10000;
+			total_blocks = 7;
+			break;
+		case 0x480000:
+			/* assume Pirelli */
+			eraseblk_size = 0x40000;
+			total_blocks = 18;
+			break;
+		default:
+noauto:			fprintf(stderr,
+	"cannot intuit the flash parameters of %s: use -e and -n options\n",
+				imgfile);
+			exit(1);
+		}
+	} else if (!total_blocks) {
+		total_blocks = st.st_size / eraseblk_size;
+		if (!total_blocks || total_blocks * eraseblk_size != st.st_size)
+			goto noauto;
+	} else if (!eraseblk_size) {
+		if (total_blocks * 0x10000 == st.st_size)
+			eraseblk_size = 0x10000;
+		else if (total_blocks * 0x40000 == st.st_size)
+			eraseblk_size = 0x40000;
+		else
+			goto noauto;
+	}
+	total_ffs_size = eraseblk_size * total_blocks;
+	if (st.st_size < total_ffs_size) {
+		fprintf(stderr, "%s has fewer than 0x%x bytes\n", imgfile,
+			total_ffs_size);
+		exit(1);
+	}
+	image = malloc(total_ffs_size);
+	if (!image) {
+		perror("malloc");
+		exit(1);
+	}
+	read(fd, image, total_ffs_size);
+	close(fd);
+}
+
+find_index_block()
+{
+	int i, abcnt;
+	u8 *ptr;
+
+	if (index_blk_num) {
+		if (index_blk_num < 0 || index_blk_num >= total_blocks) {
+			fprintf(stderr,
+				"invalid block # given with the -a option\n");
+			exit(1);
+		}
+		ptr = image + index_blk_num * eraseblk_size;
+		if (bcmp(ptr, mpffs_header, 6) || ptr[8] != 0xAB) {
+			fprintf(stderr,
+			"no MPFFS index found at the specified block #%d\n",
+				index_blk_num);
+			exit(1);
+		}
+		indexblk = ptr;
+		return(0);
+	}
+	abcnt = 0;
+	for (ptr = image, i = 0; i < total_blocks; i++, ptr += eraseblk_size) {
+		if (bcmp(ptr, mpffs_header, 6)) {
+			fprintf(stderr,
+		"warning: no MPFFS signature in erase block #%d (offset %x)\n",
+				i, ptr - image);
+			continue;
+		}
+		switch (ptr[8]) {
+		case 0xAB:
+			if (verbose)
+				printf(
+			"Found AB index in erase block #%d (offset %x)\n",
+					i, ptr - image);
+			index_blk_num = i;
+			indexblk = ptr;
+			abcnt++;
+			continue;
+		case 0xBD:
+		case 0xBF:
+			continue;
+		}
+		fprintf(stderr,
+		"warning: non-understood block type %02X at offset %x\n",
+			ptr[8], ptr - image);
+	}
+	if (!indexblk) {
+		fprintf(stderr, "could not find an MPFFS index block in %s\n",
+			imgfile);
+		exit(1);
+	}
+	if (abcnt > 1) {
+		fprintf(stderr, "found more than one AB block; use -a\n");
+		exit(1);
+	}
+	return(0);
+}
+
+get_index_entry(oi)
+	struct objinfo *oi;
+{
+	struct mpffs_index *le;
+
+	if (oi->entryno >= (eraseblk_size >> 4)) {
+		fprintf(stderr,
+		"error: index block pointer %x past the erase block size!\n",
+			oi->entryno);
+		exit(1);
+	}
+	le = (struct mpffs_index *) indexblk + oi->entryno;
+	oi->idxrec = le;
+	oi->len = le16toh(le->len);
+	oi->type = le->type;
+	oi->descend = le16toh(le->descend);
+	oi->sibling = le16toh(le->sibling);
+	return(0);
+}
+
+validate_chunk(oi)
+	struct objinfo *oi;
+{
+	u32 dptr;
+
+	if (oi->len & 0xF || !oi->len) {
+		fprintf(stderr, "index entry #%x: invalid chunk length\n",
+			oi->entryno);
+		exit(1);
+	}
+	dptr = le32toh(oi->idxrec->dataptr);
+	if (dptr > 0x0FFFFFFF) {
+invdptr:	fprintf(stderr, "index entry #%x: invalid data pointer\n",
+			oi->entryno);
+		exit(1);
+	}
+	dptr <<= 4;
+	if (dptr >= total_img_size - oi->len)
+		goto invdptr;
+	oi->offset = dptr;
+	oi->dataptr = image + dptr;
+	return(0);
+}
+
+validate_obj_name(oi)
+	struct objinfo *oi;
+{
+	u8 *cp;
+	int cnt;
+
+	for (cp = oi->dataptr, cnt = 0; ; cp++, cnt++) {
+		if (cnt >= oi->len) {
+			fprintf(stderr,
+		"object at index %x: name expected at %x: length overrun\n",
+				oi->entryno, oi->offset);
+			exit(1);
+		}
+		if (!*cp)
+			break;
+		if (*cp < '!' || *cp > '~') {
+			fprintf(stderr,
+		"object at index %x: name expected at %x: bad character\n",
+				oi->entryno, oi->offset);
+			exit(1);
+		}
+	}
+	if (!cnt) {
+		fprintf(stderr,
+		"object at index %x: name expected at %x: null string\n",
+			oi->entryno, oi->offset);
+		exit(1);
+	}
+	return(0);
+}
+
+u8 *
+find_end_of_chunk(ch)
+	struct objinfo *ch;
+{
+	u8 *p;
+	int i;
+
+	p = ch->dataptr + ch->len;
+	for (i = 1; i <= 16; i++) {
+		if (!p[-i])
+			return(p - i);
+		if (p[-1] != 0xFF)
+			break;
+	}
+	fprintf(stderr,
+	"chunk starting at %x (index entry %x): no valid termination found\n",
+		ch->offset, ch->entryno);
+	exit(1);
+}