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