Home | History | Annotate | Download | only in ext2fs
      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  */
     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 
     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  */
    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  */
    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  */
    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  */
    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  */
    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