• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
basefs_open(const char * file)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 
basefs_readline(FILE * f,const char * mountpoint,int * err)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->blocks, range_start, range_end);
76 		block_range = strtok_r(NULL, ",\n", &saveptr1);
77 	}
78 end:
79 	*err = 0;
80 	free(line);
81 	return entry;
82 
83 err_sscanf:
84 	free(entry);
85 err_alloc:
86 	free(line);
87 err_getline:
88 	*err = 1;
89 	return NULL;
90 }
91 
free_base_fs_entry(void * e)92 static void free_base_fs_entry(void *e)
93 {
94 	struct basefs_entry *entry = e;
95 	if (entry) {
96 		free(entry->path);
97 		free(entry);
98 	}
99 }
100 
basefs_parse(const char * file,const char * mountpoint)101 struct ext2fs_hashmap *basefs_parse(const char *file, const char *mountpoint)
102 {
103 	int err;
104 	struct ext2fs_hashmap *entries = NULL;
105 	struct basefs_entry *entry;
106 	FILE *f = basefs_open(file);
107 	if (!f)
108 		return NULL;
109 	entries = ext2fs_hashmap_create(ext2fs_djb2_hash, free_base_fs_entry, 1024);
110 	if (!entries)
111 		goto end;
112 
113 	while ((entry = basefs_readline(f, mountpoint, &err))) {
114 		err = ext2fs_hashmap_add(entries, entry, entry->path,
115 				   strlen(entry->path));
116 		if (err) {
117 			free_base_fs_entry(entry);
118 			fclose(f);
119 			ext2fs_hashmap_free(entries);
120 			return NULL;
121 		}
122 	}
123 	if (err) {
124 		fclose(f);
125 		ext2fs_hashmap_free(entries);
126 		return NULL;
127 	}
128 end:
129 	fclose(f);
130 	return entries;
131 }
132 
init(const char * file,const char * mountpoint)133 static void *init(const char *file, const char *mountpoint)
134 {
135 	struct base_fs *params = malloc(sizeof(*params));
136 
137 	if (!params)
138 		return NULL;
139 	params->mountpoint = mountpoint;
140 	params->file = fopen(file, "w+");
141 	if (!params->file) {
142 		free(params);
143 		return NULL;
144 	}
145 	if (fwrite(BASE_FS_VERSION"\n", 1, strlen(BASE_FS_VERSION"\n"),
146 		   params->file) != strlen(BASE_FS_VERSION"\n")) {
147 		fclose(params->file);
148 		free(params);
149 		return NULL;
150 	}
151 	return params;
152 }
153 
start_new_file(char * path,ext2_ino_t ino EXT2FS_ATTR ((unused)),struct ext2_inode * inode,void * data)154 static int start_new_file(char *path, ext2_ino_t ino EXT2FS_ATTR((unused)),
155 			  struct ext2_inode *inode, void *data)
156 {
157 	struct base_fs *params = data;
158 
159 	params->entry.path = LINUX_S_ISREG(inode->i_mode) ? path : NULL;
160 	return 0;
161 }
162 
add_block(ext2_filsys fs EXT2FS_ATTR ((unused)),blk64_t blocknr,int metadata,void * data)163 static int add_block(ext2_filsys fs EXT2FS_ATTR((unused)), blk64_t blocknr,
164 		     int metadata, void *data)
165 {
166 	struct base_fs *params = data;
167 
168 	if (params->entry.path && !metadata)
169 		add_blocks_to_range(&params->entry.blocks, blocknr, blocknr);
170 	return 0;
171 }
172 
inline_data(void * inline_data EXT2FS_ATTR ((unused)),void * data EXT2FS_ATTR ((unused)))173 static int inline_data(void *inline_data EXT2FS_ATTR((unused)),
174 		       void *data EXT2FS_ATTR((unused)))
175 {
176 	return 0;
177 }
178 
end_new_file(void * data)179 static int end_new_file(void *data)
180 {
181 	struct base_fs *params = data;
182 
183 	if (!params->entry.path)
184 		return 0;
185 	if (fprintf(params->file, "%s%s ", params->mountpoint,
186 		    params->entry.path) < 0
187 	    || write_block_ranges(params->file, params->entry.blocks.head, ",")
188 	    || fwrite("\n", 1, 1, params->file) != 1)
189 		return -1;
190 
191 	delete_block_ranges(&params->entry.blocks);
192 	return 0;
193 }
194 
cleanup(void * data)195 static int cleanup(void *data)
196 {
197 	struct base_fs *params = data;
198 
199 	fclose(params->file);
200 	free(params);
201 	return 0;
202 }
203 
204 struct fsmap_format base_fs_format = {
205 	.init = init,
206 	.start_new_file = start_new_file,
207 	.add_block = add_block,
208 	.inline_data = inline_data,
209 	.end_new_file = end_new_file,
210 	.cleanup = cleanup,
211 };
212