~jderose/ubuntu/raring/qemu/vde-again

« back to all changes in this revision

Viewing changes to qemu-img.c

  • Committer: Bazaar Package Importer
  • Author(s): Aurelien Jarno, Aurelien Jarno
  • Date: 2008-08-25 04:38:35 UTC
  • mfrom: (1.1.8 upstream)
  • Revision ID: james.westby@ubuntu.com-20080825043835-8e3tftavy8bujdch
Tags: 0.9.1-6
[ Aurelien Jarno ]
* debian/control: 
  - Update list of supported targets (Closes: bug#488339).
* debian/qemu-make-debian-root:
  - Use mktemp instead of $$ to create temporary directories (Closes: 
    bug#496394).
* debian/links:
  - Add missing links to manpages.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * QEMU disk image utility
 
3
 *
 
4
 * Copyright (c) 2003-2008 Fabrice Bellard
 
5
 *
 
6
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 
7
 * of this software and associated documentation files (the "Software"), to deal
 
8
 * in the Software without restriction, including without limitation the rights
 
9
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 
10
 * copies of the Software, and to permit persons to whom the Software is
 
11
 * furnished to do so, subject to the following conditions:
 
12
 *
 
13
 * The above copyright notice and this permission notice shall be included in
 
14
 * all copies or substantial portions of the Software.
 
15
 *
 
16
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 
17
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 
18
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 
19
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 
20
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 
21
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 
22
 * THE SOFTWARE.
 
23
 */
 
24
#include "qemu-common.h"
 
25
#include "block_int.h"
 
26
#include <assert.h>
 
27
 
 
28
#ifdef _WIN32
 
29
#define WIN32_LEAN_AND_MEAN
 
30
#include <windows.h>
 
31
#endif
 
32
 
 
33
void *get_mmap_addr(unsigned long size)
 
34
{
 
35
    return NULL;
 
36
}
 
37
 
 
38
void qemu_free(void *ptr)
 
39
{
 
40
    free(ptr);
 
41
}
 
42
 
 
43
void *qemu_malloc(size_t size)
 
44
{
 
45
    return malloc(size);
 
46
}
 
47
 
 
48
void *qemu_mallocz(size_t size)
 
49
{
 
50
    void *ptr;
 
51
    ptr = qemu_malloc(size);
 
52
    if (!ptr)
 
53
        return NULL;
 
54
    memset(ptr, 0, size);
 
55
    return ptr;
 
56
}
 
57
 
 
58
char *qemu_strdup(const char *str)
 
59
{
 
60
    char *ptr;
 
61
    ptr = qemu_malloc(strlen(str) + 1);
 
62
    if (!ptr)
 
63
        return NULL;
 
64
    strcpy(ptr, str);
 
65
    return ptr;
 
66
}
 
67
 
 
68
static void __attribute__((noreturn)) error(const char *fmt, ...)
 
69
{
 
70
    va_list ap;
 
71
    va_start(ap, fmt);
 
72
    fprintf(stderr, "qemu-img: ");
 
73
    vfprintf(stderr, fmt, ap);
 
74
    fprintf(stderr, "\n");
 
75
    exit(1);
 
76
    va_end(ap);
 
77
}
 
78
 
 
79
static void format_print(void *opaque, const char *name)
 
80
{
 
81
    printf(" %s", name);
 
82
}
 
83
 
 
84
static void help(void)
 
85
{
 
86
    printf("qemu-img version " QEMU_VERSION ", Copyright (c) 2004-2008 Fabrice Bellard\n"
 
87
           "usage: qemu-img command [command options]\n"
 
88
           "QEMU disk image utility\n"
 
89
           "\n"
 
90
           "Command syntax:\n"
 
91
           "  create [-e] [-6] [-b base_image] [-f fmt] filename [size]\n"
 
92
           "  commit [-f fmt] filename\n"
 
93
           "  convert [-c] [-e] [-6] [-f fmt] filename [filename2 [...]] [-O output_fmt] output_filename\n"
 
94
           "  info [-f fmt] filename\n"
 
95
           "\n"
 
96
           "Command parameters:\n"
 
97
           "  'filename' is a disk image filename\n"
 
98
           "  'base_image' is the read-only disk image which is used as base for a copy on\n"
 
99
           "    write image; the copy on write image only stores the modified data\n"
 
100
           "  'fmt' is the disk image format. It is guessed automatically in most cases\n"
 
101
           "  'size' is the disk image size in kilobytes. Optional suffixes 'M' (megabyte)\n"
 
102
           "    and 'G' (gigabyte) are supported\n"
 
103
           "  'output_filename' is the destination disk image filename\n"
 
104
           "  'output_fmt' is the destination format\n"
 
105
           "  '-c' indicates that target image must be compressed (qcow format only)\n"
 
106
           "  '-e' indicates that the target image must be encrypted (qcow format only)\n"
 
107
           "  '-6' indicates that the target image must use compatibility level 6 (vmdk format only)\n"
 
108
           );
 
109
    printf("\nSupported format:");
 
110
    bdrv_iterate_format(format_print, NULL);
 
111
    printf("\n");
 
112
    exit(1);
 
113
}
 
114
 
 
115
#if defined(WIN32)
 
116
/* XXX: put correct support for win32 */
 
117
static int read_password(char *buf, int buf_size)
 
118
{
 
119
    int c, i;
 
120
    printf("Password: ");
 
121
    fflush(stdout);
 
122
    i = 0;
 
123
    for(;;) {
 
124
        c = getchar();
 
125
        if (c == '\n')
 
126
            break;
 
127
        if (i < (buf_size - 1))
 
128
            buf[i++] = c;
 
129
    }
 
130
    buf[i] = '\0';
 
131
    return 0;
 
132
}
 
133
 
 
134
#else
 
135
 
 
136
#include <termios.h>
 
137
 
 
138
static struct termios oldtty;
 
139
 
 
140
static void term_exit(void)
 
141
{
 
142
    tcsetattr (0, TCSANOW, &oldtty);
 
143
}
 
144
 
 
145
static void term_init(void)
 
146
{
 
147
    struct termios tty;
 
148
 
 
149
    tcgetattr (0, &tty);
 
150
    oldtty = tty;
 
151
 
 
152
    tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP
 
153
                          |INLCR|IGNCR|ICRNL|IXON);
 
154
    tty.c_oflag |= OPOST;
 
155
    tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN);
 
156
    tty.c_cflag &= ~(CSIZE|PARENB);
 
157
    tty.c_cflag |= CS8;
 
158
    tty.c_cc[VMIN] = 1;
 
159
    tty.c_cc[VTIME] = 0;
 
160
 
 
161
    tcsetattr (0, TCSANOW, &tty);
 
162
 
 
163
    atexit(term_exit);
 
164
}
 
