changeset 705:12ae93940467

tiffs-mkfs program written, compiles
author Mychaela Falconia <falcon@freecalypso.org>
date Wed, 20 May 2020 06:55:58 +0000
parents dacd9fdc392a
children 850bf712c1fc
files .hgignore ffstools/tiffs-mkfs/Makefile ffstools/tiffs-mkfs/ffsparam.c ffstools/tiffs-mkfs/globals.c ffstools/tiffs-mkfs/globals.h ffstools/tiffs-mkfs/input.c ffstools/tiffs-mkfs/main.c ffstools/tiffs-mkfs/output.c ffstools/tiffs-mkfs/struct.h
diffstat 9 files changed, 592 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/.hgignore	Thu May 07 03:39:55 2020 +0000
+++ b/.hgignore	Wed May 20 06:55:58 2020 +0000
@@ -15,6 +15,7 @@
 ^ffstools/tiaud/compile$
 ^ffstools/tiaud/decomp$
 ^ffstools/tiaud/mkvol$
+^ffstools/tiffs-mkfs/tiffs-mkfs$
 ^ffstools/tiffs-rd/tiffs$
 ^ffstools/tiffs-wrappers/mokoffs$
 ^ffstools/tiffs-wrappers/pirffs$
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ffstools/tiffs-mkfs/Makefile	Wed May 20 06:55:58 2020 +0000
@@ -0,0 +1,23 @@
+CC=	gcc
+CFLAGS=	-O2
+PROG=	tiffs-mkfs
+OBJS=	ffsparam.o globals.o input.o main.o output.o
+HDRS=	globals.h struct.h
+
+INSTALL_PREFIX=	/opt/freecalypso
+
+INSTBIN=${INSTALL_PREFIX}/bin
+
+all:	${PROG}
+
+${PROG}:	${OBJS}
+	${CC} -o $@ ${OBJS}
+
+${OBJS}:	${HDRS}
+
+install:	${PROG}
+	mkdir -p ${INSTBIN}
+	install -c ${PROG} ${INSTBIN}
+
+clean:
+	rm -f ${PROG} *.o *.out *errs
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ffstools/tiffs-mkfs/ffsparam.c	Wed May 20 06:55:58 2020 +0000
@@ -0,0 +1,84 @@
+#include <sys/types.h>
+#include <sys/param.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include "struct.h"
+#include "globals.h"
+
+void
+parse_org_arg(arg)
+	char *arg;
+{
+	char *cp;
+
+	cp = index(arg, 'x');
+	if (!cp || !isdigit(cp[1]) || !isdigit(arg[0])) {
+		fprintf(stderr,
+		"error: TIFFS organization argument \"%s\" is invalid\n", arg);
+		exit(1);
+	}
+	*cp++ = '\0';
+	if (!strcmp(arg, "8"))
+		ffs_sector_size = 0x2000;
+	else if (!strcmp(arg, "16"))
+		ffs_sector_size = 0x4000;
+	else if (!strcmp(arg, "32"))
+		ffs_sector_size = 0x8000;
+	else if (!strcmp(arg, "64"))
+		ffs_sector_size = 0x10000;
+	else if (!strcmp(arg, "128"))
+		ffs_sector_size = 0x20000;
+	else if (!strcmp(arg, "256"))
+		ffs_sector_size = 0x40000;
+	else {
+		fprintf(stderr,
+			"error: \"%s\" is not a recognized flash sector size\n",
+			arg);
+		exit(1);
+	}
+	ffs_nsectors = atoi(cp);
+	if (ffs_nsectors < 3 || ffs_nsectors > 128) {
+		fprintf(stderr,
+		"error: \"%s\" is not a reasonable number of FFS sectors\n",
+			cp);
+		exit(1);
+	}
+}
+
+void
+preen_chunk_size_max()
+{
+	if (chunk_size_max) {
+		if (chunk_size_max > ffs_sector_size / 2) {
+			fprintf(stderr,
+		"error: max chunk size specified with -c is too large\n");
+			exit(1);
+		}
+		return;
+	}
+	/* default matching TI's code */
+	if (ffs_sector_size * ffs_nsectors > 1024*1024)
+		chunk_size_max = 8192;
+	else if (ffs_sector_size / 8 < 2048)
+		chunk_size_max = ffs_sector_size / 8;
+	else
+		chunk_size_max = 2048;
+}
+
+void
+preen_block_files_max()
+{
+	unsigned journal_size;
+
+	if (block_files_max)
+		return;
+	/* default matching TI's code */
+	journal_size = ffs_sector_size >> 4;
+	if (journal_size < 1024)
+		journal_size = 1024;
+	block_files_max = (journal_size >> 4) - 6;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ffstools/tiffs-mkfs/globals.c	Wed May 20 06:55:58 2020 +0000
@@ -0,0 +1,22 @@
+/*
+ * Definitions of global variables for the tiffs-mkfs program.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <stdint.h>
+#include "struct.h"
+
+unsigned ffs_sector_size, ffs_nsectors;
+char *format_name;
+unsigned chunk_size_max, block_files_max;
+u_char *inode_block, *data_block;
+struct tiffs_inode *inode_array;
+unsigned inode_fill_level, data_fill_level, objects_in_block;
+unsigned blocks_written;
+
+char *input_host_dir;
+struct tree_object root;
+
+char *output_filename;
+int output_fd;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ffstools/tiffs-mkfs/globals.h	Wed May 20 06:55:58 2020 +0000
@@ -0,0 +1,18 @@
+/*
+ * extern declarations of global variables
+ */
+
+extern unsigned ffs_sector_size, ffs_nsectors;
+extern unsigned ffs_nsectors;
+extern char *format_name;
+extern unsigned chunk_size_max, block_files_max;
+extern u_char *inode_block, *data_block;
+extern struct tiffs_inode *inode_array;
+extern unsigned inode_fill_level, data_fill_level, objects_in_block;
+extern unsigned blocks_written;
+
+extern char *input_host_dir;
+extern struct tree_object root;
+
+extern char *output_filename;
+extern int output_fd;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ffstools/tiffs-mkfs/input.c	Wed May 20 06:55:58 2020 +0000
@@ -0,0 +1,112 @@
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <unistd.h>
+#include "struct.h"
+#include "globals.h"
+
+void
+read_dir_level(dto, srcpath, depth)
+	struct tree_object *dto;
+	char *srcpath;
+{
+	DIR *rdd;
+	struct dirent *dirent;
+	char hostpath_child[MAXPATHLEN];
+	struct stat hst;
+	struct tree_object *cto;
+	unsigned nchildren;
+
+	dto->is_dir = 1;
+	rdd = opendir(srcpath);
+	if (!rdd) {
+		perror(srcpath);
+		exit(1);
+	}
+	nchildren = 0;
+	while (dirent = readdir(rdd)) {
+		if (dirent->d_name[0] == '.')
+			continue;
+		if (strlen(dirent->d_name) > MAX_FN_COMPONENT) {
+			fprintf(stderr,
+		"error: \"%s\" in %s exceeds the FFS component name limit\n",
+				dirent->d_name, srcpath);
+			exit(1);
+		}
+		if (nchildren >= MAX_DIR_ENTRIES) {
+			fprintf(stderr, "error: %s has too many children\n",
+				srcpath);
+			exit(1);
+		}
+		cto = malloc(sizeof(struct tree_object));
+		if (!cto) {
+			perror("malloc of struct tree_object");
+			exit(1);
+		}
+		strcpy(cto->name, dirent->d_name);
+		dto->u.d.children[nchildren++] = cto;
+		if (strlen(srcpath) + strlen(dirent->d_name) + 2 >
+		    sizeof hostpath_child) {
+			fprintf(stderr,
+				"error: host side pathname buffer overflow\n");
+			exit(1);
+		}
+		sprintf(hostpath_child, "%s/%s", srcpath, dirent->d_name);
+		if (lstat(hostpath_child, &hst) < 0) {
+			perror(hostpath_child);
+			exit(1);
+		}
+		switch (hst.st_mode & S_IFMT) {
+		case S_IFREG:
+			cto->is_dir = 0;
+			strcpy(cto->u.f.host_pathname, hostpath_child);
+			break;
+		case S_IFDIR:
+			if (depth >= MAX_DIR_NEST-1) {
+				fprintf(stderr,
+				"error: directory nesting too deep at %s\n",
+					hostpath_child);
+				exit(1);
+			}
+			read_dir_level(cto, hostpath_child, depth + 1);
+			break;
+		default:
+			fprintf(stderr,
+			"error: %s is neither a regular file nor a directory\n",
+				hostpath_child);
+			exit(1);
+		}
+	}
+	closedir(rdd);
+	dto->u.d.nchildren = nchildren;
+}
+
+static int
+compare_func(p1, p2)
+	struct tree_object **p1, **p2;
+{
+	return strcmp((*p1)->name, (*p2)->name);
+}
+
+void
+sort_dir_level(dto)
+	struct tree_object *dto;
+{
+	unsigned n;
+	struct tree_object *cto;
+
+	if (dto->u.d.nchildren > 1)
+		qsort(dto->u.d.children, dto->u.d.nchildren,
+			sizeof(struct tree_object *), compare_func);
+	for (n = 0; n < dto->u.d.nchildren; n++) {
+		cto = dto->u.d.children[n];
+		if (cto->is_dir)
+			sort_dir_level(cto);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ffstools/tiffs-mkfs/main.c	Wed May 20 06:55:58 2020 +0000
@@ -0,0 +1,67 @@
+#include <sys/types.h>
+#include <sys/param.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include "struct.h"
+#include "globals.h"
+
+void
+process_cmdline(argc, argv)
+	char **argv;
+{
+	extern int optind;
+	extern char *optarg;
+	int c;
+
+	while ((c = getopt(argc, argv, "c:f:m:")) != EOF)
+		switch (c) {
+		case 'c':
+			chunk_size_max = strtoul(optarg, 0, 0);
+			continue;
+		case 'f':
+			if (*optarg != '/') {
+				fprintf(stderr,
+				"error: format name must begin with \'/\'\n");
+				exit(1);
+			}
+			format_name = optarg;
+			continue;
+		case 'm':
+			block_files_max = strtoul(optarg, 0, 0);
+			continue;
+		default:
+usage:			fprintf(stderr,
+			"usage: %s [options] <org> <srcdir> <outfile>\n",
+				argv[0]);
+			exit(1);
+		}
+	if (argc - optind != 3)
+		goto usage;
+	parse_org_arg(argv[optind]);
+	input_host_dir = argv[optind+1];
+	output_filename = argv[optind+2];
+}
+
+main(argc, argv)
+	char **argv;
+{
+	process_cmdline(argc, argv);
+	if (!format_name)
+		format_name = "/";
+	preen_chunk_size_max();
+	preen_block_files_max();
+	/* input phase */
+	read_dir_level(&root, input_host_dir, 0);
+	sort_dir_level(&root);
+	/* output phase */
+	prepare_output_buffers();
+	open_output_file();
+	create_root_dir();
+	process_dir_level(&root);
+	finish_output();
+	close(output_fd);
+	exit(0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ffstools/tiffs-mkfs/output.c	Wed May 20 06:55:58 2020 +0000
@@ -0,0 +1,227 @@
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/file.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <endian.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <unistd.h>
+#include "struct.h"
+#include "globals.h"
+
+u_char tiffs_header[6] = {'F', 'f', 's', '#', 0x10, 0x02};
+
+void
+prepare_output_buffers()
+{
+	inode_block = malloc(ffs_sector_size);
+	if (!inode_block) {
+		perror("malloc of inode block buffer");
+		exit(1);
+	}
+	memset(inode_block, 0xFF, ffs_sector_size);
+	bcopy(tiffs_header, inode_block, 6);
+	inode_block[8] = 0xAB;
+	inode_array = (struct tiffs_inode *) inode_block;
+	inode_fill_level = 1;
+
+	data_block = malloc(ffs_sector_size);
+	if (!data_block) {
+		perror("malloc of data block buffer");
+		exit(1);
+	}
+	memset(data_block, 0xFF, ffs_sector_size);
+	bcopy(tiffs_header, data_block, 6);
+	data_block[8] = 0xBD;
+	data_fill_level = 0x10;
+	objects_in_block = 0;
+}
+
+void
+open_output_file()
+{
+	output_fd = open(output_filename, O_WRONLY|O_CREAT|O_TRUNC, 0666);
+	if (output_fd < 0) {
+		perror(output_filename);
+		exit(1);
+	}
+	lseek(output_fd, (off_t) ffs_sector_size, SEEK_SET);
+}
+
+void
+write_out_block(buf)
+	u_char *buf;
+{
+	if (write(output_fd, buf, ffs_sector_size) != ffs_sector_size) {
+		perror("write of sector bits to output file");
+		exit(1);
+	}
+}
+
+void
+flush_data_block()
+{
+	write_out_block(data_block);
+	blocks_written++;
+	memset(data_block + 0x10, 0xFF, ffs_sector_size - 0x10);
+	data_fill_level = 0x10;
+	objects_in_block = 0;
+}
+
+create_object(name, type, data, datalen)
+	char *name;
+	u_char *data;
+	unsigned datalen;
+{
+	int ino;
+	struct tiffs_inode *inp;
+	unsigned size, location;
+	u_char *dp;
+
+	if (inode_fill_level >= (ffs_sector_size >> 4)) {
+		fprintf(stderr, "error: inode block is full\n");
+		exit(1);
+	}
+	ino = inode_fill_level++;
+	inp = inode_array + ino;
+	if (name)
+		size = strlen(name) + 1;
+	else
+		size = 0;
+	if (data)
+		size += datalen + 1;
+	size = (size + 15) & ~15;
+	if (ffs_sector_size - data_fill_level < size ||
+	    objects_in_block >= block_files_max)
+		flush_data_block();
+	if (blocks_written >= ffs_nsectors - 2) {
+		fprintf(stderr, "error: wrote max number of data blocks\n");
+		exit(1);
+	}
+	location = (blocks_written + 1) * ffs_sector_size + data_fill_level;
+	/* write the data */
+	dp = data_block + data_fill_level;
+	if (name) {
+		strcpy(dp, name);
+		dp += strlen(name) + 1;
+	}
+	if (data) {
+		bcopy(data, dp, datalen);
+		dp += datalen;
+		*dp++ = 0;
+	}
+	/* fill the inode */
+	inp->size = htole16(size);
+	inp->type = type;
+	inp->location = htole32(location);
+	inp->sequence = htole16(ino - 1);
+	inp->updates = 0;
+	/* accounting */
+	data_fill_level += size;
+	objects_in_block++;
+	return ino;
+}
+
+void
+create_root_dir()
+{
+	int rootino;
+
+	rootino = create_object(format_name, OBJTYPE_DIR, (u_char *) 0, 0);
+	root.u.d.ffs_link_ptr = &inode_array[rootino].child;
+}
+
+create_file_object(to)
+	struct tree_object *to;
+{
+	int fd, cc;
+	u_char *data;
+	int head, seg;
+	struct tiffs_inode *inp;
+
+	fd = open(to->u.f.host_pathname, O_RDONLY);
+	if (fd < 0) {
+		perror(to->u.f.host_pathname);
+		exit(1);
+	}
+	data = malloc(chunk_size_max);
+	if (!data) {
+		perror("malloc of file chunk buffer");
+		exit(1);
+	}
+	cc = read(fd, data, chunk_size_max);
+	if (cc < 0) {
+read_err:	perror("error reading file content");
+		exit(1);
+	}
+	if (cc == 0) {
+		/* zero length file */
+		close(fd);
+		free(data);
+		return create_object(to->name, OBJTYPE_FILE, (u_char *) 0, 0);
+	}
+	head = create_object(to->name, OBJTYPE_FILE, data, cc);
+	inp = inode_array + head;
+	for (;;) {
+		cc = read(fd, data, chunk_size_max);
+		if (cc < 0)
+			goto read_err;
+		if (cc == 0)
+			break;
+		seg = create_object((char *) 0, OBJTYPE_SEGMENT, data, cc);
+		inp->child = htole16(seg);
+		inp = inode_array + seg;
+	}
+	close(fd);
+	free(data);
+	return head;
+}
+
+create_subdir(to)
+	struct tree_object *to;
+{
+	int ino;
+
+	ino = create_object(to->name, OBJTYPE_DIR, (u_char *) 0, 0);
+	to->u.d.ffs_link_ptr = &inode_array[ino].child;
+	return ino;
+}
+
+void
+process_dir_level(dto)
+	struct tree_object *dto;
+{
+	unsigned n;
+	struct tree_object *cto;
+	int child_ino;
+
+	for (n = 0; n < dto->u.d.nchildren; n++) {
+		cto = dto->u.d.children[n];
+		if (cto->is_dir) {
+			child_ino = create_subdir(cto);
+			process_dir_level(cto);
+		} else
+			child_ino = create_file_object(cto);
+		*dto->u.d.ffs_link_ptr = htole16(child_ino);
+		dto->u.d.ffs_link_ptr = &inode_array[child_ino].sibling;
+	}
+}
+
+void
+finish_output()
+{
+	if (objects_in_block)
+		flush_data_block();
+	while (blocks_written < ffs_nsectors - 2) {
+		write_out_block(data_block);
+		blocks_written++;
+	}
+	/* free block at the end */
+	data_block[8] = 0xBF;
+	write_out_block(data_block);
+	/* write out the inode block */
+	lseek(output_fd, (off_t) 0, SEEK_SET);
+	write_out_block(inode_block);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ffstools/tiffs-mkfs/struct.h	Wed May 20 06:55:58 2020 +0000
@@ -0,0 +1,38 @@
+/* some general limits */
+#define	MAX_FN_COMPONENT	20
+#define	MAX_DIR_NEST		6
+#define	MAX_DIR_ENTRIES		128
+
+/* tree of content to be written */
+struct tree_object {
+	char	name[MAX_FN_COMPONENT+1];
+	int	is_dir;
+	union {
+		struct {
+			struct tree_object *children[MAX_DIR_ENTRIES];
+			unsigned nchildren;
+			uint16_t *ffs_link_ptr;
+		} d;
+		struct {
+			char host_pathname[MAXPATHLEN];
+		} f;
+	} u;
+};
+
+/* actual TIFFS on-media structure */
+struct tiffs_inode {
+	uint16_t	size;
+	uint8_t		reserved1;
+	uint8_t		type;
+	uint16_t	child;
+	uint16_t	sibling;
+	uint32_t	location;
+	uint16_t	sequence;
+	uint16_t	updates;
+};
+
+/* TIFFS object types */
+#define	OBJTYPE_FILE	0xF1
+#define	OBJTYPE_DIR	0xF2
+#define	OBJTYPE_SYMLINK	0xF3
+#define	OBJTYPE_SEGMENT	0xF4