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(¶ms->entry.head, ¶ms->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