xref: /aosp_15_r20/external/e2fsprogs/lib/ext2fs/imager.c (revision 6a54128f25917bfc36a8a6e9d722c04a0b4641b6)
1*6a54128fSAndroid Build Coastguard Worker /*
2*6a54128fSAndroid Build Coastguard Worker  * image.c --- writes out the critical parts of the filesystem as a
3*6a54128fSAndroid Build Coastguard Worker  * 	flat file.
4*6a54128fSAndroid Build Coastguard Worker  *
5*6a54128fSAndroid Build Coastguard Worker  * Copyright (C) 2000 Theodore Ts'o.
6*6a54128fSAndroid Build Coastguard Worker  *
7*6a54128fSAndroid Build Coastguard Worker  * Note: this uses the POSIX IO interfaces, unlike most of the other
8*6a54128fSAndroid Build Coastguard Worker  * functions in this library.  So sue me.
9*6a54128fSAndroid Build Coastguard Worker  *
10*6a54128fSAndroid Build Coastguard Worker  * %Begin-Header%
11*6a54128fSAndroid Build Coastguard Worker  * This file may be redistributed under the terms of the GNU Library
12*6a54128fSAndroid Build Coastguard Worker  * General Public License, version 2.
13*6a54128fSAndroid Build Coastguard Worker  * %End-Header%
14*6a54128fSAndroid Build Coastguard Worker  */
15*6a54128fSAndroid Build Coastguard Worker 
16*6a54128fSAndroid Build Coastguard Worker #include "config.h"
17*6a54128fSAndroid Build Coastguard Worker #include <stdio.h>
18*6a54128fSAndroid Build Coastguard Worker #include <string.h>
19*6a54128fSAndroid Build Coastguard Worker #if HAVE_UNISTD_H
20*6a54128fSAndroid Build Coastguard Worker #include <unistd.h>
21*6a54128fSAndroid Build Coastguard Worker #endif
22*6a54128fSAndroid Build Coastguard Worker #if HAVE_ERRNO_H
23*6a54128fSAndroid Build Coastguard Worker #include <errno.h>
24*6a54128fSAndroid Build Coastguard Worker #endif
25*6a54128fSAndroid Build Coastguard Worker #include <fcntl.h>
26*6a54128fSAndroid Build Coastguard Worker #include <time.h>
27*6a54128fSAndroid Build Coastguard Worker #if HAVE_SYS_STAT_H
28*6a54128fSAndroid Build Coastguard Worker #include <sys/stat.h>
29*6a54128fSAndroid Build Coastguard Worker #endif
30*6a54128fSAndroid Build Coastguard Worker #if HAVE_SYS_TYPES_H
31*6a54128fSAndroid Build Coastguard Worker #include <sys/types.h>
32*6a54128fSAndroid Build Coastguard Worker #endif
33*6a54128fSAndroid Build Coastguard Worker 
34*6a54128fSAndroid Build Coastguard Worker #include "ext2_fs.h"
35*6a54128fSAndroid Build Coastguard Worker #include "ext2fs.h"
36*6a54128fSAndroid Build Coastguard Worker 
37*6a54128fSAndroid Build Coastguard Worker #ifndef HAVE_TYPE_SSIZE_T
38*6a54128fSAndroid Build Coastguard Worker typedef int ssize_t;
39*6a54128fSAndroid Build Coastguard Worker #endif
40*6a54128fSAndroid Build Coastguard Worker 
41*6a54128fSAndroid Build Coastguard Worker /*
42*6a54128fSAndroid Build Coastguard Worker  * This function returns 1 if the specified block is all zeros
43*6a54128fSAndroid Build Coastguard Worker  */
check_zero_block(char * buf,int blocksize)44*6a54128fSAndroid Build Coastguard Worker static int check_zero_block(char *buf, int blocksize)
45*6a54128fSAndroid Build Coastguard Worker {
46*6a54128fSAndroid Build Coastguard Worker 	char	*cp = buf;
47*6a54128fSAndroid Build Coastguard Worker 	int	left = blocksize;
48*6a54128fSAndroid Build Coastguard Worker 
49*6a54128fSAndroid Build Coastguard Worker 	while (left > 0) {
50*6a54128fSAndroid Build Coastguard Worker 		if (*cp++)
51*6a54128fSAndroid Build Coastguard Worker 			return 0;
52*6a54128fSAndroid Build Coastguard Worker 		left--;
53*6a54128fSAndroid Build Coastguard Worker 	}
54*6a54128fSAndroid Build Coastguard Worker 	return 1;
55*6a54128fSAndroid Build Coastguard Worker }
56*6a54128fSAndroid Build Coastguard Worker 
57*6a54128fSAndroid Build Coastguard Worker /*
58*6a54128fSAndroid Build Coastguard Worker  * Write the inode table out as a single block.
59*6a54128fSAndroid Build Coastguard Worker  */
60*6a54128fSAndroid Build Coastguard Worker #define BUF_BLOCKS	32
61*6a54128fSAndroid Build Coastguard Worker 
ext2fs_image_inode_write(ext2_filsys fs,int fd,int flags)62*6a54128fSAndroid Build Coastguard Worker errcode_t ext2fs_image_inode_write(ext2_filsys fs, int fd, int flags)
63*6a54128fSAndroid Build Coastguard Worker {
64*6a54128fSAndroid Build Coastguard Worker 	dgrp_t		group;
65*6a54128fSAndroid Build Coastguard Worker 	ssize_t		left, c, d;
66*6a54128fSAndroid Build Coastguard Worker 	char		*buf, *cp;
67*6a54128fSAndroid Build Coastguard Worker 	blk64_t		blk;
68*6a54128fSAndroid Build Coastguard Worker 	ssize_t		actual;
69*6a54128fSAndroid Build Coastguard Worker 	errcode_t	retval;
70*6a54128fSAndroid Build Coastguard Worker 	ext2_loff_t	r;
71*6a54128fSAndroid Build Coastguard Worker 
72*6a54128fSAndroid Build Coastguard Worker 	buf = malloc(fs->blocksize * BUF_BLOCKS);
73*6a54128fSAndroid Build Coastguard Worker 	if (!buf)
74*6a54128fSAndroid Build Coastguard Worker 		return ENOMEM;
75*6a54128fSAndroid Build Coastguard Worker 
76*6a54128fSAndroid Build Coastguard Worker 	for (group = 0; group < fs->group_desc_count; group++) {
77*6a54128fSAndroid Build Coastguard Worker 		blk = ext2fs_inode_table_loc(fs, group);
78*6a54128fSAndroid Build Coastguard Worker 		if (!blk) {
79*6a54128fSAndroid Build Coastguard Worker 			retval = EXT2_ET_MISSING_INODE_TABLE;
80*6a54128fSAndroid Build Coastguard Worker 			goto errout;
81*6a54128fSAndroid Build Coastguard Worker 		}
82*6a54128fSAndroid Build Coastguard Worker 		left = fs->inode_blocks_per_group;
83*6a54128fSAndroid Build Coastguard Worker 		if ((blk < fs->super->s_first_data_block) ||
84*6a54128fSAndroid Build Coastguard Worker 		    (blk + left - 1 >= ext2fs_blocks_count(fs->super))) {
85*6a54128fSAndroid Build Coastguard Worker 			retval = EXT2_ET_GDESC_BAD_INODE_TABLE;
86*6a54128fSAndroid Build Coastguard Worker 			goto errout;
87*6a54128fSAndroid Build Coastguard Worker 		}
88*6a54128fSAndroid Build Coastguard Worker 		while (left) {
89*6a54128fSAndroid Build Coastguard Worker 			c = BUF_BLOCKS;
90*6a54128fSAndroid Build Coastguard Worker 			if (c > left)
91*6a54128fSAndroid Build Coastguard Worker 				c = left;
92*6a54128fSAndroid Build Coastguard Worker 			retval = io_channel_read_blk64(fs->io, blk, c, buf);
93*6a54128fSAndroid Build Coastguard Worker 			if (retval)
94*6a54128fSAndroid Build Coastguard Worker 				goto errout;
95*6a54128fSAndroid Build Coastguard Worker 			cp = buf;
96*6a54128fSAndroid Build Coastguard Worker 			while (c) {
97*6a54128fSAndroid Build Coastguard Worker 				if (!(flags & IMAGER_FLAG_SPARSEWRITE)) {
98*6a54128fSAndroid Build Coastguard Worker 					d = c;
99*6a54128fSAndroid Build Coastguard Worker 					goto skip_sparse;
100*6a54128fSAndroid Build Coastguard Worker 				}
101*6a54128fSAndroid Build Coastguard Worker 				/* Skip zero blocks */
102*6a54128fSAndroid Build Coastguard Worker 				if (check_zero_block(cp, fs->blocksize)) {
103*6a54128fSAndroid Build Coastguard Worker 					c--;
104*6a54128fSAndroid Build Coastguard Worker 					blk++;
105*6a54128fSAndroid Build Coastguard Worker 					left--;
106*6a54128fSAndroid Build Coastguard Worker 					cp += fs->blocksize;
107*6a54128fSAndroid Build Coastguard Worker 					r = ext2fs_llseek(fd, fs->blocksize,
108*6a54128fSAndroid Build Coastguard Worker 							  SEEK_CUR);
109*6a54128fSAndroid Build Coastguard Worker 					if (r < 0) {
110*6a54128fSAndroid Build Coastguard Worker 						retval = errno;
111*6a54128fSAndroid Build Coastguard Worker 						goto errout;
112*6a54128fSAndroid Build Coastguard Worker 					}
113*6a54128fSAndroid Build Coastguard Worker 					continue;
114*6a54128fSAndroid Build Coastguard Worker 				}
115*6a54128fSAndroid Build Coastguard Worker 				/* Find non-zero blocks */
116*6a54128fSAndroid Build Coastguard Worker 				for (d = 1; d < c; d++) {
117*6a54128fSAndroid Build Coastguard Worker 					if (check_zero_block(cp +
118*6a54128fSAndroid Build Coastguard Worker 							     d * fs->blocksize,
119*6a54128fSAndroid Build Coastguard Worker 							     fs->blocksize))
120*6a54128fSAndroid Build Coastguard Worker 						break;
121*6a54128fSAndroid Build Coastguard Worker 				}
122*6a54128fSAndroid Build Coastguard Worker 			skip_sparse:
123*6a54128fSAndroid Build Coastguard Worker 				actual = write(fd, cp, d * fs->blocksize);
124*6a54128fSAndroid Build Coastguard Worker 				if (actual == -1) {
125*6a54128fSAndroid Build Coastguard Worker 					retval = errno;
126*6a54128fSAndroid Build Coastguard Worker 					goto errout;
127*6a54128fSAndroid Build Coastguard Worker 				}
128*6a54128fSAndroid Build Coastguard Worker 				if (actual != d * fs->blocksize) {
129*6a54128fSAndroid Build Coastguard Worker 					retval = EXT2_ET_SHORT_WRITE;
130*6a54128fSAndroid Build Coastguard Worker 					goto errout;
131*6a54128fSAndroid Build Coastguard Worker 				}
132*6a54128fSAndroid Build Coastguard Worker 				blk += d;
133*6a54128fSAndroid Build Coastguard Worker 				left -= d;
134*6a54128fSAndroid Build Coastguard Worker 				cp += d * fs->blocksize;
135*6a54128fSAndroid Build Coastguard Worker 				c -= d;
136*6a54128fSAndroid Build Coastguard Worker 			}
137*6a54128fSAndroid Build Coastguard Worker 		}
138*6a54128fSAndroid Build Coastguard Worker 	}
139*6a54128fSAndroid Build Coastguard Worker 	retval = 0;
140*6a54128fSAndroid Build Coastguard Worker 
141*6a54128fSAndroid Build Coastguard Worker errout:
142*6a54128fSAndroid Build Coastguard Worker 	free(buf);
143*6a54128fSAndroid Build Coastguard Worker 	return retval;
144*6a54128fSAndroid Build Coastguard Worker }
145*6a54128fSAndroid Build Coastguard Worker 
146*6a54128fSAndroid Build Coastguard Worker /*
147*6a54128fSAndroid Build Coastguard Worker  * Read in the inode table and stuff it into place
148*6a54128fSAndroid Build Coastguard Worker  */
ext2fs_image_inode_read(ext2_filsys fs,int fd,int flags EXT2FS_ATTR ((unused)))149*6a54128fSAndroid Build Coastguard Worker errcode_t ext2fs_image_inode_read(ext2_filsys fs, int fd,
150*6a54128fSAndroid Build Coastguard Worker 				  int flags EXT2FS_ATTR((unused)))
151*6a54128fSAndroid Build Coastguard Worker {
152*6a54128fSAndroid Build Coastguard Worker 	dgrp_t		group;
153*6a54128fSAndroid Build Coastguard Worker 	ssize_t		c, left;
154*6a54128fSAndroid Build Coastguard Worker 	char		*buf;
155*6a54128fSAndroid Build Coastguard Worker 	blk64_t		blk;
156*6a54128fSAndroid Build Coastguard Worker 	ssize_t		actual;
157*6a54128fSAndroid Build Coastguard Worker 	errcode_t	retval;
158*6a54128fSAndroid Build Coastguard Worker 
159*6a54128fSAndroid Build Coastguard Worker 	buf = malloc(fs->blocksize * BUF_BLOCKS);
160*6a54128fSAndroid Build Coastguard Worker 	if (!buf)
161*6a54128fSAndroid Build Coastguard Worker 		return ENOMEM;
162*6a54128fSAndroid Build Coastguard Worker 
163*6a54128fSAndroid Build Coastguard Worker 	for (group = 0; group < fs->group_desc_count; group++) {
164*6a54128fSAndroid Build Coastguard Worker 		blk = ext2fs_inode_table_loc(fs, group);
165*6a54128fSAndroid Build Coastguard Worker 		if (!blk) {
166*6a54128fSAndroid Build Coastguard Worker 			retval = EXT2_ET_MISSING_INODE_TABLE;
167*6a54128fSAndroid Build Coastguard Worker 			goto errout;
168*6a54128fSAndroid Build Coastguard Worker 		}
169*6a54128fSAndroid Build Coastguard Worker 		left = fs->inode_blocks_per_group;
170*6a54128fSAndroid Build Coastguard Worker 		while (left) {
171*6a54128fSAndroid Build Coastguard Worker 			c = BUF_BLOCKS;
172*6a54128fSAndroid Build Coastguard Worker 			if (c > left)
173*6a54128fSAndroid Build Coastguard Worker 				c = left;
174*6a54128fSAndroid Build Coastguard Worker 			actual = read(fd, buf, fs->blocksize * c);
175*6a54128fSAndroid Build Coastguard Worker 			if (actual == -1) {
176*6a54128fSAndroid Build Coastguard Worker 				retval = errno;
177*6a54128fSAndroid Build Coastguard Worker 				goto errout;
178*6a54128fSAndroid Build Coastguard Worker 			}
179*6a54128fSAndroid Build Coastguard Worker 			if (actual != fs->blocksize * c) {
180*6a54128fSAndroid Build Coastguard Worker 				retval = EXT2_ET_SHORT_READ;
181*6a54128fSAndroid Build Coastguard Worker 				goto errout;
182*6a54128fSAndroid Build Coastguard Worker 			}
183*6a54128fSAndroid Build Coastguard Worker 			retval = io_channel_write_blk64(fs->io, blk, c, buf);
184*6a54128fSAndroid Build Coastguard Worker 			if (retval)
185*6a54128fSAndroid Build Coastguard Worker 				goto errout;
186*6a54128fSAndroid Build Coastguard Worker 
187*6a54128fSAndroid Build Coastguard Worker 			blk += c;
188*6a54128fSAndroid Build Coastguard Worker 			left -= c;
189*6a54128fSAndroid Build Coastguard Worker 		}
190*6a54128fSAndroid Build Coastguard Worker 	}
191*6a54128fSAndroid Build Coastguard Worker 	retval = ext2fs_flush_icache(fs);
192*6a54128fSAndroid Build Coastguard Worker 
193*6a54128fSAndroid Build Coastguard Worker errout:
194*6a54128fSAndroid Build Coastguard Worker 	free(buf);
195*6a54128fSAndroid Build Coastguard Worker 	return retval;
196*6a54128fSAndroid Build Coastguard Worker }
197*6a54128fSAndroid Build Coastguard Worker 
198*6a54128fSAndroid Build Coastguard Worker /*
199*6a54128fSAndroid Build Coastguard Worker  * Write out superblock and group descriptors
200*6a54128fSAndroid Build Coastguard Worker  */
ext2fs_image_super_write(ext2_filsys fs,int fd,int flags EXT2FS_ATTR ((unused)))201*6a54128fSAndroid Build Coastguard Worker errcode_t ext2fs_image_super_write(ext2_filsys fs, int fd,
202*6a54128fSAndroid Build Coastguard Worker 				   int flags EXT2FS_ATTR((unused)))
203*6a54128fSAndroid Build Coastguard Worker {
204*6a54128fSAndroid Build Coastguard Worker 	char		*buf, *cp;
205*6a54128fSAndroid Build Coastguard Worker 	ssize_t		actual;
206*6a54128fSAndroid Build Coastguard Worker 	errcode_t	retval;
207*6a54128fSAndroid Build Coastguard Worker #ifdef WORDS_BIGENDIAN
208*6a54128fSAndroid Build Coastguard Worker 	unsigned int	groups_per_block;
209*6a54128fSAndroid Build Coastguard Worker 	struct		ext2_group_desc *gdp;
210*6a54128fSAndroid Build Coastguard Worker 	int		j;
211*6a54128fSAndroid Build Coastguard Worker #endif
212*6a54128fSAndroid Build Coastguard Worker 
213*6a54128fSAndroid Build Coastguard Worker 	if (fs->group_desc == NULL)
214*6a54128fSAndroid Build Coastguard Worker 		return EXT2_ET_NO_GDESC;
215*6a54128fSAndroid Build Coastguard Worker 
216*6a54128fSAndroid Build Coastguard Worker 	buf = malloc(fs->blocksize);
217*6a54128fSAndroid Build Coastguard Worker 	if (!buf)
218*6a54128fSAndroid Build Coastguard Worker 		return ENOMEM;
219*6a54128fSAndroid Build Coastguard Worker 
220*6a54128fSAndroid Build Coastguard Worker 	/*
221*6a54128fSAndroid Build Coastguard Worker 	 * Write out the superblock
222*6a54128fSAndroid Build Coastguard Worker 	 */
223*6a54128fSAndroid Build Coastguard Worker 	memset(buf, 0, fs->blocksize);
224*6a54128fSAndroid Build Coastguard Worker #ifdef WORDS_BIGENDIAN
225*6a54128fSAndroid Build Coastguard Worker 	/*
226*6a54128fSAndroid Build Coastguard Worker 	 * We're writing out superblock so let's convert
227*6a54128fSAndroid Build Coastguard Worker 	 * it to little endian and then back if needed
228*6a54128fSAndroid Build Coastguard Worker 	 */
229*6a54128fSAndroid Build Coastguard Worker 	ext2fs_swap_super(fs->super);
230*6a54128fSAndroid Build Coastguard Worker 	memcpy(buf, fs->super, SUPERBLOCK_SIZE);
231*6a54128fSAndroid Build Coastguard Worker 	ext2fs_swap_super(fs->super);
232*6a54128fSAndroid Build Coastguard Worker #else
233*6a54128fSAndroid Build Coastguard Worker 	memcpy(buf, fs->super, SUPERBLOCK_SIZE);
234*6a54128fSAndroid Build Coastguard Worker #endif
235*6a54128fSAndroid Build Coastguard Worker 	actual = write(fd, buf, fs->blocksize);
236*6a54128fSAndroid Build Coastguard Worker 	if (actual == -1) {
237*6a54128fSAndroid Build Coastguard Worker 		retval = errno;
238*6a54128fSAndroid Build Coastguard Worker 		goto errout;
239*6a54128fSAndroid Build Coastguard Worker 	}
240*6a54128fSAndroid Build Coastguard Worker 	if (actual != (ssize_t) fs->blocksize) {
241*6a54128fSAndroid Build Coastguard Worker 		retval = EXT2_ET_SHORT_WRITE;
242*6a54128fSAndroid Build Coastguard Worker 		goto errout;
243*6a54128fSAndroid Build Coastguard Worker 	}
244*6a54128fSAndroid Build Coastguard Worker 
245*6a54128fSAndroid Build Coastguard Worker 	/*
246*6a54128fSAndroid Build Coastguard Worker 	 * Now write out the block group descriptors
247*6a54128fSAndroid Build Coastguard Worker 	 */
248*6a54128fSAndroid Build Coastguard Worker 
249*6a54128fSAndroid Build Coastguard Worker 	cp = (char *) fs->group_desc;
250*6a54128fSAndroid Build Coastguard Worker 
251*6a54128fSAndroid Build Coastguard Worker #ifdef WORDS_BIGENDIAN
252*6a54128fSAndroid Build Coastguard Worker 	/*
253*6a54128fSAndroid Build Coastguard Worker 	 * Convert group descriptors to little endian and back
254*6a54128fSAndroid Build Coastguard Worker 	 * if needed
255*6a54128fSAndroid Build Coastguard Worker 	 */
256*6a54128fSAndroid Build Coastguard Worker 	groups_per_block = EXT2_DESC_PER_BLOCK(fs->super);
257*6a54128fSAndroid Build Coastguard Worker 	for (j=0; j < groups_per_block*fs->desc_blocks; j++) {
258*6a54128fSAndroid Build Coastguard Worker 		gdp = ext2fs_group_desc(fs, fs->group_desc, j);
259*6a54128fSAndroid Build Coastguard Worker 		if (gdp)
260*6a54128fSAndroid Build Coastguard Worker 			ext2fs_swap_group_desc2(fs, gdp);
261*6a54128fSAndroid Build Coastguard Worker 	}
262*6a54128fSAndroid Build Coastguard Worker #endif
263*6a54128fSAndroid Build Coastguard Worker 
264*6a54128fSAndroid Build Coastguard Worker 	actual = write(fd, cp, (ssize_t)fs->blocksize * fs->desc_blocks);
265*6a54128fSAndroid Build Coastguard Worker 
266*6a54128fSAndroid Build Coastguard Worker 
267*6a54128fSAndroid Build Coastguard Worker #ifdef WORDS_BIGENDIAN
268*6a54128fSAndroid Build Coastguard Worker 	groups_per_block = EXT2_DESC_PER_BLOCK(fs->super);
269*6a54128fSAndroid Build Coastguard Worker 	for (j=0; j < groups_per_block*fs->desc_blocks; j++) {
270*6a54128fSAndroid Build Coastguard Worker 		gdp = ext2fs_group_desc(fs, fs->group_desc, j);
271*6a54128fSAndroid Build Coastguard Worker 		if (gdp)
272*6a54128fSAndroid Build Coastguard Worker 			ext2fs_swap_group_desc2(fs, gdp);
273*6a54128fSAndroid Build Coastguard Worker 	}
274*6a54128fSAndroid Build Coastguard Worker #endif
275*6a54128fSAndroid Build Coastguard Worker 
276*6a54128fSAndroid Build Coastguard Worker 	if (actual == -1) {
277*6a54128fSAndroid Build Coastguard Worker 		retval = errno;
278*6a54128fSAndroid Build Coastguard Worker 		goto errout;
279*6a54128fSAndroid Build Coastguard Worker 	}
280*6a54128fSAndroid Build Coastguard Worker 	if (actual != (ssize_t)(fs->blocksize * fs->desc_blocks)) {
281*6a54128fSAndroid Build Coastguard Worker 		retval = EXT2_ET_SHORT_WRITE;
282*6a54128fSAndroid Build Coastguard Worker 		goto errout;
283*6a54128fSAndroid Build Coastguard Worker 	}
284*6a54128fSAndroid Build Coastguard Worker 
285*6a54128fSAndroid Build Coastguard Worker 	retval = 0;
286*6a54128fSAndroid Build Coastguard Worker 
287*6a54128fSAndroid Build Coastguard Worker errout:
288*6a54128fSAndroid Build Coastguard Worker 	free(buf);
289*6a54128fSAndroid Build Coastguard Worker 	return retval;
290*6a54128fSAndroid Build Coastguard Worker }
291*6a54128fSAndroid Build Coastguard Worker 
292*6a54128fSAndroid Build Coastguard Worker /*
293*6a54128fSAndroid Build Coastguard Worker  * Read the superblock and group descriptors and overwrite them.
294*6a54128fSAndroid Build Coastguard Worker  */
ext2fs_image_super_read(ext2_filsys fs,int fd,int flags EXT2FS_ATTR ((unused)))295*6a54128fSAndroid Build Coastguard Worker errcode_t ext2fs_image_super_read(ext2_filsys fs, int fd,
296*6a54128fSAndroid Build Coastguard Worker 				  int flags EXT2FS_ATTR((unused)))
297*6a54128fSAndroid Build Coastguard Worker {
298*6a54128fSAndroid Build Coastguard Worker 	char		*buf;
299*6a54128fSAndroid Build Coastguard Worker 	ssize_t		actual, size;
300*6a54128fSAndroid Build Coastguard Worker 	errcode_t	retval;
301*6a54128fSAndroid Build Coastguard Worker 
302*6a54128fSAndroid Build Coastguard Worker 	size = (ssize_t)fs->blocksize * (fs->group_desc_count + 1);
303*6a54128fSAndroid Build Coastguard Worker 	buf = malloc(size);
304*6a54128fSAndroid Build Coastguard Worker 	if (!buf)
305*6a54128fSAndroid Build Coastguard Worker 		return ENOMEM;
306*6a54128fSAndroid Build Coastguard Worker 
307*6a54128fSAndroid Build Coastguard Worker 	/*
308*6a54128fSAndroid Build Coastguard Worker 	 * Read it all in.
309*6a54128fSAndroid Build Coastguard Worker 	 */
310*6a54128fSAndroid Build Coastguard Worker 	actual = read(fd, buf, size);
311*6a54128fSAndroid Build Coastguard Worker 	if (actual == -1) {
312*6a54128fSAndroid Build Coastguard Worker 		retval = errno;
313*6a54128fSAndroid Build Coastguard Worker 		goto errout;
314*6a54128fSAndroid Build Coastguard Worker 	}
315*6a54128fSAndroid Build Coastguard Worker 	if (actual != size) {
316*6a54128fSAndroid Build Coastguard Worker 		retval = EXT2_ET_SHORT_READ;
317*6a54128fSAndroid Build Coastguard Worker 		goto errout;
318*6a54128fSAndroid Build Coastguard Worker 	}
319*6a54128fSAndroid Build Coastguard Worker 
320*6a54128fSAndroid Build Coastguard Worker 	/*
321*6a54128fSAndroid Build Coastguard Worker 	 * Now copy in the superblock and group descriptors
322*6a54128fSAndroid Build Coastguard Worker 	 */
323*6a54128fSAndroid Build Coastguard Worker 	memcpy(fs->super, buf, SUPERBLOCK_SIZE);
324*6a54128fSAndroid Build Coastguard Worker 
325*6a54128fSAndroid Build Coastguard Worker 	memcpy(fs->group_desc, buf + fs->blocksize,
326*6a54128fSAndroid Build Coastguard Worker 	       (ssize_t)fs->blocksize * fs->group_desc_count);
327*6a54128fSAndroid Build Coastguard Worker 
328*6a54128fSAndroid Build Coastguard Worker 	retval = 0;
329*6a54128fSAndroid Build Coastguard Worker 
330*6a54128fSAndroid Build Coastguard Worker errout:
331*6a54128fSAndroid Build Coastguard Worker 	free(buf);
332*6a54128fSAndroid Build Coastguard Worker 	return retval;
333*6a54128fSAndroid Build Coastguard Worker }
334*6a54128fSAndroid Build Coastguard Worker 
335*6a54128fSAndroid Build Coastguard Worker /*
336*6a54128fSAndroid Build Coastguard Worker  * Write the block/inode bitmaps.
337*6a54128fSAndroid Build Coastguard Worker  */
ext2fs_image_bitmap_write(ext2_filsys fs,int fd,int flags)338*6a54128fSAndroid Build Coastguard Worker errcode_t ext2fs_image_bitmap_write(ext2_filsys fs, int fd, int flags)
339*6a54128fSAndroid Build Coastguard Worker {
340*6a54128fSAndroid Build Coastguard Worker 	ext2fs_generic_bitmap	bmap;
341*6a54128fSAndroid Build Coastguard Worker 	errcode_t		retval;
342*6a54128fSAndroid Build Coastguard Worker 	ssize_t			actual;
343*6a54128fSAndroid Build Coastguard Worker 	size_t			c;
344*6a54128fSAndroid Build Coastguard Worker 	__u64			itr, cnt, size, total_size;
345*6a54128fSAndroid Build Coastguard Worker 	char			buf[1024];
346*6a54128fSAndroid Build Coastguard Worker 
347*6a54128fSAndroid Build Coastguard Worker 	if (flags & IMAGER_FLAG_INODEMAP) {
348*6a54128fSAndroid Build Coastguard Worker 		if (!fs->inode_map) {
349*6a54128fSAndroid Build Coastguard Worker 			retval = ext2fs_read_inode_bitmap(fs);
350*6a54128fSAndroid Build Coastguard Worker 			if (retval)
351*6a54128fSAndroid Build Coastguard Worker 				return retval;
352*6a54128fSAndroid Build Coastguard Worker 		}
353*6a54128fSAndroid Build Coastguard Worker 		bmap = fs->inode_map;
354*6a54128fSAndroid Build Coastguard Worker 		itr = 1;
355*6a54128fSAndroid Build Coastguard Worker 		cnt = (__u64)EXT2_INODES_PER_GROUP(fs->super) *
356*6a54128fSAndroid Build Coastguard Worker 			fs->group_desc_count;
357*6a54128fSAndroid Build Coastguard Worker 		size = (EXT2_INODES_PER_GROUP(fs->super) / 8);
358*6a54128fSAndroid Build Coastguard Worker 	} else {
359*6a54128fSAndroid Build Coastguard Worker 		if (!fs->block_map) {
360*6a54128fSAndroid Build Coastguard Worker 			retval = ext2fs_read_block_bitmap(fs);
361*6a54128fSAndroid Build Coastguard Worker 			if (retval)
362*6a54128fSAndroid Build Coastguard Worker 				return retval;
363*6a54128fSAndroid Build Coastguard Worker 		}
364*6a54128fSAndroid Build Coastguard Worker 		bmap = fs->block_map;
365*6a54128fSAndroid Build Coastguard Worker 		itr = fs->super->s_first_data_block;
366*6a54128fSAndroid Build Coastguard Worker 		cnt = EXT2_GROUPS_TO_CLUSTERS(fs->super, fs->group_desc_count);
367*6a54128fSAndroid Build Coastguard Worker 		size = EXT2_CLUSTERS_PER_GROUP(fs->super) / 8;
368*6a54128fSAndroid Build Coastguard Worker 	}
369*6a54128fSAndroid Build Coastguard Worker 	total_size = size * fs->group_desc_count;
370*6a54128fSAndroid Build Coastguard Worker 
371*6a54128fSAndroid Build Coastguard Worker 	while (cnt > 0) {
372*6a54128fSAndroid Build Coastguard Worker 		size = sizeof(buf);
373*6a54128fSAndroid Build Coastguard Worker 		if (size > (cnt >> 3))
374*6a54128fSAndroid Build Coastguard Worker 			size = (cnt >> 3);
375*6a54128fSAndroid Build Coastguard Worker 		if (size == 0)
376*6a54128fSAndroid Build Coastguard Worker 			break;
377*6a54128fSAndroid Build Coastguard Worker 
378*6a54128fSAndroid Build Coastguard Worker 		retval = ext2fs_get_generic_bmap_range(bmap, itr,
379*6a54128fSAndroid Build Coastguard Worker 						       size << 3, buf);
380*6a54128fSAndroid Build Coastguard Worker 		if (retval)
381*6a54128fSAndroid Build Coastguard Worker 			return retval;
382*6a54128fSAndroid Build Coastguard Worker 
383*6a54128fSAndroid Build Coastguard Worker 		actual = write(fd, buf, size);
384*6a54128fSAndroid Build Coastguard Worker 		if (actual == -1)
385*6a54128fSAndroid Build Coastguard Worker 			return errno;
386*6a54128fSAndroid Build Coastguard Worker 		if (actual != (int) size)
387*6a54128fSAndroid Build Coastguard Worker 			return EXT2_ET_SHORT_READ;
388*6a54128fSAndroid Build Coastguard Worker 
389*6a54128fSAndroid Build Coastguard Worker 		itr += size << 3;
390*6a54128fSAndroid Build Coastguard Worker 		cnt -= size << 3;
391*6a54128fSAndroid Build Coastguard Worker 	}
392*6a54128fSAndroid Build Coastguard Worker 
393*6a54128fSAndroid Build Coastguard Worker 	size = total_size % fs->blocksize;
394*6a54128fSAndroid Build Coastguard Worker 	memset(buf, 0, sizeof(buf));
395*6a54128fSAndroid Build Coastguard Worker 	if (size) {
396*6a54128fSAndroid Build Coastguard Worker 		size = fs->blocksize - size;
397*6a54128fSAndroid Build Coastguard Worker 		while (size) {
398*6a54128fSAndroid Build Coastguard Worker 			c = size;
399*6a54128fSAndroid Build Coastguard Worker 			if (c > (int) sizeof(buf))
400*6a54128fSAndroid Build Coastguard Worker 				c = sizeof(buf);
401*6a54128fSAndroid Build Coastguard Worker 			actual = write(fd, buf, c);
402*6a54128fSAndroid Build Coastguard Worker 			if (actual < 0)
403*6a54128fSAndroid Build Coastguard Worker 				return errno;
404*6a54128fSAndroid Build Coastguard Worker 			if ((size_t) actual != c)
405*6a54128fSAndroid Build Coastguard Worker 				return EXT2_ET_SHORT_WRITE;
406*6a54128fSAndroid Build Coastguard Worker 			size -= c;
407*6a54128fSAndroid Build Coastguard Worker 		}
408*6a54128fSAndroid Build Coastguard Worker 	}
409*6a54128fSAndroid Build Coastguard Worker 	return 0;
410*6a54128fSAndroid Build Coastguard Worker }
411*6a54128fSAndroid Build Coastguard Worker 
412*6a54128fSAndroid Build Coastguard Worker 
413*6a54128fSAndroid Build Coastguard Worker /*
414*6a54128fSAndroid Build Coastguard Worker  * Read the block/inode bitmaps.
415*6a54128fSAndroid Build Coastguard Worker  */
ext2fs_image_bitmap_read(ext2_filsys fs,int fd,int flags)416*6a54128fSAndroid Build Coastguard Worker errcode_t ext2fs_image_bitmap_read(ext2_filsys fs, int fd, int flags)
417*6a54128fSAndroid Build Coastguard Worker {
418*6a54128fSAndroid Build Coastguard Worker 	ext2fs_generic_bitmap	bmap;
419*6a54128fSAndroid Build Coastguard Worker 	errcode_t		retval;
420*6a54128fSAndroid Build Coastguard Worker 	__u64			itr, cnt;
421*6a54128fSAndroid Build Coastguard Worker 	char			buf[1024];
422*6a54128fSAndroid Build Coastguard Worker 	unsigned int		size;
423*6a54128fSAndroid Build Coastguard Worker 	ssize_t			actual;
424*6a54128fSAndroid Build Coastguard Worker 
425*6a54128fSAndroid Build Coastguard Worker 	if (flags & IMAGER_FLAG_INODEMAP) {
426*6a54128fSAndroid Build Coastguard Worker 		if (!fs->inode_map) {
427*6a54128fSAndroid Build Coastguard Worker 			retval = ext2fs_read_inode_bitmap(fs);
428*6a54128fSAndroid Build Coastguard Worker 			if (retval)
429*6a54128fSAndroid Build Coastguard Worker 				return retval;
430*6a54128fSAndroid Build Coastguard Worker 		}
431*6a54128fSAndroid Build Coastguard Worker 		bmap = fs->inode_map;
432*6a54128fSAndroid Build Coastguard Worker 		itr = 1;
433*6a54128fSAndroid Build Coastguard Worker 		cnt = (__u64)EXT2_INODES_PER_GROUP(fs->super) *
434*6a54128fSAndroid Build Coastguard Worker 			fs->group_desc_count;
435*6a54128fSAndroid Build Coastguard Worker 		size = (EXT2_INODES_PER_GROUP(fs->super) / 8);
436*6a54128fSAndroid Build Coastguard Worker 	} else {
437*6a54128fSAndroid Build Coastguard Worker 		if (!fs->block_map) {
438*6a54128fSAndroid Build Coastguard Worker 			retval = ext2fs_read_block_bitmap(fs);
439*6a54128fSAndroid Build Coastguard Worker 			if (retval)
440*6a54128fSAndroid Build Coastguard Worker 				return retval;
441*6a54128fSAndroid Build Coastguard Worker 		}
442*6a54128fSAndroid Build Coastguard Worker 		bmap = fs->block_map;
443*6a54128fSAndroid Build Coastguard Worker 		itr = fs->super->s_first_data_block;
444*6a54128fSAndroid Build Coastguard Worker 		cnt = EXT2_GROUPS_TO_BLOCKS(fs->super, fs->group_desc_count);
445*6a54128fSAndroid Build Coastguard Worker 		size = EXT2_BLOCKS_PER_GROUP(fs->super) / 8;
446*6a54128fSAndroid Build Coastguard Worker 	}
447*6a54128fSAndroid Build Coastguard Worker 
448*6a54128fSAndroid Build Coastguard Worker 	while (cnt > 0) {
449*6a54128fSAndroid Build Coastguard Worker 		size = sizeof(buf);
450*6a54128fSAndroid Build Coastguard Worker 		if (size > (cnt >> 3))
451*6a54128fSAndroid Build Coastguard Worker 			size = (cnt >> 3);
452*6a54128fSAndroid Build Coastguard Worker 		if (size == 0)
453*6a54128fSAndroid Build Coastguard Worker 			break;
454*6a54128fSAndroid Build Coastguard Worker 
455*6a54128fSAndroid Build Coastguard Worker 		actual = read(fd, buf, size);
456*6a54128fSAndroid Build Coastguard Worker 		if (actual == -1)
457*6a54128fSAndroid Build Coastguard Worker 			return errno;
458*6a54128fSAndroid Build Coastguard Worker 		if (actual != (int) size)
459*6a54128fSAndroid Build Coastguard Worker 			return EXT2_ET_SHORT_READ;
460*6a54128fSAndroid Build Coastguard Worker 
461*6a54128fSAndroid Build Coastguard Worker 		retval = ext2fs_set_generic_bmap_range(bmap, itr,
462*6a54128fSAndroid Build Coastguard Worker 						       size << 3, buf);
463*6a54128fSAndroid Build Coastguard Worker 		if (retval)
464*6a54128fSAndroid Build Coastguard Worker 			return retval;
465*6a54128fSAndroid Build Coastguard Worker 
466*6a54128fSAndroid Build Coastguard Worker 		itr += size << 3;
467*6a54128fSAndroid Build Coastguard Worker 		cnt -= size << 3;
468*6a54128fSAndroid Build Coastguard Worker 	}
469*6a54128fSAndroid Build Coastguard Worker 	return 0;
470*6a54128fSAndroid Build Coastguard Worker }
471