165
 
 
166
static int read_password(char *buf, int buf_size)
 
167
{
 
168
    uint8_t ch;
 
169
    int i, ret;
 
170
 
 
171
    printf("password: ");
 
172
    fflush(stdout);
 
173
    term_init();
 
174
    i = 0;
 
175
    for(;;) {
 
176
        ret = read(0, &ch, 1);
 
177
        if (ret == -1) {
 
178
            if (errno == EAGAIN || errno == EINTR) {
 
179
                continue;
 
180
            } else {
 
181
                ret = -1;
 
182
                break;
 
183
            }
 
184
        } else if (ret == 0) {
 
185
            ret = -1;
 
186
            break;
 
187
        } else {
 
188
            if (ch == '\r') {
 
189
                ret = 0;
 
190
                break;
 
191
            }
 
192
            if (i < (buf_size - 1))
 
193
                buf[i++] = ch;
 
194
        }
 
195
    }
 
196
    term_exit();
 
197
    buf[i] = '\0';
 
198
    printf("\n");
 
199
    return ret;
 
200
}
 
201
#endif
 
202
 
 
203
static BlockDriverState *bdrv_new_open(const char *filename,
 
204
                                       const char *fmt)
 
205
{
 
206
    BlockDriverState *bs;
 
207
    BlockDriver *drv;
 
208
    char password[256];
 
209
 
 
210
    bs = bdrv_new("");
 
211
    if (!bs)
 
212
        error("Not enough memory");
 
213
    if (fmt) {
 
214
        drv = bdrv_find_format(fmt);
 
215
        if (!drv)
 
216
            error("Unknown file format '%s'", fmt);
 
217
    } else {
 
218
        drv = NULL;
 
219
    }
 
220
    if (bdrv_open2(bs, filename, 0, drv) < 0) {
 
221
        error("Could not open '%s'", filename);
 
222
    }
 
223
    if (bdrv_is_encrypted(bs)) {
 
224
        printf("Disk image '%s' is encrypted.\n", filename);
 
225
        if (read_password(password, sizeof(password)) < 0)
 
226
            error("No password given");
 
227
        if (bdrv_set_key(bs, password) < 0)
 
228
            error("invalid password");
 
229
    }
 
230
    return bs;
 
231
}
 
