2 * e2image.c --- Program which writes an image file backing up
3 * critical metadata for the filesystem.
5 * Copyright 2000, 2001 by Theodore Ts'o.
8 * This file may be redistributed under the terms of the GNU Public
13 #define _LARGEFILE_SOURCE
14 #define _LARGEFILE64_SOURCE
36 #include <sys/types.h>
39 #include "ext2fs/ext2_fs.h"
40 #include "ext2fs/ext2fs.h"
41 #include "et/com_err.h"
42 #include "uuid/uuid.h"
44 #include "ext2fs/e2image.h"
45 #include "ext2fs/qcow2.h"
47 #include "../version.h"
48 #include "nls-enable.h"
50 #define QCOW_OFLAG_COPIED (1LL << 63)
53 const char * program_name
= "e2image";
54 char * device_name
= NULL
;
57 /* writing to blk device: don't skip zeroed blocks */
59 static void lseek_error_and_exit(int errnum
)
61 fprintf(stderr
, "seek: %s\n", error_message(errnum
));
65 static blk64_t
align_offset(blk64_t offset
, int n
)
67 return (offset
+ n
- 1) & ~(n
- 1);
70 static int get_bits_from_size(size_t size
)
78 /* Not a power of two */
88 static void usage(void)
90 fprintf(stderr
, _("Usage: %s [-rsIQaf] device image_file\n"),
95 static void generic_write(int fd
, void *buf
, int blocksize
, blk64_t block
)
97 int count
, free_buf
= 0;
105 err
= ext2fs_get_arrayzero(1, blocksize
, &buf
);
107 com_err(program_name
, err
, "while allocating buffer");
112 count
= write(fd
, buf
, blocksize
);
113 if (count
!= blocksize
) {
120 com_err(program_name
, err
, "error writing block %llu",
123 com_err(program_name
, err
, "error in write()");
128 ext2fs_free_mem(&buf
);
131 static void write_header(int fd
, void *hdr
, int hdr_size
, int wrt_size
)
137 if (hdr_size
> wrt_size
) {
138 fprintf(stderr
, _("Error: header size is bigger than "
142 ret
= ext2fs_get_mem(wrt_size
, &header_buf
);
144 fputs(_("Couldn't allocate header buffer\n"), stderr
);
148 if (ext2fs_llseek(fd
, 0, SEEK_SET
) < 0) {
149 perror("ext2fs_llseek while writing header");
152 memset(header_buf
, 0, wrt_size
);
155 memcpy(header_buf
, hdr
, hdr_size
);
157 generic_write(fd
, header_buf
, wrt_size
, 0);
159 ext2fs_free_mem(&header_buf
);
162 static void write_image_file(ext2_filsys fs
, int fd
)
164 struct ext2_image_hdr hdr
;
168 write_header(fd
, NULL
, sizeof(struct ext2_image_hdr
), fs
->blocksize
);
169 memset(&hdr
, 0, sizeof(struct ext2_image_hdr
));
171 hdr
.offset_super
= ext2fs_llseek(fd
, 0, SEEK_CUR
);
172 retval
= ext2fs_image_super_write(fs
, fd
, 0);
174 com_err(program_name
, retval
, _("while writing superblock"));
178 hdr
.offset_inode
= ext2fs_llseek(fd
, 0, SEEK_CUR
);
179 retval
= ext2fs_image_inode_write(fs
, fd
,
180 (fd
!= 1) ? IMAGER_FLAG_SPARSEWRITE
: 0);
182 com_err(program_name
, retval
, _("while writing inode table"));
186 hdr
.offset_blockmap
= ext2fs_llseek(fd
, 0, SEEK_CUR
);
187 retval
= ext2fs_image_bitmap_write(fs
, fd
, 0);
189 com_err(program_name
, retval
, _("while writing block bitmap"));
193 hdr
.offset_inodemap
= ext2fs_llseek(fd
, 0, SEEK_CUR
);
194 retval
= ext2fs_image_bitmap_write(fs
, fd
, IMAGER_FLAG_INODEMAP
);
196 com_err(program_name
, retval
, _("while writing inode bitmap"));
200 hdr
.magic_number
= EXT2_ET_MAGIC_E2IMAGE
;
201 strcpy(hdr
.magic_descriptor
, "Ext2 Image 1.0");
202 gethostname(hdr
.fs_hostname
, sizeof(hdr
.fs_hostname
));
203 strncpy(hdr
.fs_device_name
, device_name
, sizeof(hdr
.fs_device_name
)-1);
204 hdr
.fs_device_name
[sizeof(hdr
.fs_device_name
) - 1] = 0;
205 hdr
.fs_blocksize
= fs
->blocksize
;
207 if (stat(device_name
, &st
) == 0)
208 hdr
.fs_device
= st
.st_rdev
;
210 if (fstat(fd
, &st
) == 0) {
211 hdr
.image_device
= st
.st_dev
;
212 hdr
.image_inode
= st
.st_ino
;
214 memcpy(hdr
.fs_uuid
, fs
->super
->s_uuid
, sizeof(hdr
.fs_uuid
));
216 hdr
.image_time
= time(0);
217 write_header(fd
, &hdr
, sizeof(struct ext2_image_hdr
), fs
->blocksize
);
221 * These set of functions are used to write a RAW image file.
223 ext2fs_block_bitmap meta_block_map
;
224 ext2fs_block_bitmap scramble_block_map
; /* Directory blocks to be scrambled */
225 blk64_t meta_blocks_count
;
227 struct process_block_struct
{
233 * These subroutines short circuits ext2fs_get_blocks and
234 * ext2fs_check_directory; we use them since we already have the inode
235 * structure, so there's no point in letting the ext2fs library read
238 static ino_t stashed_ino
= 0;
239 static struct ext2_inode
*stashed_inode
;
241 static errcode_t
meta_get_blocks(ext2_filsys fs
EXT2FS_ATTR((unused
)),
247 if ((ino
!= stashed_ino
) || !stashed_inode
)
248 return EXT2_ET_CALLBACK_NOTHANDLED
;
250 for (i
=0; i
< EXT2_N_BLOCKS
; i
++)
251 blocks
[i
] = stashed_inode
->i_block
[i
];
255 static errcode_t
meta_check_directory(ext2_filsys fs
EXT2FS_ATTR((unused
)),
258 if ((ino
!= stashed_ino
) || !stashed_inode
)
259 return EXT2_ET_CALLBACK_NOTHANDLED
;
261 if (!LINUX_S_ISDIR(stashed_inode
->i_mode
))
262 return EXT2_ET_NO_DIRECTORY
;
266 static errcode_t
meta_read_inode(ext2_filsys fs
EXT2FS_ATTR((unused
)),
268 struct ext2_inode
*inode
)
270 if ((ino
!= stashed_ino
) || !stashed_inode
)
271 return EXT2_ET_CALLBACK_NOTHANDLED
;
272 *inode
= *stashed_inode
;
276 static void use_inode_shortcuts(ext2_filsys fs
, int use_shortcuts
)
279 fs
->get_blocks
= meta_get_blocks
;
280 fs
->check_directory
= meta_check_directory
;
281 fs
->read_inode
= meta_read_inode
;
285 fs
->check_directory
= 0;
290 static int process_dir_block(ext2_filsys fs
EXT2FS_ATTR((unused
)),
292 e2_blkcnt_t blockcnt
EXT2FS_ATTR((unused
)),
293 blk64_t ref_block
EXT2FS_ATTR((unused
)),
294 int ref_offset
EXT2FS_ATTR((unused
)),
295 void *priv_data
EXT2FS_ATTR((unused
)))
297 struct process_block_struct
*p
;
299 p
= (struct process_block_struct
*) priv_data
;
301 ext2fs_mark_block_bitmap2(meta_block_map
, *block_nr
);
303 if (scramble_block_map
&& p
->is_dir
&& blockcnt
>= 0)
304 ext2fs_mark_block_bitmap2(scramble_block_map
, *block_nr
);
308 static int process_file_block(ext2_filsys fs
EXT2FS_ATTR((unused
)),
310 e2_blkcnt_t blockcnt
,
311 blk64_t ref_block
EXT2FS_ATTR((unused
)),
312 int ref_offset
EXT2FS_ATTR((unused
)),
313 void *priv_data
EXT2FS_ATTR((unused
)))
315 if (blockcnt
< 0 || all_data
) {
316 ext2fs_mark_block_bitmap2(meta_block_map
, *block_nr
);
322 static void mark_table_blocks(ext2_filsys fs
)
324 blk64_t first_block
, b
;
327 first_block
= fs
->super
->s_first_data_block
;
329 * Mark primary superblock
331 ext2fs_mark_block_bitmap2(meta_block_map
, first_block
);
335 * Mark the primary superblock descriptors
337 for (j
= 0; j
< fs
->desc_blocks
; j
++) {
338 ext2fs_mark_block_bitmap2(meta_block_map
,
339 ext2fs_descriptor_block_loc2(fs
, first_block
, j
));
341 meta_blocks_count
+= fs
->desc_blocks
;
343 for (i
= 0; i
< fs
->group_desc_count
; i
++) {
345 * Mark the blocks used for the inode table
347 if ((output_is_blk
||
348 !ext2fs_bg_flags_test(fs
, i
, EXT2_BG_INODE_UNINIT
)) &&
349 ext2fs_inode_table_loc(fs
, i
)) {
350 unsigned int end
= (unsigned) fs
->inode_blocks_per_group
;
351 /* skip unused blocks */
352 if (!output_is_blk
&&
353 EXT2_HAS_RO_COMPAT_FEATURE(fs
->super
,
354 EXT4_FEATURE_RO_COMPAT_GDT_CSUM
))
355 end
-= (ext2fs_bg_itable_unused(fs
, i
) /
356 EXT2_INODES_PER_BLOCK(fs
->super
));
357 for (j
= 0, b
= ext2fs_inode_table_loc(fs
, i
);
360 ext2fs_mark_block_bitmap2(meta_block_map
, b
);
366 * Mark block used for the block bitmap
368 if (!ext2fs_bg_flags_test(fs
, i
, EXT2_BG_BLOCK_UNINIT
) &&
369 ext2fs_block_bitmap_loc(fs
, i
)) {
370 ext2fs_mark_block_bitmap2(meta_block_map
,
371 ext2fs_block_bitmap_loc(fs
, i
));
376 * Mark block used for the inode bitmap
378 if (!ext2fs_bg_flags_test(fs
, i
, EXT2_BG_INODE_UNINIT
) &&
379 ext2fs_inode_bitmap_loc(fs
, i
)) {
380 ext2fs_mark_block_bitmap2(meta_block_map
,
381 ext2fs_inode_bitmap_loc(fs
, i
));
388 * This function returns 1 if the specified block is all zeros
390 static int check_zero_block(char *buf
, int blocksize
)
393 int left
= blocksize
;
405 static void write_block(int fd
, char *buf
, int sparse_offset
,
406 int blocksize
, blk64_t block
)
411 ret
= ext2fs_llseek(fd
, sparse_offset
, SEEK_CUR
);
414 lseek_error_and_exit(errno
);
415 generic_write(fd
, buf
, blocksize
, block
);
420 #define EXT4_MAX_REC_LEN ((1<<16)-1)
422 static void scramble_dir_block(ext2_filsys fs
, blk64_t blk
, char *buf
)
425 struct ext2_dir_entry_2
*dirent
;
426 unsigned int rec_len
;
429 end
= buf
+ fs
->blocksize
;
430 for (p
= buf
; p
< end
-8; p
+= rec_len
) {
431 dirent
= (struct ext2_dir_entry_2
*) p
;
432 rec_len
= dirent
->rec_len
;
433 #ifdef WORDS_BIGENDIAN
434 rec_len
= ext2fs_swab16(rec_len
);
436 if (rec_len
== EXT4_MAX_REC_LEN
|| rec_len
== 0)
437 rec_len
= fs
->blocksize
;
439 rec_len
= (rec_len
& 65532) | ((rec_len
& 3) << 16);
441 printf("rec_len = %d, name_len = %d\n", rec_len
, dirent
->name_len
);
443 if (rec_len
< 8 || (rec_len
% 4) ||
445 printf("Corrupt directory block %lu: "
446 "bad rec_len (%d)\n", (unsigned long) blk
,
449 (void) ext2fs_set_rec_len(fs
, rec_len
,
450 (struct ext2_dir_entry
*) dirent
);
451 #ifdef WORDS_BIGENDIAN
452 dirent
->rec_len
= ext2fs_swab16(dirent
->rec_len
);
456 if (dirent
->name_len
+ 8U > rec_len
) {
457 printf("Corrupt directory block %lu: "
458 "bad name_len (%d)\n", (unsigned long) blk
,
460 dirent
->name_len
= rec_len
- 8;
464 len
= rec_len
- dirent
->name_len
- 8;
466 memset(cp
+dirent
->name_len
, 0, len
);
467 if (dirent
->name_len
==1 && cp
[0] == '.')
469 if (dirent
->name_len
==2 && cp
[0] == '.' && cp
[1] == '.')
472 memset(cp
, 'A', dirent
->name_len
);
473 len
= dirent
->name_len
;
475 while ((len
> 0) && (id
> 0)) {
484 static void output_meta_data_blocks(ext2_filsys fs
, int fd
)
488 char *buf
, *zero_buf
;
491 retval
= ext2fs_get_mem(fs
->blocksize
, &buf
);
493 com_err(program_name
, retval
, "while allocating buffer");
496 retval
= ext2fs_get_memzero(fs
->blocksize
, &zero_buf
);
498 com_err(program_name
, retval
, "while allocating buffer");
501 for (blk
= 0; blk
< ext2fs_blocks_count(fs
->super
); blk
++) {
502 if ((blk
>= fs
->super
->s_first_data_block
) &&
503 ext2fs_test_block_bitmap2(meta_block_map
, blk
)) {
504 retval
= io_channel_read_blk64(fs
->io
, blk
, 1, buf
);
506 com_err(program_name
, retval
,
507 "error reading block %llu", blk
);
509 if (scramble_block_map
&&
510 ext2fs_test_block_bitmap2(scramble_block_map
, blk
))
511 scramble_dir_block(fs
, blk
, buf
);
512 if ((fd
!= 1) && check_zero_block(buf
, fs
->blocksize
))
514 write_block(fd
, buf
, sparse
, fs
->blocksize
, blk
);
519 write_block(fd
, zero_buf
, 0,
523 sparse
+= fs
->blocksize
;
524 if (sparse
> 1024*1024) {
525 write_block(fd
, 0, 1024*1024, 0, 0);
530 #ifdef HAVE_FTRUNCATE64
532 ext2_loff_t offset
= ext2fs_llseek(fd
, sparse
, SEEK_CUR
);
535 lseek_error_and_exit(errno
);
536 if (ftruncate64(fd
, offset
) < 0)
537 write_block(fd
, zero_buf
, -1, 1, -1);
541 write_block(fd
, zero_buf
, sparse
-1, 1, -1);
543 ext2fs_free_mem(&zero_buf
);
544 ext2fs_free_mem(&buf
);
547 static void init_l1_table(struct ext2_qcow2_image
*image
)
552 ret
= ext2fs_get_arrayzero(image
->l1_size
, sizeof(__u64
), &l1_table
);
554 com_err(program_name
, ret
, "while allocating l1 table");
558 image
->l1_table
= l1_table
;
561 static void init_l2_cache(struct ext2_qcow2_image
*image
)
563 unsigned int count
, i
;
564 struct ext2_qcow2_l2_cache
*cache
;
565 struct ext2_qcow2_l2_table
*table
;
568 ret
= ext2fs_get_arrayzero(1, sizeof(struct ext2_qcow2_l2_cache
),
573 count
= (image
->l1_size
> L2_CACHE_PREALLOC
) ? L2_CACHE_PREALLOC
:
576 cache
->count
= count
;
578 cache
->next_offset
= image
->l2_offset
;
580 for (i
= 0; i
< count
; i
++) {
581 ret
= ext2fs_get_arrayzero(1,
582 sizeof(struct ext2_qcow2_l2_table
), &table
);
586 ret
= ext2fs_get_arrayzero(image
->l2_size
,
587 sizeof(__u64
), &table
->data
);
591 table
->next
= cache
->free_head
;
592 cache
->free_head
= table
;
595 image
->l2_cache
= cache
;
599 com_err(program_name
, ret
, "while allocating l2 cache");
603 static void put_l2_cache(struct ext2_qcow2_image
*image
)
605 struct ext2_qcow2_l2_cache
*cache
= image
->l2_cache
;
606 struct ext2_qcow2_l2_table
*tmp
, *table
;
611 table
= cache
->free_head
;
612 cache
->free_head
= NULL
;
617 ext2fs_free_mem(&tmp
->data
);
618 ext2fs_free_mem(&tmp
);
621 if (cache
->free
!= cache
->count
) {
622 fprintf(stderr
, "Warning: There are still tables in the "
623 "cache while putting the cache, data will "
624 "be lost so the image may not be valid.\n");
625 table
= cache
->used_head
;
626 cache
->used_head
= NULL
;
630 ext2fs_free_mem(&cache
);
633 static int init_refcount(struct ext2_qcow2_image
*img
, blk64_t table_offset
)
635 struct ext2_qcow2_refcount
*ref
;
636 blk64_t table_clusters
;
639 ref
= &(img
->refcount
);
642 * One refcount block addresses 2048 clusters, one refcount table
643 * addresses cluster/sizeof(__u64) refcount blocks, and we need
644 * to address meta_blocks_count clusters + qcow2 metadata clusters
647 table_clusters
= meta_blocks_count
+ (table_offset
>>
649 table_clusters
>>= (img
->cluster_bits
+ 6 - 1);
650 table_clusters
= (table_clusters
== 0) ? 1 : table_clusters
;
652 ref
->refcount_table_offset
= table_offset
;
653 ref
->refcount_table_clusters
= table_clusters
;
654 ref
->refcount_table_index
= 0;
655 ref
->refcount_block_index
= 0;
657 /* Allocate refcount table */
658 ret
= ext2fs_get_arrayzero(ref
->refcount_table_clusters
,
659 img
->cluster_size
, &ref
->refcount_table
);
663 /* Allocate refcount block */
664 ret
= ext2fs_get_arrayzero(1, img
->cluster_size
, &ref
->refcount_block
);
666 ext2fs_free_mem(&ref
->refcount_table
);
671 static int initialize_qcow2_image(int fd
, ext2_filsys fs
,
672 struct ext2_qcow2_image
*image
)
674 struct ext2_qcow2_hdr
*header
;
675 blk64_t total_size
, offset
;
676 int shift
, l2_bits
, header_size
, l1_size
, ret
;
677 int cluster_bits
= get_bits_from_size(fs
->blocksize
);
678 struct ext2_super_block
*sb
= fs
->super
;
680 /* Allocate header */
681 ret
= ext2fs_get_memzero(sizeof(struct ext2_qcow2_hdr
), &header
);
685 total_size
= ext2fs_blocks_count(sb
) << cluster_bits
;
686 image
->cluster_size
= fs
->blocksize
;
687 image
->l2_size
= 1 << (cluster_bits
- 3);
688 image
->cluster_bits
= cluster_bits
;
691 header
->magic
= ext2fs_cpu_to_be32(QCOW_MAGIC
);
692 header
->version
= ext2fs_cpu_to_be32(QCOW_VERSION
);
693 header
->size
= ext2fs_cpu_to_be64(total_size
);
694 header
->cluster_bits
= ext2fs_cpu_to_be32(cluster_bits
);
696 header_size
= (sizeof(struct ext2_qcow2_hdr
) + 7) & ~7;
697 offset
= align_offset(header_size
, image
->cluster_size
);
699 header
->l1_table_offset
= ext2fs_cpu_to_be64(offset
);
700 image
->l1_offset
= offset
;
702 l2_bits
= cluster_bits
- 3;
703 shift
= cluster_bits
+ l2_bits
;
704 l1_size
= ((total_size
+ (1LL << shift
) - 1) >> shift
);
705 header
->l1_size
= ext2fs_cpu_to_be32(l1_size
);
706 image
->l1_size
= l1_size
;
708 /* Make space for L1 table */
709 offset
+= align_offset(l1_size
* sizeof(blk64_t
), image
->cluster_size
);
711 /* Initialize refcounting */
712 ret
= init_refcount(image
, offset
);
714 ext2fs_free_mem(&header
);
717 header
->refcount_table_offset
= ext2fs_cpu_to_be64(offset
);
718 header
->refcount_table_clusters
=
719 ext2fs_cpu_to_be32(image
->refcount
.refcount_table_clusters
);
720 offset
+= image
->cluster_size
;
721 offset
+= image
->refcount
.refcount_table_clusters
<<
724 /* Make space for L2 tables */
725 image
->l2_offset
= offset
;
726 offset
+= image
->cluster_size
;
728 /* Make space for first refcount block */
729 image
->refcount
.refcount_block_offset
= offset
;
732 /* Initialize l1 and l2 tables */
733 init_l1_table(image
);
734 init_l2_cache(image
);
739 static void free_qcow2_image(struct ext2_qcow2_image
*img
)
745 ext2fs_free_mem(&img
->hdr
);
748 ext2fs_free_mem(&img
->l1_table
);
750 if (img
->refcount
.refcount_table
)
751 ext2fs_free_mem(&img
->refcount
.refcount_table
);
752 if (img
->refcount
.refcount_block
)
753 ext2fs_free_mem(&img
->refcount
.refcount_block
);
757 ext2fs_free_mem(&img
);
761 * Put table from used list (used_head) into free list (free_head).
762 * l2_table is used to return pointer to the next used table (used_head).
764 static void put_used_table(struct ext2_qcow2_image
*img
,
765 struct ext2_qcow2_l2_table
**l2_table
)
767 struct ext2_qcow2_l2_cache
*cache
= img
->l2_cache
;
768 struct ext2_qcow2_l2_table
*table
;
770 table
= cache
->used_head
;
771 cache
->used_head
= table
->next
;
775 cache
->used_tail
= NULL
;
777 /* Clean the table for case we will need to use it again */
778 memset(table
->data
, 0, img
->cluster_size
);
779 table
->next
= cache
->free_head
;
780 cache
->free_head
= table
;
784 *l2_table
= cache
->used_head
;
787 static void flush_l2_cache(struct ext2_qcow2_image
*image
)
791 struct ext2_qcow2_l2_cache
*cache
= image
->l2_cache
;
792 struct ext2_qcow2_l2_table
*table
= cache
->used_head
;
795 /* Store current position */
796 if ((offset
= ext2fs_llseek(fd
, 0, SEEK_CUR
)) < 0)
797 lseek_error_and_exit(errno
);
800 while (cache
->free
< cache
->count
) {
801 if (seek
!= table
->offset
) {
802 if (ext2fs_llseek(fd
, table
->offset
, SEEK_SET
) < 0)
803 lseek_error_and_exit(errno
);
804 seek
= table
->offset
;
807 generic_write(fd
, (char *)table
->data
, image
->cluster_size
, 0);
808 put_used_table(image
, &table
);
809 seek
+= image
->cluster_size
;
812 /* Restore previous position */
813 if (ext2fs_llseek(fd
, offset
, SEEK_SET
) < 0)
814 lseek_error_and_exit(errno
);
818 * Get first free table (from free_head) and put it into tail of used list
820 * l2_table is used to return pointer to moved table.
821 * Returns 1 if the cache is full, 0 otherwise.
823 static void get_free_table(struct ext2_qcow2_image
*image
,
824 struct ext2_qcow2_l2_table
**l2_table
)
826 struct ext2_qcow2_l2_table
*table
;
827 struct ext2_qcow2_l2_cache
*cache
= image
->l2_cache
;
829 if (0 == cache
->free
)
830 flush_l2_cache(image
);
832 table
= cache
->free_head
;
834 cache
->free_head
= table
->next
;
836 if (cache
->used_tail
)
837 cache
->used_tail
->next
= table
;
839 /* First item in the used list */
840 cache
->used_head
= table
;
842 cache
->used_tail
= table
;
848 static int add_l2_item(struct ext2_qcow2_image
*img
, blk64_t blk
,
849 blk64_t data
, blk64_t next
)
851 struct ext2_qcow2_l2_cache
*cache
= img
->l2_cache
;
852 struct ext2_qcow2_l2_table
*table
= cache
->used_tail
;
853 blk64_t l1_index
= blk
/ img
->l2_size
;
854 blk64_t l2_index
= blk
& (img
->l2_size
- 1);
858 * Need to create new table if it does not exist,
861 if (!table
|| (table
->l1_index
!= l1_index
)) {
862 get_free_table(img
, &table
);
863 table
->l1_index
= l1_index
;
864 table
->offset
= cache
->next_offset
;
865 cache
->next_offset
= next
;
866 img
->l1_table
[l1_index
] =
867 ext2fs_cpu_to_be64(table
->offset
| QCOW_OFLAG_COPIED
);
871 table
->data
[l2_index
] = ext2fs_cpu_to_be64(data
| QCOW_OFLAG_COPIED
);
875 static int update_refcount(int fd
, struct ext2_qcow2_image
*img
,
876 blk64_t offset
, blk64_t rfblk_pos
)
878 struct ext2_qcow2_refcount
*ref
;
882 ref
= &(img
->refcount
);
883 table_index
= offset
>> (2 * img
->cluster_bits
- 1);
886 * Need to create new refcount block when the offset addresses
887 * another item in the refcount table
889 if (table_index
!= ref
->refcount_table_index
) {
891 if (ext2fs_llseek(fd
, ref
->refcount_block_offset
, SEEK_SET
) < 0)
892 lseek_error_and_exit(errno
);
894 generic_write(fd
, (char *)ref
->refcount_block
,
895 img
->cluster_size
, 0);
896 memset(ref
->refcount_block
, 0, img
->cluster_size
);
898 ref
->refcount_table
[ref
->refcount_table_index
] =
899 ext2fs_cpu_to_be64(ref
->refcount_block_offset
);
900 ref
->refcount_block_offset
= rfblk_pos
;
901 ref
->refcount_block_index
= 0;
902 ref
->refcount_table_index
= table_index
;
907 * We are relying on the fact that we are creating the qcow2
908 * image sequentially, hence we will always allocate refcount
909 * block items sequentialy.
911 ref
->refcount_block
[ref
->refcount_block_index
] = ext2fs_cpu_to_be16(1);
912 ref
->refcount_block_index
++;
916 static int sync_refcount(int fd
, struct ext2_qcow2_image
*img
)
918 struct ext2_qcow2_refcount
*ref
;
920 ref
= &(img
->refcount
);
922 ref
->refcount_table
[ref
->refcount_table_index
] =
923 ext2fs_cpu_to_be64(ref
->refcount_block_offset
);
924 if (ext2fs_llseek(fd
, ref
->refcount_table_offset
, SEEK_SET
) < 0)
925 lseek_error_and_exit(errno
);
926 generic_write(fd
, (char *)ref
->refcount_table
,
927 ref
->refcount_table_clusters
<< img
->cluster_bits
, 0);
929 if (ext2fs_llseek(fd
, ref
->refcount_block_offset
, SEEK_SET
) < 0)
930 lseek_error_and_exit(errno
);
931 generic_write(fd
, (char *)ref
->refcount_block
, img
->cluster_size
, 0);
935 static void output_qcow2_meta_data_blocks(ext2_filsys fs
, int fd
)
938 blk64_t blk
, offset
, size
, end
;
940 struct ext2_qcow2_image
*img
;
941 unsigned int header_size
;
943 /* allocate struct ext2_qcow2_image */
944 retval
= ext2fs_get_mem(sizeof(struct ext2_qcow2_image
), &img
);
946 com_err(program_name
, retval
,
947 "while allocating ext2_qcow2_image");
951 retval
= initialize_qcow2_image(fd
, fs
, img
);
953 com_err(program_name
, retval
,
954 "while initializing ext2_qcow2_image");
957 header_size
= align_offset(sizeof(struct ext2_qcow2_hdr
),
959 write_header(fd
, img
->hdr
, sizeof(struct ext2_qcow2_hdr
), header_size
);
961 /* Refcount all qcow2 related metadata up to refcount_block_offset */
962 end
= img
->refcount
.refcount_block_offset
;
963 if (ext2fs_llseek(fd
, end
, SEEK_SET
) < 0)
964 lseek_error_and_exit(errno
);
965 blk
= end
+ img
->cluster_size
;
966 for (offset
= 0; offset
<= end
; offset
+= img
->cluster_size
) {
967 if (update_refcount(fd
, img
, offset
, blk
)) {
968 blk
+= img
->cluster_size
;
970 * If we create new refcount block, we need to refcount
973 end
+= img
->cluster_size
;
976 if (ext2fs_llseek(fd
, offset
, SEEK_SET
) < 0)
977 lseek_error_and_exit(errno
);
979 retval
= ext2fs_get_mem(fs
->blocksize
, &buf
);
981 com_err(program_name
, retval
, "while allocating buffer");
984 /* Write qcow2 data blocks */
985 for (blk
= 0; blk
< ext2fs_blocks_count(fs
->super
); blk
++) {
986 if ((blk
>= fs
->super
->s_first_data_block
) &&
987 ext2fs_test_block_bitmap2(meta_block_map
, blk
)) {
988 retval
= io_channel_read_blk64(fs
->io
, blk
, 1, buf
);
990 com_err(program_name
, retval
,
991 "error reading block %llu", blk
);
994 if (scramble_block_map
&&
995 ext2fs_test_block_bitmap2(scramble_block_map
, blk
))
996 scramble_dir_block(fs
, blk
, buf
);
997 if (check_zero_block(buf
, fs
->blocksize
))
1000 if (update_refcount(fd
, img
, offset
, offset
)) {
1001 /* Make space for another refcount block */
1002 offset
+= img
->cluster_size
;
1003 if (ext2fs_llseek(fd
, offset
, SEEK_SET
) < 0)
1004 lseek_error_and_exit(errno
);
1006 * We have created the new refcount block, this
1007 * means that we need to refcount it as well.
1008 * So the previous update_refcount refcounted
1009 * the block itself and now we are going to
1010 * create refcount for data. New refcount
1011 * block should not be created!
1013 if (update_refcount(fd
, img
, offset
, offset
)) {
1014 fprintf(stderr
, "Programming error: "
1015 "multiple sequential refcount "
1016 "blocks created!\n");
1021 generic_write(fd
, buf
, fs
->blocksize
, 0);
1023 if (add_l2_item(img
, blk
, offset
,
1024 offset
+ img
->cluster_size
)) {
1025 offset
+= img
->cluster_size
;
1026 if (update_refcount(fd
, img
, offset
,
1027 offset
+ img
->cluster_size
)) {
1028 offset
+= img
->cluster_size
;
1029 if (update_refcount(fd
, img
, offset
,
1032 "Programming error: multiple sequential refcount "
1033 "blocks created!\n");
1037 offset
+= img
->cluster_size
;
1038 if (ext2fs_llseek(fd
, offset
, SEEK_SET
) < 0)
1039 lseek_error_and_exit(errno
);
1043 offset
+= img
->cluster_size
;
1046 update_refcount(fd
, img
, offset
, offset
);
1047 flush_l2_cache(img
);
1048 sync_refcount(fd
, img
);
1051 if (ext2fs_llseek(fd
, img
->l1_offset
, SEEK_SET
) < 0)
1052 lseek_error_and_exit(errno
);
1053 size
= img
->l1_size
* sizeof(__u64
);
1054 generic_write(fd
, (char *)img
->l1_table
, size
, 0);
1056 ext2fs_free_mem(&buf
);
1057 free_qcow2_image(img
);
1060 static void write_raw_image_file(ext2_filsys fs
, int fd
, int type
, int flags
)
1062 struct process_block_struct pb
;
1063 struct ext2_inode inode
;
1064 ext2_inode_scan scan
;
1069 meta_blocks_count
= 0;
1070 retval
= ext2fs_allocate_block_bitmap(fs
, "in-use block map",
1073 com_err(program_name
, retval
, "while allocating block bitmap");
1077 if (flags
& E2IMAGE_SCRAMBLE_FLAG
) {
1078 retval
= ext2fs_allocate_block_bitmap(fs
, "scramble block map",
1079 &scramble_block_map
);
1081 com_err(program_name
, retval
,
1082 "while allocating scramble block bitmap");
1087 mark_table_blocks(fs
);
1089 retval
= ext2fs_open_inode_scan(fs
, 0, &scan
);
1091 com_err(program_name
, retval
, _("while opening inode scan"));
1095 retval
= ext2fs_get_mem(fs
->blocksize
* 3, &block_buf
);
1097 com_err(program_name
, 0, "Can't allocate block buffer");
1101 use_inode_shortcuts(fs
, 1);
1102 stashed_inode
= &inode
;
1104 retval
= ext2fs_get_next_inode(scan
, &ino
, &inode
);
1105 if (retval
== EXT2_ET_BAD_BLOCK_IN_INODE_TABLE
)
1108 com_err(program_name
, retval
,
1109 _("while getting next inode"));
1114 if (!inode
.i_links_count
)
1116 if (ext2fs_file_acl_block(fs
, &inode
)) {
1117 ext2fs_mark_block_bitmap2(meta_block_map
,
1118 ext2fs_file_acl_block(fs
, &inode
));
1119 meta_blocks_count
++;
1121 if (!ext2fs_inode_has_valid_blocks2(fs
, &inode
))
1126 pb
.is_dir
= LINUX_S_ISDIR(inode
.i_mode
);
1127 if (LINUX_S_ISDIR(inode
.i_mode
) ||
1128 (LINUX_S_ISLNK(inode
.i_mode
) &&
1129 ext2fs_inode_has_valid_blocks2(fs
, &inode
)) ||
1130 ino
== fs
->super
->s_journal_inum
) {
1131 retval
= ext2fs_block_iterate3(fs
, ino
,
1132 BLOCK_FLAG_READ_ONLY
, block_buf
,
1133 process_dir_block
, &pb
);
1135 com_err(program_name
, retval
,
1136 "while iterating over inode %u",
1141 if ((inode
.i_flags
& EXT4_EXTENTS_FL
) ||
1142 inode
.i_block
[EXT2_IND_BLOCK
] ||
1143 inode
.i_block
[EXT2_DIND_BLOCK
] ||
1144 inode
.i_block
[EXT2_TIND_BLOCK
] || all_data
) {
1145 retval
= ext2fs_block_iterate3(fs
,
1146 ino
, BLOCK_FLAG_READ_ONLY
, block_buf
,
1147 process_file_block
, &pb
);
1149 com_err(program_name
, retval
,
1150 "while iterating over inode %u", ino
);
1156 use_inode_shortcuts(fs
, 0);
1158 if (type
& E2IMAGE_QCOW2
)
1159 output_qcow2_meta_data_blocks(fs
, fd
);
1161 output_meta_data_blocks(fs
, fd
);
1163 ext2fs_free_mem(&block_buf
);
1164 ext2fs_close_inode_scan(scan
);
1165 ext2fs_free_block_bitmap(meta_block_map
);
1166 if (type
& E2IMAGE_SCRAMBLE_FLAG
)
1167 ext2fs_free_block_bitmap(scramble_block_map
);
1170 static void install_image(char *device
, char *image_fn
, int type
)
1174 int open_flag
= EXT2_FLAG_IMAGE_FILE
| EXT2_FLAG_64BITS
;
1180 com_err(program_name
, 0, "Raw and qcow2 images cannot"
1185 #ifdef CONFIG_TESTIO_DEBUG
1186 if (getenv("TEST_IO_FLAGS") || getenv("TEST_IO_BLOCK")) {
1187 io_ptr
= test_io_manager
;
1188 test_io_backing_manager
= unix_io_manager
;
1191 io_ptr
= unix_io_manager
;
1193 retval
= ext2fs_open (image_fn
, open_flag
, 0, 0,
1196 com_err (program_name
, retval
, _("while trying to open %s"),
1201 retval
= ext2fs_read_bitmaps (fs
);
1203 com_err(program_name
, retval
, "error reading bitmaps");
1207 fd
= ext2fs_open_file(image_fn
, O_RDONLY
, 0);
1213 retval
= io_ptr
->open(device
, IO_FLAG_RW
, &io
);
1215 com_err(device
, 0, "while opening device file");
1219 ext2fs_rewrite_to_io(fs
, io
);
1221 if (ext2fs_llseek(fd
, fs
->image_header
->offset_inode
, SEEK_SET
) < 0) {
1222 perror("ext2fs_llseek");
1226 retval
= ext2fs_image_inode_read(fs
, fd
, 0);
1228 com_err(image_fn
, 0, "while restoring the image table");
1236 static struct ext2_qcow2_hdr
*check_qcow2_image(int *fd
, char *name
)
1239 *fd
= ext2fs_open_file(name
, O_RDONLY
, 0600);
1243 return qcow2_read_header(*fd
);
1246 int main (int argc
, char ** argv
)
1252 struct ext2_qcow2_hdr
*header
= NULL
;
1253 int open_flag
= EXT2_FLAG_64BITS
;
1256 int mount_flags
= 0;
1260 int ignore_rw_mount
= 0;
1264 setlocale(LC_MESSAGES
, "");
1265 setlocale(LC_CTYPE
, "");
1266 bindtextdomain(NLS_CAT_NAME
, LOCALEDIR
);
1267 textdomain(NLS_CAT_NAME
);
1268 set_com_err_gettext(gettext
);
1270 fprintf (stderr
, "e2image %s (%s)\n", E2FSPROGS_VERSION
,
1273 program_name
= *argv
;
1274 add_error_table(&et_ext2_error_table
);
1275 while ((c
= getopt(argc
, argv
, "rsIQaf")) != EOF
)
1278 flags
|= E2IMAGE_INSTALL_FLAG
;
1283 img_type
|= E2IMAGE_QCOW2
;
1288 img_type
|= E2IMAGE_RAW
;
1291 flags
|= E2IMAGE_SCRAMBLE_FLAG
;
1297 ignore_rw_mount
= 1;
1302 if (optind
!= argc
- 2 )
1305 if (all_data
&& !img_type
) {
1306 com_err(program_name
, 0, "-a option can only be used "
1307 "with raw or QCOW2 images.");
1311 device_name
= argv
[optind
];
1312 image_fn
= argv
[optind
+1];
1314 ext2fs_check_if_mounted(device_name
, &mount_flags
);
1316 if (img_type
&& !ignore_rw_mount
&&
1317 (mount_flags
& EXT2_MF_MOUNTED
) &&
1318 !(mount_flags
& EXT2_MF_READONLY
)) {
1319 fprintf(stderr
, "\nRunning e2image on a R/W mounted "
1320 "filesystem can result in an\n"
1321 "inconsistent image which will not be useful "
1322 "for debugging purposes.\n"
1323 "Use -f option if you really want to do that.\n");
1327 if (flags
& E2IMAGE_INSTALL_FLAG
) {
1328 install_image(device_name
, image_fn
, img_type
);
1332 if (img_type
& E2IMAGE_RAW
) {
1333 header
= check_qcow2_image(&qcow2_fd
, device_name
);
1335 flags
|= E2IMAGE_IS_QCOW2_FLAG
;
1340 retval
= ext2fs_open (device_name
, open_flag
, 0, 0,
1341 unix_io_manager
, &fs
);
1343 com_err (program_name
, retval
, _("while trying to open %s"),
1345 fputs(_("Couldn't find valid filesystem superblock.\n"), stdout
);
1350 if (strcmp(image_fn
, "-") == 0)
1353 fd
= ext2fs_open_file(image_fn
, O_CREAT
|O_TRUNC
|O_WRONLY
, 0600);
1355 com_err(program_name
, errno
,
1356 _("while trying to open %s"), argv
[optind
+1]);
1361 if ((img_type
& E2IMAGE_QCOW2
) && (fd
== 1)) {
1362 com_err(program_name
, 0, "QCOW2 image can not be written to "
1367 if (fstat(fd
, &st
)) {
1368 com_err(program_name
, 0, "Can not stat output\n");
1371 if (S_ISBLK(st
.st_mode
))
1374 if (flags
& E2IMAGE_IS_QCOW2_FLAG
) {
1375 ret
= qcow2_write_raw_image(qcow2_fd
, fd
, header
);
1377 if (ret
== -QCOW_COMPRESSED
)
1378 fprintf(stderr
, "Image (%s) is compressed\n",
1380 if (ret
== -QCOW_ENCRYPTED
)
1381 fprintf(stderr
, "Image (%s) is encrypted\n",
1383 com_err(program_name
, ret
,
1384 _("while trying to convert qcow2 image"
1385 " (%s) into raw image (%s)"),
1386 device_name
, image_fn
);
1393 write_raw_image_file(fs
, fd
, img_type
, flags
);
1395 write_image_file(fs
, fd
);
1403 remove_error_table(&et_ext2_error_table
);