Revision 47cea614

b/Makefile
8 8
LIBS=
9 9
DEFINES+=-D_GNU_SOURCE
10 10
ifndef CONFIG_WIN32
11
TOOLS=qemu-mkcow
11
TOOLS=qemu-mkcow vmdk2raw
12 12
endif
13 13
ifdef CONFIG_STATIC
14 14
LDFLAGS+=-static
......
22 22
qemu-mkcow: qemu-mkcow.c
23 23
	$(CC) $(CFLAGS) $(LDFLAGS) $(DEFINES) -o $@ $^ $(LIBS)
24 24

  
25
vmdk2raw: vmdk2raw.c
26
	$(CC) $(CFLAGS) $(LDFLAGS) $(DEFINES) -o $@ $^ $(LIBS)
27

  
25 28
dyngen$(EXESUF): dyngen.c
26 29
	$(HOST_CC) $(CFLAGS) $(DEFINES) -o $@ $^
27 30

  
......
91 94
        $(bindir)/qemu-arm \
92 95
        $(bindir)/qemu-sparc \
93 96
        $(bindir)/qemu-ppc \
94
        $(bindir)/qemu-mkcow \
97
        $(bindir)/qemu-mkcow $(bindir)/vmdk2raw \
95 98
	$(datadir)/bios.bin \
96 99
	$(datadir)/vgabios.bin \
97 100
	$(datadir)/linux_boot.bin \
b/vmdk.h
1
/*
2
   Copyright (C) Matthew Chapman 2003
3

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

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

  
14
   You should have received a copy of the GNU General Public License
15
   along with this program; if not, write to the Free Software
16
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
*/
18

  
19
#define SECTOR_BITS	9
20
#define SECTOR_SIZE	(1 << SECTOR_BITS)
21
#define SECTOR_MASK	(SECTOR_SIZE - 1)
22

  
23
#define L1_BITS		(SECTOR_BITS - 3)
24
#define L1_SIZE		(1 << L1_BITS)
25
#define L1_MASK		(L1_SIZE - 1)
26

  
27
#define L2_BITS		SECTOR_BITS
28
#define L2_SIZE		(1 << L2_BITS)
29
#define L2_MASK		(L2_SIZE - 1)
30

  
31
#define MIN(x,y)	(((x) < (y)) ? (x) : (y))
32

  
33
struct cowdisk_header
34
{
35
    char magic[4]; /* COWD */
36
    uint32_t version;
37
    uint32_t flags;
38
    uint32_t disk_sectors;
39
    uint32_t granularity;
40
    uint32_t l1dir_sector;
41
    uint32_t l1dir_size;
42
    uint32_t file_sectors;
43
    uint32_t cylinders;
44
    uint32_t heads;
45
    uint32_t sectors_per_track;
46
};
47

  
48
struct cowdisk_header2
49
{
50
   uint32_t parent_ts;
51
   uint32_t timestamp;
52
};
b/vmdk2raw.c
1
/*
2
   vmdk2raw: convert vmware images to raw disk images
3
   Copyright (C) Net Integration Technologies 2004
4
   Copyright (C) Matthew Chapman 2003
5

  
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.
10

  
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.
15

  
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.
19
*/
20

  
21
#include <stdlib.h>
22
#include <stdio.h>
23
#include <unistd.h>
24
#include <fcntl.h>
25
#include <inttypes.h>
26
#include <sys/types.h>
27
#include <string.h>
28
#include <sys/stat.h>
29
#include <errno.h>
30
#include "vmdk.h"
31
#include "config-host.h"
32

  
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];
38

  
39
unsigned int cached_l2dir;
40
uint32_t l2dir[L2_SIZE];
41

  
42
size_t read_physical(int fd, off64_t offset, size_t length, void *buffer)
43
{
44
    size_t n;
45

  
46
    if (lseek64(fd, offset, SEEK_SET) == -1)
47
    {
48
        perror("lseek");
49
        return -1;
50
    }
51

  
52
    n = read(fd, buffer, length);
53
    if (n == -1)
54
    {
55
        perror("read from disk");
56
        return -1;
57
    }
58

  
59
    return n;
60
}
61

  
62
size_t copy_virtual(int in_fd, int out_fd, off64_t offset, void *buffer, size_t length)
63
{
64
    unsigned int granule_index, granule_offset;
65
    unsigned int l1index, l2index;
66

  
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);
71

  
72
    l1index = (granule_index >> L2_BITS) & L1_MASK;
73
    l2index = granule_index & L2_MASK;
74

  
75
    if (l1dir[l1index] == 0)
76
        goto zero_fill;
77

  
78
    if (l1index != cached_l2dir)
79
    {
80
        if (read_physical(in_fd, (l1dir[l1index] << SECTOR_BITS), sizeof(l2dir), (char *)l2dir) != sizeof(l2dir))
81
            return 0;
82

  
83
        cached_l2dir = l1index;
84
    }
85

  
86
    if (l2dir[l2index] == 0)
87
        goto zero_fill;
88

  
89
    if (read_physical(in_fd, (l2dir[l2index] << SECTOR_BITS) + granule_offset, length, buffer) != length)
90
        return 0;
91

  
92
    write(out_fd, buffer, length);
93
    return length;
94

  
95
zero_fill:
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);
101
    } else {
102
        if (lseek(out_fd, length, SEEK_CUR) == (off_t)-1)
103
            perror("lseek");
104
    }
105
    return length;
106
}
107

  
108

  
109
int open_vmdk(const char *filename)
110
{
111
    int fd = open(filename, O_RDONLY);
112
    if (fd == -1)
113
    {
114
        perror(filename);
115
        return -1;
116
    }
117

  
118
    if (read(fd, &header, sizeof(header)) != sizeof(header))
119
    {
120
        perror("read from disk");
121
        return -1;
122
    }
123

  
124
    if (memcmp(header.magic, "COWD", 4) != 0)
125
    {
126
        fprintf(stderr, "%s is not a VMware virtual disk image\n", filename);
127
        return -1;
128
    }
129

  
130
    granule_size = header.granularity << SECTOR_BITS;
131
    if (read_physical(fd, header.l1dir_sector << SECTOR_BITS, sizeof(l1dir), (char *)l1dir) != sizeof(l1dir))
132
        return -1;
133

  
134
    disk_limit = header.disk_sectors << SECTOR_BITS;
135

  
136
    cached_l2dir = -1;
137
    return fd;
138
}
139

  
140
void help(void)
141
{
142
    printf("vmdk2raw\n"
143
           "usage: vmdk2raw vmware_image output_image\n"
144
           "\n"
145
           "vmware_image   a vmware 2.x/3.x cow image\n"
146
           "output_image   the created disk image\n" 
147
          );
148
    exit(1);
149
}
150

  
151
#define BUF_SIZE granule_size
152
void copy_disk(in_fd, out_fd)
153
{
154
    char buf[BUF_SIZE];
155
    off64_t i = 0;
156
    while (i < disk_limit) {
157
        i += copy_virtual(in_fd, out_fd, i, buf, sizeof(buf));
158
    }
159
}
160

  
161
int main(int argc, char **argv)
162
{
163
    int out_fd, in_fd;
164

  
165
    if (argc < 3)
166
        help();
167

  
168
    in_fd = open_vmdk(argv[1]);
169
    if (in_fd < 0) {
170
        return -1;
171
    }
172

  
173
    out_fd = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
174
    if (out_fd < 0) {
175
        perror(argv[2]);
176
        return -1;
177
    }
178

  
179
    copy_disk(in_fd, out_fd);
180
    close(out_fd);
181
    return 0;
182
}

Also available in: Unified diff