~daniel-mehrmann/e2fsprogs/master

« back to all changes in this revision

Viewing changes to .pc/git-update-to-3b0018beee/misc/e2image.c

  • Committer: Package Import Robot
  • Author(s): Dmitrijs Ledkovs
  • Date: 2012-06-14 13:01:21 UTC
  • mfrom: (8.4.18 sid)
  • Revision ID: package-import@ubuntu.com-20120614130121-t2gct0d09jepx0y6
Tags: 1.42.4-3ubuntu1
* Merge from Debian unstable (LP: #978012), remainging changes:
  - debian/control.in: 
      Build-depend on gettext:any instead of on gettext for (cross-building)
      Drop build dependency on dc, which hasn't been needed for some time.
      Update maintainer field.
  - debian/rules:
      Block pkg-create-dbgsym from operating on this package.
      Build without dietlibc-dev, which is in universe 
  - debian/control:
      Regenerate with ./debian/rules debian/control

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * e2image.c --- Program which writes an image file backing up
3
 
 * critical metadata for the filesystem.
4
 
 *
5
 
 * Copyright 2000, 2001 by Theodore Ts'o.
6
 
 *
7
 
 * %Begin-Header%
8
 
 * This file may be redistributed under the terms of the GNU Public
9
 
 * License.
10
 
 * %End-Header%
11
 
 */
12
 
 
13
 
#define _LARGEFILE_SOURCE
14
 
#define _LARGEFILE64_SOURCE
15
 
 
16
 
#include "config.h"
17
 
#include <fcntl.h>
18
 
#include <grp.h>
19
 
#ifdef HAVE_GETOPT_H
20
 
#include <getopt.h>
21
 
#else
22
 
extern char *optarg;
23
 
extern int optind;
24
 
#endif
25
 
#include <pwd.h>
26
 
#include <stdio.h>
27
 
#ifdef HAVE_STDLIB_H
28
 
#include <stdlib.h>
29
 
#endif
30
 
#include <string.h>
31
 
#include <time.h>
32
 
#include <unistd.h>
33
 
#include <fcntl.h>
34
 
#include <errno.h>
35
 
#include <sys/stat.h>
36
 
#include <sys/types.h>
37
 
#include <assert.h>
38
 
 
39
 
#include "ext2fs/ext2_fs.h"
40
 
#include "ext2fs/ext2fs.h"
41
 
#include "et/com_err.h"
42
 
#include "uuid/uuid.h"
43
 
#include "e2p/e2p.h"
44
 
#include "ext2fs/e2image.h"
45
 
#include "ext2fs/qcow2.h"
46
 
 
47
 
#include "../version.h"
48
 
#include "nls-enable.h"
49
 
 
50
 
#define QCOW_OFLAG_COPIED     (1LL << 63)
51
 
 
52
 
 
53
 
const char * program_name = "e2image";
54
 
char * device_name = NULL;
55
 
 
56
 
static void lseek_error_and_exit(int errnum)
57
 
{
58
 
        perror("seek");
59
 
        exit(1);
60
 
}
61
 
 
62
 
static blk64_t align_offset(blk64_t offset, int n)
63
 
{
64
 
        return (offset + n - 1) & ~(n - 1);
65
 
}
66
 
 
67
 
static int get_bits_from_size(size_t size)
68
 
{
69
 
        int res = 0;
70
 
 
71
 
        if (size == 0)
72
 
                return -1;
73
 
 
74
 
        while (size != 1) {
75
 
                /* Not a power of two */
76
 
                if (size & 1)
77
 
                        return -1;
78
 
 
79
 
                size >>= 1;
80
 
                res++;
81
 
        }
82
 
        return res;
83
 
}
84
 
 
85
 
static void usage(void)
86
 
{
87
 
        fprintf(stderr, _("Usage: %s [-rsIQ] device image_file\n"),
88
 
                program_name);
89
 
        exit (1);
90
 
}
91
 
 
92
 
static void generic_write(int fd, void *buf, int blocksize, blk64_t block)
93
 
{
94
 
        int count, free_buf = 0;
95
 
        errcode_t err;
96
 
 
97
 
        if (!blocksize)
98
 
                return;
99
 
 
100
 
        if (!buf) {
101
 
                free_buf = 1;
102
 
                err = ext2fs_get_arrayzero(1, blocksize, &buf);
103
 
                if (err) {
104
 
                        com_err(program_name, err, "while allocating buffer");
105
 
                        exit(1);
106
 
                }
107
 
        }
108
 
 
109
 
        count = write(fd, buf, blocksize);
110
 
        if (count != blocksize) {
111
 
                if (count == -1)
112
 
                        err = errno;
113
 
                else
114
 
                        err = 0;
115
 
 
116
 
                if (block)
117
 
                        com_err(program_name, err, "error writing block %llu",
118
 
                                block);
119
 
                else
120
 
                        com_err(program_name, err, "error in write()");
121
 
 
122
 
                exit(1);
123
 
        }
124
 
        if (free_buf)
125
 
                ext2fs_free_mem(&buf);
126
 
}
127
 
 
128
 
static void write_header(int fd, void *hdr, int hdr_size, int wrt_size)
129
 
{
130
 
        char *header_buf;
131
 
        int ret;
132
 
 
133
 
        /* Sanity check */
134
 
        if (hdr_size > wrt_size) {
135
 
                fprintf(stderr, _("Error: header size is bigger than "
136
 
                                  "wrt_size\n"));
137
 
        }
138
 
 
139
 
        ret = ext2fs_get_mem(wrt_size, &header_buf);
140
 
        if (ret) {
141
 
                fputs(_("Couldn't allocate header buffer\n"), stderr);
142
 
                exit(1);
143
 
        }
144
 
 
145
 
        if (ext2fs_llseek(fd, 0, SEEK_SET) < 0) {
146
 
                perror("ext2fs_llseek while writing header");
147
 
                exit(1);
148
 
        }
149
 
        memset(header_buf, 0, wrt_size);
150
 
 
151
 
        if (hdr)
152
 
                memcpy(header_buf, hdr, hdr_size);
153
 
 
154
 
        generic_write(fd, header_buf, wrt_size, 0);
155
 
 
156
 
        ext2fs_free_mem(&header_buf);
157
 
}
158
 
 
159
 
static void write_image_file(ext2_filsys fs, int fd)
160
 
{
161
 
        struct ext2_image_hdr   hdr;
162
 
        struct stat             st;
163
 
        errcode_t               retval;
164
 
 
165
 
        write_header(fd, NULL, fs->blocksize, fs->blocksize);
166
 
        memset(&hdr, 0, sizeof(struct ext2_image_hdr));
167
 
 
168
 
        hdr.offset_super = ext2fs_llseek(fd, 0, SEEK_CUR);
169
 
        retval = ext2fs_image_super_write(fs, fd, 0);
170
 
        if (retval) {
171
 
                com_err(program_name, retval, _("while writing superblock"));
172
 
                exit(1);
173
 
        }
174
 
 
175
 
        hdr.offset_inode = ext2fs_llseek(fd, 0, SEEK_CUR);
176
 
        retval = ext2fs_image_inode_write(fs, fd,
177
 
                                  (fd != 1) ? IMAGER_FLAG_SPARSEWRITE : 0);
178
 
        if (retval) {
179
 
                com_err(program_name, retval, _("while writing inode table"));
180
 
                exit(1);
181
 
        }
182
 
 
183
 
        hdr.offset_blockmap = ext2fs_llseek(fd, 0, SEEK_CUR);
184
 
        retval = ext2fs_image_bitmap_write(fs, fd, 0);
185
 
        if (retval) {
186
 
                com_err(program_name, retval, _("while writing block bitmap"));
187
 
                exit(1);
188
 
        }
189
 
 
190
 
        hdr.offset_inodemap = ext2fs_llseek(fd, 0, SEEK_CUR);
191
 
        retval = ext2fs_image_bitmap_write(fs, fd, IMAGER_FLAG_INODEMAP);
192
 
        if (retval) {
193
 
                com_err(program_name, retval, _("while writing inode bitmap"));
194
 
                exit(1);
195
 
        }
196
 
 
197
 
        hdr.magic_number = EXT2_ET_MAGIC_E2IMAGE;
198
 
        strcpy(hdr.magic_descriptor, "Ext2 Image 1.0");
199
 
        gethostname(hdr.fs_hostname, sizeof(hdr.fs_hostname));
200
 
        strncpy(hdr.fs_device_name, device_name, sizeof(hdr.fs_device_name)-1);
201
 
        hdr.fs_device_name[sizeof(hdr.fs_device_name) - 1] = 0;
202
 
        hdr.fs_blocksize = fs->blocksize;
203
 
 
204
 
        if (stat(device_name, &st) == 0)
205
 
                hdr.fs_device = st.st_rdev;
206
 
 
207
 
        if (fstat(fd, &st) == 0) {
208
 
                hdr.image_device = st.st_dev;
209
 
                hdr.image_inode = st.st_ino;
210
 
        }
211
 
        memcpy(hdr.fs_uuid, fs->super->s_uuid, sizeof(hdr.fs_uuid));
212
 
 
213
 
        hdr.image_time = time(0);
214
 
        write_header(fd, &hdr, fs->blocksize, fs->blocksize);
215
 
}
216
 
 
217
 
/*
218
 
 * These set of functions are used to write a RAW image file.
219
 
 */
220
 
ext2fs_block_bitmap meta_block_map;
221
 
ext2fs_block_bitmap scramble_block_map; /* Directory blocks to be scrambled */
222
 
blk64_t meta_blocks_count;
223
 
 
224
 
struct process_block_struct {
225
 
        ext2_ino_t      ino;
226
 
        int             is_dir;
227
 
};
228
 
 
229
 
/*
230
 
 * These subroutines short circuits ext2fs_get_blocks and
231
 
 * ext2fs_check_directory; we use them since we already have the inode
232
 
 * structure, so there's no point in letting the ext2fs library read
233
 
 * the inode again.
234
 
 */
235
 
static ino_t stashed_ino = 0;
236
 
static struct ext2_inode *stashed_inode;
237
 
 
238
 
static errcode_t meta_get_blocks(ext2_filsys fs EXT2FS_ATTR((unused)),
239
 
                                 ext2_ino_t ino,
240
 
                                 blk_t *blocks)
241
 
{
242
 
        int     i;
243
 
 
244
 
        if ((ino != stashed_ino) || !stashed_inode)
245
 
                return EXT2_ET_CALLBACK_NOTHANDLED;
246
 
 
247
 
        for (i=0; i < EXT2_N_BLOCKS; i++)
248
 
                blocks[i] = stashed_inode->i_block[i];
249
 
        return 0;
250
 
}
251
 
 
252
 
static errcode_t meta_check_directory(ext2_filsys fs EXT2FS_ATTR((unused)),
253
 
                                      ext2_ino_t ino)
254
 
{
255
 
        if ((ino != stashed_ino) || !stashed_inode)
256
 
                return EXT2_ET_CALLBACK_NOTHANDLED;
257
 
 
258
 
        if (!LINUX_S_ISDIR(stashed_inode->i_mode))
259
 
                return EXT2_ET_NO_DIRECTORY;
260
 
        return 0;
261
 
}
262
 
 
263
 
static errcode_t meta_read_inode(ext2_filsys fs EXT2FS_ATTR((unused)),
264
 
                                 ext2_ino_t ino,
265
 
                                 struct ext2_inode *inode)
266
 
{
267
 
        if ((ino != stashed_ino) || !stashed_inode)
268
 
                return EXT2_ET_CALLBACK_NOTHANDLED;
269
 
        *inode = *stashed_inode;
270
 
        return 0;
271
 
}
272
 
 
273
 
static void use_inode_shortcuts(ext2_filsys fs, int bool)
274
 
{
275
 
        if (bool) {
276
 
                fs->get_blocks = meta_get_blocks;
277
 
                fs->check_directory = meta_check_directory;
278
 
                fs->read_inode = meta_read_inode;
279
 
                stashed_ino = 0;
280
 
        } else {
281
 
                fs->get_blocks = 0;
282
 
                fs->check_directory = 0;
283
 
                fs->read_inode = 0;
284
 
        }
285
 
}
286
 
 
287
 
static int process_dir_block(ext2_filsys fs EXT2FS_ATTR((unused)),
288
 
                             blk64_t *block_nr,
289
 
                             e2_blkcnt_t blockcnt EXT2FS_ATTR((unused)),
290
 
                             blk64_t ref_block EXT2FS_ATTR((unused)),
291
 
                             int ref_offset EXT2FS_ATTR((unused)),
292
 
                             void *priv_data EXT2FS_ATTR((unused)))
293
 
{
294
 
        struct process_block_struct *p;
295
 
 
296
 
        p = (struct process_block_struct *) priv_data;
297
 
 
298
 
        ext2fs_mark_block_bitmap2(meta_block_map, *block_nr);
299
 
        meta_blocks_count++;
300
 
        if (scramble_block_map && p->is_dir && blockcnt >= 0)
301
 
                ext2fs_mark_block_bitmap2(scramble_block_map, *block_nr);
302
 
        return 0;
303
 
}
304
 
 
305
 
static int process_file_block(ext2_filsys fs EXT2FS_ATTR((unused)),
306
 
                              blk64_t *block_nr,
307
 
                              e2_blkcnt_t blockcnt,
308
 
                              blk64_t ref_block EXT2FS_ATTR((unused)),
309
 
                              int ref_offset EXT2FS_ATTR((unused)),
310
 
                              void *priv_data EXT2FS_ATTR((unused)))
311
 
{
312
 
        if (blockcnt < 0) {
313
 
                ext2fs_mark_block_bitmap2(meta_block_map, *block_nr);
314
 
                meta_blocks_count++;
315
 
        }
316
 
        return 0;
317
 
}
318
 
 
319
 
static void mark_table_blocks(ext2_filsys fs)
320
 
{
321
 
        blk64_t first_block, b;
322
 
        unsigned int    i,j;
323
 
 
324
 
        first_block = fs->super->s_first_data_block;
325
 
        /*
326
 
         * Mark primary superblock
327
 
         */
328
 
        ext2fs_mark_block_bitmap2(meta_block_map, first_block);
329
 
        meta_blocks_count++;
330
 
 
331
 
        /*
332
 
         * Mark the primary superblock descriptors
333
 
         */
334
 
        for (j = 0; j < fs->desc_blocks; j++) {
335
 
                ext2fs_mark_block_bitmap2(meta_block_map,
336
 
                         ext2fs_descriptor_block_loc2(fs, first_block, j));
337
 
        }
338
 
        meta_blocks_count += fs->desc_blocks;
339
 
 
340
 
        for (i = 0; i < fs->group_desc_count; i++) {
341
 
                /*
342
 
                 * Mark the blocks used for the inode table
343
 
                 */
344
 
                if (!ext2fs_bg_flags_test(fs, i, EXT2_BG_INODE_UNINIT) &&
345
 
                    ext2fs_inode_table_loc(fs, i)) {
346
 
                        unsigned int end = (unsigned) fs->inode_blocks_per_group;
347
 
                        /* skip unused blocks */
348
 
                        if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
349
 
                                                       EXT4_FEATURE_RO_COMPAT_GDT_CSUM))
350
 
                                end -= (ext2fs_bg_itable_unused(fs, i) /
351
 
                                        EXT2_INODES_PER_BLOCK(fs->super));
352
 
                        for (j = 0, b = ext2fs_inode_table_loc(fs, i);
353
 
                             j < end;
354
 
                             j++, b++) {
355
 
                                ext2fs_mark_block_bitmap2(meta_block_map, b);
356
 
                                meta_blocks_count++;
357
 
                        }
358
 
                }
359
 
 
360
 
                /*
361
 
                 * Mark block used for the block bitmap
362
 
                 */
363
 
                if (!ext2fs_bg_flags_test(fs, i, EXT2_BG_BLOCK_UNINIT) &&
364
 
                    ext2fs_block_bitmap_loc(fs, i)) {
365
 
                        ext2fs_mark_block_bitmap2(meta_block_map,
366
 
                                     ext2fs_block_bitmap_loc(fs, i));
367
 
                        meta_blocks_count++;
368
 
                }
369
 
 
370
 
                /*
371
 
                 * Mark block used for the inode bitmap
372
 
                 */
373
 
                if (!ext2fs_bg_flags_test(fs, i, EXT2_BG_INODE_UNINIT) &&
374
 
                    ext2fs_inode_bitmap_loc(fs, i)) {
375
 
                        ext2fs_mark_block_bitmap2(meta_block_map,
376
 
                                 ext2fs_inode_bitmap_loc(fs, i));
377
 
                        meta_blocks_count++;
378
 
                }
379
 
        }
