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