Browse Source

hello world

K. Lange 7 months ago
commit
e27cf3ada1
4 changed files with 188 additions and 0 deletions
  1. 2 0
      .gitignore
  2. 1 0
      Makefile
  3. BIN
      tfstool
  4. 185 0
      tfstool.c

+ 2 - 0
.gitignore

@@ -0,0 +1,2 @@
+tsftool
+test.img

+ 1 - 0
Makefile

@@ -0,0 +1 @@
+all: tfstool

BIN
tfstool


+ 185 - 0
tfstool.c

@@ -0,0 +1,185 @@
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+/**
+ * ToaruFS is a simple, flexible filesystem designed to be a
+ * dumbed-down ext2-like block-and-inode-based filesystem.
+ *
+ * ToaruFS employs a fixed block size of 4096 bytes (512×8 sectors)
+ * which eases some pain of supporting multiple block sizes.
+ *
+ * ToaruFS has only one "block group" - a single bitmap describes
+ * the allocation of blocks throughout the disk. Part of this is
+ * to simplify lookups but also because the Authors assert that
+ * block groups are no longer a necessary seek-reduction measure
+ * on modern SSDs.
+ *
+ * ToaruFS adds chained inode tables, eliminating the problem
+ * of pre-allocating space for inodes in exchange for requiring
+ * the host driver to keep track of where a sporadic collection
+ * of inode tables may be found. Inode tables are stored in
+ * arbitrary blocks as a linked list, with each table pointing
+ * to the next. Each table has a small bitmap describing which
+ * entries are available.
+ */
+
+/* BEGIN ToaruFS Structures */
+
+#define TOARUFS_SUPERBLOCK_MAGIC 0x46a881e3
+#define TOARUFS_VERSION 1
+
+/* Superblock */
+struct toarufs_superblock {
+	uint32_t magic;
+	uint32_t version;
+	uint8_t  partition_name[16];
+
+	uint32_t block_count;
+	uint32_t free_blocks;
+	uint32_t last_mount;
+	uint32_t last_write;
+	uint32_t first_inode_block;
+	uint32_t mount_count;
+};
+
+/* Inode Table Header */
+struct toarufs_inode_table {
+	uint32_t checksum;
+	uint32_t next_table;
+	uint16_t table_id;
+	uint8_t free_inodes;
+	uint8_t inode_bitmap[5];
+};
+
+struct toarufs_inode_entry {
+	uint16_t mode, owner;
+	uint16_t group, flags;
+	uint32_t bytes;
+	uint32_t atime, ctime, mtime, dtime;
+	uint32_t data_blocks[15];
+	uint8_t  reserved[12];
+};
+
+/* This is the same as ext2 */
+struct toarufs_directory_entry {
+	uint32_t inode;
+	uint16_t entry_length;
+	uint8_t  name_length;
+	uint8_t  file_type;
+	char     name[];
+};
+
+#define BLOCK_SIZE       4096
+#define INODE_TABLE_SIZE (sizeof(struct toarufs_inode_table))
+#define INODE_ENTRY_SIZE (sizeof(struct toarufs_inode_entry))
+#define INODE_SPACE      (BLOCK_SIZE - INODE_TABLE_SIZE)
+#define INODES_PER_TABLE (INODE_SPACE / INODE_ENTRY_SIZE)
+#define INODE_TABLE_EXT  (INODE_SPACE - (INODES_PER_TABLE * INODE_ENTRY_SIZE))
+#define INODE_TABLE_START (INODE_TABLE_SIZE + INODE_TABLE_EXT)
+
+static void toarufs_set_block(char * block_bitmap, int block) {
+	/* Get index */
+	uint32_t block_number = block / 8;
+	uint32_t block_index  = block % 8;
+
+	block_bitmap[block_number] |= (1 << block_index);
+
+	/* Write block bitmap back to disk */
+	// TODO
+}
+
+static void toarufs_unset_block(char * block_bitmap, int block) {
+	/* Get index */
+	uint32_t block_number = block / 8;
+	uint32_t block_index  = block % 8;
+
+	block_bitmap[block_number] &= ~(1 << block_index);
+
+	/* Write block bitmap back to disk */
+	// TODO
+}
+
+static int toarufs_test_block(char * block_bitmap, int block) {
+	/* Get index */
+	uint32_t block_number = block / 8;
+	uint32_t block_index  = block % 8;
+
+	return block_bitmap[block_number] & (1 << block_index);
+}
+
+static uint32_t toarufs_allocate_block(char * block_bitmap, int bitmap_size) {
+	for (int i = 0; i < bitmap_size; ++i) {
+		if (block_bitmap[i] != 0xFF) {
+			for (int j = 0; j < 8; ++j) {
+				if (!(block_bitmap[i] & (1 << j))) {
+					uint32_t out = ((uint32_t)i * 8 + (uint32_t)j);
+					toarufs_set_block(block_bitmap, out);
+					return out;
+				}
+			}
+		}
+	}
+	return 0; /* 0 is always invalid (it's the reserved block) */
+}
+
+
+int main(int argc, char * argv[]) {
+	if (argc < 2) {
+		fprintf(stderr, "usage: %s FILE\n", argv[0]);
+		return 1;
+	}
+
+	FILE * image = fopen(argv[1], "r+");
+
+	if (!image) {
+		fprintf(stderr, "%s: could not open %s\n", argv[0], argv[1]);
+		return 1;
+	}
+
+	fprintf(stderr, "Building a ToaruFS v%d partition\n", TOARUFS_VERSION);
+	fprintf(stderr, "   inode table size = %zd\n", INODE_TABLE_SIZE);
+	fprintf(stderr, "   inode entry size = %zd\n", INODE_ENTRY_SIZE);
+	fprintf(stderr, "      remaining block size = %zd\n", INODE_SPACE);
+	fprintf(stderr, "      inodes per table = %zd\n", INODES_PER_TABLE);
+	fprintf(stderr, "      available additional inode table space = %zd\n", INODE_TABLE_EXT);
+	fprintf(stderr, "      this means table entries start at %zd\n", INODE_TABLE_START);
+
+	fseek(image, 0, SEEK_END);
+	long image_size = ftell(image);
+	fseek(image, 0, SEEK_SET);
+
+	long image_blocks = image_size / BLOCK_SIZE;
+
+	fprintf(stderr, "Image is %ld bytes, can fit %ld blocks.\n", image_size, image_blocks);
+
+	long bitmap_size = 0;
+	for (int i = 0; i < image_blocks; ++i) {
+		if (8 * BLOCK_SIZE * i >= image_blocks) {
+			bitmap_size = i;
+			break;
+		}
+	}
+	fprintf(stderr, "With 8 blocks per per byte and %d bytes per block, need %ld blocks for block bitmaps.\n",
+			BLOCK_SIZE, bitmap_size);
+	fprintf(stderr, "This gives %ld potential blocks, wasting space for %ld.",
+			bitmap_size * 8 * BLOCK_SIZE, bitmap_size * 8 * BLOCK_SIZE - image_blocks);
+	fprintf(stderr, " (which amounts to %ld bytes of waste)\n",
+			(bitmap_size * 8 * BLOCK_SIZE - image_blocks) / 8);
+
+	/* Allocate block bitmap */
+	char * block_bitmap = calloc(bitmap_size, BLOCK_SIZE);
+	toarufs_set_block(block_bitmap, 0); /* Reserved space */
+	toarufs_set_block(block_bitmap, 1); /* Super block */
+	for (unsigned int i = 0; i < bitmap_size; ++i) {
+		toarufs_set_block(block_bitmap, 1 + i); /* Block bitmap self-storage */
+	}
+
+	/* Allocate a block for the first inode table */
+	fprintf(stderr, "Allocating a block yields: %u\n", toarufs_allocate_block(block_bitmap, bitmap_size));
+	fprintf(stderr, "Allocating a block yields: %u\n", toarufs_allocate_block(block_bitmap, bitmap_size));
+	fprintf(stderr, "Allocating a block yields: %u\n", toarufs_allocate_block(block_bitmap, bitmap_size));
+	fprintf(stderr, "Allocating a block yields: %u\n", toarufs_allocate_block(block_bitmap, bitmap_size));
+
+	return 0;
+}