2 * image.c --- writes out the critical parts of the filesystem as a
5 * Copyright (C) 2000 Theodore Ts'o.
7 * Note: this uses the POSIX IO interfaces, unlike most of the other
8 * functions in this library. So sue me.
11 * This file may be redistributed under the terms of the GNU Library
12 * General Public License, version 2.
31 #include <sys/types.h>
37 #ifndef HAVE_TYPE_SSIZE_T
42 * This function returns 1 if the specified block is all zeros
44 static int check_zero_block(char *buf, int blocksize)
58 * Write the inode table out as a single block.
62 errcode_t ext2fs_image_inode_write(ext2_filsys fs, int fd, int flags)
64 unsigned int group, left, c, d;
71 buf = malloc(fs->blocksize * BUF_BLOCKS);
75 for (group = 0; group < fs->group_desc_count; group++) {
76 blk = ext2fs_inode_table_loc(fs, (unsigned)group);
78 retval = EXT2_ET_MISSING_INODE_TABLE;
81 left = fs->inode_blocks_per_group;
86 retval = io_channel_read_blk64(fs->io, blk, c, buf);
91 if (!(flags & IMAGER_FLAG_SPARSEWRITE)) {
95 /* Skip zero blocks */
96 if (check_zero_block(cp, fs->blocksize)) {
101 r = ext2fs_llseek(fd, fs->blocksize,
109 /* Find non-zero blocks */
110 for (d=1; d < c; d++) {
111 if (check_zero_block(cp + d*fs->blocksize, fs->blocksize))
115 actual = write(fd, cp, fs->blocksize * d);
120 if (actual != (ssize_t) (fs->blocksize * d)) {
121 retval = EXT2_ET_SHORT_WRITE;
126 cp += fs->blocksize * d;
139 * Read in the inode table and stuff it into place
141 errcode_t ext2fs_image_inode_read(ext2_filsys fs, int fd,
142 int flags EXT2FS_ATTR((unused)))
144 unsigned int group, c, left;
150 buf = malloc(fs->blocksize * BUF_BLOCKS);
154 for (group = 0; group < fs->group_desc_count; group++) {
155 blk = ext2fs_inode_table_loc(fs, (unsigned)group);
157 retval = EXT2_ET_MISSING_INODE_TABLE;
160 left = fs->inode_blocks_per_group;
165 actual = read(fd, buf, fs->blocksize * c);
170 if (actual != (ssize_t) (fs->blocksize * c)) {
171 retval = EXT2_ET_SHORT_READ;
174 retval = io_channel_write_blk64(fs->io, blk, c, buf);
182 retval = ext2fs_flush_icache(fs);
190 * Write out superblock and group descriptors
192 errcode_t ext2fs_image_super_write(ext2_filsys fs, int fd,
193 int flags EXT2FS_ATTR((unused)))
198 #ifdef WORDS_BIGENDIAN
199 unsigned int groups_per_block;
200 struct ext2_group_desc *gdp;
204 if (fs->group_desc == NULL)
205 return EXT2_ET_NO_GDESC;
207 buf = malloc(fs->blocksize);
212 * Write out the superblock
214 memset(buf, 0, fs->blocksize);
215 #ifdef WORDS_BIGENDIAN
217 * We're writing out superblock so let's convert
218 * it to little endian and then back if needed
220 ext2fs_swap_super(fs->super);
221 memcpy(buf, fs->super, SUPERBLOCK_SIZE);
222 ext2fs_swap_super(fs->super);
224 memcpy(buf, fs->super, SUPERBLOCK_SIZE);
226 actual = write(fd, buf, fs->blocksize);
231 if (actual != (ssize_t) fs->blocksize) {
232 retval = EXT2_ET_SHORT_WRITE;
237 * Now write out the block group descriptors
240 cp = (char *) fs->group_desc;
242 #ifdef WORDS_BIGENDIAN
244 * Convert group descriptors to little endian and back
247 groups_per_block = EXT2_DESC_PER_BLOCK(fs->super);
248 gdp = (struct ext2_group_desc *) cp;
249 for (j=0; j < groups_per_block*fs->desc_blocks; j++) {
250 gdp = ext2fs_group_desc(fs, fs->group_desc, j);
251 ext2fs_swap_group_desc2(fs, gdp);
255 actual = write(fd, cp, fs->blocksize * fs->desc_blocks);
258 #ifdef WORDS_BIGENDIAN
259 groups_per_block = EXT2_DESC_PER_BLOCK(fs->super);
260 gdp = (struct ext2_group_desc *) cp;
261 for (j=0; j < groups_per_block*fs->desc_blocks; j++) {
262 gdp = ext2fs_group_desc(fs, fs->group_desc, j);
263 ext2fs_swap_group_desc2(fs, gdp);
271 if (actual != (ssize_t) (fs->blocksize * fs->desc_blocks)) {
272 retval = EXT2_ET_SHORT_WRITE;
284 * Read the superblock and group descriptors and overwrite them.
286 errcode_t ext2fs_image_super_read(ext2_filsys fs, int fd,
287 int flags EXT2FS_ATTR((unused)))
290 ssize_t actual, size;
293 size = fs->blocksize * (fs->group_desc_count + 1);
301 actual = read(fd, buf, size);
306 if (actual != size) {
307 retval = EXT2_ET_SHORT_READ;
312 * Now copy in the superblock and group descriptors
314 memcpy(fs->super, buf, SUPERBLOCK_SIZE);
316 memcpy(fs->group_desc, buf + fs->blocksize,
317 fs->blocksize * fs->group_desc_count);
327 * Write the block/inode bitmaps.
329 errcode_t ext2fs_image_bitmap_write(ext2_filsys fs, int fd, int flags)
331 ext2fs_generic_bitmap bmap;
335 __u64 itr, cnt, size, total_size;
338 if (flags & IMAGER_FLAG_INODEMAP) {
339 if (!fs->inode_map) {
340 retval = ext2fs_read_inode_bitmap(fs);
344 bmap = fs->inode_map;
346 cnt = EXT2_INODES_PER_GROUP(fs->super) * fs->group_desc_count;
347 size = (EXT2_INODES_PER_GROUP(fs->super) / 8);
349 if (!fs->block_map) {
350 retval = ext2fs_read_block_bitmap(fs);
354 bmap = fs->block_map;
355 itr = fs->super->s_first_data_block;
356 cnt = EXT2_GROUPS_TO_CLUSTERS(fs->super, fs->group_desc_count);
357 size = EXT2_CLUSTERS_PER_GROUP(fs->super) / 8;
359 total_size = size * fs->group_desc_count;
363 if (size > (cnt >> 3))
366 retval = ext2fs_get_generic_bmap_range(bmap, itr,
371 actual = write(fd, buf, size);
374 if (actual != (int) size)
375 return EXT2_ET_SHORT_READ;
381 size = total_size % fs->blocksize;
382 memset(buf, 0, sizeof(buf));
384 size = fs->blocksize - size;
387 if (c > (int) sizeof(buf))
389 actual = write(fd, buf, c);
392 if ((size_t) actual != c)
393 return EXT2_ET_SHORT_WRITE;
402 * Read the block/inode bitmaps.
404 errcode_t ext2fs_image_bitmap_read(ext2_filsys fs, int fd, int flags)
406 ext2fs_generic_bitmap bmap;
413 if (flags & IMAGER_FLAG_INODEMAP) {
414 if (!fs->inode_map) {
415 retval = ext2fs_read_inode_bitmap(fs);
419 bmap = fs->inode_map;
421 cnt = EXT2_INODES_PER_GROUP(fs->super) * fs->group_desc_count;
422 size = (EXT2_INODES_PER_GROUP(fs->super) / 8);
424 if (!fs->block_map) {
425 retval = ext2fs_read_block_bitmap(fs);
429 bmap = fs->block_map;
430 itr = fs->super->s_first_data_block;
431 cnt = EXT2_GROUPS_TO_BLOCKS(fs->super, fs->group_desc_count);
432 size = EXT2_BLOCKS_PER_GROUP(fs->super) / 8;
437 if (size > (cnt >> 3))
440 actual = read(fd, buf, size);
443 if (actual != (int) size)
444 return EXT2_ET_SHORT_READ;
446 retval = ext2fs_set_generic_bmap_range(bmap, itr,