380
 
}
381
 
 
382
 
/*
383
 
 * This function returns 1 if the specified block is all zeros
384
 
 */
385
 
static int check_zero_block(char *buf, int blocksize)
386
 
{
387
 
        char    *cp = buf;
388
 
        int     left = blocksize;
389
 
 
390
 
        while (left > 0) {
391
 
                if (*cp++)
392
 
                        return 0;
393
 
                left--;
394
 
        }
395
 
        return 1;
396
 
}
397
 
 
398
 
static void write_block(int fd, char *buf, int sparse_offset,
399
 
                        int blocksize, blk64_t block)
400
 
{
401
 
        ext2_loff_t     ret = 0;
402
 
 
403
 
        if (sparse_offset)
404
 
                ret = ext2fs_llseek(fd, sparse_offset, SEEK_CUR);
405
 
 
406
 
        if (ret < 0)
407
 
                lseek_error_and_exit(errno);
408
 
        generic_write(fd, buf, blocksize, block);
409
 
}
410
 
 
411
 
int name_id[256];
412
 
 
413
 
#define EXT4_MAX_REC_LEN                ((1<<16)-1)
414
 
 
415
 
static void scramble_dir_block(ext2_filsys fs, blk64_t blk, char *buf)
416
 
{
417
 
        char *p, *end, *cp;
418
 
        struct ext2_dir_entry_2 *dirent;
419
 
        unsigned int rec_len;
420
 
        int id, len;
421
 
 
422
 
        end = buf + fs->blocksize;
423
 
        for (p = buf; p < end-8; p += rec_len) {
424
 
                dirent = (struct ext2_dir_entry_2 *) p;
425
 
                rec_len = dirent->rec_len;
426
 
#ifdef WORDS_BIGENDIAN
427
 
                rec_len = ext2fs_swab16(rec_len);
428
 
#endif
429
 
                if (rec_len == EXT4_MAX_REC_LEN || rec_len == 0)
430
 
                        rec_len = fs->blocksize;
431
 
                else 
432
 
                        rec_len = (rec_len & 65532) | ((rec_len & 3) << 16);
433
 
#if 0
434
 
                printf("rec_len = %d, name_len = %d\n", rec_len, dirent->name_len);
435
 
#endif
436
 
                if (rec_len < 8 || (rec_len % 4) ||
437
 
                    (p+rec_len > end)) {
438
 
                        printf("Corrupt directory block %lu: "
439
 
                               "bad rec_len (%d)\n", (unsigned long) blk,
440
 
                               rec_len);
441
 
                        rec_len = end - p;
442
 
                        (void) ext2fs_set_rec_len(fs, rec_len,
443
 
                                        (struct ext2_dir_entry *) dirent);
444
 
#ifdef WORDS_BIGENDIAN
445
 
                        dirent->rec_len = ext2fs_swab16(dirent->rec_len);
446
 
#endif
447
 
                        continue;
448
 
                }
449
 
                if (dirent->name_len + 8 > rec_len) {
450
 
                        printf("Corrupt directory block %lu: "
451
 
                               "bad name_len (%d)\n", (unsigned long) blk,
452
 
                               dirent->name_len);
453
 
                        dirent->name_len = rec_len - 8;
454
 
                        continue;
455
 
                }
456
 
                cp = p+8;
457
 
                len = rec_len - dirent->name_len - 8;
458
 
                if (len > 0)
459
 
                        memset(cp+dirent->name_len, 0, len);
460
 
                if (dirent->name_len==1 && cp[0] == '.')
461
 
                        continue;
462
 
                if (dirent->name_len==2 && cp[0] == '.' && cp[1] == '.')
463
 
                        continue;
464
 
 
465
 
                memset(cp, 'A', dirent->name_len);
466
 
                len = dirent->name_len;
467
 
                id = name_id[len]++;
468
 
                while ((len > 0) && (id > 0)) {
469
 
                        *cp += id % 26;
470
 
                        id = id / 26;
471
 
                        cp++;
472
 
                        len--;
473
 
                }
474
 
        }
475
 
}
476
 
 
477
 