232
 
 
233
static int img_create(int argc, char **argv)
 
234
{
 
235
    int c, ret, flags;
 
236
    const char *fmt = "raw";
 
237
    const char *filename;
 
238
    const char *base_filename = NULL;
 
239
    uint64_t size;
 
240
    const char *p;
 
241
    BlockDriver *drv;
 
242
 
 
243
    flags = 0;
 
244
    for(;;) {
 
245
        c = getopt(argc, argv, "b:f:he6");
 
246
        if (c == -1)
 
247
            break;
 
248
        switch(c) {
 
249
        case 'h':
 
250
            help();
 
251
            break;
 
252
        case 'b':
 
253
            base_filename = optarg;
 
254
            break;
 
255
        case 'f':
 
256
            fmt = optarg;
 
257
            break;
 
258
        case 'e':
 
259
            flags |= BLOCK_FLAG_ENCRYPT;
 
260
            break;
 
261
        case '6':
 
262
            flags |= BLOCK_FLAG_COMPAT6;
 
263
            break;
 
264
        }
 
265
    }
 
266
    if (optind >= argc)
 
267
        help();
 
268
    filename = argv[optind++];
 
269
    size = 0;
 
270
    if (base_filename) {
 
271
        BlockDriverState *bs;
 
272
        bs = bdrv_new_open(base_filename, NULL);
 
273
        bdrv_get_geometry(bs, &size);
 
274
        size *= 512;
 
275
        bdrv_delete(bs);
 
276
    } else {
 
277
        if (optind >= argc)
 
278
            help();
 
279
        p = argv[optind];
 
280
        size = strtoul(p, (char **)&p, 0);
 
281
        if (*p == 'M') {
 
282
            size *= 1024 * 1024;
 
283
        } else if (*p == 'G') {
 
284
            size *= 1024 * 1024 * 1024;
 
285
        } else if (*p == 'k' || *p == 'K' || *p == '\0') {
 
286
            size *= 1024;
 
287
        } else {
 
288
            help();
 
289
        }
 
290
    }
 
291
    drv = bdrv_find_format(fmt);
 
292
    if (!drv)
 
293
        error("Unknown file format '%s'", fmt);
 
294
    printf("Formatting '%s', fmt=%s",
 
295
           filename, fmt);
 
296
    if (flags & BLOCK_FLAG_ENCRYPT)
 
297
        printf(", encrypted");
 
298
    if (flags & BLOCK_FLAG_COMPAT6)
 
299
        printf(", compatibility level=6");
 
300
    if (base_filename) {
 
301
        printf(", backing_file=%s",
 
302
               base_filename);
 
303
    }
 
304
    printf(", size=%" PRIu64 " kB\n", size / 1024);
 
305
    ret = bdrv_create(drv, filename, size / 512, base_filename, flags);
 
306
    if (ret < 0) {
 
307
        if (ret == -ENOTSUP) {
 
308
            error("Formatting or formatting option not supported for file format '%s'", fmt);
 
309
        } else {
 
310
            error("Error while formatting");
 
311
        }
 
312
    }
 
313
    return 0;
 
314
}
 
315
 
 
316
static int img_commit(int argc, char **argv)
 
