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 | } |