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 buf
= malloc(fs
->blocksize
);
209 * Write out the superblock
211 memset(buf
, 0, fs
->blocksize
);
212 #ifdef WORDS_BIGENDIAN
214 * We're writing out superblock so let's convert
215 * it to little endian and then back if needed
217 ext2fs_swap_super(fs
->super
);
218 memcpy(buf
, fs
->super
, SUPERBLOCK_SIZE
);
219 ext2fs_swap_super(fs
->super
);
221 memcpy(buf
, fs
->super
, SUPERBLOCK_SIZE
);
223 actual
= write(fd
, buf
, fs
->blocksize
);
228 if (actual
!= (ssize_t
) fs
->blocksize
) {
229 retval
= EXT2_ET_SHORT_WRITE
;
234 * Now write out the block group descriptors
237 cp
= (char *) fs
->group_desc
;
239 #ifdef WORDS_BIGENDIAN
241 * Convert group descriptors to little endian and back
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
);
252 actual
= write(fd
, cp
, fs
->blocksize
* fs
->desc_blocks
);
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
);
268 if (actual
!= (ssize_t
) (fs
->blocksize
* fs
->desc_blocks
)) {
269 retval
= EXT2_ET_SHORT_WRITE
;
281 * Read the superblock and group descriptors and overwrite them.
283 errcode_t
ext2fs_image_super_read(ext2_filsys fs
, int fd
,
284 int flags
EXT2FS_ATTR((unused
)))
287 ssize_t actual
, size
;
290 size
= fs
->blocksize
* (fs
->group_desc_count
+ 1);
298 actual
= read(fd
, buf
, size
);
303 if (actual
!= size
) {
304 retval
= EXT2_ET_SHORT_READ
;
309 * Now copy in the superblock and group descriptors
311 memcpy(fs
->super
, buf
, SUPERBLOCK_SIZE
);
313 memcpy(fs
->group_desc
, buf
+ fs
->blocksize
,
314 fs
->blocksize
* fs
->group_desc_count
);
324 * Write the block/inode bitmaps.
326 errcode_t
ext2fs_image_bitmap_write(ext2_filsys fs
, int fd
, int flags
)
328 ext2fs_generic_bitmap bmap
;
332 __u64 itr
, cnt
, size
, total_size
;
335 if (flags
& IMAGER_FLAG_INODEMAP
) {
336 if (!fs
->inode_map
) {
337 retval
= ext2fs_read_inode_bitmap(fs
);
341 bmap
= fs
->inode_map
;
343 cnt
= EXT2_INODES_PER_GROUP(fs
->super
) * fs
->group_desc_count
;
344 size
= (EXT2_INODES_PER_GROUP(fs
->super
) / 8);
346 if (!fs
->block_map
) {
347 retval
= ext2fs_read_block_bitmap(fs
);
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;
356 total_size
= size
* fs
->group_desc_count
;
360 if (size
> (cnt
>> 3))
363 retval
= ext2fs_get_generic_bmap_range(bmap
, itr
,
368 actual
= write(fd
, buf
, size
);
371 if (actual
!= (int) size
)
372 return EXT2_ET_SHORT_READ
;
378 size
= total_size
% fs
->blocksize
;
379 memset(buf
, 0, sizeof(buf
));
381 size
= fs
->blocksize
- size
;
384 if (c
> (int) sizeof(buf
))
386 actual
= write(fd
, buf
, c
);
389 if ((size_t) actual
!= c
)
390 return EXT2_ET_SHORT_WRITE
;
399 * Read the block/inode bitmaps.
401 errcode_t
ext2fs_image_bitmap_read(ext2_filsys fs
, int fd
, int flags
)
403 ext2fs_generic_bitmap bmap
;
410 if (flags
& IMAGER_FLAG_INODEMAP
) {
411 if (!fs
->inode_map
) {
412 retval
= ext2fs_read_inode_bitmap(fs
);
416 bmap
= fs
->inode_map
;
418 cnt
= EXT2_INODES_PER_GROUP(fs
->super
) * fs
->group_desc_count
;
419 size
= (EXT2_INODES_PER_GROUP(fs
->super
) / 8);
421 if (!fs
->block_map
) {
422 retval
= ext2fs_read_block_bitmap(fs
);
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;
434 if (size
> (cnt
>> 3))
437 actual
= read(fd
, buf
, size
);
440 if (actual
!= (int) size
)
441 return EXT2_ET_SHORT_READ
;
443 retval
= ext2fs_set_generic_bmap_range(bmap
, itr
,