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 struct cowdisk_header header
;
34 struct cowdisk_header2 header2
;
35 off_t disk_base
, disk_limit
;
36 unsigned int granule_size
;
37 uint32_t l1dir
[L1_SIZE
];
39 unsigned int cached_l2dir
;
40 uint32_t l2dir
[L2_SIZE
];
42 size_t read_physical(int fd
, off64_t offset
, size_t length
, void *buffer
)
46 if (lseek64(fd
, offset
, SEEK_SET
) == -1)
52 n
= read(fd
, buffer
, length
);
55 perror("read from disk");
62 size_t copy_virtual(int in_fd
, int out_fd
, off64_t offset
, void *buffer
, size_t length
)
64 unsigned int granule_index
, granule_offset
;
65 unsigned int l1index
, l2index
;
67 granule_index
= offset
/ granule_size
;
68 granule_offset
= offset
% granule_size
;
69 length
= MIN(length
, granule_size
- granule_offset
);
70 length
= MIN(length
, disk_limit
- offset
);
72 l1index
= (granule_index
>> L2_BITS
) & L1_MASK
;
73 l2index
= granule_index
& L2_MASK
;
75 if (l1dir
[l1index
] == 0)
78 if (l1index
!= cached_l2dir
)
80 if (read_physical(in_fd
, (l1dir
[l1index
] << SECTOR_BITS
), sizeof(l2dir
), (char *)l2dir
) != sizeof(l2dir
))
83 cached_l2dir
= l1index
;
86 if (l2dir
[l2index
] == 0)
89 if (read_physical(in_fd
, (l2dir
[l2index
] << SECTOR_BITS
) + granule_offset
, length
, buffer
) != length
)
92 write(out_fd
, buffer
, length
);
96 /* the last chunk of the file can not be sparse
97 * or the file will be truncated */
98 if (offset
+ length
< disk_limit
) {
99 memset(buffer
, 0, length
);
100 write(out_fd
, buffer
, length
);
102 if (lseek(out_fd
, length
, SEEK_CUR
) == (off_t
)-1)
109 int open_vmdk(const char *filename
)
111 int fd
= open(filename
, O_RDONLY
| O_LARGEFILE
);
118 if (read(fd
, &header
, sizeof(header
)) != sizeof(header
))
120 perror("read from disk");
124 if (memcmp(header
.magic
, "COWD", 4) != 0)
126 fprintf(stderr
, "%s is not a VMware virtual disk image\n", filename
);
130 granule_size
= header
.granularity
<< SECTOR_BITS
;
131 if (read_physical(fd
, header
.l1dir_sector
<< SECTOR_BITS
, sizeof(l1dir
), (char *)l1dir
) != sizeof(l1dir
))
134 disk_limit
= header
.disk_sectors
<< SECTOR_BITS
;
143 "usage: vmdk2raw vmware_image output_image\n"
145 "vmware_image a vmware 2.x/3.x cow image\n"
146 "output_image the created disk image\n"
151 #define BUF_SIZE granule_size
152 void copy_disk(in_fd
, out_fd
)
156 while (i
< disk_limit
) {
157 i
+= copy_virtual(in_fd
, out_fd
, i
, buf
, sizeof(buf
));
161 int main(int argc
, char **argv
)
168 in_fd
= open_vmdk(argv
[1]);
173 out_fd
= open(argv
[2], O_WRONLY
| O_CREAT
| O_TRUNC
, S_IRUSR
| S_IWUSR
);
179 copy_disk(in_fd
, out_fd
);