Home | History | Annotate | Download | only in android
      1 #include "base_fs.h"
      2 #include <stdio.h>
      3 
      4 #define BASE_FS_VERSION "Base EXT4 version 1.0"
      5 
      6 struct base_fs {
      7 	FILE *file;
      8 	const char *mountpoint;
      9 	struct basefs_entry entry;
     10 };
     11 
     12 static FILE *basefs_open(const char *file)
     13 {
     14 	char *line = NULL;
     15 	size_t len;
     16 	FILE *f = fopen(file, "r");
     17 	if (!f)
     18 		return NULL;
     19 
     20 	if (getline(&line, &len, f) == -1 || !line)
     21 		goto err_getline;
     22 
     23 	if (strncmp(line, BASE_FS_VERSION, strlen(BASE_FS_VERSION)))
     24 		goto err_header;
     25 
     26 	free(line);
     27 	return f;
     28 
     29 err_header:
     30 	free(line);
     31 err_getline:
     32 	fclose(f);
     33 	return NULL;
     34 }
     35 
     36 static struct basefs_entry *basefs_readline(FILE *f, const char *mountpoint,
     37 					    int *err)
     38 {
     39 	char *line = NULL, *saveptr1, *saveptr2, *block_range, *block;
     40 	int offset;
     41 	size_t len;
     42 	struct basefs_entry *entry = NULL;
     43 	blk64_t range_start, range_end;
     44 
     45 	if (getline(&line, &len, f) == -1) {
     46 		if (feof(f))
     47 			goto end;
     48 		goto err_getline;
     49 	}
     50 
     51 	entry = calloc(1, sizeof(*entry));
     52 	if (!entry)
     53 		goto err_alloc;
     54 
     55 	/*
     56 	 * With BASEFS version 1.0, a typical line looks like this:
     57 	 * /bin/mke2fs 5000-5004,8000,9000-9990
     58 	 */
     59 	if (sscanf(line, "%ms%n", &entry->path, &offset) != 1)
     60 		goto err_sscanf;
     61 	len = strlen(mountpoint);
     62 	memmove(entry->path, entry->path + len, strlen(entry->path) - len + 1);
     63 
     64 	while (line[offset] == ' ')
     65 		++offset;
     66 
     67 	block_range = strtok_r(line + offset, ",\n", &saveptr1);
     68 	while (block_range) {
     69 		block = strtok_r(block_range, "-", &saveptr2);
     70 		if (!block)
     71 			break;
     72 		range_start = atoll(block);
     73 		block = strtok_r(NULL, "-", &saveptr2);
     74 		range_end = block ? atoll(block) : range_start;
     75 		add_blocks_to_range(&entry->head, &entry->tail, range_start,
     76 				    range_end);
     77 		block_range = strtok_r(NULL, ",\n", &saveptr1);
     78 	}
     79 end:
     80 	*err = 0;
     81 	free(line);
     82 	return entry;
     83 
     84 err_sscanf:
     85 	free(entry);
     86 err_alloc:
     87 	free(line);
     88 err_getline:
     89 	*err = 1;
     90 	return NULL;
     91 }
     92 
     93 static void free_base_fs_entry(void *e)
     94 {
     95 	struct basefs_entry *entry = e;
     96 	if (entry) {
     97 		free(entry->path);
     98 		free(entry);
     99 	}
    100 }
    101 
    102 struct ext2fs_hashmap *basefs_parse(const char *file, const char *mountpoint)
    103 {
    104 	int err;
    105 	struct ext2fs_hashmap *entries = NULL;
    106 	struct basefs_entry *entry;
    107 	FILE *f = basefs_open(file);
    108 	if (!f)
    109 		return NULL;
    110 	entries = ext2fs_hashmap_create(ext2fs_djb2_hash, free_base_fs_entry, 1024);
    111 	if (!entries)
    112 		goto end;
    113 
    114 	while ((entry = basefs_readline(f, mountpoint, &err)))
    115 		ext2fs_hashmap_add(entries, entry, entry->path,
    116 				   strlen(entry->path));
    117 
    118 	if (err) {
    119 		fclose(f);
    120 		ext2fs_hashmap_free(entries);
    121 		return NULL;
    122 	}
    123 end:
    124 	fclose(f);
    125 	return entries;
    126 }
    127 
    128 static void *init(const char *file, const char *mountpoint)
    129 {
    130 	struct base_fs *params = malloc(sizeof(*params));
    131 
    132 	if (!params)
    133 		return NULL;
    134 	params->mountpoint = mountpoint;
    135 	params->file = fopen(file, "w+");
    136 	if (!params->file) {
    137 		free(params);
    138 		return NULL;
    139 	}
    140 	if (fwrite(BASE_FS_VERSION"\n", 1, strlen(BASE_FS_VERSION"\n"),
    141 		   params->file) != strlen(BASE_FS_VERSION"\n")) {
    142 		fclose(params->file);
    143 		free(params);
    144 		return NULL;
    145 	}
    146 	return params;
    147 }
    148 
    149 static int start_new_file(char *path, ext2_ino_t ino EXT2FS_ATTR((unused)),
    150 			  struct ext2_inode *inode, void *data)
    151 {
    152 	struct base_fs *params = data;
    153 
    154 	params->entry.head = params->entry.tail = NULL;
    155 	params->entry.path = LINUX_S_ISREG(inode->i_mode) ? path : NULL;
    156 	return 0;
    157 }
    158 
    159 static int add_block(ext2_filsys fs EXT2FS_ATTR((unused)), blk64_t blocknr,
    160 		     int metadata, void *data)
    161 {
    162 	struct base_fs *params = data;
    163 
    164 	if (params->entry.path && !metadata)
    165 		add_blocks_to_range(&params->entry.head, &params->entry.tail,
    166 				    blocknr, blocknr);
    167 	return 0;
    168 }
    169 
    170 static int inline_data(void *inline_data EXT2FS_ATTR((unused)),
    171 		       void *data EXT2FS_ATTR((unused)))
    172 {
    173 	return 0;
    174 }
    175 
    176 static int end_new_file(void *data)
    177 {
    178 	struct base_fs *params = data;
    179 
    180 	if (!params->entry.path)
    181 		return 0;
    182 	if (fprintf(params->file, "%s%s ", params->mountpoint,
    183 		    params->entry.path) < 0
    184 	    || write_block_ranges(params->file, params->entry.head, ",")
    185 	    || fwrite("\n", 1, 1, params->file) != 1)
    186 		return -1;
    187 
    188 	delete_block_ranges(params->entry.head);
    189 	return 0;
    190 }
    191 
    192 static int cleanup(void *data)
    193 {
    194 	struct base_fs *params = data;
    195 
    196 	fclose(params->file);
    197 	free(params);
    198 	return 0;
    199 }
    200 
    201 struct fsmap_format base_fs_format = {
    202 	.init = init,
    203 	.start_new_file = start_new_file,
    204 	.add_block = add_block,
    205 	.inline_data = inline_data,
    206 	.end_new_file = end_new_file,
    207 	.cleanup = cleanup,
    208 };
    209