imager.c revision 72ed12648368b3f3ea14e8102e20bf5d3a3be6d3
15c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/*
25c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * image.c --- writes out the critical parts of the filesystem as a
35c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * 	flat file.
45c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *
55c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Copyright (C) 2000 Theodore Ts'o.
65c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *
75c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Note: this uses the POSIX IO interfaces, unlike most of the other
85c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * functions in this library.  So sue me.
95c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *
105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * %Begin-Header%
115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * This file may be redistributed under the terms of the GNU Public
125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * License.
135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * %End-Header%
145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */
155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include <stdio.h>
175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include <string.h>
185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#if HAVE_UNISTD_H
195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include <unistd.h>
205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#endif
215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#if HAVE_ERRNO_H
225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include <errno.h>
235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#endif
245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include <fcntl.h>
255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include <time.h>
265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#if HAVE_SYS_STAT_H
275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include <sys/stat.h>
285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#endif
295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#if HAVE_SYS_TYPES_H
3053e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include <sys/types.h>
315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#endif
325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3353e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#if EXT2_FLAT_INCLUDES
3453e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "ext2_fs.h"
3553e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#else
361e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)#include <linux/ext2_fs.h>
3753e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#endif
381e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)
3953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "ext2fs.h"
4053e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)
4153e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)/*
421e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles) * This function returns 1 if the specified block is all zeros
435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */
445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static int check_zero_block(char *buf, int blocksize)
455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	char	*cp = buf;
475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	int	left = blocksize;
485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	while (left > 0) {
505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		if (*cp++)
515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)			return 0;
525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		left--;
535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	}
545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	return 1;
555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/*
585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Write the inode table out as a single block.
595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */
605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#define BUF_BLOCKS	32
615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)errcode_t ext2fs_image_inode_write(ext2_filsys fs, int fd, int flags)
635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	unsigned int	group, left, c, d;
655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	char		*buf, *cp;
665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	blk_t		blk;
675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	ssize_t		actual;
685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	errcode_t	retval;
695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
70e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch	buf = malloc(fs->blocksize * BUF_BLOCKS);
71e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch	if (!buf)
725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		return ENOMEM;
735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	for (group = 0; group < fs->group_desc_count; group++) {
755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		blk = fs->group_desc[(unsigned)group].bg_inode_table;
765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		if (!blk)
775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)			return EXT2_ET_MISSING_INODE_TABLE;
785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		left = fs->inode_blocks_per_group;
795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		while (left) {
805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)			c = BUF_BLOCKS;
815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)			if (c > left)
825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)				c = left;
835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)			retval = io_channel_read_blk(fs->io, blk, c, buf);
845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)			if (retval)
855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)				goto errout;
865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)			cp = buf;
875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)			while (c) {
885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)				if (!(flags & IMAGER_FLAG_SPARSEWRITE)) {
895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)					d = c;
905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)					goto skip_sparse;
915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)				}
925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)				/* Skip zero blocks */
93926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)				if (check_zero_block(cp, fs->blocksize)) {
945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)					c--;
955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)					blk++;
965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)					left--;
975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)					cp += fs->blocksize;
985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)					lseek(fd, fs->blocksize, SEEK_CUR);
995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)					continue;
1005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)				}
1015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)				/* Find non-zero blocks */
1025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)				for (d=1; d < c; d++) {
1035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)					if (check_zero_block(cp + d*fs->blocksize, fs->blocksize))
1045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)						break;
1055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)				}
1065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)			skip_sparse:
1075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)				actual = write(fd, cp, fs->blocksize * d);
1085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)				if (actual == -1) {
1095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)					errno = retval;
1105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)					goto errout;
1115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)				}
1125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)				if (actual != fs->blocksize * d) {
1135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)					retval = EXT2_ET_SHORT_WRITE;
1145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)					goto errout;
1155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)				}
1165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)				blk += d;
1175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)				left -= d;
1185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)				cp += fs->blocksize * d;
1195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)				c -= d;
1205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)			}
1215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		}
1225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	}
1235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	retval = 0;
1245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)errout:
1265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	free(buf);
1275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	return retval;
1285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/*
1315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Read in the inode table and stuff it into place
1325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */
1335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)errcode_t ext2fs_image_inode_read(ext2_filsys fs, int fd, int flags)
1345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	unsigned int	group, i, c, left;
1365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	char		*buf;
1375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	blk_t		blk;
1385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	ssize_t		actual;
1395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	errcode_t	retval;
1405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	buf = malloc(fs->blocksize * BUF_BLOCKS);
1425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	if (!buf)
1435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		return ENOMEM;
1445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	for (group = 0; group < fs->group_desc_count; group++) {
1465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		blk = fs->group_desc[(unsigned)group].bg_inode_table;
1475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		if (!blk)
1485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)			return EXT2_ET_MISSING_INODE_TABLE;
1495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		left = fs->inode_blocks_per_group;
1505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		while (left) {
1515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)			c = BUF_BLOCKS;
1525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)			if (c > left)
1535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)				c = left;
1545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)			actual = read(fd, buf, fs->blocksize * c);
1555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)			if (actual == -1) {
1565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)				errno = retval;
1575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)				goto errout;
1585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)			}
1595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)			if (actual != fs->blocksize * c) {
1605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)				retval = EXT2_ET_SHORT_READ;
1615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)				goto errout;
1625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)			}
1635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)			retval = io_channel_write_blk(fs->io, blk, c, buf);
1645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)			if (retval)
1655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)				goto errout;
1665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)			blk += c;
1685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)			left -= c;
1695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		}
1705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	}
1715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	retval = ext2fs_flush_icache(fs);
1725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)errout:
1745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	free(buf);
1755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	return retval;
1765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/*
1795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Write out superblock and group descriptors
1805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */
1815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)errcode_t ext2fs_image_super_write(ext2_filsys fs, int fd, int flags)
1825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	unsigned int	i;
1845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	char		*buf, *cp;
1855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	blk_t		blk;
1865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	ssize_t		actual;
1875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	errcode_t	retval;
1885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	buf = malloc(fs->blocksize);
1905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	if (!buf)
1915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		return ENOMEM;
1925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	/*
1945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	 * Write out the superblock
1955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	 */
1965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	memset(buf, 0, fs->blocksize);
1975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	memcpy(buf, fs->super, SUPERBLOCK_SIZE);
1985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	actual = write(fd, buf, fs->blocksize);
1995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	if (actual == -1) {
2005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		errno = retval;
2015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		goto errout;
2025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	}
2035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	if (actual != fs->blocksize) {
2045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		retval = EXT2_ET_SHORT_WRITE;
2055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		goto errout;
2065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	}
2075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	/*
2095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	 * Now write out the block group descriptors
2105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	 */
2115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	cp = (char *) fs->group_desc;
2125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	actual = write(fd, cp, fs->blocksize * fs->desc_blocks);
2135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	if (actual == -1) {
2145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		errno = retval;
2155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		goto errout;
2165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	}
2175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	if (actual != fs->blocksize * fs->desc_blocks) {
2185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		retval = EXT2_ET_SHORT_WRITE;
2195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		goto errout;
2205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	}
2215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	retval = 0;
2235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)errout:
2255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	free(buf);
2265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	return retval;
2275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
2285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/*
2305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Read the superblock and group descriptors and overwrite them.
2315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */
2325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)errcode_t ext2fs_image_super_read(ext2_filsys fs, int fd, int flags)
2335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
2345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	unsigned int	i;
2355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	char		*buf, *cp;
2365267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)	blk_t		blk;
2375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	ssize_t		actual, size;
2385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	errcode_t	retval;
2395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	size = fs->blocksize * (fs->group_desc_count + 1);
2415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	buf = malloc(size);
2425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	if (!buf)
2435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		return ENOMEM;
2445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	/*
2465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	 * Read it all in.
2475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	 */
2485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	actual = read(fd, buf, size);
2495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	if (actual == -1) {
2505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		errno = retval;
2515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		goto errout;
2525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	}
2535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	if (actual != size) {
2545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		retval = EXT2_ET_SHORT_READ;
2555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		goto errout;
2565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	}
2575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	/*
2595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	 * Now copy in the superblock and group descriptors
2605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	 */
2615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	memcpy(fs->super, buf, SUPERBLOCK_SIZE);
2625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	memcpy(fs->group_desc, buf + fs->blocksize,
2645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	       fs->blocksize * fs->group_desc_count);
2655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	retval = 0;
2675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)errout:
2695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	free(buf);
2705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	return retval;
2715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
2725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/*
2745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Write the block/inode bitmaps.
2755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */
2765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)errcode_t ext2fs_image_bitmap_write(ext2_filsys fs, int fd, int flags)
2775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
2785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	char		*ptr;
2795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	int		c, size;
2805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	char		zero_buf[1024];
2815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	ssize_t		actual;
2825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	errcode_t	retval;
2835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	if (flags & IMAGER_FLAG_INODEMAP) {
2855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		if (!fs->inode_map) {
2865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)			retval = ext2fs_read_inode_bitmap(fs);
2875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)			if (retval)
2885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)				return retval;
2895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		}
2905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		ptr = fs->inode_map->bitmap;
2915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		size = ((EXT2_INODES_PER_GROUP(fs->super)+7) / 8);
2925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	} else {
2935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		if (!fs->block_map) {
2945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)			retval = ext2fs_read_block_bitmap(fs);
2958abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles)			if (retval)
2965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)				return retval;
2975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		}
2985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		ptr = fs->block_map->bitmap;
2995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		size = EXT2_BLOCKS_PER_GROUP(fs->super) / 8;
3005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	}
3015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	actual = write(fd, ptr, size);
3035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	if (actual == -1) {
3045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		errno = retval;
3055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		goto errout;
3065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	}
3075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	if (actual != size) {
308f5e4ad553afbc08dd2e729bb77e937a9a94d5827Torne (Richard Coles)		retval = EXT2_ET_SHORT_WRITE;
309f5e4ad553afbc08dd2e729bb77e937a9a94d5827Torne (Richard Coles)		goto errout;
3105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	}
3115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	size = size % fs->blocksize;
312f5e4ad553afbc08dd2e729bb77e937a9a94d5827Torne (Richard Coles)	memset(zero_buf, 0, sizeof(zero_buf));
3135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	if (size) {
3145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		size = fs->blocksize - size;
315f5e4ad553afbc08dd2e729bb77e937a9a94d5827Torne (Richard Coles)		while (size) {
316f5e4ad553afbc08dd2e729bb77e937a9a94d5827Torne (Richard Coles)			c = size;
3175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)			if (c > sizeof(zero_buf))
3185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)				c = sizeof(zero_buf);
319f5e4ad553afbc08dd2e729bb77e937a9a94d5827Torne (Richard Coles)			actual = write(fd, zero_buf, c);
3205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)			if (actual == -1) {
3215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)				errno = retval;
3225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)				goto errout;
3235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)			}
3245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)			if (actual != c) {
3255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)				retval = EXT2_ET_SHORT_WRITE;
3265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)				goto errout;
3275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)			}
3285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)			size -= c;
3295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		}
3305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	}
3315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	retval = 0;
3325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)errout:
3335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	return (retval);
3345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
3355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/*
3385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Read the block/inode bitmaps.
3395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */
3405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)errcode_t ext2fs_image_bitmap_read(ext2_filsys fs, int fd, int flags)
3415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
3425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	char		*ptr, *buf = 0;
3435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	int		c, size;
3445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	char		zero_buf[1024];
345f5e4ad553afbc08dd2e729bb77e937a9a94d5827Torne (Richard Coles)	ssize_t		actual;
3465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	errcode_t	retval;
3475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
348f5e4ad553afbc08dd2e729bb77e937a9a94d5827Torne (Richard Coles)	if (flags & IMAGER_FLAG_INODEMAP) {
3495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		if (!fs->inode_map) {
3505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)			retval = ext2fs_read_inode_bitmap(fs);
351f5e4ad553afbc08dd2e729bb77e937a9a94d5827Torne (Richard Coles)			if (retval)
3525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)				return retval;
3535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		}
354f5e4ad553afbc08dd2e729bb77e937a9a94d5827Torne (Richard Coles)		ptr = fs->inode_map->bitmap;
3555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		size = ((EXT2_INODES_PER_GROUP(fs->super)+7) / 8);
3565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	} else {
3575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		if (!fs->block_map) {
3585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)			retval = ext2fs_read_block_bitmap(fs);
3595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)			if (retval)
3605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)				return retval;
3615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		}
3625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		ptr = fs->block_map->bitmap;
3635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		size = EXT2_BLOCKS_PER_GROUP(fs->super) / 8;
3645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	}
3655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	buf = malloc(size);
3675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	if (!buf)
3685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		return ENOMEM;
3695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	actual = read(fd, buf, size);
371926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)	if (actual == -1) {
3725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		errno = retval;
3735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		goto errout;
3745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	}
3755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	if (actual != size) {
3765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		retval = EXT2_ET_SHORT_WRITE;
3775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		goto errout;
3785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	}
3795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	memcpy(ptr, buf, size);
3805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
381e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles)	retval = 0;
3825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)errout:
3835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)	if (buf)
3845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)		free(buf);
385e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles)	return (retval);
3865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
3875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)