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