static void output_meta_data_blocks(ext2_filsys fs, int fd)
478
 
{
479
 
        errcode_t       retval;
480
 
        blk64_t         blk;
481
 
        char            *buf, *zero_buf;
482
 
        int             sparse = 0;
483
 
 
484
 
        retval = ext2fs_get_mem(fs->blocksize, &buf);
485
 
        if (retval) {
486
 
                com_err(program_name, retval, "while allocating buffer");
487
 
                exit(1);
488
 
        }
489
 
        retval = ext2fs_get_memzero(fs->blocksize, &zero_buf);
490
 
        if (retval) {
491
 
                com_err(program_name, retval, "while allocating buffer");
492
 
                exit(1);
493
 
        }
494
 
        for (blk = 0; blk < ext2fs_blocks_count(fs->super); blk++) {
495
 
                if ((blk >= fs->super->s_first_data_block) &&
496
 
                    ext2fs_test_block_bitmap2(meta_block_map, blk)) {
497
 
                        retval = io_channel_read_blk64(fs->io, blk, 1, buf);
498
 
                        if (retval) {
499
 
                                com_err(program_name, retval,
500
 
                                        "error reading block %llu", blk);
501
 
                        }
502
 
                        if (scramble_block_map &&
503
 
                            ext2fs_test_block_bitmap2(scramble_block_map, blk))
504
 
                                scramble_dir_block(fs, blk, buf);
505
 
                        if ((fd != 1) && check_zero_block(buf, fs->blocksize))
506
 
                                goto sparse_write;
507
 
                        write_block(fd, buf, sparse, fs->blocksize, blk);
508
 
                        sparse = 0;
509
 
                } else {
510
 
                sparse_write:
511
 
                        if (fd == 1) {
512
 
                                write_block(fd, zero_buf, 0,
513
 
                                            fs->blocksize, blk);
514
 
                                continue;
515
 
                        }
516
 
                        sparse += fs->blocksize;
517
 
                        if (sparse > 1024*1024) {
518
 
                                write_block(fd, 0, 1024*1024, 0, 0);
519
 
                                sparse -= 1024*1024;
520
 
                        }
521
 
                }
522
 
        }
523
 
#ifdef HAVE_FTRUNCATE64
524
 
        if (sparse) {
525
 
                ext2_loff_t offset = ext2fs_llseek(fd, sparse, SEEK_CUR);
526
 
 
527
 
                if (offset < 0)
528
 
                        lseek_error_and_exit(errno);
529
 
                if (ftruncate64(fd, offset) < 0)
530
 
                        write_block(fd, zero_buf, -1, 1, -1);
531
 
        }
532
 
#else
533
 
        if (sparse)
534
 
                write_block(fd, zero_buf, sparse-1, 1, -1);
535
 
#endif
536
 
        ext2fs_free_mem(&zero_buf);
537
 
        ext2fs_free_mem(&buf);
538
 
}
539
 
 
540
 