317
{
 
318
    int c, ret;
 
319
    const char *filename, *fmt;
 
320
    BlockDriver *drv;
 
321
    BlockDriverState *bs;
 
322
 
 
323
    fmt = NULL;
 
324
    for(;;) {
 
325
        c = getopt(argc, argv, "f:h");
 
326
        if (c == -1)
 
327
            break;
 
328
        switch(c) {
 
329
        case 'h':
 
330
            help();
 
331
            break;
 
332
        case 'f':
 
333
            fmt = optarg;
 
334
            break;
 
335
        }
 
336
    }
 
337
    if (optind >= argc)
 
338
        help();
 
339
    filename = argv[optind++];
 
340
 
 
341
    bs = bdrv_new("");
 
342
    if (!bs)
 
343
        error("Not enough memory");
 
344
    if (fmt) {
 
345
        drv = bdrv_find_format(fmt);
 
346
        if (!drv)
 
347
            error("Unknown file format '%s'", fmt);
 
348
    } else {
 
349
        drv = NULL;
 
350
    }
 
351
    if (bdrv_open2(bs, filename, 0, drv) < 0) {
 
352
        error("Could not open '%s'", filename);
 
353
    }
 
354
    ret = bdrv_commit(bs);
 
355
    switch(ret) {
 
356
    case 0:
 
357
        printf("Image committed.\n");
 
358
        break;
 
359
    case -ENOENT:
 
360
        error("No disk inserted");
 
361
        break;
 
362
    case -EACCES:
 
363
        error("Image is read-only");
 
364
        break;
 
365
    case -ENOTSUP:
 
366
        error("Image is already committed");
 
367
        break;
 
368
    default:
 
369
        error("Error while committing image");
 
370
        break;
 
371
    }
 
372
 
 
373
    bdrv_delete(bs);
 
374
    return 0;
 
375
}
 
376
 
 
377
static int is_not_zero(const uint8_t *sector, int len)
 
378
{
 
379
    int i;
 
380
    len >>= 2;
 
381
    for(i = 0;i < len; i++) {
 
382
        if (((uint32_t *)sector)[i] != 0)
 
383
            return 1;
 
384
    }
 
385
    return 0;
 
386
}
 
387
 
 
388
static int is_allocated_sectors(const uint8_t *buf, int n, int *pnum)
 
389
{
 
390
    int v, i;
 
391
 
 
392
    if (n <= 0) {
 
393
        *pnum = 0;
 
394
        return 0;
 
395
    }
 
396
    v = is_not_zero(buf, 512);
 
397
    for(i = 1; i < n; i++) {
 
398
        buf += 512;
 
399
        if (v != is_not_zero(buf, 512))
 
400
            break;
 
401
    }
 
402
    *pnum = i;
 
403
    return v;
 
404
}
 
405
 
 
406
#define IO_BUF_SIZE 65536
 
407
 
 
408
static int img_convert(int argc, char **argv)
 
