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