static void init_l1_table(struct ext2_super_block *sb,
541
 
                          struct ext2_qcow2_image *image)
542
 
{
543
 
        __u64 *l1_table;
544
 
        errcode_t ret;
545
 
 
546
 
        ret = ext2fs_get_arrayzero(image->l1_size, sizeof(__u64), &l1_table);
547
 
        if (ret) {
548
 
                com_err(program_name, ret, "while allocating l1 table");
549
 
                exit(1);
550
 
        }
551
 
 
552
 
        image->l1_table = l1_table;
553
 
}
554
 
 
555
 
static void init_l2_cache(struct ext2_qcow2_image *image)
556
 
{
557
 
        unsigned int count, i;
558
 
        struct ext2_qcow2_l2_cache *cache;
559
 
        struct ext2_qcow2_l2_table *table;
560
 
        errcode_t ret;
561
 
 
562
 
        ret = ext2fs_get_arrayzero(1, sizeof(struct ext2_qcow2_l2_cache),
563
 
                                   &cache);
564
 
        if (ret)
565
 
                goto alloc_err;
566
 
 
567
 
        count = (image->l1_size > L2_CACHE_PREALLOC) ? L2_CACHE_PREALLOC :
568
 
                 image->l1_size;
569
 
 
570
 
        cache->count = count;
571
 
        cache->free = count;
572
 
        cache->next_offset = image->l2_offset;
573
 
 
574
 
        for (i = 0; i < count; i++) {
575
 
                ret = ext2fs_get_arrayzero(1,
576
 
                                sizeof(struct ext2_qcow2_l2_table), &table);
577
 
                if (ret)
578
 
                        goto alloc_err;
579
 
 
580
 
                ret = ext2fs_get_arrayzero(image->l2_size,
581
 
                                                   sizeof(__u64), &table->data);
582
 
                if (ret)
583
 
                        goto alloc_err;
584
 
 
585
 
                table->next = cache->free_head;
586
 
                cache->free_head = table;
587
 
        }
588
 
 
589
 
        image->l2_cache = cache;
590
 
        return;
591
 
 
592
 
alloc_err:
593
 
        com_err(program_name, ret, "while allocating l2 cache");
594
 
        exit(1);
595
 
}
596
 
 
597
 
static void put_l2_cache(struct ext2_qcow2_image *image)
598
 
{
599
 
        struct ext2_qcow2_l2_cache *cache = image->l2_cache;
600
 
        struct ext2_qcow2_l2_table *tmp, *table;
601
 
 
602
 
        if (!cache)
603
 
                return;
604
 
 
605
 
        table = cache->free_head;
606
 
        cache->free_head = NULL;
607
 
again:
608
 
        while (table) {
609
 
                tmp = table;
610
 
                table = table->next;
611
 
                ext2fs_free_mem(&tmp->data);
612
 
                ext2fs_free_mem(&tmp);
613
 
        }
614
 
 
615
 
        if (cache->free != cache->count) {
616
 
                fprintf(stderr, "Warning: There are still tables in the "
617
 
                                "cache while putting the cache, data will "
618
 
                                "be lost so the image may not be valid.\n");
619
 
                table = cache->used_head;
620
 
                cache->used_head = NULL;
621
 
                goto again;
622
 
        }
623
 
 
624
 
        ext2fs_free_mem(&cache);
625
 
}
626
 
 
627
 
static int init_refcount(struct ext2_qcow2_image *img, blk64_t table_offset)
628
 
{
629
 
        struct  ext2_qcow2_refcount     *ref;
630
 
        blk64_t table_clusters;
631
 
        errcode_t ret;
632
 
 
633
 
        ref = &(img->refcount);
634
 
 
635
 
        /*
636
 
         * One refcount block addresses 2048 clusters, one refcount table
637
 
         * addresses cluster/sizeof(__u64) refcount blocks, and we need
638
 
         * to address meta_blocks_count clusters + qcow2 metadata clusters
639
 
         * in the worst case.
640
 
         */
641
 
        table_clusters = meta_blocks_count + (table_offset >>
642
 
                                              img->cluster_bits);
643
 
        table_clusters >>= (img->cluster_bits + 6 - 1);
644
 
        table_clusters = (table_clusters == 0) ? 1 : table_clusters;
645
 
 
646
 
        ref->refcount_table_offset = table_offset;
647
 
        ref->refcount_table_clusters = table_clusters;
648
 
        ref->refcount_table_index = 0;
649
 
        ref->refcount_block_index = 0;
650
 
 
651
 
        /* Allocate refcount table */
652
 
        ret = ext2fs_get_arrayzero(ref->refcount_table_clusters,
653
 
                                   img->cluster_size, &ref->refcount_table);
654
 
        if (ret)
655
 
                return ret;
656
 
 
657
 
        /* Allocate refcount block */
658
 
        ret = ext2fs_get_arrayzero(1, img->cluster_size, &ref->refcount_block);
659
 
        if (ret)
660
 
                ext2fs_free_mem(&ref->refcount_table);
661
 
 
662
 
        return ret;
663
 
}
664
 
 
665
 
static int initialize_qcow2_image(int fd, ext2_filsys fs,
666
 
                            struct ext2_qcow2_image *image)
667
 