409
{
 
410
    int c, ret, n, n1, bs_n, bs_i, flags, cluster_size, cluster_sectors;
 
411
    const char *fmt, *out_fmt, *out_filename;
 
412
    BlockDriver *drv;
 
413
    BlockDriverState **bs, *out_bs;
 
414
    int64_t total_sectors, nb_sectors, sector_num, bs_offset;
 
415
    uint64_t bs_sectors;
 
416
    uint8_t buf[IO_BUF_SIZE];
 
417
    const uint8_t *buf1;
 
418
    BlockDriverInfo bdi;
 
419
 
 
420
    fmt = NULL;
 
421
    out_fmt = "raw";
 
422
    flags = 0;
 
423
    for(;;) {
 
424
        c = getopt(argc, argv, "f:O:hce6");
 
425
        if (c == -1)
 
426
            break;
 
427
        switch(c) {
 
428
        case 'h':
 
429
            help();
 
430
            break;
 
431
        case 'f':
 
432
            fmt = optarg;
 
433
            break;
 
434
        case 'O':
 
435
            out_fmt = optarg;
 
436
            break;
 
437
        case 'c':
 
438
            flags |= BLOCK_FLAG_COMPRESS;
 
439
            break;
 
440
        case 'e':
 
441
            flags |= BLOCK_FLAG_ENCRYPT;
 
442
            break;
 
443
        case '6':
 
444
            flags |= BLOCK_FLAG_COMPAT6;
 
445
            break;
 
446
        }
 
447
    }
 
448
 
 
449
    bs_n = argc - optind - 1;
 
450
    if (bs_n < 1) help();
 
451
 
 
452
    out_filename = argv[argc - 1];
 
453
        
 
454
    bs = calloc(bs_n, sizeof(BlockDriverState *));
 
455
    if (!bs)
 
456
        error("Out of memory");
 
457
 
 
458
    total_sectors = 0;
 
459
    for (bs_i = 0; bs_i < bs_n; bs_i++) {
 
460
        bs[bs_i] = bdrv_new_open(argv[optind + bs_i], fmt);
 
461
        if (!bs[bs_i])
 
462
            error("Could not open '%s'", argv[optind + bs_i]);
 
463
        bdrv_get_geometry(bs[bs_i], &bs_sectors);
 
464
        total_sectors += bs_sectors;
 
465
    }
 
466
 
 
467
    drv = bdrv_find_format(out_fmt);
 
468
    if (!drv)
 
469
        error("Unknown file format '%s'", out_fmt);
 
470
    if (flags & BLOCK_FLAG_COMPRESS && drv != &bdrv_qcow && drv != &bdrv_qcow2)
 
471
        error("Compression not supported for this file format");
 
472
    if (flags & BLOCK_FLAG_ENCRYPT && drv != &bdrv_qcow && drv != &bdrv_qcow2)
 
473
        error("Encryption not supported for this file format");
 
474
    if (flags & BLOCK_FLAG_COMPAT6 && drv != &bdrv_vmdk)
 
475
        error("Alternative compatibility level not supported for this file format");
 
476
    if (flags & BLOCK_FLAG_ENCRYPT && flags & BLOCK_FLAG_COMPRESS)
 
477
        error("Compression and encryption not supported at the same time");
 
478
 
 
479
    ret = bdrv_create(drv, out_filename, total_sectors, NULL, flags);
 
480
    if (ret < 0) {
 
481
        if (ret == -ENOTSUP) {
 
482
            error("Formatting not supported for file format '%s'", fmt);
 
483
        } else {
 
484
            error("Error while formatting '%s'", out_filename);
 
485
        }
 
486
    }
 
487
 
 
488
    out_bs = bdrv_new_open(out_filename, out_fmt);
 
489
 
 
490
    bs_i = 0;
 
491
    bs_offset = 0;
 
492
    bdrv_get_geometry(bs[0], &bs_sectors);
 
493
 
 
494
    if (flags & BLOCK_FLAG_COMPRESS) {
 
495
        if (bdrv_get_info(out_bs, &bdi) < 0)
 
496
            error("could not get block driver info");
 
497
        cluster_size = bdi.cluster_size;
 
498
        if (cluster_size <= 0 || cluster_size > IO_BUF_SIZE)
 
499
            error("invalid cluster size");
 
500
        cluster_sectors = cluster_size >> 9;
 
501
        sector_num = 0;
 
502
        for(;;) {
 
503
            int64_t bs_num;
 
504
            int remainder;
 
505
            uint8_t *buf2;
 
506
 
 
507
            nb_sectors = total_sectors - sector_num;
 
508
            if (nb_sectors <= 0)
 
509
                break;
 
510
            if (nb_sectors >= cluster_sectors)
 
511
                n = cluster_sectors;
 
512
            else
 
513
                n = nb_sectors;
 
514
 
 
515
            bs_num = sector_num - bs_offset;
 
516
            assert (bs_num >= 0);
 
517
            remainder = n;
 
518
            buf2 = buf;
 
519
            while (remainder > 0) {
 
520
                int nlow;
 
521
                while (bs_num == bs_sectors) {
 
522
                    bs_i++;
 
523
                    assert (bs_i < bs_n);
 
524
                    bs_offset += bs_sectors;
 
525
                    bdrv_get_geometry(bs[bs_i], &bs_sectors);
 
526
                    bs_num = 0;
 
527
                    /* printf("changing part: sector_num=%lld, "
 
528
                       "bs_i=%d, bs_offset=%lld, bs_sectors=%lld\n",
 
529
                       sector_num, bs_i, bs_offset, bs_sectors); */
 
530
                }
 
531
                assert (bs_num < bs_sectors);
 
532
 
 
533
                nlow = (remainder > bs_sectors - bs_num) ? bs_sectors - bs_num : remainder;
 
534
 
 
535
                if (bdrv_read(bs[bs_i], bs_num, buf2, nlow) < 0) 
 
536
                    error("error while reading");
 
537
 
 
538
                buf2 += nlow * 512;
 
539
                bs_num += nlow;
 
540
 
 
541
                remainder -= nlow;
 
542
            }
 
543
            assert (remainder == 0);
 
544
 
 
545
            if (n < cluster_sectors)
 
546
                memset(buf + n * 512, 0, cluster_size - n * 512);
 
547
            if (is_not_zero(buf, cluster_size)) {
 
548
                if (bdrv_write_compressed(out_bs, sector_num, buf,
 
549
                                          cluster_sectors) != 0)
 
550
                    error("error while compressing sector %" PRId64,
 
551
                          sector_num);
 
552
            }
 
553
            sector_num += n;
 
554
        }
 
555
        /* signal EOF to align */
 
556
        bdrv_write_compressed(out_bs, 0, NULL, 0);
 
557
    } else {
 
558
        sector_num = 0;
 
559
        for(;;) {
 
560
            nb_sectors = total_sectors - sector_num;
 
561
            if (nb_sectors <= 0)
 
562
                break;
 
563
            if (nb_sectors >= (IO_BUF_SIZE / 512))
 
564
                n = (IO_BUF_SIZE / 512);
 
565
            else
 
566
                n = nb_sectors;
 
567
 
 
568
            while (sector_num - bs_offset >= bs_sectors) {
 
569
                bs_i ++;
 
570
                assert (bs_i < bs_n);
 
571
                bs_offset += bs_sectors;
 
572
                bdrv_get_geometry(bs[bs_i], &bs_sectors);
 
573
                /* printf("changing part: sector_num=%lld, bs_i=%d, "
 
574
                  "bs_offset=%lld, bs_sectors=%lld\n",
 
575
                   sector_num, bs_i, bs_offset, bs_sectors); */
 
576
            }
 
577
 
 
578
            if (n > bs_offset + bs_sectors - sector_num)
 
579
                n = bs_offset + bs_sectors - sector_num;
 
580
 
 
581
            if (bdrv_read(bs[bs_i], sector_num - bs_offset, buf, n) < 0) 
 
582
                error("error while reading");
 
583
            /* NOTE: at the same time we convert, we do not write zero
 
584
               sectors to have a chance to compress the image. Ideally, we
 
585
               should add a specific call to have the info to go faster */
 
586
            buf1 = buf;
 
587
            while (n > 0) {
 
588
                if (is_allocated_sectors(buf1, n, &n1)) {
 
589
                    if (bdrv_write(out_bs, sector_num, buf1, n1) < 0)
 
590
                        error("error while writing");
 
591
                }
 
592
                sector_num += n1;
 
593
                n -= n1;
 
594
                buf1 += n1 * 512;
 
595
            }
 
596
        }
 
597
    }
 
598
    bdrv_delete(out_bs);
 
599
    for (bs_i = 0; bs_i < bs_n; bs_i++)
 
600
        bdrv_delete(bs[bs_i]);
 
601
    free(bs);
 
602
    return 0;
 
603
}
 
