Statistics
| Branch: | Revision:

root / vmdk2raw.c @ 63ce9e0a

History | View | Annotate | Download (4.4 kB)

1 47cea614 bellard
/*
2 47cea614 bellard
   vmdk2raw: convert vmware images to raw disk images
3 47cea614 bellard
   Copyright (C) Net Integration Technologies 2004
4 47cea614 bellard
   Copyright (C) Matthew Chapman 2003
5 47cea614 bellard

6 47cea614 bellard
   This program is free software; you can redistribute it and/or modify
7 47cea614 bellard
   it under the terms of the GNU General Public License as published by
8 47cea614 bellard
   the Free Software Foundation; either version 2 of the License, or
9 47cea614 bellard
   (at your option) any later version.
10 47cea614 bellard

11 47cea614 bellard
   This program is distributed in the hope that it will be useful,
12 47cea614 bellard
   but WITHOUT ANY WARRANTY; without even the implied warranty of
13 47cea614 bellard
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 47cea614 bellard
   GNU General Public License for more details.
15 47cea614 bellard

16 47cea614 bellard
   You should have received a copy of the GNU General Public License
17 47cea614 bellard
   along with this program; if not, write to the Free Software
18 47cea614 bellard
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 47cea614 bellard
*/
20 47cea614 bellard
21 47cea614 bellard
#include <stdlib.h>
22 47cea614 bellard
#include <stdio.h>
23 47cea614 bellard
#include <unistd.h>
24 47cea614 bellard
#include <fcntl.h>
25 47cea614 bellard
#include <inttypes.h>
26 47cea614 bellard
#include <sys/types.h>
27 47cea614 bellard
#include <string.h>
28 47cea614 bellard
#include <sys/stat.h>
29 47cea614 bellard
#include <errno.h>
30 47cea614 bellard
#include "vmdk.h"
31 47cea614 bellard
#include "config-host.h"
32 47cea614 bellard
33 47cea614 bellard
struct cowdisk_header header;
34 47cea614 bellard
struct cowdisk_header2 header2;
35 47cea614 bellard
off_t disk_base, disk_limit;
36 47cea614 bellard
unsigned int granule_size;
37 47cea614 bellard
uint32_t l1dir[L1_SIZE];
38 47cea614 bellard
39 47cea614 bellard
unsigned int cached_l2dir;
40 47cea614 bellard
uint32_t l2dir[L2_SIZE];
41 47cea614 bellard
42 47cea614 bellard
size_t read_physical(int fd, off64_t offset, size_t length, void *buffer)
43 47cea614 bellard
{
44 47cea614 bellard
    size_t n;
45 47cea614 bellard
46 47cea614 bellard
    if (lseek64(fd, offset, SEEK_SET) == -1)
47 47cea614 bellard
    {
48 47cea614 bellard
        perror("lseek");
49 47cea614 bellard
        return -1;
50 47cea614 bellard
    }
51 47cea614 bellard
52 47cea614 bellard
    n = read(fd, buffer, length);
53 47cea614 bellard
    if (n == -1)
54 47cea614 bellard
    {
55 47cea614 bellard
        perror("read from disk");
56 47cea614 bellard
        return -1;
57 47cea614 bellard
    }
58 47cea614 bellard
59 47cea614 bellard
    return n;
60 47cea614 bellard
}
61 47cea614 bellard
62 47cea614 bellard
size_t copy_virtual(int in_fd, int out_fd, off64_t offset, void *buffer, size_t length)
63 47cea614 bellard
{
64 47cea614 bellard
    unsigned int granule_index, granule_offset;
65 47cea614 bellard
    unsigned int l1index, l2index;
66 47cea614 bellard
67 47cea614 bellard
    granule_index = offset / granule_size;
68 47cea614 bellard
    granule_offset = offset % granule_size;
69 47cea614 bellard
    length = MIN(length, granule_size - granule_offset);
70 47cea614 bellard
    length = MIN(length, disk_limit - offset);
71 47cea614 bellard
72 47cea614 bellard
    l1index = (granule_index >> L2_BITS) & L1_MASK;
73 47cea614 bellard
    l2index = granule_index & L2_MASK;
74 47cea614 bellard
75 47cea614 bellard
    if (l1dir[l1index] == 0)
76 47cea614 bellard
        goto zero_fill;
77 47cea614 bellard
78 47cea614 bellard
    if (l1index != cached_l2dir)
79 47cea614 bellard
    {
80 47cea614 bellard
        if (read_physical(in_fd, (l1dir[l1index] << SECTOR_BITS), sizeof(l2dir), (char *)l2dir) != sizeof(l2dir))
81 47cea614 bellard
            return 0;
82 47cea614 bellard
83 47cea614 bellard
        cached_l2dir = l1index;
84 47cea614 bellard
    }
85 47cea614 bellard
86 47cea614 bellard
    if (l2dir[l2index] == 0)
87 47cea614 bellard
        goto zero_fill;
88 47cea614 bellard
89 47cea614 bellard
    if (read_physical(in_fd, (l2dir[l2index] << SECTOR_BITS) + granule_offset, length, buffer) != length)
90 47cea614 bellard
        return 0;
91 47cea614 bellard
92 47cea614 bellard
    write(out_fd, buffer, length);
93 47cea614 bellard
    return length;
94 47cea614 bellard
95 47cea614 bellard
zero_fill:
96 47cea614 bellard
    /* the last chunk of the file can not be sparse
97 47cea614 bellard
     * or the file will be truncated */
98 47cea614 bellard
    if (offset + length < disk_limit) {
99 47cea614 bellard
        memset(buffer, 0, length);
100 47cea614 bellard
        write(out_fd, buffer, length);
101 47cea614 bellard
    } else {
102 47cea614 bellard
        if (lseek(out_fd, length, SEEK_CUR) == (off_t)-1)
103 47cea614 bellard
            perror("lseek");
104 47cea614 bellard
    }
105 47cea614 bellard
    return length;
106 47cea614 bellard
}
107 47cea614 bellard
108 47cea614 bellard
109 47cea614 bellard
int open_vmdk(const char *filename)
110 47cea614 bellard
{
111 04a3b84c bellard
    int fd = open(filename, O_RDONLY | O_LARGEFILE);
112 47cea614 bellard
    if (fd == -1)
113 47cea614 bellard
    {
114 47cea614 bellard
        perror(filename);
115 47cea614 bellard
        return -1;
116 47cea614 bellard
    }
117 47cea614 bellard
118 47cea614 bellard
    if (read(fd, &header, sizeof(header)) != sizeof(header))
119 47cea614 bellard
    {
120 47cea614 bellard
        perror("read from disk");
121 47cea614 bellard
        return -1;
122 47cea614 bellard
    }
123 47cea614 bellard
124 47cea614 bellard
    if (memcmp(header.magic, "COWD", 4) != 0)
125 47cea614 bellard
    {
126 47cea614 bellard
        fprintf(stderr, "%s is not a VMware virtual disk image\n", filename);
127 47cea614 bellard
        return -1;
128 47cea614 bellard
    }
129 47cea614 bellard
130 47cea614 bellard
    granule_size = header.granularity << SECTOR_BITS;
131 47cea614 bellard
    if (read_physical(fd, header.l1dir_sector << SECTOR_BITS, sizeof(l1dir), (char *)l1dir) != sizeof(l1dir))
132 47cea614 bellard
        return -1;
133 47cea614 bellard
134 47cea614 bellard
    disk_limit = header.disk_sectors << SECTOR_BITS;
135 47cea614 bellard
136 47cea614 bellard
    cached_l2dir = -1;
137 47cea614 bellard
    return fd;
138 47cea614 bellard
}
139 47cea614 bellard
140 47cea614 bellard
void help(void)
141 47cea614 bellard
{
142 47cea614 bellard
    printf("vmdk2raw\n"
143 47cea614 bellard
           "usage: vmdk2raw vmware_image output_image\n"
144 47cea614 bellard
           "\n"
145 47cea614 bellard
           "vmware_image   a vmware 2.x/3.x cow image\n"
146 47cea614 bellard
           "output_image   the created disk image\n" 
147 47cea614 bellard
          );
148 47cea614 bellard
    exit(1);
149 47cea614 bellard
}
150 47cea614 bellard
151 47cea614 bellard
#define BUF_SIZE granule_size
152 47cea614 bellard
void copy_disk(in_fd, out_fd)
153 47cea614 bellard
{
154 47cea614 bellard
    char buf[BUF_SIZE];
155 47cea614 bellard
    off64_t i = 0;
156 47cea614 bellard
    while (i < disk_limit) {
157 47cea614 bellard
        i += copy_virtual(in_fd, out_fd, i, buf, sizeof(buf));
158 47cea614 bellard
    }
159 47cea614 bellard
}
160 47cea614 bellard
161 47cea614 bellard
int main(int argc, char **argv)
162 47cea614 bellard
{
163 47cea614 bellard
    int out_fd, in_fd;
164 47cea614 bellard
165 47cea614 bellard
    if (argc < 3)
166 47cea614 bellard
        help();
167 47cea614 bellard
168 47cea614 bellard
    in_fd = open_vmdk(argv[1]);
169 47cea614 bellard
    if (in_fd < 0) {
170 47cea614 bellard
        return -1;
171 47cea614 bellard
    }
172 47cea614 bellard
173 47cea614 bellard
    out_fd = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
174 47cea614 bellard
    if (out_fd < 0) {
175 47cea614 bellard
        perror(argv[2]);
176 47cea614 bellard
        return -1;
177 47cea614 bellard
    }
178 47cea614 bellard
179 47cea614 bellard
    copy_disk(in_fd, out_fd);
180 47cea614 bellard
    close(out_fd);
181 47cea614 bellard
    return 0;
182 47cea614 bellard
}