{
668
 
        struct ext2_qcow2_hdr *header;
669
 
        blk64_t total_size, offset;
670
 
        int shift, l2_bits, header_size, l1_size, ret;
671
 
        int cluster_bits = get_bits_from_size(fs->blocksize);
672
 
        struct ext2_super_block *sb = fs->super;
673
 
 
674
 
        /* Allocate header */
675
 
        ret = ext2fs_get_memzero(sizeof(struct ext2_qcow2_hdr), &header);
676
 
        if (ret)
677
 
                return ret;
678
 
 
679
 
        total_size = ext2fs_blocks_count(sb) << cluster_bits;
680
 
        image->cluster_size = fs->blocksize;
681
 
        image->l2_size = 1 << (cluster_bits - 3);
682
 
        image->cluster_bits = cluster_bits;
683
 
        image->fd = fd;
684
 
 
685
 
        header->magic = ext2fs_cpu_to_be32(QCOW_MAGIC);
686
 
        header->version = ext2fs_cpu_to_be32(QCOW_VERSION);
687
 
        header->size = ext2fs_cpu_to_be64(total_size);
688
 
        header->cluster_bits = ext2fs_cpu_to_be32(cluster_bits);
689
 
 
690
 
        header_size = (sizeof(struct ext2_qcow2_hdr) + 7) & ~7;
691
 
        offset = align_offset(header_size, image->cluster_size);
692
 
 
693
 
        header->l1_table_offset = ext2fs_cpu_to_be64(offset);
694
 
        image->l1_offset = offset;
695
 
 
696
 
        l2_bits = cluster_bits - 3;
697
 
        shift = cluster_bits + l2_bits;
698
 
        l1_size = ((total_size + (1LL << shift) - 1) >> shift);
699
 
        header->l1_size = ext2fs_cpu_to_be32(l1_size);
700
 
        image->l1_size = l1_size;
701
 
 
702
 
        /* Make space for L1 table */
703
 
        offset += align_offset(l1_size * sizeof(blk64_t), image->cluster_size);
704
 
 
705
 
        /* Initialize refcounting */
706
 
        ret = init_refcount(image, offset);
707
 
        if (ret) {
708
 
                ext2fs_free_mem(&header);
709
 
                return ret;
710
 
        }
711
 
        header->refcount_table_offset = ext2fs_cpu_to_be64(offset);
712
 
        header->refcount_table_clusters =
713
 
                ext2fs_cpu_to_be32(image->refcount.refcount_table_clusters);
714
 
        offset += image->cluster_size;
715
 
        offset += image->refcount.refcount_table_clusters <<
716
 
                image->cluster_bits;
717
 
 
718
 
        /* Make space for L2 tables */
719
 
        image->l2_offset = offset;
720
 
        offset += image->cluster_size;
721
 
 
722
 
        /* Make space for first refcount block */
723
 
        image->refcount.refcount_block_offset = offset;
724
 
 
725
 
        image->hdr = header;
726
 
        /* Initialize l1 and l2 tables */
727
 
        init_l1_table(sb, image);
728
 
        init_l2_cache(image);
729
 
 
730
 
        return 0;
731
 
}
732
 
 
733
 
static void free_qcow2_image(struct ext2_qcow2_image *img)
734
 
{
735
 
        if (!img)
736
 
                return;
737
 
 
738
 
        if (img->hdr)
739
 
                ext2fs_free_mem(&img->hdr);
740
 
 
741
 
        if (img->l1_table)
742
 
                ext2fs_free_mem(&img->l1_table);
743
 
 
744
 
        if (img->refcount.refcount_table)
745
 
                ext2fs_free_mem(&img->refcount.refcount_table);
746
 
        if (img->refcount.refcount_block)
747
 
                ext2fs_free_mem(&img->refcount.refcount_block);
748
 
 
749
 
        put_l2_cache(img);
750
 
 
751
 
        ext2fs_free_mem(&img);
752
 
}
753
 
 
754
 
/**
755
 
 * Put table from used list (used_head) into free list (free_head).
756
 
 * l2_table is used to return pointer to the next used table (used_head).
757
 
 */
758
 
static void put_used_table(struct ext2_qcow2_image *img,
759
 
                          struct ext2_qcow2_l2_table **l2_table)
760
 
{
761
 
        struct ext2_qcow2_l2_cache *cache = img->l2_cache;
762
 
        struct ext2_qcow2_l2_table *table;
763
 
 
764
 
        table = cache->used_head;
765
 
        cache->used_head = table->next;
766
 
 
767
 
        assert(table);
768
 
        if (!table->next)
769
 
                cache->used_tail = NULL;
770
 
 
771
 
        /* Clean the table for case we will need to use it again */
772
 
        memset(table->data, 0, img->cluster_size);
773
 
        table->next = cache->free_head;
774
 
        cache->free_head = table;
775
 
 
776
 
        cache->free++;
777
 
 
778
 
        *l2_table = cache->used_head;
779
 
}
780
 
 
781
 
static void flush_l2_cache(struct ext2_qcow2_image *image)
782
 
{
783
 
        blk64_t seek = 0;
784
 
        ext2_loff_t offset;
785
 
        struct ext2_qcow2_l2_cache *cache = image->l2_cache;
786
 
        struct ext2_qcow2_l2_table *table = cache->used_head;
787
 
        int fd = image->fd;
788
 
 
789
 
        /* Store current position */
790
 
        if ((offset = ext2fs_llseek(fd, 0, SEEK_CUR)) < 0)
791
 
                lseek_error_and_exit(errno);
792
 
 
793
 
        assert(table);
794
 
        while (cache->free < cache->count) {
795
 
                if (seek != table->offset) {
796
 
                        if (ext2fs_llseek(fd, table->offset, SEEK_SET) < 0)
797
 
                                lseek_error_and_exit(errno);
798
 
                        seek = table->offset;
799
 
                }
800
 
 
801
 
                generic_write(fd, (char *)table->data, image->cluster_size , 0);
802
 
                put_used_table(image, &table);
803
 
                seek += image->cluster_size;
804
 
        }
805
 
 
806
 
        /* Restore previous position */
807
 
        if (ext2fs_llseek(fd, offset, SEEK_SET) < 0)
808
 
                lseek_error_and_exit(errno);
809
 
}
810
 
 
811
 
/**
812
 
 * Get first free table (from free_head) and put it into tail of used list
813
 
 * (to used_tail).
814
 
 * l2_table is used to return pointer to moved table.
815
 
 * Returns 1 if the cache is full, 0 otherwise.
816
 
 */
817
 
static void get_free_table(struct ext2_qcow2_image *image,
818
 
                          struct ext2_qcow2_l2_table **l2_table)
819
 
{
820
 
        struct ext2_qcow2_l2_table *table;
821
 
        struct ext2_qcow2_l2_cache *cache = image->l2_cache;
822
 
 
823
 
        if (0 == cache->free)
824
 
                flush_l2_cache(image);
825
 
 
826
 
        table = cache->free_head;
827
 
        assert(table);
828
 
        cache->free_head = table->next;
829
 
 
830
 
        if (cache->used_tail)
831
 
                cache->used_tail->next = table;
832
 
        else
833
 
                /* First item in the used list */
834
 
                cache->used_head = table;
835
 
 
836
 
        cache->used_tail = table;
837
 
        cache->free--;
838
 
 
839
 
        *l2_table = table;
840
 
}
841
 
 
842
 
static int add_l2_item(struct ext2_qcow2_image *img, blk64_t blk,
843
 
                       blk64_t data, blk64_t next)
844
 
{
845
 
        struct ext2_qcow2_l2_cache *cache = img->l2_cache;
846
 
        struct ext2_qcow2_l2_table *table = cache->used_tail;
847
 
        blk64_t l1_index = blk / img->l2_size;
848
 
        blk64_t l2_index = blk & (img->l2_size - 1);
849
 
        int ret = 0;
850
 
 
851
 
        /*
852
 
         * Need to create new table if it does not exist,
853
 
         * or if it is full
854
 
         */
855
 
        if (!table || (table->l1_index != l1_index)) {
856
 
                get_free_table(img, &table);
857
 
                table->l1_index = l1_index;
858
 
                table->offset = cache->next_offset;
859
 
                cache->next_offset = next;
860
 
                img->l1_table[l1_index] =
861
 
                        ext2fs_cpu_to_be64(table->offset | QCOW_OFLAG_COPIED);
862
 
                ret++;
863
 
        }
864
 
 
865
 
        table->data[l2_index] = ext2fs_cpu_to_be64(data | QCOW_OFLAG_COPIED);
866
 
        return ret;
867
 
}
868
 
 
869
 
