]> git.ipfire.org Git - thirdparty/e2fsprogs.git/blame - misc/e2image.c
Merge tag 'v1.43.9' into next
[thirdparty/e2fsprogs.git] / misc / e2image.c
CommitLineData
72ed1264
TT
1/*
2 * e2image.c --- Program which writes an image file backing up
3 * critical metadata for the filesystem.
4 *
a3827953 5 * Copyright 2000, 2001 by Theodore Ts'o.
72ed1264
TT
6 *
7 * %Begin-Header%
8 * This file may be redistributed under the terms of the GNU Public
9 * License.
10 * %End-Header%
11 */
12
f1644c32 13#ifndef _LARGEFILE_SOURCE
6304baf2 14#define _LARGEFILE_SOURCE
f1644c32
TT
15#endif
16#ifndef _LARGEFILE64_SOURCE
6304baf2 17#define _LARGEFILE64_SOURCE
f1644c32 18#endif
6304baf2 19
d1154eb4 20#include "config.h"
72ed1264
TT
21#include <fcntl.h>
22#include <grp.h>
23#ifdef HAVE_GETOPT_H
24#include <getopt.h>
25#else
26extern char *optarg;
27extern int optind;
28#endif
29#include <pwd.h>
30#include <stdio.h>
f38cf3cb 31#ifdef HAVE_STDLIB_H
72ed1264 32#include <stdlib.h>
f38cf3cb 33#endif
72ed1264
TT
34#include <string.h>
35#include <time.h>
36#include <unistd.h>
37#include <fcntl.h>
38#include <errno.h>
39#include <sys/stat.h>
40#include <sys/types.h>
bf0449b1 41#include <assert.h>
ecc859b2 42#include <signal.h>
72ed1264 43
54c637d4 44#include "ext2fs/ext2_fs.h"
72ed1264 45#include "ext2fs/ext2fs.h"
f61aa76e 46#include "ext2fs/ext2fsP.h"
72ed1264
TT
47#include "et/com_err.h"
48#include "uuid/uuid.h"
49#include "e2p/e2p.h"
50#include "ext2fs/e2image.h"
bf0449b1 51#include "ext2fs/qcow2.h"
72ed1264 52
99ceb8ec
TT
53#include "support/nls-enable.h"
54#include "support/plausible.h"
72ed1264 55#include "../version.h"
72ed1264 56
bf0449b1 57#define QCOW_OFLAG_COPIED (1LL << 63)
0155e770 58#define NO_BLK ((blk64_t) -1)
bf0449b1 59
aa2c7433
TT
60/* Image types */
61#define E2IMAGE_RAW 1
62#define E2IMAGE_QCOW2 2
63
64/* Image flags */
65#define E2IMAGE_INSTALL_FLAG 1
66#define E2IMAGE_SCRAMBLE_FLAG 2
67#define E2IMAGE_IS_QCOW2_FLAG 4
68#define E2IMAGE_CHECK_ZERO_FLAG 8
bf0449b1 69
f404167d
TT
70static const char * program_name = "e2image";
71static char * device_name = NULL;
72static char all_data;
73static char output_is_blk;
0155e770 74static char nop_flag;
0e51f5ae 75/* writing to blk device: don't skip zeroed blocks */
d28759b2
TT
76static blk64_t source_offset, dest_offset;
77static char move_mode;
78static char show_progress;
38c771d6
TT
79static char *check_buf;
80static int skipped_blocks;
72ed1264 81
d28759b2 82static blk64_t align_offset(blk64_t offset, unsigned int n)
bf0449b1 83{
d28759b2 84 return (offset + n - 1) & ~((blk64_t) n - 1);
bf0449b1
LC
85}
86
87static int get_bits_from_size(size_t size)
88{
89 int res = 0;
90
91 if (size == 0)
92 return -1;
93
94 while (size != 1) {
95 /* Not a power of two */
96 if (size & 1)
97 return -1;
98
99 size >>= 1;
100 res++;
101 }
102 return res;
103}
104
72ed1264
TT
105static void usage(void)
106{
75dd3c47 107 fprintf(stderr, _("Usage: %s [ -r|Q ] [ -f ] device image-file\n"),
c003f48b
TT
108 program_name);
109 fprintf(stderr, _(" %s -I device image-file\n"), program_name);
110 fprintf(stderr, _(" %s -ra [ -cfnp ] [ -o src_offset ] "
111 "[ -O dest_offset ] src_fs [ dest_fs ]\n"),
d851ed39 112 program_name);
72ed1264
TT
113 exit (1);
114}
115
80fe25a2
TT
116static ext2_loff_t seek_relative(int fd, int offset)
117{
118 ext2_loff_t ret = ext2fs_llseek(fd, offset, SEEK_CUR);
119 if (ret < 0) {
120 perror("seek_relative");
121 exit(1);
122 }
123 return ret;
124}
125
126static ext2_loff_t seek_set(int fd, ext2_loff_t offset)
127{
128 ext2_loff_t ret = ext2fs_llseek(fd, offset, SEEK_SET);
129 if (ret < 0) {
130 perror("seek_set");
131 exit(1);
132 }
133 return ret;
134}
135
38c771d6
TT
136/*
137 * Returns true if the block we are about to write is identical to
138 * what is already on the disk.
139 */
140static int check_block(int fd, void *buf, void *cbuf, int blocksize)
141{
142 char *cp = cbuf;
143 int count = blocksize, ret;
144
145 if (cbuf == NULL)
146 return 0;
147
148 while (count > 0) {
149 ret = read(fd, cp, count);
150 if (ret < 0) {
151 perror("check_block");
152 exit(1);
153 }
154 count -= ret;
155 cp += ret;
156 }
157 ret = memcmp(buf, cbuf, blocksize);
158 seek_relative(fd, -blocksize);
159 return (ret == 0) ? 1 : 0;
160}
161
bf0449b1 162static void generic_write(int fd, void *buf, int blocksize, blk64_t block)
72ed1264 163{
bf0449b1
LC
164 int count, free_buf = 0;
165 errcode_t err;
72ed1264 166
bf0449b1
LC
167 if (!blocksize)
168 return;
169
170 if (!buf) {
171 free_buf = 1;
172 err = ext2fs_get_arrayzero(1, blocksize, &buf);
173 if (err) {
4d46e6c7 174 com_err(program_name, err, "%s",
737a8867 175 _("while allocating buffer"));
bf0449b1
LC
176 exit(1);
177 }
095b459d 178 }
0155e770 179 if (nop_flag) {
737a8867 180 printf(_("Writing block %llu\n"), (unsigned long long) block);
c8ee0d60
TT
181 if (fd != 1)
182 seek_relative(fd, blocksize);
e9b59235 183 goto free_and_return;
0155e770 184 }
bf0449b1
LC
185 count = write(fd, buf, blocksize);
186 if (count != blocksize) {
187 if (count == -1)
188 err = errno;
189 else
190 err = 0;
191
192 if (block)
737a8867
TT
193 com_err(program_name, err,
194 _("error writing block %llu"), block);
bf0449b1 195 else
4d46e6c7
AD
196 com_err(program_name, err, "%s",
197 _("error in generic_write()"));
bf0449b1 198
72ed1264
TT
199 exit(1);
200 }
e9b59235 201free_and_return:
bf0449b1
LC
202 if (free_buf)
203 ext2fs_free_mem(&buf);
204}
efc6f628 205
bf0449b1
LC
206static void write_header(int fd, void *hdr, int hdr_size, int wrt_size)
207{
208 char *header_buf;
96367ad3 209 int ret;
efc6f628 210
bf0449b1
LC
211 /* Sanity check */
212 if (hdr_size > wrt_size) {
45ff69ff
AD
213 fprintf(stderr, "%s",
214 _("Error: header size is bigger than wrt_size\n"));
bf0449b1
LC
215 }
216
217 ret = ext2fs_get_mem(wrt_size, &header_buf);
218 if (ret) {
219 fputs(_("Couldn't allocate header buffer\n"), stderr);
72ed1264
TT
220 exit(1);
221 }
bf0449b1 222
80fe25a2 223 seek_set(fd, 0);
bf0449b1
LC
224 memset(header_buf, 0, wrt_size);
225
226 if (hdr)
227 memcpy(header_buf, hdr, hdr_size);
228
0155e770 229 generic_write(fd, header_buf, wrt_size, NO_BLK);
bf0449b1
LC
230
231 ext2fs_free_mem(&header_buf);
72ed1264
TT
232}
233
6304baf2 234static void write_image_file(ext2_filsys fs, int fd)
72ed1264 235{
6304baf2
TT
236 struct ext2_image_hdr hdr;
237 struct stat st;
238 errcode_t retval;
72ed1264 239
4c2ae57d 240 write_header(fd, NULL, sizeof(struct ext2_image_hdr), fs->blocksize);
72ed1264 241 memset(&hdr, 0, sizeof(struct ext2_image_hdr));
6304baf2 242
80fe25a2 243 hdr.offset_super = seek_relative(fd, 0);
72ed1264
TT
244 retval = ext2fs_image_super_write(fs, fd, 0);
245 if (retval) {
45ff69ff
AD
246 com_err(program_name, retval, "%s",
247 _("while writing superblock"));
72ed1264
TT
248 exit(1);
249 }
efc6f628 250
80fe25a2 251 hdr.offset_inode = seek_relative(fd, 0);
6304baf2
TT
252 retval = ext2fs_image_inode_write(fs, fd,
253 (fd != 1) ? IMAGER_FLAG_SPARSEWRITE : 0);
72ed1264 254 if (retval) {
45ff69ff
AD
255 com_err(program_name, retval, "%s",
256 _("while writing inode table"));
72ed1264
TT
257 exit(1);
258 }
efc6f628 259
80fe25a2 260 hdr.offset_blockmap = seek_relative(fd, 0);
72ed1264
TT
261 retval = ext2fs_image_bitmap_write(fs, fd, 0);
262 if (retval) {
45ff69ff
AD
263 com_err(program_name, retval, "%s",
264 _("while writing block bitmap"));
72ed1264
TT
265 exit(1);
266 }
267
80fe25a2 268 hdr.offset_inodemap = seek_relative(fd, 0);
72ed1264
TT
269 retval = ext2fs_image_bitmap_write(fs, fd, IMAGER_FLAG_INODEMAP);
270 if (retval) {
45ff69ff
AD
271 com_err(program_name, retval, "%s",
272 _("while writing inode bitmap"));
72ed1264
TT
273 exit(1);
274 }
c5423c5b
TT
275
276 hdr.magic_number = EXT2_ET_MAGIC_E2IMAGE;
277 strcpy(hdr.magic_descriptor, "Ext2 Image 1.0");
278 gethostname(hdr.fs_hostname, sizeof(hdr.fs_hostname));
df200fff 279 strncpy(hdr.fs_device_name, device_name, sizeof(hdr.fs_device_name)-1);
095b459d
TT
280 hdr.fs_device_name[sizeof(hdr.fs_device_name) - 1] = 0;
281 hdr.fs_blocksize = fs->blocksize;
efc6f628 282
c5423c5b
TT
283 if (stat(device_name, &st) == 0)
284 hdr.fs_device = st.st_rdev;
285
286 if (fstat(fd, &st) == 0) {
287 hdr.image_device = st.st_dev;
288 hdr.image_inode = st.st_ino;
289 }
290 memcpy(hdr.fs_uuid, fs->super->s_uuid, sizeof(hdr.fs_uuid));
291
292 hdr.image_time = time(0);
4c2ae57d 293 write_header(fd, &hdr, sizeof(struct ext2_image_hdr), fs->blocksize);
6304baf2
TT
294}
295
296/*
297 * These set of functions are used to write a RAW image file.
298 */
f404167d
TT
299static ext2fs_block_bitmap meta_block_map;
300static ext2fs_block_bitmap scramble_block_map; /* Directory blocks to be scrambled */
301static blk64_t meta_blocks_count;
6304baf2
TT
302
303struct process_block_struct {
304 ext2_ino_t ino;
d851ed39 305 int is_dir;
6304baf2
TT
306};
307
308/*
309 * These subroutines short circuits ext2fs_get_blocks and
310 * ext2fs_check_directory; we use them since we already have the inode
311 * structure, so there's no point in letting the ext2fs library read
312 * the inode again.
313 */
314static ino_t stashed_ino = 0;
315static struct ext2_inode *stashed_inode;
316
efc6f628 317static errcode_t meta_get_blocks(ext2_filsys fs EXT2FS_ATTR((unused)),
54434927
TT
318 ext2_ino_t ino,
319 blk_t *blocks)
6304baf2
TT
320{
321 int i;
efc6f628 322
6304baf2
TT
323 if ((ino != stashed_ino) || !stashed_inode)
324 return EXT2_ET_CALLBACK_NOTHANDLED;
325
326 for (i=0; i < EXT2_N_BLOCKS; i++)
327 blocks[i] = stashed_inode->i_block[i];
328 return 0;
329}
330
efc6f628 331static errcode_t meta_check_directory(ext2_filsys fs EXT2FS_ATTR((unused)),
54434927 332 ext2_ino_t ino)
4ea7bd04
TT
333{
334 if ((ino != stashed_ino) || !stashed_inode)
335 return EXT2_ET_CALLBACK_NOTHANDLED;
336
337 if (!LINUX_S_ISDIR(stashed_inode->i_mode))
338 return EXT2_ET_NO_DIRECTORY;
339 return 0;
340}
341
efc6f628 342static errcode_t meta_read_inode(ext2_filsys fs EXT2FS_ATTR((unused)),
54434927 343 ext2_ino_t ino,
6304baf2
TT
344 struct ext2_inode *inode)
345{
346 if ((ino != stashed_ino) || !stashed_inode)
347 return EXT2_ET_CALLBACK_NOTHANDLED;
348 *inode = *stashed_inode;
349 return 0;
350}
351
2d2abcc6 352static void use_inode_shortcuts(ext2_filsys fs, int use_shortcuts)
4ea7bd04 353{
2d2abcc6 354 if (use_shortcuts) {
4ea7bd04
TT
355 fs->get_blocks = meta_get_blocks;
356 fs->check_directory = meta_check_directory;
357 fs->read_inode = meta_read_inode;
358 stashed_ino = 0;
359 } else {
360 fs->get_blocks = 0;
361 fs->check_directory = 0;
362 fs->read_inode = 0;
363 }
364}
365
efc6f628 366static int process_dir_block(ext2_filsys fs EXT2FS_ATTR((unused)),
d991bc74 367 blk64_t *block_nr,
efc6f628 368 e2_blkcnt_t blockcnt EXT2FS_ATTR((unused)),
d991bc74 369 blk64_t ref_block EXT2FS_ATTR((unused)),
efc6f628 370 int ref_offset EXT2FS_ATTR((unused)),
54434927 371 void *priv_data EXT2FS_ATTR((unused)))
6304baf2 372{
d851ed39
TT
373 struct process_block_struct *p;
374
375 p = (struct process_block_struct *) priv_data;
376
3c041a51 377 ext2fs_mark_block_bitmap2(meta_block_map, *block_nr);
bf0449b1 378 meta_blocks_count++;
efc6f628 379 if (scramble_block_map && p->is_dir && blockcnt >= 0)
3c041a51 380 ext2fs_mark_block_bitmap2(scramble_block_map, *block_nr);
6304baf2
TT
381 return 0;
382}
383
efc6f628 384static int process_file_block(ext2_filsys fs EXT2FS_ATTR((unused)),
d991bc74 385 blk64_t *block_nr,
efc6f628 386 e2_blkcnt_t blockcnt,
d991bc74 387 blk64_t ref_block EXT2FS_ATTR((unused)),
efc6f628 388 int ref_offset EXT2FS_ATTR((unused)),
54434927 389 void *priv_data EXT2FS_ATTR((unused)))
6304baf2 390{
0e51f5ae 391 if (blockcnt < 0 || all_data) {
3c041a51 392 ext2fs_mark_block_bitmap2(meta_block_map, *block_nr);
bf0449b1 393 meta_blocks_count++;
6304baf2
TT
394 }
395 return 0;
396}
397
398static void mark_table_blocks(ext2_filsys fs)
399{
d991bc74 400 blk64_t first_block, b;
54434927 401 unsigned int i,j;
efc6f628 402
bb1a46a4 403 first_block = fs->super->s_first_data_block;
6304baf2
TT
404 /*
405 * Mark primary superblock
406 */
3c041a51 407 ext2fs_mark_block_bitmap2(meta_block_map, first_block);
bf0449b1 408 meta_blocks_count++;
efc6f628 409
6304baf2
TT
410 /*
411 * Mark the primary superblock descriptors
412 */
413 for (j = 0; j < fs->desc_blocks; j++) {
3c041a51 414 ext2fs_mark_block_bitmap2(meta_block_map,
d991bc74 415 ext2fs_descriptor_block_loc2(fs, first_block, j));
6304baf2 416 }
bf0449b1 417 meta_blocks_count += fs->desc_blocks;
6304baf2
TT
418
419 for (i = 0; i < fs->group_desc_count; i++) {
420 /*
421 * Mark the blocks used for the inode table
422 */
0e51f5ae
PS
423 if ((output_is_blk ||
424 !ext2fs_bg_flags_test(fs, i, EXT2_BG_INODE_UNINIT)) &&
6c9ce8a9
PS
425 ext2fs_inode_table_loc(fs, i)) {
426 unsigned int end = (unsigned) fs->inode_blocks_per_group;
427 /* skip unused blocks */
22cde009 428 if (!output_is_blk && ext2fs_has_group_desc_csum(fs))
6c9ce8a9
PS
429 end -= (ext2fs_bg_itable_unused(fs, i) /
430 EXT2_INODES_PER_BLOCK(fs->super));
d7cca6b0 431 for (j = 0, b = ext2fs_inode_table_loc(fs, i);
6c9ce8a9
PS
432 j < end;
433 j++, b++) {
3c041a51 434 ext2fs_mark_block_bitmap2(meta_block_map, b);
6c9ce8a9
PS
435 meta_blocks_count++;
436 }
6304baf2 437 }
efc6f628 438
6304baf2 439 /*
efc6f628 440 * Mark block used for the block bitmap
6304baf2 441 */
6c9ce8a9
PS
442 if (!ext2fs_bg_flags_test(fs, i, EXT2_BG_BLOCK_UNINIT) &&
443 ext2fs_block_bitmap_loc(fs, i)) {
3c041a51 444 ext2fs_mark_block_bitmap2(meta_block_map,
d7cca6b0 445 ext2fs_block_bitmap_loc(fs, i));
bf0449b1 446 meta_blocks_count++;
6304baf2 447 }
efc6f628 448
6304baf2 449 /*
efc6f628 450 * Mark block used for the inode bitmap
6304baf2 451 */
6c9ce8a9
PS
452 if (!ext2fs_bg_flags_test(fs, i, EXT2_BG_INODE_UNINIT) &&
453 ext2fs_inode_bitmap_loc(fs, i)) {
3c041a51 454 ext2fs_mark_block_bitmap2(meta_block_map,
d7cca6b0 455 ext2fs_inode_bitmap_loc(fs, i));
bf0449b1 456 meta_blocks_count++;
6304baf2 457 }
6304baf2
TT
458 }
459}
460
461/*
462 * This function returns 1 if the specified block is all zeros
463 */
464static int check_zero_block(char *buf, int blocksize)
465{
466 char *cp = buf;
467 int left = blocksize;
468
0e51f5ae
PS
469 if (output_is_blk)
470 return 0;
6304baf2
TT
471 while (left > 0) {
472 if (*cp++)
473 return 0;
474 left--;
475 }
476 return 1;
477}
478
f404167d 479static int name_id[256];
d851ed39 480
8a480350
TT
481#define EXT4_MAX_REC_LEN ((1<<16)-1)
482
d991bc74 483static void scramble_dir_block(ext2_filsys fs, blk64_t blk, char *buf)
d851ed39
TT
484{
485 char *p, *end, *cp;
486 struct ext2_dir_entry_2 *dirent;
8a480350
TT
487 unsigned int rec_len;
488 int id, len;
d851ed39 489
d851ed39
TT
490 end = buf + fs->blocksize;
491 for (p = buf; p < end-8; p += rec_len) {
492 dirent = (struct ext2_dir_entry_2 *) p;
493 rec_len = dirent->rec_len;
2eae0930
TT
494#ifdef WORDS_BIGENDIAN
495 rec_len = ext2fs_swab16(rec_len);
d851ed39 496#endif
8a480350
TT
497 if (rec_len == EXT4_MAX_REC_LEN || rec_len == 0)
498 rec_len = fs->blocksize;
499 else
500 rec_len = (rec_len & 65532) | ((rec_len & 3) << 16);
d851ed39
TT
501#if 0
502 printf("rec_len = %d, name_len = %d\n", rec_len, dirent->name_len);
503#endif
504 if (rec_len < 8 || (rec_len % 4) ||
505 (p+rec_len > end)) {
737a8867
TT
506 printf(_("Corrupt directory block %llu: "
507 "bad rec_len (%d)\n"),
508 (unsigned long long) blk, rec_len);
d851ed39 509 rec_len = end - p;
8a480350
TT
510 (void) ext2fs_set_rec_len(fs, rec_len,
511 (struct ext2_dir_entry *) dirent);
2eae0930 512#ifdef WORDS_BIGENDIAN
8a480350 513 dirent->rec_len = ext2fs_swab16(dirent->rec_len);
d851ed39
TT
514#endif
515 continue;
516 }
577c773a 517 if (dirent->name_len + 8U > rec_len) {
737a8867
TT
518 printf(_("Corrupt directory block %llu: "
519 "bad name_len (%d)\n"),
520 (unsigned long long) blk, dirent->name_len);
d851ed39
TT
521 dirent->name_len = rec_len - 8;
522 continue;
523 }
d851ed39 524 cp = p+8;
d851ed39
TT
525 len = rec_len - dirent->name_len - 8;
526 if (len > 0)
527 memset(cp+dirent->name_len, 0, len);
79fc2a99
TT
528 if (dirent->name_len==1 && cp[0] == '.')
529 continue;
530 if (dirent->name_len==2 && cp[0] == '.' && cp[1] == '.')
531 continue;
532
533 memset(cp, 'A', dirent->name_len);
d851ed39
TT
534 len = dirent->name_len;
535 id = name_id[len]++;
536 while ((len > 0) && (id > 0)) {
537 *cp += id % 26;
538 id = id / 26;
539 cp++;
540 len--;
541 }
542 }
543}
544
ecc859b2
PS
545static char got_sigint;
546
d28759b2 547static void sigint_handler(int unused EXT2FS_ATTR((unused)))
ecc859b2
PS
548{
549 got_sigint = 1;
550 signal (SIGINT, SIG_DFL);
551}
552
212c9948
TT
553#define calc_percent(a, b) ((int) ((100.0 * (((float) (a)) / \
554 ((float) (b)))) + 0.5))
555#define calc_rate(t, b, d) (((float)(t) / ((1024 * 1024) / (b))) / (d))
556
557static int print_progress(blk64_t num, blk64_t total)
558{
c8ee0d60 559 return fprintf(stderr, _("%llu / %llu blocks (%d%%)"), num, total,
212c9948
TT
560 calc_percent(num, total));
561}
562
aa2c7433 563static void output_meta_data_blocks(ext2_filsys fs, int fd, int flags)
6304baf2
TT
564{
565 errcode_t retval;
d991bc74 566 blk64_t blk;
d851ed39 567 char *buf, *zero_buf;
e3ef3502 568 int sparse = 0;
22b83f62
PS
569 blk64_t start = 0;
570 blk64_t distance = 0;
571 blk64_t end = ext2fs_blocks_count(fs->super);
d28759b2
TT
572 time_t last_update = 0;
573 time_t start_time = 0;
c40c7cef 574 blk64_t total_written = 0;
d28759b2 575 int bscount = 0;
6304baf2 576
bf0449b1
LC
577 retval = ext2fs_get_mem(fs->blocksize, &buf);
578 if (retval) {
4d46e6c7
AD
579 com_err(program_name, retval, "%s",
580 _("while allocating buffer"));
d851ed39
TT
581 exit(1);
582 }
bf0449b1
LC
583 retval = ext2fs_get_memzero(fs->blocksize, &zero_buf);
584 if (retval) {
4d46e6c7
AD
585 com_err(program_name, retval, "%s",
586 _("while allocating buffer"));
d851ed39
TT
587 exit(1);
588 }
c40c7cef 589 if (show_progress) {
4d46e6c7 590 fprintf(stderr, "%s", _("Copying "));
212c9948 591 bscount = print_progress(total_written, meta_blocks_count);
c8ee0d60 592 fflush(stderr);
c40c7cef
PS
593 last_update = time(NULL);
594 start_time = time(NULL);
595 }
22b83f62
PS
596 /* when doing an in place move to the right, you can't start
597 at the beginning or you will overwrite data, so instead
598 divide the fs up into distance size chunks and write them
599 in reverse. */
600 if (move_mode && dest_offset > source_offset) {
601 distance = (dest_offset - source_offset) / fs->blocksize;
602 if (distance < ext2fs_blocks_count(fs->super))
603 start = ext2fs_blocks_count(fs->super) - distance;
604 }
ecc859b2
PS
605 if (move_mode)
606 signal (SIGINT, sigint_handler);
22b83f62
PS
607more_blocks:
608 if (distance)
80fe25a2 609 seek_set(fd, (start * fs->blocksize) + dest_offset);
22b83f62 610 for (blk = start; blk < end; blk++) {
ecc859b2
PS
611 if (got_sigint) {
612 if (distance) {
613 /* moving to the right */
4d46e6c7
AD
614 if (distance >= ext2fs_blocks_count(fs->super)||
615 start == ext2fs_blocks_count(fs->super) -
616 distance)
617 kill(getpid(), SIGINT);
ecc859b2
PS
618 } else {
619 /* moving to the left */
4d46e6c7
AD
620 if (blk < (source_offset - dest_offset) /
621 fs->blocksize)
622 kill(getpid(), SIGINT);
ecc859b2
PS
623 }
624 if (show_progress)
c8ee0d60 625 fputc('\r', stderr);
4d46e6c7 626 fprintf(stderr, "%s",
c8ee0d60 627 _("Stopping now will destroy the filesystem, "
737a8867 628 "interrupt again if you are sure\n"));
ecc859b2 629 if (show_progress) {
4d46e6c7 630 fprintf(stderr, "%s", _("Copying "));
212c9948
TT
631 bscount = print_progress(total_written,
632 meta_blocks_count);
c8ee0d60 633 fflush(stderr);
ecc859b2
PS
634 }
635
636 got_sigint = 0;
637 }
c40c7cef 638 if (show_progress && last_update != time(NULL)) {
d28759b2 639 time_t duration;
c40c7cef
PS
640 last_update = time(NULL);
641 while (bscount--)
c8ee0d60 642 fputc('\b', stderr);
212c9948
TT
643 bscount = print_progress(total_written,
644 meta_blocks_count);
d28759b2 645 duration = time(NULL) - start_time;
fa24c8fa 646 if (duration > 5 && total_written) {
212c9948
TT
647 time_t est = (duration * meta_blocks_count /
648 total_written) - duration;
c40c7cef
PS
649 char buff[30];
650 strftime(buff, 30, "%T", gmtime(&est));
4d46e6c7
AD
651 bscount +=
652 fprintf(stderr,
653 _(" %s remaining at %.2f MB/s"),
654 buff, calc_rate(total_written,
655 fs->blocksize,
656 duration));
c40c7cef 657 }
c8ee0d60 658 fflush (stderr);
c40c7cef 659 }
6304baf2 660 if ((blk >= fs->super->s_first_data_block) &&
3c041a51 661 ext2fs_test_block_bitmap2(meta_block_map, blk)) {
24a117ab 662 retval = io_channel_read_blk64(fs->io, blk, 1, buf);
6304baf2
TT
663 if (retval) {
664 com_err(program_name, retval,
737a8867 665 _("error reading block %llu"), blk);
6304baf2 666 }
c40c7cef 667 total_written++;
efc6f628 668 if (scramble_block_map &&
3c041a51 669 ext2fs_test_block_bitmap2(scramble_block_map, blk))
d851ed39 670 scramble_dir_block(fs, blk, buf);
aa2c7433
TT
671 if ((flags & E2IMAGE_CHECK_ZERO_FLAG) &&
672 check_zero_block(buf, fs->blocksize))
6304baf2 673 goto sparse_write;
80fe25a2
TT
674 if (sparse)
675 seek_relative(fd, sparse);
e3ef3502 676 sparse = 0;
38c771d6
TT
677 if (check_block(fd, buf, check_buf, fs->blocksize)) {
678 seek_relative(fd, fs->blocksize);
679 skipped_blocks++;
680 } else
681 generic_write(fd, buf, fs->blocksize, blk);
6304baf2
TT
682 } else {
683 sparse_write:
684 if (fd == 1) {
c8ee0d60
TT
685 if (!nop_flag)
686 generic_write(fd, zero_buf,
687 fs->blocksize, blk);
6304baf2
TT
688 continue;
689 }
e3ef3502 690 sparse += fs->blocksize;
2b7a30cc 691 if (sparse > 1024*1024) {
80fe25a2 692 seek_relative(fd, 1024*1024);
2b7a30cc 693 sparse -= 1024*1024;
e3ef3502 694 }
6304baf2
TT
695 }
696 }
22b83f62
PS
697 if (distance && start) {
698 if (start < distance) {
699 end = start;
700 start = 0;
701 } else {
702 end -= distance;
703 start -= distance;
704 if (end < distance) {
705 /* past overlap, do rest in one go */
706 end = start;
707 start = 0;
708 }
709 }
710 sparse = 0;
711 goto more_blocks;
712 }
ecc859b2 713 signal (SIGINT, SIG_DFL);
c40c7cef 714 if (show_progress) {
c40c7cef
PS
715 time_t duration = time(NULL) - start_time;
716 char buff[30];
781c0df5 717 fputc('\r', stderr);
c40c7cef 718 strftime(buff, 30, "%T", gmtime(&duration));
781c0df5
TT
719 fprintf(stderr, _("Copied %llu / %llu blocks (%d%%) in %s "),
720 total_written, meta_blocks_count,
721 calc_percent(total_written, meta_blocks_count), buff);
722 if (duration)
723 fprintf(stderr, _("at %.2f MB/s"),
724 calc_rate(total_written, fs->blocksize, duration));
725 fputs(" \n", stderr);
c40c7cef 726 }
50a676e9
TT
727#ifdef HAVE_FTRUNCATE64
728 if (sparse) {
22b83f62
PS
729 ext2_loff_t offset;
730 if (distance)
80fe25a2
TT
731 offset = seek_set(fd,
732 fs->blocksize * ext2fs_blocks_count(fs->super) + dest_offset);
733 else
734 offset = seek_relative(fd, sparse);
50a676e9 735
80fe25a2
TT
736 if (ftruncate64(fd, offset) < 0) {
737 seek_relative(fd, -1);
0155e770 738 generic_write(fd, zero_buf, 1, NO_BLK);
80fe25a2 739 }
50a676e9
TT
740 }
741#else
80fe25a2
TT
742 if (sparse && !distance) {
743 seek_relative(fd, sparse-1);
0155e770 744 generic_write(fd, zero_buf, 1, NO_BLK);
80fe25a2 745 }
50a676e9 746#endif
bf0449b1
LC
747 ext2fs_free_mem(&zero_buf);
748 ext2fs_free_mem(&buf);
6304baf2
TT
749}
750
e64e6761 751static void init_l1_table(struct ext2_qcow2_image *image)
bf0449b1
LC
752{
753 __u64 *l1_table;
754 errcode_t ret;
755
756 ret = ext2fs_get_arrayzero(image->l1_size, sizeof(__u64), &l1_table);
757 if (ret) {
4d46e6c7
AD
758 com_err(program_name, ret, "%s",
759 _("while allocating l1 table"));
bf0449b1
LC
760 exit(1);
761 }
762
763 image->l1_table = l1_table;
764}
765
766static void init_l2_cache(struct ext2_qcow2_image *image)
767{
768 unsigned int count, i;
769 struct ext2_qcow2_l2_cache *cache;
770 struct ext2_qcow2_l2_table *table;
771 errcode_t ret;
772
773 ret = ext2fs_get_arrayzero(1, sizeof(struct ext2_qcow2_l2_cache),
774 &cache);
775 if (ret)
776 goto alloc_err;
777
778 count = (image->l1_size > L2_CACHE_PREALLOC) ? L2_CACHE_PREALLOC :
779 image->l1_size;
780
781 cache->count = count;
782 cache->free = count;
783 cache->next_offset = image->l2_offset;
784
785 for (i = 0; i < count; i++) {
786 ret = ext2fs_get_arrayzero(1,
787 sizeof(struct ext2_qcow2_l2_table), &table);
788 if (ret)
789 goto alloc_err;
790
791 ret = ext2fs_get_arrayzero(image->l2_size,
792 sizeof(__u64), &table->data);
793 if (ret)
794 goto alloc_err;
795
796 table->next = cache->free_head;
797 cache->free_head = table;
798 }
799
800 image->l2_cache = cache;
801 return;
802
803alloc_err:
4d46e6c7 804 com_err(program_name, ret, "%s", _("while allocating l2 cache"));
bf0449b1
LC
805 exit(1);
806}
807
808static void put_l2_cache(struct ext2_qcow2_image *image)
809{
810 struct ext2_qcow2_l2_cache *cache = image->l2_cache;
811 struct ext2_qcow2_l2_table *tmp, *table;
812
813 if (!cache)
814 return;
815
816 table = cache->free_head;
817 cache->free_head = NULL;
818again:
819 while (table) {
820 tmp = table;
821 table = table->next;
822 ext2fs_free_mem(&tmp->data);
823 ext2fs_free_mem(&tmp);
824 }
825
826 if (cache->free != cache->count) {
4d46e6c7
AD
827 fprintf(stderr, "%s", _("Warning: There are still tables in "
828 "the cache while putting the cache, "
829 "data will be lost so the image may "
830 "not be valid.\n"));
bf0449b1
LC
831 table = cache->used_head;
832 cache->used_head = NULL;
833 goto again;
834 }
835
836 ext2fs_free_mem(&cache);
837}
838
839static int init_refcount(struct ext2_qcow2_image *img, blk64_t table_offset)
840{
841 struct ext2_qcow2_refcount *ref;
842 blk64_t table_clusters;
843 errcode_t ret;
844
845 ref = &(img->refcount);
846
847 /*
848 * One refcount block addresses 2048 clusters, one refcount table
849 * addresses cluster/sizeof(__u64) refcount blocks, and we need
850 * to address meta_blocks_count clusters + qcow2 metadata clusters
851 * in the worst case.
852 */
853 table_clusters = meta_blocks_count + (table_offset >>
854 img->cluster_bits);
855 table_clusters >>= (img->cluster_bits + 6 - 1);
856 table_clusters = (table_clusters == 0) ? 1 : table_clusters;
857
858 ref->refcount_table_offset = table_offset;
859 ref->refcount_table_clusters = table_clusters;
860 ref->refcount_table_index = 0;
861 ref->refcount_block_index = 0;
862
863 /* Allocate refcount table */
864 ret = ext2fs_get_arrayzero(ref->refcount_table_clusters,
865 img->cluster_size, &ref->refcount_table);
866 if (ret)
867 return ret;
868
869 /* Allocate refcount block */
870 ret = ext2fs_get_arrayzero(1, img->cluster_size, &ref->refcount_block);
871 if (ret)
872 ext2fs_free_mem(&ref->refcount_table);
873
874 return ret;
875}
876
877static int initialize_qcow2_image(int fd, ext2_filsys fs,
878 struct ext2_qcow2_image *image)
879{
880 struct ext2_qcow2_hdr *header;
881 blk64_t total_size, offset;
882 int shift, l2_bits, header_size, l1_size, ret;
883 int cluster_bits = get_bits_from_size(fs->blocksize);
884 struct ext2_super_block *sb = fs->super;
885
886 /* Allocate header */
887 ret = ext2fs_get_memzero(sizeof(struct ext2_qcow2_hdr), &header);
888 if (ret)
889 return ret;
890
891 total_size = ext2fs_blocks_count(sb) << cluster_bits;
892 image->cluster_size = fs->blocksize;
893 image->l2_size = 1 << (cluster_bits - 3);
894 image->cluster_bits = cluster_bits;
895 image->fd = fd;
896
897 header->magic = ext2fs_cpu_to_be32(QCOW_MAGIC);
898 header->version = ext2fs_cpu_to_be32(QCOW_VERSION);
899 header->size = ext2fs_cpu_to_be64(total_size);
900 header->cluster_bits = ext2fs_cpu_to_be32(cluster_bits);
901
902 header_size = (sizeof(struct ext2_qcow2_hdr) + 7) & ~7;
903 offset = align_offset(header_size, image->cluster_size);
904
905 header->l1_table_offset = ext2fs_cpu_to_be64(offset);
906 image->l1_offset = offset;
907
908 l2_bits = cluster_bits - 3;
909 shift = cluster_bits + l2_bits;
910 l1_size = ((total_size + (1LL << shift) - 1) >> shift);
911 header->l1_size = ext2fs_cpu_to_be32(l1_size);
912 image->l1_size = l1_size;
913
914 /* Make space for L1 table */
915 offset += align_offset(l1_size * sizeof(blk64_t), image->cluster_size);
916
917 /* Initialize refcounting */
918 ret = init_refcount(image, offset);
919 if (ret) {
920 ext2fs_free_mem(&header);
921 return ret;
922 }
923 header->refcount_table_offset = ext2fs_cpu_to_be64(offset);
924 header->refcount_table_clusters =
925 ext2fs_cpu_to_be32(image->refcount.refcount_table_clusters);
926 offset += image->cluster_size;
927 offset += image->refcount.refcount_table_clusters <<
928 image->cluster_bits;
929
930 /* Make space for L2 tables */
931 image->l2_offset = offset;
932 offset += image->cluster_size;
933
934 /* Make space for first refcount block */
935 image->refcount.refcount_block_offset = offset;
936
937 image->hdr = header;
938 /* Initialize l1 and l2 tables */
e64e6761 939 init_l1_table(image);
bf0449b1
LC
940 init_l2_cache(image);
941
942 return 0;
943}
944
945static void free_qcow2_image(struct ext2_qcow2_image *img)
946{
bf0449b1
LC
947 if (!img)
948 return;
949
950 if (img->hdr)
951 ext2fs_free_mem(&img->hdr);
952
953 if (img->l1_table)
954 ext2fs_free_mem(&img->l1_table);
955
956 if (img->refcount.refcount_table)
957 ext2fs_free_mem(&img->refcount.refcount_table);
958 if (img->refcount.refcount_block)
959 ext2fs_free_mem(&img->refcount.refcount_block);
960
961 put_l2_cache(img);
962
963 ext2fs_free_mem(&img);
964}
965
966/**
967 * Put table from used list (used_head) into free list (free_head).
968 * l2_table is used to return pointer to the next used table (used_head).
969 */
970static void put_used_table(struct ext2_qcow2_image *img,
971 struct ext2_qcow2_l2_table **l2_table)
972{
973 struct ext2_qcow2_l2_cache *cache = img->l2_cache;
974 struct ext2_qcow2_l2_table *table;
975
976 table = cache->used_head;
977 cache->used_head = table->next;
978
979 assert(table);
980 if (!table->next)
981 cache->used_tail = NULL;
982
983 /* Clean the table for case we will need to use it again */
984 memset(table->data, 0, img->cluster_size);
985 table->next = cache->free_head;
986 cache->free_head = table;
987
988 cache->free++;
989
990 *l2_table = cache->used_head;
991}
992
993static void flush_l2_cache(struct ext2_qcow2_image *image)
994{
9d10f017
LC
995 blk64_t seek = 0;
996 ext2_loff_t offset;
bf0449b1
LC
997 struct ext2_qcow2_l2_cache *cache = image->l2_cache;
998 struct ext2_qcow2_l2_table *table = cache->used_head;
999 int fd = image->fd;
1000
1001 /* Store current position */
80fe25a2 1002 offset = seek_relative(fd, 0);
bf0449b1
LC
1003
1004 assert(table);
1005 while (cache->free < cache->count) {
1006 if (seek != table->offset) {
80fe25a2 1007 seek_set(fd, table->offset);
bf0449b1
LC
1008 seek = table->offset;
1009 }
1010
0155e770
TT
1011 generic_write(fd, (char *)table->data, image->cluster_size,
1012 NO_BLK);
bf0449b1
LC
1013 put_used_table(image, &table);
1014 seek += image->cluster_size;
1015 }
1016
1017 /* Restore previous position */
80fe25a2 1018 seek_set(fd, offset);
bf0449b1
LC
1019}
1020
1021/**
1022 * Get first free table (from free_head) and put it into tail of used list
1023 * (to used_tail).
1024 * l2_table is used to return pointer to moved table.
1025 * Returns 1 if the cache is full, 0 otherwise.
1026 */
1027static void get_free_table(struct ext2_qcow2_image *image,
1028 struct ext2_qcow2_l2_table **l2_table)
1029{
1030 struct ext2_qcow2_l2_table *table;
1031 struct ext2_qcow2_l2_cache *cache = image->l2_cache;
1032
1033 if (0 == cache->free)
1034 flush_l2_cache(image);
1035
1036 table = cache->free_head;
1037 assert(table);
1038 cache->free_head = table->next;
1039
1040 if (cache->used_tail)
1041 cache->used_tail->next = table;
1042 else
1043 /* First item in the used list */
1044 cache->used_head = table;
1045
1046 cache->used_tail = table;
1047 cache->free--;
1048
1049 *l2_table = table;
1050}
1051
1052static int add_l2_item(struct ext2_qcow2_image *img, blk64_t blk,
1053 blk64_t data, blk64_t next)
1054{
1055 struct ext2_qcow2_l2_cache *cache = img->l2_cache;
1056 struct ext2_qcow2_l2_table *table = cache->used_tail;
1057 blk64_t l1_index = blk / img->l2_size;
1058 blk64_t l2_index = blk & (img->l2_size - 1);
1059 int ret = 0;
1060
1061 /*
1062 * Need to create new table if it does not exist,
1063 * or if it is full
1064 */
1065 if (!table || (table->l1_index != l1_index)) {
1066 get_free_table(img, &table);
1067 table->l1_index = l1_index;
1068 table->offset = cache->next_offset;
1069 cache->next_offset = next;
1070 img->l1_table[l1_index] =
1071 ext2fs_cpu_to_be64(table->offset | QCOW_OFLAG_COPIED);
1072 ret++;
1073 }
1074
1075 table->data[l2_index] = ext2fs_cpu_to_be64(data | QCOW_OFLAG_COPIED);
1076 return ret;
1077}
1078
1079static int update_refcount(int fd, struct ext2_qcow2_image *img,
1080 blk64_t offset, blk64_t rfblk_pos)
1081{
1082 struct ext2_qcow2_refcount *ref;
1083 __u32 table_index;
1084 int ret = 0;
1085
1086 ref = &(img->refcount);
1087 table_index = offset >> (2 * img->cluster_bits - 1);
1088
1089 /*
1090 * Need to create new refcount block when the offset addresses
1091 * another item in the refcount table
1092 */
1093 if (table_index != ref->refcount_table_index) {
1094
80fe25a2 1095 seek_set(fd, ref->refcount_block_offset);
bf0449b1
LC
1096
1097 generic_write(fd, (char *)ref->refcount_block,
0155e770 1098 img->cluster_size, NO_BLK);
bf0449b1
LC
1099 memset(ref->refcount_block, 0, img->cluster_size);
1100
1101 ref->refcount_table[ref->refcount_table_index] =
1102 ext2fs_cpu_to_be64(ref->refcount_block_offset);
1103 ref->refcount_block_offset = rfblk_pos;
1104 ref->refcount_block_index = 0;
1105 ref->refcount_table_index = table_index;
1106 ret++;
1107 }
1108
1109 /*
1110 * We are relying on the fact that we are creating the qcow2
1111 * image sequentially, hence we will always allocate refcount
055866d8 1112 * block items sequentially.
bf0449b1
LC
1113 */
1114 ref->refcount_block[ref->refcount_block_index] = ext2fs_cpu_to_be16(1);
1115 ref->refcount_block_index++;
1116 return ret;
1117}
1118
1119static int sync_refcount(int fd, struct ext2_qcow2_image *img)
1120{
1121 struct ext2_qcow2_refcount *ref;
1122
1123 ref = &(img->refcount);
1124
1125 ref->refcount_table[ref->refcount_table_index] =
1126 ext2fs_cpu_to_be64(ref->refcount_block_offset);
80fe25a2 1127 seek_set(fd, ref->refcount_table_offset);
bf0449b1 1128 generic_write(fd, (char *)ref->refcount_table,
0155e770 1129 ref->refcount_table_clusters << img->cluster_bits, NO_BLK);
bf0449b1 1130
80fe25a2 1131 seek_set(fd, ref->refcount_block_offset);
0155e770
TT
1132 generic_write(fd, (char *)ref->refcount_block, img->cluster_size,
1133 NO_BLK);
bf0449b1
LC
1134 return 0;
1135}
1136
1137static void output_qcow2_meta_data_blocks(ext2_filsys fs, int fd)
1138{
1139 errcode_t retval;
96367ad3 1140 blk64_t blk, offset, size, end;
bf0449b1 1141 char *buf;
bf0449b1 1142 struct ext2_qcow2_image *img;
96367ad3 1143 unsigned int header_size;
bf0449b1
LC
1144
1145 /* allocate struct ext2_qcow2_image */
1146 retval = ext2fs_get_mem(sizeof(struct ext2_qcow2_image), &img);
1147 if (retval) {
4d46e6c7 1148 com_err(program_name, retval, "%s",
737a8867 1149 _("while allocating ext2_qcow2_image"));
bf0449b1
LC
1150 exit(1);
1151 }
1152
1153 retval = initialize_qcow2_image(fd, fs, img);
1154 if (retval) {
4d46e6c7 1155 com_err(program_name, retval, "%s",
737a8867 1156 _("while initializing ext2_qcow2_image"));
bf0449b1
LC
1157 exit(1);
1158 }
1159 header_size = align_offset(sizeof(struct ext2_qcow2_hdr),
1160 img->cluster_size);
1161 write_header(fd, img->hdr, sizeof(struct ext2_qcow2_hdr), header_size);
1162
1163 /* Refcount all qcow2 related metadata up to refcount_block_offset */
1164 end = img->refcount.refcount_block_offset;
80fe25a2 1165 seek_set(fd, end);
bf0449b1
LC
1166 blk = end + img->cluster_size;
1167 for (offset = 0; offset <= end; offset += img->cluster_size) {
1168 if (update_refcount(fd, img, offset, blk)) {
1169 blk += img->cluster_size;
1170 /*
1171 * If we create new refcount block, we need to refcount
1172 * it as well.
1173 */
1174 end += img->cluster_size;
1175 }
1176 }
80fe25a2 1177 seek_set(fd, offset);
bf0449b1
LC
1178
1179 retval = ext2fs_get_mem(fs->blocksize, &buf);
1180 if (retval) {
4d46e6c7
AD
1181 com_err(program_name, retval, "%s",
1182 _("while allocating buffer"));
bf0449b1
LC
1183 exit(1);
1184 }
1185 /* Write qcow2 data blocks */
1186 for (blk = 0; blk < ext2fs_blocks_count(fs->super); blk++) {
1187 if ((blk >= fs->super->s_first_data_block) &&
1188 ext2fs_test_block_bitmap2(meta_block_map, blk)) {
1189 retval = io_channel_read_blk64(fs->io, blk, 1, buf);
1190 if (retval) {
1191 com_err(program_name, retval,
737a8867 1192 _("error reading block %llu"), blk);
bf0449b1
LC
1193 continue;
1194 }
1195 if (scramble_block_map &&
1196 ext2fs_test_block_bitmap2(scramble_block_map, blk))
1197 scramble_dir_block(fs, blk, buf);
1198 if (check_zero_block(buf, fs->blocksize))
1199 continue;
1200
1201 if (update_refcount(fd, img, offset, offset)) {
1202 /* Make space for another refcount block */
1203 offset += img->cluster_size;
80fe25a2 1204 seek_set(fd, offset);
bf0449b1
LC
1205 /*
1206 * We have created the new refcount block, this
1207 * means that we need to refcount it as well.
1208 * So the previous update_refcount refcounted
1209 * the block itself and now we are going to
1210 * create refcount for data. New refcount
1211 * block should not be created!
1212 */
1213 if (update_refcount(fd, img, offset, offset)) {
4d46e6c7
AD
1214 fprintf(stderr, "%s",
1215 _("Programming error: multiple "
1216 "sequential refcount blocks "
1217 "created!\n"));
bf0449b1
LC
1218 exit(1);
1219 }
1220 }
1221
0155e770 1222 generic_write(fd, buf, fs->blocksize, blk);
bf0449b1
LC
1223
1224 if (add_l2_item(img, blk, offset,
1225 offset + img->cluster_size)) {
1226 offset += img->cluster_size;
1227 if (update_refcount(fd, img, offset,
1228 offset + img->cluster_size)) {
1229 offset += img->cluster_size;
1230 if (update_refcount(fd, img, offset,
1231 offset)) {
4d46e6c7 1232 fprintf(stderr, "%s",
737a8867
TT
1233 _("Programming error: multiple sequential refcount "
1234 "blocks created!\n"));
bf0449b1
LC
1235 exit(1);
1236 }
1237 }
1238 offset += img->cluster_size;
80fe25a2 1239 seek_set(fd, offset);
bf0449b1
LC
1240 continue;
1241 }
1242
1243 offset += img->cluster_size;
1244 }
1245 }
1246 update_refcount(fd, img, offset, offset);
1247 flush_l2_cache(img);
1248 sync_refcount(fd, img);
1249
1250 /* Write l1_table*/
80fe25a2 1251 seek_set(fd, img->l1_offset);
bf0449b1 1252 size = img->l1_size * sizeof(__u64);
0155e770 1253 generic_write(fd, (char *)img->l1_table, size, NO_BLK);
bf0449b1
LC
1254
1255 ext2fs_free_mem(&buf);
1256 free_qcow2_image(img);
1257}
1258
1259static void write_raw_image_file(ext2_filsys fs, int fd, int type, int flags)
6304baf2
TT
1260{
1261 struct process_block_struct pb;
1262 struct ext2_inode inode;
1263 ext2_inode_scan scan;
1264 ext2_ino_t ino;
1265 errcode_t retval;
1266 char * block_buf;
efc6f628 1267
bf0449b1 1268 meta_blocks_count = 0;
737a8867 1269 retval = ext2fs_allocate_block_bitmap(fs, _("in-use block map"),
6304baf2
TT
1270 &meta_block_map);
1271 if (retval) {
4d46e6c7 1272 com_err(program_name, retval, "%s",
737a8867 1273 _("while allocating block bitmap"));
6304baf2
TT
1274 exit(1);
1275 }
d851ed39 1276
bf0449b1 1277 if (flags & E2IMAGE_SCRAMBLE_FLAG) {
d851ed39
TT
1278 retval = ext2fs_allocate_block_bitmap(fs, "scramble block map",
1279 &scramble_block_map);
1280 if (retval) {
4d46e6c7 1281 com_err(program_name, retval, "%s",
737a8867 1282 _("while allocating scramble block bitmap"));
d851ed39
TT
1283 exit(1);
1284 }
1285 }
efc6f628 1286
6304baf2 1287 mark_table_blocks(fs);
c40c7cef 1288 if (show_progress)
be5ce275 1289 fprintf(stderr, "%s", _("Scanning inodes...\n"));
6304baf2
TT
1290
1291 retval = ext2fs_open_inode_scan(fs, 0, &scan);
1292 if (retval) {
4d46e6c7 1293 com_err(program_name, retval, "%s",
45ff69ff 1294 _("while opening inode scan"));
6304baf2
TT
1295 exit(1);
1296 }
1297
bf0449b1
LC
1298 retval = ext2fs_get_mem(fs->blocksize * 3, &block_buf);
1299 if (retval) {
45ff69ff
AD
1300 com_err(program_name, 0, "%s",
1301 _("Can't allocate block buffer"));
6304baf2
TT
1302 exit(1);
1303 }
efc6f628 1304
4ea7bd04 1305 use_inode_shortcuts(fs, 1);
6304baf2
TT
1306 stashed_inode = &inode;
1307 while (1) {
1308 retval = ext2fs_get_next_inode(scan, &ino, &inode);
3432a916
TT
1309 if (retval == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE)
1310 continue;
6304baf2 1311 if (retval) {
45ff69ff 1312 com_err(program_name, retval, "%s",
6304baf2
TT
1313 _("while getting next inode"));
1314 exit(1);
1315 }
1316 if (ino == 0)
1317 break;
ed909bbe
TT
1318 if (!inode.i_links_count)
1319 continue;
0c80c44b 1320 if (ext2fs_file_acl_block(fs, &inode)) {
3c041a51 1321 ext2fs_mark_block_bitmap2(meta_block_map,
0c80c44b 1322 ext2fs_file_acl_block(fs, &inode));
bf0449b1 1323 meta_blocks_count++;
ed909bbe 1324 }
0c80c44b 1325 if (!ext2fs_inode_has_valid_blocks2(fs, &inode))
6304baf2 1326 continue;
efc6f628 1327
6304baf2 1328 stashed_ino = ino;
d851ed39
TT
1329 pb.ino = ino;
1330 pb.is_dir = LINUX_S_ISDIR(inode.i_mode);
1c1e0049 1331 if (LINUX_S_ISDIR(inode.i_mode) ||
eca53e3c 1332 (LINUX_S_ISLNK(inode.i_mode) &&
0c80c44b 1333 ext2fs_inode_has_valid_blocks2(fs, &inode)) ||
1c1e0049 1334 ino == fs->super->s_journal_inum) {
d991bc74 1335 retval = ext2fs_block_iterate3(fs, ino,
43323be9
TT
1336 BLOCK_FLAG_READ_ONLY, block_buf,
1337 process_dir_block, &pb);
6304baf2
TT
1338 if (retval) {
1339 com_err(program_name, retval,
737a8867 1340 _("while iterating over inode %u"),
6304baf2
TT
1341 ino);
1342 exit(1);
1343 }
1344 } else {
43323be9
TT
1345 if ((inode.i_flags & EXT4_EXTENTS_FL) ||
1346 inode.i_block[EXT2_IND_BLOCK] ||
6304baf2 1347 inode.i_block[EXT2_DIND_BLOCK] ||
0e51f5ae 1348 inode.i_block[EXT2_TIND_BLOCK] || all_data) {
d991bc74 1349 retval = ext2fs_block_iterate3(fs,
43323be9 1350 ino, BLOCK_FLAG_READ_ONLY, block_buf,
6304baf2
TT
1351 process_file_block, &pb);
1352 if (retval) {
1353 com_err(program_name, retval,
737a8867 1354 _("while iterating over inode %u"), ino);
6304baf2
TT
1355 exit(1);
1356 }
1357 }
6304baf2
TT
1358 }
1359 }
4ea7bd04 1360 use_inode_shortcuts(fs, 0);
bf0449b1
LC
1361
1362 if (type & E2IMAGE_QCOW2)
1363 output_qcow2_meta_data_blocks(fs, fd);
1364 else
aa2c7433 1365 output_meta_data_blocks(fs, fd, flags);
bf0449b1
LC
1366
1367 ext2fs_free_mem(&block_buf);
1368 ext2fs_close_inode_scan(scan);
1369 ext2fs_free_block_bitmap(meta_block_map);
1370 if (type & E2IMAGE_SCRAMBLE_FLAG)
1371 ext2fs_free_block_bitmap(scramble_block_map);
6304baf2
TT
1372}
1373
bf0449b1 1374static void install_image(char *device, char *image_fn, int type)
8c6b6483 1375{
8c6b6483
TT
1376 errcode_t retval;
1377 ext2_filsys fs;
7dd0dfca
DW
1378 int open_flag = EXT2_FLAG_IMAGE_FILE | EXT2_FLAG_64BITS |
1379 EXT2_FLAG_IGNORE_CSUM_ERRORS;
8c6b6483
TT
1380 int fd = 0;
1381 io_manager io_ptr;
bf0449b1 1382 io_channel io;
8c6b6483 1383
bf0449b1 1384 if (type) {
4d46e6c7
AD
1385 com_err(program_name, 0, "%s",
1386 _("Raw and qcow2 images cannot be installed"));
8c6b6483
TT
1387 exit(1);
1388 }
efc6f628 1389
8c6b6483 1390#ifdef CONFIG_TESTIO_DEBUG
f38cf3cb
TT
1391 if (getenv("TEST_IO_FLAGS") || getenv("TEST_IO_BLOCK")) {
1392 io_ptr = test_io_manager;
1393 test_io_backing_manager = unix_io_manager;
1394 } else
8c6b6483 1395#endif
f38cf3cb 1396 io_ptr = unix_io_manager;
8c6b6483
TT
1397
1398 retval = ext2fs_open (image_fn, open_flag, 0, 0,
1399 io_ptr, &fs);
1400 if (retval) {
4d46e6c7
AD
1401 com_err(program_name, retval, _("while trying to open %s"),
1402 image_fn);
8c6b6483
TT
1403 exit(1);
1404 }
1405
1406 retval = ext2fs_read_bitmaps (fs);
1407 if (retval) {
4d46e6c7 1408 com_err(program_name, retval, "%s", _("error reading bitmaps"));
8c6b6483
TT
1409 exit(1);
1410 }
1411
c4012e5a 1412 fd = ext2fs_open_file(image_fn, O_RDONLY, 0);
8c6b6483
TT
1413 if (fd < 0) {
1414 perror(image_fn);
1415 exit(1);
1416 }
1417
efc6f628 1418 retval = io_ptr->open(device, IO_FLAG_RW, &io);
8c6b6483 1419 if (retval) {
4d46e6c7 1420 com_err(device, 0, "%s", _("while opening device file"));
8c6b6483
TT
1421 exit(1);
1422 }
1423
8c6b6483
TT
1424 ext2fs_rewrite_to_io(fs, io);
1425
80fe25a2 1426 seek_set(fd, fs->image_header->offset_inode);
8c6b6483
TT
1427
1428 retval = ext2fs_image_inode_read(fs, fd, 0);
1429 if (retval) {
4d46e6c7
AD
1430 com_err(image_fn, 0, "%s",
1431 _("while restoring the image table"));
8c6b6483
TT
1432 exit(1);
1433 }
1434
e39082e2 1435 close(fd);
47fee2ef 1436 ext2fs_close_free(&fs);
8c6b6483
TT
1437}
1438
92dcfb76
LC
1439static struct ext2_qcow2_hdr *check_qcow2_image(int *fd, char *name)
1440{
1441
c859cb1d 1442 *fd = ext2fs_open_file(name, O_RDONLY, 0600);
92dcfb76
LC
1443 if (*fd < 0)
1444 return NULL;
1445
1446 return qcow2_read_header(*fd);
1447}
1448
6304baf2
TT
1449int main (int argc, char ** argv)
1450{
1451 int c;
1452 errcode_t retval;
1453 ext2_filsys fs;
d28759b2 1454 char *image_fn, offset_opt[64];
92dcfb76 1455 struct ext2_qcow2_hdr *header = NULL;
7dd0dfca 1456 int open_flag = EXT2_FLAG_64BITS | EXT2_FLAG_IGNORE_CSUM_ERRORS;
bf0449b1
LC
1457 int img_type = 0;
1458 int flags = 0;
6c327e9c 1459 int mount_flags = 0;
92dcfb76 1460 int qcow2_fd = 0;
6304baf2 1461 int fd = 0;
92dcfb76 1462 int ret = 0;
6c327e9c 1463 int ignore_rw_mount = 0;
38c771d6 1464 int check = 0;
0e51f5ae 1465 struct stat st;
6304baf2
TT
1466
1467#ifdef ENABLE_NLS
1468 setlocale(LC_MESSAGES, "");
14308a53 1469 setlocale(LC_CTYPE, "");
6304baf2
TT
1470 bindtextdomain(NLS_CAT_NAME, LOCALEDIR);
1471 textdomain(NLS_CAT_NAME);
9d4507c5 1472 set_com_err_gettext(gettext);
6304baf2 1473#endif
0f8973fb
TT
1474 fprintf (stderr, "e2image %s (%s)\n", E2FSPROGS_VERSION,
1475 E2FSPROGS_DATE);
6304baf2
TT
1476 if (argc && *argv)
1477 program_name = *argv;
a6d8302b 1478 add_error_table(&et_ext2_error_table);
0155e770 1479 while ((c = getopt(argc, argv, "nrsIQafo:O:pc")) != EOF)
6304baf2 1480 switch (c) {
bf0449b1
LC
1481 case 'I':
1482 flags |= E2IMAGE_INSTALL_FLAG;
1483 break;
1484 case 'Q':
1485 if (img_type)
1486 usage();
1487 img_type |= E2IMAGE_QCOW2;
1488 break;
6304baf2 1489 case 'r':
bf0449b1
LC
1490 if (img_type)
1491 usage();
1492 img_type |= E2IMAGE_RAW;
6304baf2 1493 break;
d851ed39 1494 case 's':
bf0449b1 1495 flags |= E2IMAGE_SCRAMBLE_FLAG;
8c6b6483 1496 break;
0e51f5ae
PS
1497 case 'a':
1498 all_data = 1;
1499 break;
6c327e9c
CM
1500 case 'f':
1501 ignore_rw_mount = 1;
1502 break;
0155e770
TT
1503 case 'n':
1504 nop_flag = 1;
1505 break;
6b5535f4
PS
1506 case 'o':
1507 source_offset = strtoull(optarg, NULL, 0);
1508 break;
1509 case 'O':
1510 dest_offset = strtoull(optarg, NULL, 0);
1511 break;
c40c7cef
PS
1512 case 'p':
1513 show_progress = 1;
1514 break;
38c771d6
TT
1515 case 'c':
1516 check = 1;
1517 break;
6304baf2
TT
1518 default:
1519 usage();
1520 }
22b83f62
PS
1521 if (optind == argc - 1 &&
1522 (source_offset || dest_offset))
1523 move_mode = 1;
1524 else if (optind != argc - 2 )
6304baf2 1525 usage();
fdaf34f8
TR
1526
1527 if (all_data && !img_type) {
4d46e6c7
AD
1528 com_err(program_name, 0, "%s", _("-a option can only be used "
1529 "with raw or QCOW2 images."));
fdaf34f8
TR
1530 exit(1);
1531 }
6b5535f4 1532 if ((source_offset || dest_offset) && img_type != E2IMAGE_RAW) {
4d46e6c7 1533 com_err(program_name, 0, "%s",
737a8867 1534 _("Offsets are only allowed with raw images."));
6b5535f4
PS
1535 exit(1);
1536 }
22b83f62 1537 if (move_mode && img_type != E2IMAGE_RAW) {
4d46e6c7 1538 com_err(program_name, 0, "%s",
737a8867 1539 _("Move mode is only allowed with raw images."));
22b83f62
PS
1540 exit(1);
1541 }
1542 if (move_mode && !all_data) {
4d46e6c7 1543 com_err(program_name, 0, "%s",
737a8867 1544 _("Move mode requires all data mode."));
fdaf34f8
TR
1545 exit(1);
1546 }
6304baf2 1547 device_name = argv[optind];
22b83f62
PS
1548 if (move_mode)
1549 image_fn = device_name;
1550 else image_fn = argv[optind+1];
8c6b6483 1551
b3993825
DW
1552 retval = ext2fs_check_if_mounted(device_name, &mount_flags);
1553 if (retval) {
4d46e6c7 1554 com_err(program_name, retval, "%s", _("checking if mounted"));
b3993825
DW
1555 exit(1);
1556 }
6c327e9c
CM
1557
1558 if (img_type && !ignore_rw_mount &&
1559 (mount_flags & EXT2_MF_MOUNTED) &&
1560 !(mount_flags & EXT2_MF_READONLY)) {
4d46e6c7 1561 fprintf(stderr, "%s", _("\nRunning e2image on a R/W mounted "
6c327e9c
CM
1562 "filesystem can result in an\n"
1563 "inconsistent image which will not be useful "
1564 "for debugging purposes.\n"
737a8867 1565 "Use -f option if you really want to do that.\n"));
6c327e9c
CM
1566 exit(1);
1567 }
1568
bf0449b1
LC
1569 if (flags & E2IMAGE_INSTALL_FLAG) {
1570 install_image(device_name, image_fn, img_type);
6e82cd7e 1571 exit (0);
8c6b6483
TT
1572 }
1573
92dcfb76
LC
1574 if (img_type & E2IMAGE_RAW) {
1575 header = check_qcow2_image(&qcow2_fd, device_name);
1576 if (header) {
1577 flags |= E2IMAGE_IS_QCOW2_FLAG;
1578 goto skip_device;
1579 }
1580 }
d28759b2
TT
1581 sprintf(offset_opt, "offset=%llu", source_offset);
1582 retval = ext2fs_open2(device_name, offset_opt, open_flag, 0, 0,
6304baf2
TT
1583 unix_io_manager, &fs);
1584 if (retval) {
1585 com_err (program_name, retval, _("while trying to open %s"),
1586 device_name);
54434927 1587 fputs(_("Couldn't find valid filesystem superblock.\n"), stdout);
c8b20b40
DW
1588 if (retval == EXT2_ET_BAD_MAGIC)
1589 check_plausibility(device_name, CHECK_FS_EXIST, NULL);
6304baf2
TT
1590 exit(1);
1591 }
1592
92dcfb76 1593skip_device:
8c6b6483 1594 if (strcmp(image_fn, "-") == 0)
1c1e0049
TT
1595 fd = 1;
1596 else {
38c771d6 1597 int o_flags = O_CREAT|O_RDWR;
22b83f62
PS
1598
1599 if (img_type != E2IMAGE_RAW)
1600 o_flags |= O_TRUNC;
aa2c7433
TT
1601 if (access(image_fn, F_OK) != 0)
1602 flags |= E2IMAGE_CHECK_ZERO_FLAG;
22b83f62 1603 fd = ext2fs_open_file(image_fn, o_flags, 0600);
1c1e0049
TT
1604 if (fd < 0) {
1605 com_err(program_name, errno,
22b83f62 1606 _("while trying to open %s"), image_fn);
1c1e0049
TT
1607 exit(1);
1608 }
6304baf2 1609 }
6b5535f4 1610 if (dest_offset)
80fe25a2 1611 seek_set(fd, dest_offset);
6304baf2 1612
bf0449b1 1613 if ((img_type & E2IMAGE_QCOW2) && (fd == 1)) {
4d46e6c7
AD
1614 com_err(program_name, 0, "%s",
1615 _("QCOW2 image can not be written to the stdout!\n"));
bf0449b1
LC
1616 exit(1);
1617 }
0e51f5ae
PS
1618 if (fd != 1) {
1619 if (fstat(fd, &st)) {
4d46e6c7
AD
1620 com_err(program_name, 0, "%s",
1621 _("Can not stat output\n"));
0e51f5ae
PS
1622 exit(1);
1623 }
f61aa76e 1624 if (ext2fsP_is_disk_device(st.st_mode))
0e51f5ae
PS
1625 output_is_blk = 1;
1626 }
92dcfb76
LC
1627 if (flags & E2IMAGE_IS_QCOW2_FLAG) {
1628 ret = qcow2_write_raw_image(qcow2_fd, fd, header);
1629 if (ret) {
1630 if (ret == -QCOW_COMPRESSED)
737a8867 1631 fprintf(stderr, _("Image (%s) is compressed\n"),
92dcfb76
LC
1632 image_fn);
1633 if (ret == -QCOW_ENCRYPTED)
737a8867 1634 fprintf(stderr, _("Image (%s) is encrypted\n"),
92dcfb76
LC
1635 image_fn);
1636 com_err(program_name, ret,
1637 _("while trying to convert qcow2 image"
737a8867 1638 " (%s) into raw image (%s)"),
92dcfb76
LC
1639 device_name, image_fn);
1640 }
1641 goto out;
1642 }
1643
38c771d6
TT
1644 if (check) {
1645 if (img_type != E2IMAGE_RAW) {
4d46e6c7
AD
1646 fprintf(stderr, "%s", _("The -c option only supported "
1647 "in raw mode\n"));
38c771d6
TT
1648 exit(1);
1649 }
1650 if (fd == 1) {
4d46e6c7
AD
1651 fprintf(stderr, "%s", _("The -c option not supported "
1652 "when writing to stdout\n"));
38c771d6
TT
1653 exit(1);
1654 }
1655 retval = ext2fs_get_mem(fs->blocksize, &check_buf);
1656 if (retval) {
4d46e6c7 1657 com_err(program_name, retval, "%s",
737a8867 1658 _("while allocating check_buf"));
38c771d6
TT
1659 exit(1);
1660 }
1661 }
c8ee0d60 1662 if (show_progress && (img_type != E2IMAGE_RAW)) {
4d46e6c7
AD
1663 fprintf(stderr, "%s",
1664 _("The -p option only supported in raw mode\n"));
c8ee0d60
TT
1665 exit(1);
1666 }
bf0449b1
LC
1667 if (img_type)
1668 write_raw_image_file(fs, fd, img_type, flags);
6304baf2
TT
1669 else
1670 write_image_file(fs, fd);
c5423c5b 1671
47fee2ef 1672 ext2fs_close_free(&fs);
38c771d6 1673 if (check)
4d46e6c7 1674 printf(_("%d blocks already contained the data to be copied\n"),
38c771d6
TT
1675 skipped_blocks);
1676
92dcfb76
LC
1677out:
1678 if (header)
1679 free(header);
1680 if (qcow2_fd)
1681 close(qcow2_fd);
a6d8302b 1682 remove_error_table(&et_ext2_error_table);
92dcfb76 1683 return ret;
72ed1264 1684}