2 vmdk2raw: convert vmware images to raw disk images
3 Copyright (C) Net Integration Technologies 2004
4 Copyright (C) Matthew Chapman 2003
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 #include <sys/types.h>
31 #include "config-host.h"
33 static struct cowdisk_header header
;
34 static struct vmdisk_header header4
;
35 static off64_t disk_limit
;
36 static unsigned int granule_size
;
37 static uint32_t *l1dir
;
39 static unsigned int cached_l2dir
;
40 static uint32_t l2dir
[L2_SIZE
];
42 static struct vmdk_prm
{
43 uint32_t grain_table_size
;
44 uint32_t sectors_per_grain
;
45 uint32_t sectors_per_table
;
46 uint32_t directory_size
;
49 static size_t read_physical(int fd
, off64_t offset
, size_t length
, void *buffer
)
53 if (lseek64(fd
, offset
, SEEK_SET
) == -1) {
54 printf(" error trying to seek lseek to %lld", offset
);
58 n
= read(fd
, buffer
, length
);
61 printf("read from disk %lld", offset
);
68 static int read_l1dir(int fd
, size_t offset
, int num
)
70 l1dir
= malloc(sizeof(*l1dir
) * num
);
73 return read_physical(fd
, offset
<< SECTOR_BITS
, sizeof(*l1dir
) * num
, (char *)l1dir
) != (sizeof(*l1dir
) * num
);
76 static int read_l2dir(int fd
, size_t offset
, int num
)
78 return read_physical(fd
, offset
<< SECTOR_BITS
, sizeof(l2dir
[0]) * num
, (char *)l2dir
) != sizeof(l2dir
);
81 static size_t copy_virtual(struct vmdk_prm
*dsk
, int in_fd
, int out_fd
, off64_t offset
, void *buffer
, size_t length
)
84 unsigned int granule_offset
;
85 unsigned int grain_index
;
86 unsigned int sector_map_idx
;
88 granule_offset
= offset
% granule_size
;
89 length
= MIN(length
, granule_size
- granule_offset
);
90 length
= MIN(length
, disk_limit
- offset
);
92 sector_map_idx
= (offset
>> SECTOR_BITS
) / dsk
->sectors_per_table
;
94 if (sector_map_idx
>= dsk
->directory_size
) {
95 fprintf(stderr
, "cannot locate grain table for %d in %d\n", sector_map_idx
, dsk
->directory_size
);
99 if (l1dir
[sector_map_idx
] == 0)
102 if (sector_map_idx
!= cached_l2dir
) {
103 if (read_l2dir(in_fd
, l1dir
[sector_map_idx
], dsk
->grain_table_size
)) {
104 fprintf(stderr
, "read failed\n");
107 cached_l2dir
= sector_map_idx
;
110 grain_index
= ((offset
>> SECTOR_BITS
) % dsk
->sectors_per_table
) / dsk
->sectors_per_grain
;
112 if (grain_index
>= dsk
->grain_table_size
) {
113 fprintf(stderr
, "grain to large");
117 if (l2dir
[grain_index
] == 0)
120 if (read_physical(in_fd
, (l2dir
[grain_index
] << SECTOR_BITS
) + granule_offset
, length
, buffer
) != length
) {
121 fprintf(stderr
, "read error 2\n");
125 write(out_fd
, buffer
, length
);
129 /* the last chunk of the file can not be sparse
130 * or the file will be truncated */
131 if (offset
+ length
>= disk_limit
) {
132 if (lseek64(out_fd
, length
-1, SEEK_CUR
) == (off_t
)-1)
134 /* write the last NULL byte instead of seeking */
136 write(out_fd
, &nil
, 1);
138 if (lseek64(out_fd
, length
, SEEK_CUR
) == (off_t
)-1)
144 static int open_vmdk4(int fd
)
146 if (read(fd
, &header4
, sizeof(header4
)) != sizeof(header4
)) {
147 perror("read from disk");
151 granule_size
= header4
.granularity
<< SECTOR_BITS
;
152 disk_limit
= header4
.capacity
<< SECTOR_BITS
;
155 vdsk
.grain_table_size
= header4
.num_gtes_per_gte
;
156 vdsk
.sectors_per_grain
= header4
.granularity
;
157 vdsk
.sectors_per_table
= vdsk
.grain_table_size
* vdsk
.sectors_per_grain
;
158 vdsk
.directory_size
= (header4
.capacity
+ vdsk
.sectors_per_table
- 1) / vdsk
.sectors_per_table
+ 1;
160 if (read_l1dir(fd
, header4
.rgd_offset
, vdsk
.directory_size
))
167 static int open_vmdk3(int fd
)
169 if (read(fd
, &header
, sizeof(header
)) != sizeof(header
)) {
170 perror("read from disk\n");
173 granule_size
= header
.granularity
<< SECTOR_BITS
;
174 vdsk
.sectors_per_grain
= header
.granularity
;
175 vdsk
.grain_table_size
= L2_SIZE
;
176 vdsk
.sectors_per_table
= vdsk
.grain_table_size
* vdsk
.sectors_per_grain
;
177 vdsk
.directory_size
= L1_SIZE
;
178 if (read_l1dir(fd
, header
.l1dir_offset
, L1_SIZE
))
181 disk_limit
= header
.disk_sectors
<< SECTOR_BITS
;
186 static int open_vmdk(const char *filename
)
188 int fd
= open(filename
, O_RDONLY
| O_LARGEFILE
);
195 if (read(fd
, &magic
, sizeof(magic
)) != sizeof(magic
)) {
196 perror("read from disk");
200 if (!memcmp(magic
, "KDMV", sizeof(magic
))) {
202 } else if (!memcmp(magic
, "COWD", sizeof(magic
))) {
205 fprintf(stderr
, "%s is not a VMware virtual disk image\n", filename
);
213 static void help(void)
216 "usage: vmdk2raw vmware_image output_image\n"
218 "vmware_image a vmware cow image\n"
219 "output_image the created disk image\n"
224 #define BUF_SIZE 0x10000
225 static void copy_disk(in_fd
, out_fd
)
230 while (i
< disk_limit
) {
231 ret
= copy_virtual(&vdsk
, in_fd
, out_fd
, i
, buf
, sizeof(buf
));
233 fprintf(stderr
, "copying failed\n");
240 int main(int argc
, char **argv
)
247 in_fd
= open_vmdk(argv
[1]);
252 out_fd
= open(argv
[2], O_WRONLY
| O_LARGEFILE
| O_CREAT
| O_TRUNC
, S_IRUSR
| S_IWUSR
);
258 copy_disk(in_fd
, out_fd
);