static int update_refcount(int fd, struct ext2_qcow2_image *img,
870
 
                           blk64_t offset, blk64_t rfblk_pos)
871
 
{
872
 
        struct  ext2_qcow2_refcount     *ref;
873
 
        __u32   table_index;
874
 
        int ret = 0;
875
 
 
876
 
        ref = &(img->refcount);
877
 
        table_index = offset >> (2 * img->cluster_bits - 1);
878
 
 
879
 
        /*
880
 
         * Need to create new refcount block when the offset addresses
881
 
         * another item in the refcount table
882
 
         */
883
 
        if (table_index != ref->refcount_table_index) {
884
 
 
885
 
                if (ext2fs_llseek(fd, ref->refcount_block_offset, SEEK_SET) < 0)
886
 
                        lseek_error_and_exit(errno);
887
 
 
888
 
                generic_write(fd, (char *)ref->refcount_block,
889
 
                              img->cluster_size, 0);
890
 
                memset(ref->refcount_block, 0, img->cluster_size);
891
 
 
892
 
                ref->refcount_table[ref->refcount_table_index] =
893
 
                        ext2fs_cpu_to_be64(ref->refcount_block_offset);
894
 
                ref->refcount_block_offset = rfblk_pos;
895
 
                ref->refcount_block_index = 0;
896
 
                ref->refcount_table_index = table_index;
897
 
                ret++;
898
 
        }
899
 
 
900
 
        /*
901
 
         * We are relying on the fact that we are creating the qcow2
902
 
         * image sequentially, hence we will always allocate refcount
903
 
         * block items sequentialy.
904
 
         */
905
 
        ref->refcount_block[ref->refcount_block_index] = ext2fs_cpu_to_be16(1);
906
 
        ref->refcount_block_index++;
907
 
        return ret;
908
 
}
909
 
 
910
 
static int sync_refcount(int fd, struct ext2_qcow2_image *img)
911
 
{
912
 
        struct  ext2_qcow2_refcount     *ref;
913
 
 
914
 
        ref = &(img->refcount);
915
 
 
916
 
        ref->refcount_table[ref->refcount_table_index] =
917
 
                ext2fs_cpu_to_be64(ref->refcount_block_offset);
918
 
        if (ext2fs_llseek(fd, ref->refcount_table_offset, SEEK_SET) < 0)
919
 
                lseek_error_and_exit(errno);
920
 
        generic_write(fd, (char *)ref->refcount_table,
921
 
                ref->refcount_table_clusters << img->cluster_bits, 0);
922
 
 
923
 
        if (ext2fs_llseek(fd, ref->refcount_block_offset, SEEK_SET) < 0)
924
 
                lseek_error_and_exit(errno);
925
 
        generic_write(fd, (char *)ref->refcount_block, img->cluster_size, 0);
926
 
        return 0;
927
 
}
928
 
 
929
 
static void output_qcow2_meta_data_blocks(ext2_filsys fs, int fd)
930
 
{
931
 
        errcode_t               retval;
932
 
        blk64_t                 blk, offset, size, end;
933
 
        char                    *buf;
934
 
        struct ext2_qcow2_image *img;
935
 
        unsigned int            header_size;
936
 
 
937
 
        /* allocate  struct ext2_qcow2_image */
938
 
        retval = ext2fs_get_mem(sizeof(struct ext2_qcow2_image), &img);
939
 
        if (retval) {
940
 
                com_err(program_name, retval,
941
 
                        "while allocating ext2_qcow2_image");
942
 
                exit(1);
943
 
        }
944
 
 
945
 
        retval = initialize_qcow2_image(fd, fs, img);
946
 
        if (retval) {
947
 
                com_err(program_name, retval,
948
 
                        "while initializing ext2_qcow2_image");
949
 
                exit(1);
950
 
        }
951
 
        header_size = align_offset(sizeof(struct ext2_qcow2_hdr),
952
 
                                   img->cluster_size);
953
 
        write_header(fd, img->hdr, sizeof(struct ext2_qcow2_hdr), header_size);
954
 
 
955
 
        /* Refcount all qcow2 related metadata up to refcount_block_offset */
956
 
        end = img->refcount.refcount_block_offset;
957
 
        if (ext2fs_llseek(fd, end, SEEK_SET) < 0)
958
 
                lseek_error_and_exit(errno);
959
 
        blk = end + img->cluster_size;
960
 
        for (offset = 0; offset <= end; offset += img->cluster_size) {
961
 
                if (update_refcount(fd, img, offset, blk)) {
962
 
                        blk += img->cluster_size;
963
 
                        /*
964
 
                         * If we create new refcount block, we need to refcount
965
 
                         * it as well.
966
 
                         */
967
 
                        end += img->cluster_size;
968
 
                }
969
 
        }
970
 
        if (ext2fs_llseek(fd, offset, SEEK_SET) < 0)
971
 
                lseek_error_and_exit(errno);
972
 
 
973
 
        retval = ext2fs_get_mem(fs->blocksize, &buf);
974
 
        if (retval) {
975
 
                com_err(program_name, retval, "while allocating buffer");
976
 
                exit(1);
977
 
        }
978
 
        /* Write qcow2 data blocks */
979
 
        for (blk = 0; blk < ext2fs_blocks_count(fs->super); blk++) {
980
 
                if ((blk >= fs->super->s_first_data_block) &&
981
 
                    ext2fs_test_block_bitmap2(meta_block_map, blk)) {
982
 
                        retval = io_channel_read_blk64(fs->io, blk, 1, buf);
983
 
                        if (retval) {
984
 
                                com_err(program_name, retval,
985
 
                                        "error reading block %llu", blk);
986
 
                                continue;
987
 
                        }
988
 
                        if (scramble_block_map &&
989
 
                            ext2fs_test_block_bitmap2(scramble_block_map, blk))
990
 
                                scramble_dir_block(fs, blk, buf);
991
 
                        if (check_zero_block(buf, fs->blocksize))
992
 
                                continue;
993
 
 
994
 
                        if (update_refcount(fd, img, offset, offset)) {
995
 
                                /* Make space for another refcount block */
996
 
                                offset += img->cluster_size;
997
 
                                if (ext2fs_llseek(fd, offset, SEEK_SET) < 0)
998
 
                                        lseek_error_and_exit(errno);
999
 
                                /*
1000
 
                                 * We have created the new refcount block, this
1001
 
                                 * means that we need to refcount it as well.
1002
 
                                 * So the previous update_refcount refcounted
1003
 
                                 * the block itself and now we are going to
1004
 
                                 * create refcount for data. New refcount
1005
 
                                 * block should not be created!
1006
 
                                 */
1007
 
                                if (update_refcount(fd, img, offset, offset)) {
1008
 
                                        fprintf(stderr, "Programming error: "
1009
 
                                                "multiple sequential refcount "
1010
 
                                                "blocks created!\n");
1011
 
                                        exit(1);
1012
 
                                }
1013
 
                        }
1014
 
 
1015
 
                        generic_write(fd, buf, fs->blocksize, 0);
1016
 
 
1017
 
                        if (add_l2_item(img, blk, offset,
1018
 
                                        offset + img->cluster_size)) {
1019
 
                                offset += img->cluster_size;
1020
 
                                if (update_refcount(fd, img, offset,
1021
 
                                        offset + img->cluster_size)) {
1022
 
                                        offset += img->cluster_size;
1023
 
                                        if (update_refcount(fd, img, offset,
1024
 
                                                            offset)) {
1025
 
                                                fprintf(stderr,
1026
 
                        "Programming error: multiple sequential refcount "
1027
 
                        "blocks created!\n");
1028
 
                                                exit(1);
1029
 
                                        }
1030
 
                                }
1031
 
                                offset += img->cluster_size;
1032
 
                                if (ext2fs_llseek(fd, offset, SEEK_SET) < 0)
1033
 
                                        lseek_error_and_exit(errno);
1034
 
                                continue;
1035
 
                        }
1036
 
 
1037
 
                        offset += img->cluster_size;
1038
 
                }
1039
 
        }
1040
 
        update_refcount(fd, img, offset, offset);
1041
 
        flush_l2_cache(img);
1042
 
        sync_refcount(fd, img);
1043
 
 
1044
 
        /* Write l1_table*/
1045
 
        if (ext2fs_llseek(fd, img->l1_offset, SEEK_SET) < 0)
1046
 
                lseek_error_and_exit(errno);
1047
 
        size = img->l1_size * sizeof(__u64);
1048
 
        generic_write(fd, (char *)img->l1_table, size, 0);
1049
 
 
1050
 
        ext2fs_free_mem(&buf);
1051
 
        free_qcow2_image(img);
1052
 
}
1053
 
 
1054
 
