view ffstools/tiffs-mkfs/output.c @ 1004:d15d337ac0a9

loadtools/scripts: remove long-deprecated -h gta02 config
author Mychaela Falconia <falcon@freecalypso.org>
date Sat, 09 Dec 2023 18:35:30 +0000
parents 178ed445021d
children
line wrap: on
line source

#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;

	chunk_buffer = malloc(chunk_size_max);
	if (!chunk_buffer) {
		perror("malloc of file chunk buffer");
		exit(1);
	}
}

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 (datalen)
		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 (datalen) {
		if (data)
			bcopy(data, dp, datalen);
		dp += datalen;
		*dp++ = 0;
	}
	/* fill the inode */
	inp->size = htole16(size);
	inp->type = type;
	inp->location = htole32(location >> 4);
	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;
	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);
	}
	cc = read(fd, chunk_buffer, chunk_size_max);
	if (cc < 0) {
read_err:	perror("error reading file content");
		exit(1);
	}
	if (cc == 0) {
		/* zero length file */
		close(fd);
		return create_object(to->name, OBJTYPE_FILE, (u_char *) 0, 0);
	}
	head = create_object(to->name, OBJTYPE_FILE, chunk_buffer, cc);
	inp = inode_array + head;
	for (;;) {
		cc = read(fd, chunk_buffer, chunk_size_max);
		if (cc < 0)
			goto read_err;
		if (cc == 0)
			break;
		seg = create_object((char *) 0, OBJTYPE_SEGMENT, chunk_buffer,
					cc);
		inp->child = htole16(seg);
		inp = inode_array + seg;
	}
	close(fd);
	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
create_journal()
{
	int ino;

	ino = create_object(".journal", OBJTYPE_FILE_RO, (u_char *) 0,
				journal_size);
	*root.u.d.ffs_link_ptr = htole16(ino);
	root.u.d.ffs_link_ptr = &inode_array[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);
}