604
 
 
605
#ifdef _WIN32
 
606
static int64_t get_allocated_file_size(const char *filename)
 
607
{
 
608
    typedef DWORD (WINAPI * get_compressed_t)(const char *filename, DWORD *high);
 
609
    get_compressed_t get_compressed;
 
610
    struct _stati64 st;
 
611
 
 
612
    /* WinNT support GetCompressedFileSize to determine allocate size */
 
613
    get_compressed = (get_compressed_t) GetProcAddress(GetModuleHandle("kernel32"), "GetCompressedFileSizeA");
 
614
    if (get_compressed) {
 
615
        DWORD high, low;
 
616
        low = get_compressed(filename, &high);
 
617
        if (low != 0xFFFFFFFFlu || GetLastError() == NO_ERROR)
 
618
            return (((int64_t) high) << 32) + low;
 
619
    }
 
620
 
 
621
    if (_stati64(filename, &st) < 0)
 
622
        return -1;
 
623
    return st.st_size;
 
624
}
 
625
#else
 
626
static int64_t get_allocated_file_size(const char *filename)
 
627
{
 
628
    struct stat st;
 
629
    if (stat(filename, &st) < 0)
 
630
        return -1;
 
631
    return (int64_t)st.st_blocks * 512;
 
632
}
 
633
#endif
 
634
 
 
635
static void dump_snapshots(BlockDriverState *bs)
 
636
{
 
637
    QEMUSnapshotInfo *sn_tab, *sn;
 
638
    int nb_sns, i;
 
639
    char buf[256];
 
640
 
 
641
    nb_sns = bdrv_snapshot_list(bs, &sn_tab);
 
642
    if (nb_sns <= 0)
 
643
        return;
 
644
    printf("Snapshot list:\n");
 
645
    printf("%s\n", bdrv_snapshot_dump(buf, sizeof(buf), NULL));
 
646
    for(i = 0; i < nb_sns; i++) {
 
647
        sn = &sn_tab[i];
 
648
        printf("%s\n", bdrv_snapshot_dump(buf, sizeof(buf), sn));
 
649
    }
 
650
    qemu_free(sn_tab);
 
651
}
 