static void write_raw_image_file(ext2_filsys fs, int fd, int type, int flags)
1055
 
{
1056
 
        struct process_block_struct     pb;
1057
 
        struct ext2_inode               inode;
1058
 
        ext2_inode_scan                 scan;
1059
 
        ext2_ino_t                      ino;
1060
 
        errcode_t                       retval;
1061
 
        char *                          block_buf;
1062
 
 
1063
 
        meta_blocks_count = 0;
1064
 
        retval = ext2fs_allocate_block_bitmap(fs, "in-use block map",
1065
 
                                              &meta_block_map);
1066
 
        if (retval) {
1067
 
                com_err(program_name, retval, "while allocating block bitmap");
1068
 
                exit(1);
1069
 
        }
1070
 
 
1071
 
        if (flags & E2IMAGE_SCRAMBLE_FLAG) {
1072
 
                retval = ext2fs_allocate_block_bitmap(fs, "scramble block map",
1073
 
                                                      &scramble_block_map);
1074
 
                if (retval) {
1075
 
                        com_err(program_name, retval,
1076
 
                                "while allocating scramble block bitmap");
1077
 
                        exit(1);
1078
 
                }
1079
 
        }
1080
 
 
1081
 
        mark_table_blocks(fs);
1082
 
 
1083
 
        retval = ext2fs_open_inode_scan(fs, 0, &scan);
1084
 
        if (retval) {
1085
 
                com_err(program_name, retval, _("while opening inode scan"));
1086
 
                exit(1);
1087
 
        }
1088
 
 
1089
 
        retval = ext2fs_get_mem(fs->blocksize * 3, &block_buf);
1090
 
        if (retval) {
1091
 
                com_err(program_name, 0, "Can't allocate block buffer");
1092
 
                exit(1);
1093
 
        }
1094
 
 
1095
 
        use_inode_shortcuts(fs, 1);
1096
 
        stashed_inode = &inode;
1097
 
        while (1) {
1098
 
                retval = ext2fs_get_next_inode(scan, &ino, &inode);
1099
 
                if (retval == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE)
1100
 
                        continue;
1101
 
                if (retval) {
1102
 
                        com_err(program_name, retval,
1103
 
                                _("while getting next inode"));
1104
 
                        exit(1);
1105
 
                }
1106
 
                if (ino == 0)
1107
 
                        break;
1108
 
                if (!inode.i_links_count)
1109
 
                        continue;
1110
 
                if (ext2fs_file_acl_block(fs, &inode)) {
1111
 
                        ext2fs_mark_block_bitmap2(meta_block_map,
1112
 
                                        ext2fs_file_acl_block(fs, &inode));
1113
 
                        meta_blocks_count++;
1114
 
                }
1115
 
                if (!ext2fs_inode_has_valid_blocks2(fs, &inode))
1116
 
                        continue;
1117
 
 
1118
 
                stashed_ino = ino;
1119
 
                pb.ino = ino;
1120
 
                pb.is_dir = LINUX_S_ISDIR(inode.i_mode);
1121
 
                if (LINUX_S_ISDIR(inode.i_mode) ||
1122
 
                    (LINUX_S_ISLNK(inode.i_mode) &&
1123
 
                     ext2fs_inode_has_valid_blocks2(fs, &inode)) ||
1124
 
                    ino == fs->super->s_journal_inum) {
1125
 
                        retval = ext2fs_block_iterate3(fs, ino,
1126
 
                                        BLOCK_FLAG_READ_ONLY, block_buf,
1127
 
                                        process_dir_block, &pb);
1128
 
                        if (retval) {
1129
 
                                com_err(program_name, retval,
1130
 
                                        "while iterating over inode %u",
1131
 
                                        ino);
1132
 
                                exit(1);
1133
 
                        }
1134
 
                } else {
1135
 
                        if ((inode.i_flags & EXT4_EXTENTS_FL) ||
1136
 
                            inode.i_block[EXT2_IND_BLOCK] ||
1137
 
                            inode.i_block[EXT2_DIND_BLOCK] ||
1138
 
                            inode.i_block[EXT2_TIND_BLOCK]) {
1139
 
                                retval = ext2fs_block_iterate3(fs,
1140
 
                                       ino, BLOCK_FLAG_READ_ONLY, block_buf,
1141
 
                                       process_file_block, &pb);
1142
 
                                if (retval) {
1143
 
                                        com_err(program_name, retval,
1144
 
                                        "while iterating over inode %u", ino);
1145
 
                                        exit(1);
1146
 
                                }
1147
 
                        }
1148
 
                }
1149
 
        }
1150
 
        use_inode_shortcuts(fs, 0);
1151
 
 
1152
 
        if (type & E2IMAGE_QCOW2)
1153
 
                output_qcow2_meta_data_blocks(fs, fd);
1154
 
        else
1155
 
                output_meta_data_blocks(fs, fd);
1156
 
 
1157
 
        ext2fs_free_mem(&block_buf);
1158
 
        ext2fs_close_inode_scan(scan);
1159
 
        ext2fs_free_block_bitmap(meta_block_map);
1160
 
        if (type & E2IMAGE_SCRAMBLE_FLAG)
1161
 
                ext2fs_free_block_bitmap(scramble_block_map);
1162
 
}
1163
 
 
1164
 
static void install_image(char *device, char *image_fn, int type)
1165
 
