10fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknecht#include "base_fs.h"
20fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknecht#include <stdio.h>
30fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknecht
40fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknecht#define BASE_FS_VERSION "Base EXT4 version 1.0"
50fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknecht
60fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknechtstruct base_fs {
70fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknecht	FILE *file;
80fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknecht	const char *mountpoint;
90fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknecht	struct basefs_entry entry;
100fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknecht};
110fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknecht
1216babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknechtstatic FILE *basefs_open(const char *file)
1316babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht{
1416babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht	char *line = NULL;
1516babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht	size_t len;
1616babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht	FILE *f = fopen(file, "r");
1716babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht	if (!f)
1816babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht		return NULL;
1916babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht
2016babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht	if (getline(&line, &len, f) == -1 || !line)
2116babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht		goto err_getline;
2216babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht
2316babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht	if (strncmp(line, BASE_FS_VERSION, strlen(BASE_FS_VERSION)))
2416babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht		goto err_header;
2516babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht
2616babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht	free(line);
2716babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht	return f;
2816babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht
2916babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknechterr_header:
3016babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht	free(line);
3116babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknechterr_getline:
3216babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht	fclose(f);
3316babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht	return NULL;
3416babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht}
3516babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht
3616babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknechtstatic struct basefs_entry *basefs_readline(FILE *f, const char *mountpoint,
3716babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht					    int *err)
3816babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht{
3916babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht	char *line = NULL, *saveptr1, *saveptr2, *block_range, *block;
4016babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht	int offset;
4116babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht	size_t len;
4216babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht	struct basefs_entry *entry = NULL;
4316babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht	blk64_t range_start, range_end;
4416babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht
4516babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht	if (getline(&line, &len, f) == -1) {
4616babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht		if (feof(f))
4716babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht			goto end;
4816babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht		goto err_getline;
4916babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht	}
5016babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht
5116babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht	entry = calloc(1, sizeof(*entry));
5216babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht	if (!entry)
5316babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht		goto err_alloc;
5416babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht
5516babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht	/*
5616babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht	 * With BASEFS version 1.0, a typical line looks like this:
5716babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht	 * /bin/mke2fs 5000-5004,8000,9000-9990
5816babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht	 */
5916babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht	if (sscanf(line, "%ms%n", &entry->path, &offset) != 1)
6016babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht		goto err_sscanf;
6116babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht	len = strlen(mountpoint);
6216babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht	memmove(entry->path, entry->path + len, strlen(entry->path) - len + 1);
6316babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht
6416babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht	while (line[offset] == ' ')
6516babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht		++offset;
6616babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht
6716babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht	block_range = strtok_r(line + offset, ",\n", &saveptr1);
6816babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht	while (block_range) {
6916babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht		block = strtok_r(block_range, "-", &saveptr2);
7016babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht		if (!block)
7116babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht			break;
7216babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht		range_start = atoll(block);
7316babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht		block = strtok_r(NULL, "-", &saveptr2);
7416babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht		range_end = block ? atoll(block) : range_start;
7516babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht		add_blocks_to_range(&entry->head, &entry->tail, range_start,
7616babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht				    range_end);
7716babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht		block_range = strtok_r(NULL, ",\n", &saveptr1);
7816babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht	}
7916babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknechtend:
8016babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht	*err = 0;
8116babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht	free(line);
8216babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht	return entry;
8316babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht
8416babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknechterr_sscanf:
8516babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht	free(entry);
8616babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknechterr_alloc:
8716babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht	free(line);
8816babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknechterr_getline:
8916babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht	*err = 1;
9016babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht	return NULL;
9116babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht}
9216babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht
9316babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknechtstatic void free_base_fs_entry(void *e)
9416babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht{
9516babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht	struct basefs_entry *entry = e;
9616babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht	if (entry) {
9716babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht		free(entry->path);
9816babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht		free(entry);
9916babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht	}
10016babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht}
10116babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht
10216babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknechtstruct hashmap *basefs_parse(const char *file, const char *mountpoint)
10316babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht{
10416babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht	int err;
10516babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht	struct hashmap *entries = NULL;
10616babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht	struct basefs_entry *entry;
10716babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht	FILE *f = basefs_open(file);
10816babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht	if (!f)
10916babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht		return NULL;
11016babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht	entries = hashmap_create(djb2_hash, free_base_fs_entry, 1024);
11116babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht	if (!entries)
11216babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht		goto end;
11316babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht
11416babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht	while ((entry = basefs_readline(f, mountpoint, &err)))
11516babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht		hashmap_add(entries, entry, entry->path);
11616babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht
11716babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht	if (err) {
11816babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht		fclose(f);
11916babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht		hashmap_free(entries);
12016babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht		return NULL;
12116babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht	}
12216babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknechtend:
12316babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht	fclose(f);
12416babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht	return entries;
12516babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht}
12616babe7b79c4c9b6d75d60e30c04a8e24278e4faAdrien Schildknecht
1270fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknechtstatic void *init(const char *file, const char *mountpoint)
1280fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknecht{
1290fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknecht	struct base_fs *params = malloc(sizeof(*params));
1300fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknecht
1310fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknecht	if (!params)
1320fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknecht		return NULL;
1330fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknecht	params->mountpoint = mountpoint;
1340fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknecht	params->file = fopen(file, "w+");
1350fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknecht	if (!params->file) {
1360fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknecht		free(params);
1370fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknecht		return NULL;
1380fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknecht	}
1390fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknecht	if (fwrite(BASE_FS_VERSION"\n", 1, strlen(BASE_FS_VERSION"\n"),
1400fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknecht		   params->file) != strlen(BASE_FS_VERSION"\n")) {
1410fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknecht		fclose(params->file);
1420fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknecht		free(params);
1430fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknecht		return NULL;
1440fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknecht	}
1450fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknecht	return params;
1460fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknecht}
1470fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknecht
1480fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknechtstatic int start_new_file(char *path, ext2_ino_t ino EXT2FS_ATTR((unused)),
1490fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknecht			  struct ext2_inode *inode, void *data)
1500fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknecht{
1510fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknecht	struct base_fs *params = data;
1520fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknecht
1530fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknecht	params->entry.head = params->entry.tail = NULL;
1540fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknecht	params->entry.path = LINUX_S_ISREG(inode->i_mode) ? path : NULL;
1550fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknecht	return 0;
1560fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknecht}
1570fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknecht
1580fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknechtstatic int add_block(ext2_filsys fs EXT2FS_ATTR((unused)), blk64_t blocknr,
1590fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknecht		     int metadata, void *data)
1600fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknecht{
1610fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknecht	struct base_fs *params = data;
1620fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknecht
1630fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknecht	if (params->entry.path && !metadata)
1640fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknecht		add_blocks_to_range(&params->entry.head, &params->entry.tail,
1650fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknecht				    blocknr, blocknr);
1660fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknecht	return 0;
1670fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknecht}
1680fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknecht
1690fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknechtstatic int inline_data(void *inline_data EXT2FS_ATTR((unused)),
1700fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknecht		       void *data EXT2FS_ATTR((unused)))
1710fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknecht{
1720fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknecht	return 0;
1730fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknecht}
1740fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknecht
1750fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknechtstatic int end_new_file(void *data)
1760fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknecht{
1770fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknecht	struct base_fs *params = data;
1780fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknecht
1790fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknecht	if (!params->entry.path)
1800fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknecht		return 0;
1810fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknecht	if (fprintf(params->file, "%s%s ", params->mountpoint,
1820fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknecht		    params->entry.path) < 0
1830fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknecht	    || write_block_ranges(params->file, params->entry.head, ",")
1840fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknecht	    || fwrite("\n", 1, 1, params->file) != 1)
1850fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknecht		return -1;
1860fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknecht
1870fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknecht	delete_block_ranges(params->entry.head);
1880fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknecht	return 0;
1890fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknecht}
1900fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknecht
1910fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknechtstatic int cleanup(void *data)
1920fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknecht{
1930fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknecht	struct base_fs *params = data;
1940fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknecht
1950fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknecht	fclose(params->file);
1960fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknecht	free(params);
1970fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknecht	return 0;
1980fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknecht}
1990fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknecht
2000fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknechtstruct fsmap_format base_fs_format = {
2010fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknecht	.init = init,
2020fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknecht	.start_new_file = start_new_file,
2030fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknecht	.add_block = add_block,
2040fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknecht	.inline_data = inline_data,
2050fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknecht	.end_new_file = end_new_file,
2060fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknecht	.cleanup = cleanup,
2070fe9949ca0cae4be6cde69e084db922506eda11aAdrien Schildknecht};
208