652
 
 
653
static int img_info(int argc, char **argv)
 
654
{
 
655
    int c;
 
656
    const char *filename, *fmt;
 
657
    BlockDriver *drv;
 
658
    BlockDriverState *bs;
 
659
    char fmt_name[128], size_buf[128], dsize_buf[128];
 
660
    uint64_t total_sectors;
 
661
    int64_t allocated_size;
 
662
    char backing_filename[1024];
 
663
    char backing_filename2[1024];
 
664
    BlockDriverInfo bdi;
 
665
 
 
666
    fmt = NULL;
 
667
    for(;;) {
 
668
        c = getopt(argc, argv, "f:h");
 
669
        if (c == -1)
 
670
            break;
 
671
        switch(c) {
 
672
        case 'h':
 
673
            help();
 
674
            break;
 
675
        case 'f':
 
676
            fmt = optarg;
 
677
            break;
 
678
        }
 
679
    }
 
680
    if (optind >= argc)
 
681
        help();
 
682
    filename = argv[optind++];
 
683
 
 
684
    bs = bdrv_new("");
 
685
    if (!bs)
 
686
        error("Not enough memory");
 
687
    if (fmt) {
 
688
        drv = bdrv_find_format(fmt);
 
689
        if (!drv)
 
690
            error("Unknown file format '%s'", fmt);
 
691
    } else {
 
692
        drv = NULL;
 
693
    }
 
694
    if (bdrv_open2(bs, filename, 0, drv) < 0) {
 
695
        error("Could not open '%s'", filename);
 
696
    }
 
697
    bdrv_get_format(bs, fmt_name, sizeof(fmt_name));
 
698
    bdrv_get_geometry(bs, &total_sectors);
 
699
    get_human_readable_size(size_buf, sizeof(size_buf), total_sectors * 512);
 
700
    allocated_size = get_allocated_file_size(filename);
 
701
    if (allocated_size < 0)
 
702
        sprintf(dsize_buf, "unavailable");
 
703
    else
 
704
        get_human_readable_size(dsize_buf, sizeof(dsize_buf),
 
705
                                allocated_size);
 
706
    printf("image: %s\n"
 
707
           "file format: %s\n"
 
708
           "virtual size: %s (%" PRId64 " bytes)\n"
 
709
           "disk size: %s\n",
 
710
           filename, fmt_name, size_buf,
 
711
           (total_sectors * 512),
 
712
           dsize_buf);
 
713
    if (bdrv_is_encrypted(bs))
 
714
        printf("encrypted: yes\n");
 
715
    if (bdrv_get_info(bs, &bdi) >= 0) {
 
716
        if (bdi.cluster_size != 0)
 
717
            printf("cluster_size: %d\n", bdi.cluster_size);
 
718
    }
 
719
    bdrv_get_backing_filename(bs, backing_filename, sizeof(backing_filename));
 
720
    if (backing_filename[0] != '\0') {
 
721
        path_combine(backing_filename2, sizeof(backing_filename2),
 
722
                     filename, backing_filename);
 
723
        printf("backing file: %s (actual path: %s)\n",
 
724
               backing_filename,
 
725
               backing_filename2);
 
726
    }
 
727
    dump_snapshots(bs);
 
728
    bdrv_delete(bs);
 
729
    return 0;
 
730
}
 
731
 
 
732
int main(int argc, char **argv)
 
733
{
 
734
    const char *cmd;
 
735
 
 
736
    bdrv_init();
 
737
    if (argc < 2)
 
738
        help();
 
739
    cmd = argv[1];
 
740
    optind++;
 
741
    if (!strcmp(cmd, "create")) {
 
742
        img_create(argc, argv);
 
743
    } else if (!strcmp(cmd, "commit")) {
 
744
        img_commit(argc, argv);
 
745
    } else if (!strcmp(cmd, "convert")) {
 
746
        img_convert(argc, argv);
 
747
    } else if (!strcmp(cmd, "info")) {
 
748
        img_info(argc, argv);
 
749
    } else {
 
750
        help();
 
751
    }
 
752
    return 0;
 
753
}