{
1166
 
        errcode_t retval;
1167
 
        ext2_filsys fs;
1168
 
        int open_flag = EXT2_FLAG_IMAGE_FILE;
1169
 
        int fd = 0;
1170
 
        io_manager      io_ptr;
1171
 
        io_channel      io;
1172
 
 
1173
 
        if (type) {
1174
 
                com_err(program_name, 0, "Raw and qcow2 images cannot"
1175
 
                        "be installed");
1176
 
                exit(1);
1177
 
        }
1178
 
 
1179
 
#ifdef CONFIG_TESTIO_DEBUG
1180
 
        if (getenv("TEST_IO_FLAGS") || getenv("TEST_IO_BLOCK")) {
1181
 
                io_ptr = test_io_manager;
1182
 
                test_io_backing_manager = unix_io_manager;
1183
 
        } else
1184
 
#endif
1185
 
                io_ptr = unix_io_manager;
1186
 
 
1187
 
        retval = ext2fs_open (image_fn, open_flag, 0, 0,
1188
 
                              io_ptr, &fs);
1189
 
        if (retval) {
1190
 
                com_err (program_name, retval, _("while trying to open %s"),
1191
 
                         image_fn);
1192
 
                exit(1);
1193
 
        }
1194
 
 
1195
 
        retval = ext2fs_read_bitmaps (fs);
1196
 
        if (retval) {
1197
 
                com_err(program_name, retval, "error reading bitmaps");
1198
 
                exit(1);
1199
 
        }
1200
 
 
1201
 
        fd = ext2fs_open_file(image_fn, O_RDONLY, 0);
1202
 
        if (fd < 0) {
1203
 
                perror(image_fn);
1204
 
                exit(1);
1205
 
        }
1206
 
 
1207
 
        retval = io_ptr->open(device, IO_FLAG_RW, &io);
1208
 
        if (retval) {
1209
 
                com_err(device, 0, "while opening device file");
1210
 
                exit(1);
1211
 
        }
1212
 
 
1213
 
        ext2fs_rewrite_to_io(fs, io);
1214
 
 
1215
 
        if (ext2fs_llseek(fd, fs->image_header->offset_inode, SEEK_SET) < 0) {
1216
 
                perror("ext2fs_llseek");
1217
 
                exit(1);
1218
 
        }
1219
 
 
1220
 
        retval = ext2fs_image_inode_read(fs, fd, 0);
1221
 
        if (retval) {
1222
 
                com_err(image_fn, 0, "while restoring the image table");
1223
 
                exit(1);
1224
 
        }
1225
 
 
1226
 
        ext2fs_close (fs);
1227
 
        exit (0);
1228
 
}
1229
 
 
1230
 
static struct ext2_qcow2_hdr *check_qcow2_image(int *fd, char *name)
1231
 
{
1232
 
 
1233
 
        *fd = ext2fs_open_file(name, O_RDONLY, 0600);
1234
 
        if (*fd < 0)
1235
 
                return NULL;
1236
 
 
1237
 
        return qcow2_read_header(*fd);
1238
 
}
1239
 
 
1240
 
int main (int argc, char ** argv)
1241
 
{
1242
 
        int c;
1243
 
        errcode_t retval;
1244
 
        ext2_filsys fs;
1245
 
        char *image_fn;
1246
 
        struct ext2_qcow2_hdr *header = NULL;
1247
 
        int open_flag = EXT2_FLAG_64BITS;
1248
 
        int img_type = 0;
1249
 
        int flags = 0;
1250
 
        int qcow2_fd = 0;
1251
 
        int fd = 0;
1252
 
        int ret = 0;
1253
 
 
1254
 
#ifdef ENABLE_NLS
1255
 
        setlocale(LC_MESSAGES, "");
1256
 
        setlocale(LC_CTYPE, "");
1257
 
        bindtextdomain(NLS_CAT_NAME, LOCALEDIR);
1258
 
        textdomain(NLS_CAT_NAME);
1259
 
        set_com_err_gettext(gettext);
1260
 
#endif
1261
 
        fprintf (stderr, "e2image %s (%s)\n", E2FSPROGS_VERSION,
1262
 
                 E2FSPROGS_DATE);
1263
 
        if (argc && *argv)
1264
 
                program_name = *argv;
1265
 
        add_error_table(&et_ext2_error_table);
1266
 
        while ((c = getopt(argc, argv, "rsIQ")) != EOF)
1267
 
                switch (c) {
1268
 
                case 'I':
1269
 
                        flags |= E2IMAGE_INSTALL_FLAG;
1270
 
                        break;
1271
 
                case 'Q':
1272
 
                        if (img_type)
1273
 
                                usage();
1274
 
                        img_type |= E2IMAGE_QCOW2;
1275
 
                        break;
1276
 
                case 'r':
1277
 
                        if (img_type)
1278
 
                                usage();
1279
 
                        img_type |= E2IMAGE_RAW;
1280
 
                        break;
1281
 
                case 's':
1282
 
                        flags |= E2IMAGE_SCRAMBLE_FLAG;
1283
 
                        break;
1284
 
                default:
1285
 
                        usage();
1286
 
                }
1287
 
        if (optind != argc - 2 )
1288
 
                usage();
1289
 
        device_name = argv[optind];
1290
 
        image_fn = argv[optind+1];
1291
 
 
1292
 
        if (flags & E2IMAGE_INSTALL_FLAG) {
1293
 
                install_image(device_name, image_fn, img_type);
1294
 
                exit (0);
1295
 
        }
1296
 
 
1297
 
        if (img_type & E2IMAGE_RAW) {
1298
 
                header = check_qcow2_image(&qcow2_fd, device_name);
1299
 
                if (header) {
1300
 
                        flags |= E2IMAGE_IS_QCOW2_FLAG;
1301
 
                        goto skip_device;
1302
 
                }
1303
 
        }
1304
 
 
1305
 
        retval = ext2fs_open (device_name, open_flag, 0, 0,
1306
 
                              unix_io_manager, &fs);
1307
 
        if (retval) {
1308
 
                com_err (program_name, retval, _("while trying to open %s"),
1309
 
                         device_name);
1310
 
                fputs(_("Couldn't find valid filesystem superblock.\n"), stdout);
1311
 
                exit(1);
1312
 
        }
1313
 
 
1314
 
skip_device:
1315
 
        if (strcmp(image_fn, "-") == 0)
1316
 
                fd = 1;
1317
 
        else {
1318
 
                fd = ext2fs_open_file(image_fn, O_CREAT|O_TRUNC|O_WRONLY, 0600);
1319
 
                if (fd < 0) {
1320
 
                        com_err(program_name, errno,
1321
 
                                _("while trying to open %s"), argv[optind+1]);
1322
 
                        exit(1);
1323
 
                }
1324
 
        }
1325
 
 
1326
 
        if ((img_type & E2IMAGE_QCOW2) && (fd == 1)) {
1327
 
                com_err(program_name, 0, "QCOW2 image can not be written to "
1328
 
                                         "the stdout!\n");
1329
 
                exit(1);
1330
 
        }
1331
 
 
1332
 
        if (flags & E2IMAGE_IS_QCOW2_FLAG) {
1333
 
                ret = qcow2_write_raw_image(qcow2_fd, fd, header);
1334
 
                if (ret) {
1335
 
                        if (ret == -QCOW_COMPRESSED)
1336
 
                                fprintf(stderr, "Image (%s) is compressed\n",
1337
 
                                        image_fn);
1338
 
                        if (ret == -QCOW_ENCRYPTED)
1339
 
                                fprintf(stderr, "Image (%s) is encrypted\n",
1340
 
                                        image_fn);
1341
 
                        com_err(program_name, ret,
1342
 
                                _("while trying to convert qcow2 image"
1343
 
                                " (%s) into raw image (%s)"),
1344
 
                                device_name, image_fn);
1345
 
                }
1346
 
                goto out;
1347
 
        }
1348
 
 
1349
 
 
1350
 
        if (img_type)
1351
 
                write_raw_image_file(fs, fd, img_type, flags);
1352
 
        else
1353
 
                write_image_file(fs, fd);
1354
 
 
1355
 
        ext2fs_close (fs);
1356
 
out:
1357
 
        if (header)
1358
 
                free(header);
1359
 
        if (qcow2_fd)
1360
 
                close(qcow2_fd);
1361
 
        remove_error_table(&et_ext2_error_table);
1362
 
        return ret;
1363
 
}