Statistics
| Branch: | Revision:

root / vmdk2raw.c @ 63ce9e0a

History | View | Annotate | Download (4.4 kB)

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 | O_LARGEFILE);
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
}