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