Statistics
| Branch: | Revision:

root / block / vmdk.c @ b4b3ab14

History | View | Annotate | Download (31.6 kB)

1 ea2384d3 bellard
/*
2 ea2384d3 bellard
 * Block driver for the VMDK format
3 5fafdf24 ths
 *
4 ea2384d3 bellard
 * Copyright (c) 2004 Fabrice Bellard
5 ff1afc72 bellard
 * Copyright (c) 2005 Filip Navara
6 5fafdf24 ths
 *
7 ea2384d3 bellard
 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 ea2384d3 bellard
 * of this software and associated documentation files (the "Software"), to deal
9 ea2384d3 bellard
 * in the Software without restriction, including without limitation the rights
10 ea2384d3 bellard
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 ea2384d3 bellard
 * copies of the Software, and to permit persons to whom the Software is
12 ea2384d3 bellard
 * furnished to do so, subject to the following conditions:
13 ea2384d3 bellard
 *
14 ea2384d3 bellard
 * The above copyright notice and this permission notice shall be included in
15 ea2384d3 bellard
 * all copies or substantial portions of the Software.
16 ea2384d3 bellard
 *
17 ea2384d3 bellard
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 ea2384d3 bellard
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 ea2384d3 bellard
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 ea2384d3 bellard
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 ea2384d3 bellard
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 ea2384d3 bellard
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 ea2384d3 bellard
 * THE SOFTWARE.
24 ea2384d3 bellard
 */
25 5f4da8c0 ths
26 faf07963 pbrook
#include "qemu-common.h"
27 ea2384d3 bellard
#include "block_int.h"
28 5efa9d5a Anthony Liguori
#include "module.h"
29 ea2384d3 bellard
30 ea2384d3 bellard
#define VMDK3_MAGIC (('C' << 24) | ('O' << 16) | ('W' << 8) | 'D')
31 ea2384d3 bellard
#define VMDK4_MAGIC (('K' << 24) | ('D' << 16) | ('M' << 8) | 'V')
32 ea2384d3 bellard
33 ea2384d3 bellard
typedef struct {
34 ea2384d3 bellard
    uint32_t version;
35 ea2384d3 bellard
    uint32_t flags;
36 ea2384d3 bellard
    uint32_t disk_sectors;
37 ea2384d3 bellard
    uint32_t granularity;
38 ea2384d3 bellard
    uint32_t l1dir_offset;
39 ea2384d3 bellard
    uint32_t l1dir_size;
40 ea2384d3 bellard
    uint32_t file_sectors;
41 ea2384d3 bellard
    uint32_t cylinders;
42 ea2384d3 bellard
    uint32_t heads;
43 ea2384d3 bellard
    uint32_t sectors_per_track;
44 ea2384d3 bellard
} VMDK3Header;
45 ea2384d3 bellard
46 ea2384d3 bellard
typedef struct {
47 ea2384d3 bellard
    uint32_t version;
48 ea2384d3 bellard
    uint32_t flags;
49 ea2384d3 bellard
    int64_t capacity;
50 ea2384d3 bellard
    int64_t granularity;
51 ea2384d3 bellard
    int64_t desc_offset;
52 ea2384d3 bellard
    int64_t desc_size;
53 ea2384d3 bellard
    int32_t num_gtes_per_gte;
54 ea2384d3 bellard
    int64_t rgd_offset;
55 ea2384d3 bellard
    int64_t gd_offset;
56 ea2384d3 bellard
    int64_t grain_offset;
57 ea2384d3 bellard
    char filler[1];
58 ea2384d3 bellard
    char check_bytes[4];
59 ff1afc72 bellard
} __attribute__((packed)) VMDK4Header;
60 ea2384d3 bellard
61 ea2384d3 bellard
#define L2_CACHE_SIZE 16
62 ea2384d3 bellard
63 b3976d3c Fam Zheng
typedef struct VmdkExtent {
64 b3976d3c Fam Zheng
    BlockDriverState *file;
65 b3976d3c Fam Zheng
    bool flat;
66 b3976d3c Fam Zheng
    int64_t sectors;
67 b3976d3c Fam Zheng
    int64_t end_sector;
68 ea2384d3 bellard
    int64_t l1_table_offset;
69 ff1afc72 bellard
    int64_t l1_backup_table_offset;
70 ea2384d3 bellard
    uint32_t *l1_table;
71 ff1afc72 bellard
    uint32_t *l1_backup_table;
72 ea2384d3 bellard
    unsigned int l1_size;
73 ea2384d3 bellard
    uint32_t l1_entry_sectors;
74 ea2384d3 bellard
75 ea2384d3 bellard
    unsigned int l2_size;
76 ea2384d3 bellard
    uint32_t *l2_cache;
77 ea2384d3 bellard
    uint32_t l2_cache_offsets[L2_CACHE_SIZE];
78 ea2384d3 bellard
    uint32_t l2_cache_counts[L2_CACHE_SIZE];
79 ea2384d3 bellard
80 ea2384d3 bellard
    unsigned int cluster_sectors;
81 b3976d3c Fam Zheng
} VmdkExtent;
82 b3976d3c Fam Zheng
83 b3976d3c Fam Zheng
typedef struct BDRVVmdkState {
84 5f4da8c0 ths
    uint32_t parent_cid;
85 b3976d3c Fam Zheng
    int num_extents;
86 b3976d3c Fam Zheng
    /* Extent array with num_extents entries, ascend ordered by address */
87 b3976d3c Fam Zheng
    VmdkExtent *extents;
88 ea2384d3 bellard
} BDRVVmdkState;
89 ea2384d3 bellard
90 630530a6 ths
typedef struct VmdkMetaData {
91 630530a6 ths
    uint32_t offset;
92 630530a6 ths
    unsigned int l1_index;
93 630530a6 ths
    unsigned int l2_index;
94 630530a6 ths
    unsigned int l2_offset;
95 630530a6 ths
    int valid;
96 630530a6 ths
} VmdkMetaData;
97 630530a6 ths
98 ea2384d3 bellard
static int vmdk_probe(const uint8_t *buf, int buf_size, const char *filename)
99 ea2384d3 bellard
{
100 ea2384d3 bellard
    uint32_t magic;
101 ea2384d3 bellard
102 ea2384d3 bellard
    if (buf_size < 4)
103 ea2384d3 bellard
        return 0;
104 ea2384d3 bellard
    magic = be32_to_cpu(*(uint32_t *)buf);
105 ea2384d3 bellard
    if (magic == VMDK3_MAGIC ||
106 01fc99d6 Fam Zheng
        magic == VMDK4_MAGIC) {
107 ea2384d3 bellard
        return 100;
108 01fc99d6 Fam Zheng
    } else {
109 01fc99d6 Fam Zheng
        const char *p = (const char *)buf;
110 01fc99d6 Fam Zheng
        const char *end = p + buf_size;
111 01fc99d6 Fam Zheng
        while (p < end) {
112 01fc99d6 Fam Zheng
            if (*p == '#') {
113 01fc99d6 Fam Zheng
                /* skip comment line */
114 01fc99d6 Fam Zheng
                while (p < end && *p != '\n') {
115 01fc99d6 Fam Zheng
                    p++;
116 01fc99d6 Fam Zheng
                }
117 01fc99d6 Fam Zheng
                p++;
118 01fc99d6 Fam Zheng
                continue;
119 01fc99d6 Fam Zheng
            }
120 01fc99d6 Fam Zheng
            if (*p == ' ') {
121 01fc99d6 Fam Zheng
                while (p < end && *p == ' ') {
122 01fc99d6 Fam Zheng
                    p++;
123 01fc99d6 Fam Zheng
                }
124 01fc99d6 Fam Zheng
                /* skip '\r' if windows line endings used. */
125 01fc99d6 Fam Zheng
                if (p < end && *p == '\r') {
126 01fc99d6 Fam Zheng
                    p++;
127 01fc99d6 Fam Zheng
                }
128 01fc99d6 Fam Zheng
                /* only accept blank lines before 'version=' line */
129 01fc99d6 Fam Zheng
                if (p == end || *p != '\n') {
130 01fc99d6 Fam Zheng
                    return 0;
131 01fc99d6 Fam Zheng
                }
132 01fc99d6 Fam Zheng
                p++;
133 01fc99d6 Fam Zheng
                continue;
134 01fc99d6 Fam Zheng
            }
135 01fc99d6 Fam Zheng
            if (end - p >= strlen("version=X\n")) {
136 01fc99d6 Fam Zheng
                if (strncmp("version=1\n", p, strlen("version=1\n")) == 0 ||
137 01fc99d6 Fam Zheng
                    strncmp("version=2\n", p, strlen("version=2\n")) == 0) {
138 01fc99d6 Fam Zheng
                    return 100;
139 01fc99d6 Fam Zheng
                }
140 01fc99d6 Fam Zheng
            }
141 01fc99d6 Fam Zheng
            if (end - p >= strlen("version=X\r\n")) {
142 01fc99d6 Fam Zheng
                if (strncmp("version=1\r\n", p, strlen("version=1\r\n")) == 0 ||
143 01fc99d6 Fam Zheng
                    strncmp("version=2\r\n", p, strlen("version=2\r\n")) == 0) {
144 01fc99d6 Fam Zheng
                    return 100;
145 01fc99d6 Fam Zheng
                }
146 01fc99d6 Fam Zheng
            }
147 01fc99d6 Fam Zheng
            return 0;
148 01fc99d6 Fam Zheng
        }
149 ea2384d3 bellard
        return 0;
150 01fc99d6 Fam Zheng
    }
151 ea2384d3 bellard
}
152 ea2384d3 bellard
153 5f4da8c0 ths
#define CHECK_CID 1
154 5f4da8c0 ths
155 3b46e624 ths
#define SECTOR_SIZE 512
156 5f4da8c0 ths
#define DESC_SIZE 20*SECTOR_SIZE        // 20 sectors of 512 bytes each
157 5fafdf24 ths
#define HEADER_SIZE 512                           // first sector of 512 bytes
158 5f4da8c0 ths
159 b3976d3c Fam Zheng
static void vmdk_free_extents(BlockDriverState *bs)
160 b3976d3c Fam Zheng
{
161 b3976d3c Fam Zheng
    int i;
162 b3976d3c Fam Zheng
    BDRVVmdkState *s = bs->opaque;
163 b3976d3c Fam Zheng
164 b3976d3c Fam Zheng
    for (i = 0; i < s->num_extents; i++) {
165 b3976d3c Fam Zheng
        qemu_free(s->extents[i].l1_table);
166 b3976d3c Fam Zheng
        qemu_free(s->extents[i].l2_cache);
167 b3976d3c Fam Zheng
        qemu_free(s->extents[i].l1_backup_table);
168 b3976d3c Fam Zheng
    }
169 b3976d3c Fam Zheng
    qemu_free(s->extents);
170 b3976d3c Fam Zheng
}
171 b3976d3c Fam Zheng
172 5f4da8c0 ths
static uint32_t vmdk_read_cid(BlockDriverState *bs, int parent)
173 ea2384d3 bellard
{
174 5f4da8c0 ths
    char desc[DESC_SIZE];
175 5f4da8c0 ths
    uint32_t cid;
176 7ccfb2eb blueswir1
    const char *p_name, *cid_str;
177 5f4da8c0 ths
    size_t cid_str_size;
178 5f4da8c0 ths
179 5f4da8c0 ths
    /* the descriptor offset = 0x200 */
180 6511ef77 Kevin Wolf
    if (bdrv_pread(bs->file, 0x200, desc, DESC_SIZE) != DESC_SIZE)
181 5f4da8c0 ths
        return 0;
182 5f4da8c0 ths
183 5f4da8c0 ths
    if (parent) {
184 5f4da8c0 ths
        cid_str = "parentCID";
185 5f4da8c0 ths
        cid_str_size = sizeof("parentCID");
186 5f4da8c0 ths
    } else {
187 5f4da8c0 ths
        cid_str = "CID";
188 5f4da8c0 ths
        cid_str_size = sizeof("CID");
189 5f4da8c0 ths
    }
190 5f4da8c0 ths
191 511d2b14 blueswir1
    if ((p_name = strstr(desc,cid_str)) != NULL) {
192 5f4da8c0 ths
        p_name += cid_str_size;
193 5f4da8c0 ths
        sscanf(p_name,"%x",&cid);
194 5f4da8c0 ths
    }
195 5f4da8c0 ths
196 5f4da8c0 ths
    return cid;
197 5f4da8c0 ths
}
198 5f4da8c0 ths
199 5f4da8c0 ths
static int vmdk_write_cid(BlockDriverState *bs, uint32_t cid)
200 5f4da8c0 ths
{
201 5f4da8c0 ths
    char desc[DESC_SIZE], tmp_desc[DESC_SIZE];
202 5f4da8c0 ths
    char *p_name, *tmp_str;
203 5f4da8c0 ths
204 5f4da8c0 ths
    /* the descriptor offset = 0x200 */
205 6511ef77 Kevin Wolf
    if (bdrv_pread(bs->file, 0x200, desc, DESC_SIZE) != DESC_SIZE)
206 5f4da8c0 ths
        return -1;
207 5f4da8c0 ths
208 5f4da8c0 ths
    tmp_str = strstr(desc,"parentCID");
209 363a37d5 blueswir1
    pstrcpy(tmp_desc, sizeof(tmp_desc), tmp_str);
210 511d2b14 blueswir1
    if ((p_name = strstr(desc,"CID")) != NULL) {
211 5f4da8c0 ths
        p_name += sizeof("CID");
212 363a37d5 blueswir1
        snprintf(p_name, sizeof(desc) - (p_name - desc), "%x\n", cid);
213 363a37d5 blueswir1
        pstrcat(desc, sizeof(desc), tmp_desc);
214 5f4da8c0 ths
    }
215 5f4da8c0 ths
216 b8852e87 Kevin Wolf
    if (bdrv_pwrite_sync(bs->file, 0x200, desc, DESC_SIZE) < 0)
217 5f4da8c0 ths
        return -1;
218 5f4da8c0 ths
    return 0;
219 5f4da8c0 ths
}
220 5f4da8c0 ths
221 5f4da8c0 ths
static int vmdk_is_cid_valid(BlockDriverState *bs)
222 5f4da8c0 ths
{
223 5f4da8c0 ths
#ifdef CHECK_CID
224 5f4da8c0 ths
    BDRVVmdkState *s = bs->opaque;
225 b171271a Kevin Wolf
    BlockDriverState *p_bs = bs->backing_hd;
226 5f4da8c0 ths
    uint32_t cur_pcid;
227 5f4da8c0 ths
228 5f4da8c0 ths
    if (p_bs) {
229 5f4da8c0 ths
        cur_pcid = vmdk_read_cid(p_bs,0);
230 5f4da8c0 ths
        if (s->parent_cid != cur_pcid)
231 5f4da8c0 ths
            // CID not valid
232 5f4da8c0 ths
            return 0;
233 5f4da8c0 ths
    }
234 5f4da8c0 ths
#endif
235 5f4da8c0 ths
    // CID valid
236 5f4da8c0 ths
    return 1;
237 5f4da8c0 ths
}
238 5f4da8c0 ths
239 5f4da8c0 ths
static int vmdk_snapshot_create(const char *filename, const char *backing_file)
240 5f4da8c0 ths
{
241 5f4da8c0 ths
    int snp_fd, p_fd;
242 53c2e716 Juan Quintela
    int ret;
243 5f4da8c0 ths
    uint32_t p_cid;
244 5fafdf24 ths
    char *p_name, *gd_buf, *rgd_buf;
245 5f4da8c0 ths
    const char *real_filename, *temp_str;
246 5f4da8c0 ths
    VMDK4Header header;
247 5f4da8c0 ths
    uint32_t gde_entries, gd_size;
248 5f4da8c0 ths
    int64_t gd_offset, rgd_offset, capacity, gt_size;
249 5f4da8c0 ths
    char p_desc[DESC_SIZE], s_desc[DESC_SIZE], hdr[HEADER_SIZE];
250 7ccfb2eb blueswir1
    static const char desc_template[] =
251 5f4da8c0 ths
    "# Disk DescriptorFile\n"
252 5f4da8c0 ths
    "version=1\n"
253 5f4da8c0 ths
    "CID=%x\n"
254 5f4da8c0 ths
    "parentCID=%x\n"
255 5f4da8c0 ths
    "createType=\"monolithicSparse\"\n"
256 5f4da8c0 ths
    "parentFileNameHint=\"%s\"\n"
257 5f4da8c0 ths
    "\n"
258 5f4da8c0 ths
    "# Extent description\n"
259 7ccfb2eb blueswir1
    "RW %u SPARSE \"%s\"\n"
260 5f4da8c0 ths
    "\n"
261 5f4da8c0 ths
    "# The Disk Data Base \n"
262 5f4da8c0 ths
    "#DDB\n"
263 5f4da8c0 ths
    "\n";
264 5f4da8c0 ths
265 5f4da8c0 ths
    snp_fd = open(filename, O_RDWR | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE, 0644);
266 5f4da8c0 ths
    if (snp_fd < 0)
267 53c2e716 Juan Quintela
        return -errno;
268 5f4da8c0 ths
    p_fd = open(backing_file, O_RDONLY | O_BINARY | O_LARGEFILE);
269 5f4da8c0 ths
    if (p_fd < 0) {
270 5f4da8c0 ths
        close(snp_fd);
271 53c2e716 Juan Quintela
        return -errno;
272 5f4da8c0 ths
    }
273 5f4da8c0 ths
274 5f4da8c0 ths
    /* read the header */
275 53c2e716 Juan Quintela
    if (lseek(p_fd, 0x0, SEEK_SET) == -1) {
276 53c2e716 Juan Quintela
        ret = -errno;
277 5f4da8c0 ths
        goto fail;
278 53c2e716 Juan Quintela
    }
279 53c2e716 Juan Quintela
    if (read(p_fd, hdr, HEADER_SIZE) != HEADER_SIZE) {
280 53c2e716 Juan Quintela
        ret = -errno;
281 5f4da8c0 ths
        goto fail;
282 53c2e716 Juan Quintela
    }
283 5f4da8c0 ths
284 5f4da8c0 ths
    /* write the header */
285 53c2e716 Juan Quintela
    if (lseek(snp_fd, 0x0, SEEK_SET) == -1) {
286 53c2e716 Juan Quintela
        ret = -errno;
287 5f4da8c0 ths
        goto fail;
288 53c2e716 Juan Quintela
    }
289 53c2e716 Juan Quintela
    if (write(snp_fd, hdr, HEADER_SIZE) == -1) {
290 53c2e716 Juan Quintela
        ret = -errno;
291 5f4da8c0 ths
        goto fail;
292 53c2e716 Juan Quintela
    }
293 5f4da8c0 ths
294 5f4da8c0 ths
    memset(&header, 0, sizeof(header));
295 5f4da8c0 ths
    memcpy(&header,&hdr[4], sizeof(header)); // skip the VMDK4_MAGIC
296 5f4da8c0 ths
297 53c2e716 Juan Quintela
    if (ftruncate(snp_fd, header.grain_offset << 9)) {
298 53c2e716 Juan Quintela
        ret = -errno;
299 1640366c Kirill A. Shutemov
        goto fail;
300 53c2e716 Juan Quintela
    }
301 5f4da8c0 ths
    /* the descriptor offset = 0x200 */
302 53c2e716 Juan Quintela
    if (lseek(p_fd, 0x200, SEEK_SET) == -1) {
303 53c2e716 Juan Quintela
        ret = -errno;
304 5f4da8c0 ths
        goto fail;
305 53c2e716 Juan Quintela
    }
306 53c2e716 Juan Quintela
    if (read(p_fd, p_desc, DESC_SIZE) != DESC_SIZE) {
307 53c2e716 Juan Quintela
        ret = -errno;
308 5f4da8c0 ths
        goto fail;
309 53c2e716 Juan Quintela
    }
310 5f4da8c0 ths
311 511d2b14 blueswir1
    if ((p_name = strstr(p_desc,"CID")) != NULL) {
312 5f4da8c0 ths
        p_name += sizeof("CID");
313 5f4da8c0 ths
        sscanf(p_name,"%x",&p_cid);
314 5f4da8c0 ths
    }
315 5f4da8c0 ths
316 5f4da8c0 ths
    real_filename = filename;
317 5f4da8c0 ths
    if ((temp_str = strrchr(real_filename, '\\')) != NULL)
318 5f4da8c0 ths
        real_filename = temp_str + 1;
319 5f4da8c0 ths
    if ((temp_str = strrchr(real_filename, '/')) != NULL)
320 5f4da8c0 ths
        real_filename = temp_str + 1;
321 5f4da8c0 ths
    if ((temp_str = strrchr(real_filename, ':')) != NULL)
322 5f4da8c0 ths
        real_filename = temp_str + 1;
323 5f4da8c0 ths
324 363a37d5 blueswir1
    snprintf(s_desc, sizeof(s_desc), desc_template, p_cid, p_cid, backing_file,
325 363a37d5 blueswir1
             (uint32_t)header.capacity, real_filename);
326 5f4da8c0 ths
327 5f4da8c0 ths
    /* write the descriptor */
328 53c2e716 Juan Quintela
    if (lseek(snp_fd, 0x200, SEEK_SET) == -1) {
329 53c2e716 Juan Quintela
        ret = -errno;
330 5f4da8c0 ths
        goto fail;
331 53c2e716 Juan Quintela
    }
332 53c2e716 Juan Quintela
    if (write(snp_fd, s_desc, strlen(s_desc)) == -1) {
333 53c2e716 Juan Quintela
        ret = -errno;
334 5f4da8c0 ths
        goto fail;
335 53c2e716 Juan Quintela
    }
336 ea2384d3 bellard
337 5f4da8c0 ths
    gd_offset = header.gd_offset * SECTOR_SIZE;     // offset of GD table
338 5f4da8c0 ths
    rgd_offset = header.rgd_offset * SECTOR_SIZE;   // offset of RGD table
339 5f4da8c0 ths
    capacity = header.capacity * SECTOR_SIZE;       // Extent size
340 5f4da8c0 ths
    /*
341 5f4da8c0 ths
     * Each GDE span 32M disk, means:
342 5f4da8c0 ths
     * 512 GTE per GT, each GTE points to grain
343 5f4da8c0 ths
     */
344 5f4da8c0 ths
    gt_size = (int64_t)header.num_gtes_per_gte * header.granularity * SECTOR_SIZE;
345 53c2e716 Juan Quintela
    if (!gt_size) {
346 53c2e716 Juan Quintela
        ret = -EINVAL;
347 5f4da8c0 ths
        goto fail;
348 53c2e716 Juan Quintela
    }
349 5fafdf24 ths
    gde_entries = (uint32_t)(capacity / gt_size);  // number of gde/rgde
350 5f4da8c0 ths
    gd_size = gde_entries * sizeof(uint32_t);
351 5f4da8c0 ths
352 5f4da8c0 ths
    /* write RGD */
353 5f4da8c0 ths
    rgd_buf = qemu_malloc(gd_size);
354 53c2e716 Juan Quintela
    if (lseek(p_fd, rgd_offset, SEEK_SET) == -1) {
355 53c2e716 Juan Quintela
        ret = -errno;
356 5f4da8c0 ths
        goto fail_rgd;
357 53c2e716 Juan Quintela
    }
358 53c2e716 Juan Quintela
    if (read(p_fd, rgd_buf, gd_size) != gd_size) {
359 53c2e716 Juan Quintela
        ret = -errno;
360 5f4da8c0 ths
        goto fail_rgd;
361 53c2e716 Juan Quintela
    }
362 53c2e716 Juan Quintela
    if (lseek(snp_fd, rgd_offset, SEEK_SET) == -1) {
363 53c2e716 Juan Quintela
        ret = -errno;
364 5f4da8c0 ths
        goto fail_rgd;
365 53c2e716 Juan Quintela
    }
366 53c2e716 Juan Quintela
    if (write(snp_fd, rgd_buf, gd_size) == -1) {
367 53c2e716 Juan Quintela
        ret = -errno;
368 5f4da8c0 ths
        goto fail_rgd;
369 53c2e716 Juan Quintela
    }
370 5f4da8c0 ths
371 5f4da8c0 ths
    /* write GD */
372 5f4da8c0 ths
    gd_buf = qemu_malloc(gd_size);
373 53c2e716 Juan Quintela
    if (lseek(p_fd, gd_offset, SEEK_SET) == -1) {
374 53c2e716 Juan Quintela
        ret = -errno;
375 5f4da8c0 ths
        goto fail_gd;
376 53c2e716 Juan Quintela
    }
377 53c2e716 Juan Quintela
    if (read(p_fd, gd_buf, gd_size) != gd_size) {
378 53c2e716 Juan Quintela
        ret = -errno;
379 5f4da8c0 ths
        goto fail_gd;
380 53c2e716 Juan Quintela
    }
381 53c2e716 Juan Quintela
    if (lseek(snp_fd, gd_offset, SEEK_SET) == -1) {
382 53c2e716 Juan Quintela
        ret = -errno;
383 5f4da8c0 ths
        goto fail_gd;
384 53c2e716 Juan Quintela
    }
385 53c2e716 Juan Quintela
    if (write(snp_fd, gd_buf, gd_size) == -1) {
386 53c2e716 Juan Quintela
        ret = -errno;
387 5f4da8c0 ths
        goto fail_gd;
388 53c2e716 Juan Quintela
    }
389 3829cb46 Juan Quintela
    ret = 0;
390 5f4da8c0 ths
391 3829cb46 Juan Quintela
fail_gd:
392 5f4da8c0 ths
    qemu_free(gd_buf);
393 3829cb46 Juan Quintela
fail_rgd:
394 5f4da8c0 ths
    qemu_free(rgd_buf);
395 3829cb46 Juan Quintela
fail:
396 5f4da8c0 ths
    close(p_fd);
397 5f4da8c0 ths
    close(snp_fd);
398 53c2e716 Juan Quintela
    return ret;
399 5f4da8c0 ths
}
400 5f4da8c0 ths
401 9949f97e Kevin Wolf
static int vmdk_parent_open(BlockDriverState *bs)
402 5f4da8c0 ths
{
403 5fafdf24 ths
    char *p_name;
404 5f4da8c0 ths
    char desc[DESC_SIZE];
405 5f4da8c0 ths
406 5f4da8c0 ths
    /* the descriptor offset = 0x200 */
407 6511ef77 Kevin Wolf
    if (bdrv_pread(bs->file, 0x200, desc, DESC_SIZE) != DESC_SIZE)
408 5f4da8c0 ths
        return -1;
409 5f4da8c0 ths
410 511d2b14 blueswir1
    if ((p_name = strstr(desc,"parentFileNameHint")) != NULL) {
411 5f4da8c0 ths
        char *end_name;
412 5f4da8c0 ths
413 5f4da8c0 ths
        p_name += sizeof("parentFileNameHint") + 1;
414 511d2b14 blueswir1
        if ((end_name = strchr(p_name,'\"')) == NULL)
415 5f4da8c0 ths
            return -1;
416 b171271a Kevin Wolf
        if ((end_name - p_name) > sizeof (bs->backing_file) - 1)
417 b34d259a balrog
            return -1;
418 3b46e624 ths
419 b171271a Kevin Wolf
        pstrcpy(bs->backing_file, end_name - p_name + 1, p_name);
420 ff1afc72 bellard
    }
421 5f4da8c0 ths
422 5f4da8c0 ths
    return 0;
423 5f4da8c0 ths
}
424 5f4da8c0 ths
425 b3976d3c Fam Zheng
/* Create and append extent to the extent array. Return the added VmdkExtent
426 b3976d3c Fam Zheng
 * address. return NULL if allocation failed. */
427 b3976d3c Fam Zheng
static VmdkExtent *vmdk_add_extent(BlockDriverState *bs,
428 b3976d3c Fam Zheng
                           BlockDriverState *file, bool flat, int64_t sectors,
429 b3976d3c Fam Zheng
                           int64_t l1_offset, int64_t l1_backup_offset,
430 b3976d3c Fam Zheng
                           uint32_t l1_size,
431 b3976d3c Fam Zheng
                           int l2_size, unsigned int cluster_sectors)
432 b3976d3c Fam Zheng
{
433 b3976d3c Fam Zheng
    VmdkExtent *extent;
434 b3976d3c Fam Zheng
    BDRVVmdkState *s = bs->opaque;
435 b3976d3c Fam Zheng
436 b3976d3c Fam Zheng
    s->extents = qemu_realloc(s->extents,
437 b3976d3c Fam Zheng
                              (s->num_extents + 1) * sizeof(VmdkExtent));
438 b3976d3c Fam Zheng
    extent = &s->extents[s->num_extents];
439 b3976d3c Fam Zheng
    s->num_extents++;
440 b3976d3c Fam Zheng
441 b3976d3c Fam Zheng
    memset(extent, 0, sizeof(VmdkExtent));
442 b3976d3c Fam Zheng
    extent->file = file;
443 b3976d3c Fam Zheng
    extent->flat = flat;
444 b3976d3c Fam Zheng
    extent->sectors = sectors;
445 b3976d3c Fam Zheng
    extent->l1_table_offset = l1_offset;
446 b3976d3c Fam Zheng
    extent->l1_backup_table_offset = l1_backup_offset;
447 b3976d3c Fam Zheng
    extent->l1_size = l1_size;
448 b3976d3c Fam Zheng
    extent->l1_entry_sectors = l2_size * cluster_sectors;
449 b3976d3c Fam Zheng
    extent->l2_size = l2_size;
450 b3976d3c Fam Zheng
    extent->cluster_sectors = cluster_sectors;
451 b3976d3c Fam Zheng
452 b3976d3c Fam Zheng
    if (s->num_extents > 1) {
453 b3976d3c Fam Zheng
        extent->end_sector = (*(extent - 1)).end_sector + extent->sectors;
454 b3976d3c Fam Zheng
    } else {
455 b3976d3c Fam Zheng
        extent->end_sector = extent->sectors;
456 b3976d3c Fam Zheng
    }
457 b3976d3c Fam Zheng
    bs->total_sectors = extent->end_sector;
458 b3976d3c Fam Zheng
    return extent;
459 b3976d3c Fam Zheng
}
460 b3976d3c Fam Zheng
461 b4b3ab14 Fam Zheng
static int vmdk_init_tables(BlockDriverState *bs, VmdkExtent *extent)
462 5f4da8c0 ths
{
463 b4b3ab14 Fam Zheng
    int ret;
464 b4b3ab14 Fam Zheng
    int l1_size, i;
465 5f4da8c0 ths
466 ea2384d3 bellard
    /* read the L1 table */
467 b3976d3c Fam Zheng
    l1_size = extent->l1_size * sizeof(uint32_t);
468 b3976d3c Fam Zheng
    extent->l1_table = qemu_malloc(l1_size);
469 b4b3ab14 Fam Zheng
    ret = bdrv_pread(extent->file,
470 b4b3ab14 Fam Zheng
                    extent->l1_table_offset,
471 b4b3ab14 Fam Zheng
                    extent->l1_table,
472 b4b3ab14 Fam Zheng
                    l1_size);
473 b4b3ab14 Fam Zheng
    if (ret < 0) {
474 b4b3ab14 Fam Zheng
        goto fail_l1;
475 b3976d3c Fam Zheng
    }
476 b3976d3c Fam Zheng
    for (i = 0; i < extent->l1_size; i++) {
477 b3976d3c Fam Zheng
        le32_to_cpus(&extent->l1_table[i]);
478 ea2384d3 bellard
    }
479 ea2384d3 bellard
480 b3976d3c Fam Zheng
    if (extent->l1_backup_table_offset) {
481 b3976d3c Fam Zheng
        extent->l1_backup_table = qemu_malloc(l1_size);
482 b4b3ab14 Fam Zheng
        ret = bdrv_pread(extent->file,
483 b4b3ab14 Fam Zheng
                        extent->l1_backup_table_offset,
484 b4b3ab14 Fam Zheng
                        extent->l1_backup_table,
485 b4b3ab14 Fam Zheng
                        l1_size);
486 b4b3ab14 Fam Zheng
        if (ret < 0) {
487 b4b3ab14 Fam Zheng
            goto fail_l1b;
488 b3976d3c Fam Zheng
        }
489 b3976d3c Fam Zheng
        for (i = 0; i < extent->l1_size; i++) {
490 b3976d3c Fam Zheng
            le32_to_cpus(&extent->l1_backup_table[i]);
491 ff1afc72 bellard
        }
492 ff1afc72 bellard
    }
493 ff1afc72 bellard
494 b3976d3c Fam Zheng
    extent->l2_cache =
495 b3976d3c Fam Zheng
        qemu_malloc(extent->l2_size * L2_CACHE_SIZE * sizeof(uint32_t));
496 ea2384d3 bellard
    return 0;
497 b4b3ab14 Fam Zheng
 fail_l1b:
498 b4b3ab14 Fam Zheng
    qemu_free(extent->l1_backup_table);
499 b4b3ab14 Fam Zheng
 fail_l1:
500 b4b3ab14 Fam Zheng
    qemu_free(extent->l1_table);
501 b4b3ab14 Fam Zheng
    return ret;
502 b4b3ab14 Fam Zheng
}
503 b4b3ab14 Fam Zheng
504 b4b3ab14 Fam Zheng
static int vmdk_open_vmdk3(BlockDriverState *bs, int flags)
505 b4b3ab14 Fam Zheng
{
506 b4b3ab14 Fam Zheng
    int ret;
507 b4b3ab14 Fam Zheng
    uint32_t magic;
508 b4b3ab14 Fam Zheng
    VMDK3Header header;
509 b4b3ab14 Fam Zheng
    VmdkExtent *extent;
510 b4b3ab14 Fam Zheng
511 b4b3ab14 Fam Zheng
    ret = bdrv_pread(bs->file, sizeof(magic), &header, sizeof(header));
512 b4b3ab14 Fam Zheng
    if (ret < 0) {
513 b4b3ab14 Fam Zheng
        goto fail;
514 b4b3ab14 Fam Zheng
    }
515 b4b3ab14 Fam Zheng
    extent = vmdk_add_extent(bs,
516 b4b3ab14 Fam Zheng
                             bs->file, false,
517 b4b3ab14 Fam Zheng
                             le32_to_cpu(header.disk_sectors),
518 b4b3ab14 Fam Zheng
                             le32_to_cpu(header.l1dir_offset) << 9,
519 b4b3ab14 Fam Zheng
                             0, 1 << 6, 1 << 9,
520 b4b3ab14 Fam Zheng
                             le32_to_cpu(header.granularity));
521 b4b3ab14 Fam Zheng
    ret = vmdk_init_tables(bs, extent);
522 b4b3ab14 Fam Zheng
    if (ret) {
523 b4b3ab14 Fam Zheng
        /* vmdk_init_tables cleans up on fail, so only free allocation of
524 b4b3ab14 Fam Zheng
         * vmdk_add_extent here. */
525 b4b3ab14 Fam Zheng
        goto fail;
526 b4b3ab14 Fam Zheng
    }
527 b4b3ab14 Fam Zheng
    return 0;
528 ea2384d3 bellard
 fail:
529 b3976d3c Fam Zheng
    vmdk_free_extents(bs);
530 b4b3ab14 Fam Zheng
    return ret;
531 b4b3ab14 Fam Zheng
}
532 b4b3ab14 Fam Zheng
533 b4b3ab14 Fam Zheng
static int vmdk_open_vmdk4(BlockDriverState *bs, int flags)
534 b4b3ab14 Fam Zheng
{
535 b4b3ab14 Fam Zheng
    int ret;
536 b4b3ab14 Fam Zheng
    uint32_t magic;
537 b4b3ab14 Fam Zheng
    uint32_t l1_size, l1_entry_sectors;
538 b4b3ab14 Fam Zheng
    VMDK4Header header;
539 b4b3ab14 Fam Zheng
    BDRVVmdkState *s = bs->opaque;
540 b4b3ab14 Fam Zheng
    VmdkExtent *extent;
541 b4b3ab14 Fam Zheng
542 b4b3ab14 Fam Zheng
    ret = bdrv_pread(bs->file, sizeof(magic), &header, sizeof(header));
543 b4b3ab14 Fam Zheng
    if (ret < 0) {
544 b4b3ab14 Fam Zheng
        goto fail;
545 b4b3ab14 Fam Zheng
    }
546 b4b3ab14 Fam Zheng
    l1_entry_sectors = le32_to_cpu(header.num_gtes_per_gte)
547 b4b3ab14 Fam Zheng
                        * le64_to_cpu(header.granularity);
548 b4b3ab14 Fam Zheng
    l1_size = (le64_to_cpu(header.capacity) + l1_entry_sectors - 1)
549 b4b3ab14 Fam Zheng
                / l1_entry_sectors;
550 b4b3ab14 Fam Zheng
    extent = vmdk_add_extent(bs, bs->file, false,
551 b4b3ab14 Fam Zheng
                          le64_to_cpu(header.capacity),
552 b4b3ab14 Fam Zheng
                          le64_to_cpu(header.gd_offset) << 9,
553 b4b3ab14 Fam Zheng
                          le64_to_cpu(header.rgd_offset) << 9,
554 b4b3ab14 Fam Zheng
                          l1_size,
555 b4b3ab14 Fam Zheng
                          le32_to_cpu(header.num_gtes_per_gte),
556 b4b3ab14 Fam Zheng
                          le64_to_cpu(header.granularity));
557 b4b3ab14 Fam Zheng
    if (extent->l1_entry_sectors <= 0) {
558 b4b3ab14 Fam Zheng
        ret = -EINVAL;
559 b4b3ab14 Fam Zheng
        goto fail;
560 b4b3ab14 Fam Zheng
    }
561 b4b3ab14 Fam Zheng
    /* try to open parent images, if exist */
562 b4b3ab14 Fam Zheng
    ret = vmdk_parent_open(bs);
563 b4b3ab14 Fam Zheng
    if (ret) {
564 b4b3ab14 Fam Zheng
        goto fail;
565 b4b3ab14 Fam Zheng
    }
566 b4b3ab14 Fam Zheng
    s->parent_cid = vmdk_read_cid(bs, 1);
567 b4b3ab14 Fam Zheng
    ret = vmdk_init_tables(bs, extent);
568 b4b3ab14 Fam Zheng
    if (ret) {
569 b4b3ab14 Fam Zheng
        goto fail;
570 b4b3ab14 Fam Zheng
    }
571 b4b3ab14 Fam Zheng
    return 0;
572 b4b3ab14 Fam Zheng
 fail:
573 b4b3ab14 Fam Zheng
    vmdk_free_extents(bs);
574 b4b3ab14 Fam Zheng
    return ret;
575 b4b3ab14 Fam Zheng
}
576 b4b3ab14 Fam Zheng
577 b4b3ab14 Fam Zheng
static int vmdk_open(BlockDriverState *bs, int flags)
578 b4b3ab14 Fam Zheng
{
579 b4b3ab14 Fam Zheng
    uint32_t magic;
580 b4b3ab14 Fam Zheng
581 b4b3ab14 Fam Zheng
    if (bdrv_pread(bs->file, 0, &magic, sizeof(magic)) != sizeof(magic)) {
582 b4b3ab14 Fam Zheng
        return -EIO;
583 b4b3ab14 Fam Zheng
    }
584 b4b3ab14 Fam Zheng
585 b4b3ab14 Fam Zheng
    magic = be32_to_cpu(magic);
586 b4b3ab14 Fam Zheng
    if (magic == VMDK3_MAGIC) {
587 b4b3ab14 Fam Zheng
        return vmdk_open_vmdk3(bs, flags);
588 b4b3ab14 Fam Zheng
    } else if (magic == VMDK4_MAGIC) {
589 b4b3ab14 Fam Zheng
        return vmdk_open_vmdk4(bs, flags);
590 b4b3ab14 Fam Zheng
    } else {
591 b4b3ab14 Fam Zheng
        return -EINVAL;
592 b4b3ab14 Fam Zheng
    }
593 ea2384d3 bellard
}
594 ea2384d3 bellard
595 b3976d3c Fam Zheng
static int get_whole_cluster(BlockDriverState *bs,
596 b3976d3c Fam Zheng
                VmdkExtent *extent,
597 b3976d3c Fam Zheng
                uint64_t cluster_offset,
598 b3976d3c Fam Zheng
                uint64_t offset,
599 b3976d3c Fam Zheng
                bool allocate)
600 5f4da8c0 ths
{
601 b3976d3c Fam Zheng
    /* 128 sectors * 512 bytes each = grain size 64KB */
602 b3976d3c Fam Zheng
    uint8_t  whole_grain[extent->cluster_sectors * 512];
603 5f4da8c0 ths
604 0e69c543 Fam Zheng
    /* we will be here if it's first write on non-exist grain(cluster).
605 0e69c543 Fam Zheng
     * try to read from parent image, if exist */
606 b171271a Kevin Wolf
    if (bs->backing_hd) {
607 c336500d Kevin Wolf
        int ret;
608 5f4da8c0 ths
609 5f4da8c0 ths
        if (!vmdk_is_cid_valid(bs))
610 5f4da8c0 ths
            return -1;
611 5f4da8c0 ths
612 0e69c543 Fam Zheng
        /* floor offset to cluster */
613 0e69c543 Fam Zheng
        offset -= offset % (extent->cluster_sectors * 512);
614 c336500d Kevin Wolf
        ret = bdrv_read(bs->backing_hd, offset >> 9, whole_grain,
615 b3976d3c Fam Zheng
                extent->cluster_sectors);
616 c336500d Kevin Wolf
        if (ret < 0) {
617 c336500d Kevin Wolf
            return -1;
618 c336500d Kevin Wolf
        }
619 630530a6 ths
620 0e69c543 Fam Zheng
        /* Write grain only into the active image */
621 b3976d3c Fam Zheng
        ret = bdrv_write(extent->file, cluster_offset, whole_grain,
622 b3976d3c Fam Zheng
                extent->cluster_sectors);
623 c336500d Kevin Wolf
        if (ret < 0) {
624 c336500d Kevin Wolf
            return -1;
625 630530a6 ths
        }
626 630530a6 ths
    }
627 630530a6 ths
    return 0;
628 630530a6 ths
}
629 630530a6 ths
630 b3976d3c Fam Zheng
static int vmdk_L2update(VmdkExtent *extent, VmdkMetaData *m_data)
631 630530a6 ths
{
632 630530a6 ths
    /* update L2 table */
633 b3976d3c Fam Zheng
    if (bdrv_pwrite_sync(
634 b3976d3c Fam Zheng
                extent->file,
635 b3976d3c Fam Zheng
                ((int64_t)m_data->l2_offset * 512)
636 b3976d3c Fam Zheng
                    + (m_data->l2_index * sizeof(m_data->offset)),
637 b3976d3c Fam Zheng
                &(m_data->offset),
638 b3976d3c Fam Zheng
                sizeof(m_data->offset)
639 b3976d3c Fam Zheng
            ) < 0) {
640 630530a6 ths
        return -1;
641 b3976d3c Fam Zheng
    }
642 630530a6 ths
    /* update backup L2 table */
643 b3976d3c Fam Zheng
    if (extent->l1_backup_table_offset != 0) {
644 b3976d3c Fam Zheng
        m_data->l2_offset = extent->l1_backup_table[m_data->l1_index];
645 b3976d3c Fam Zheng
        if (bdrv_pwrite_sync(
646 b3976d3c Fam Zheng
                    extent->file,
647 b3976d3c Fam Zheng
                    ((int64_t)m_data->l2_offset * 512)
648 b3976d3c Fam Zheng
                        + (m_data->l2_index * sizeof(m_data->offset)),
649 b3976d3c Fam Zheng
                    &(m_data->offset), sizeof(m_data->offset)
650 b3976d3c Fam Zheng
                ) < 0) {
651 5f4da8c0 ths
            return -1;
652 b3976d3c Fam Zheng
        }
653 5f4da8c0 ths
    }
654 630530a6 ths
655 5f4da8c0 ths
    return 0;
656 5f4da8c0 ths
}
657 5f4da8c0 ths
658 b3976d3c Fam Zheng
static uint64_t get_cluster_offset(BlockDriverState *bs,
659 b3976d3c Fam Zheng
                                    VmdkExtent *extent,
660 b3976d3c Fam Zheng
                                    VmdkMetaData *m_data,
661 b3976d3c Fam Zheng
                                    uint64_t offset, int allocate)
662 ea2384d3 bellard
{
663 ea2384d3 bellard
    unsigned int l1_index, l2_offset, l2_index;
664 ea2384d3 bellard
    int min_index, i, j;
665 630530a6 ths
    uint32_t min_count, *l2_table, tmp = 0;
666 ea2384d3 bellard
    uint64_t cluster_offset;
667 630530a6 ths
668 630530a6 ths
    if (m_data)
669 630530a6 ths
        m_data->valid = 0;
670 630530a6 ths
671 b3976d3c Fam Zheng
    l1_index = (offset >> 9) / extent->l1_entry_sectors;
672 b3976d3c Fam Zheng
    if (l1_index >= extent->l1_size) {
673 ea2384d3 bellard
        return 0;
674 b3976d3c Fam Zheng
    }
675 b3976d3c Fam Zheng
    l2_offset = extent->l1_table[l1_index];
676 b3976d3c Fam Zheng
    if (!l2_offset) {
677 ea2384d3 bellard
        return 0;
678 b3976d3c Fam Zheng
    }
679 b4b3ab14 Fam Zheng
    for (i = 0; i < L2_CACHE_SIZE; i++) {
680 b3976d3c Fam Zheng
        if (l2_offset == extent->l2_cache_offsets[i]) {
681 ea2384d3 bellard
            /* increment the hit count */
682 b3976d3c Fam Zheng
            if (++extent->l2_cache_counts[i] == 0xffffffff) {
683 b4b3ab14 Fam Zheng
                for (j = 0; j < L2_CACHE_SIZE; j++) {
684 b3976d3c Fam Zheng
                    extent->l2_cache_counts[j] >>= 1;
685 ea2384d3 bellard
                }
686 ea2384d3 bellard
            }
687 b3976d3c Fam Zheng
            l2_table = extent->l2_cache + (i * extent->l2_size);
688 ea2384d3 bellard
            goto found;
689 ea2384d3 bellard
        }
690 ea2384d3 bellard
    }
691 ea2384d3 bellard
    /* not found: load a new entry in the least used one */
692 ea2384d3 bellard
    min_index = 0;
693 ea2384d3 bellard
    min_count = 0xffffffff;
694 b4b3ab14 Fam Zheng
    for (i = 0; i < L2_CACHE_SIZE; i++) {
695 b3976d3c Fam Zheng
        if (extent->l2_cache_counts[i] < min_count) {
696 b3976d3c Fam Zheng
            min_count = extent->l2_cache_counts[i];
697 ea2384d3 bellard
            min_index = i;
698 ea2384d3 bellard
        }
699 ea2384d3 bellard
    }
700 b3976d3c Fam Zheng
    l2_table = extent->l2_cache + (min_index * extent->l2_size);
701 b3976d3c Fam Zheng
    if (bdrv_pread(
702 b3976d3c Fam Zheng
                extent->file,
703 b3976d3c Fam Zheng
                (int64_t)l2_offset * 512,
704 b3976d3c Fam Zheng
                l2_table,
705 b3976d3c Fam Zheng
                extent->l2_size * sizeof(uint32_t)
706 b3976d3c Fam Zheng
            ) != extent->l2_size * sizeof(uint32_t)) {
707 ea2384d3 bellard
        return 0;
708 b3976d3c Fam Zheng
    }
709 5f4da8c0 ths
710 b3976d3c Fam Zheng
    extent->l2_cache_offsets[min_index] = l2_offset;
711 b3976d3c Fam Zheng
    extent->l2_cache_counts[min_index] = 1;
712 ea2384d3 bellard
 found:
713 b3976d3c Fam Zheng
    l2_index = ((offset >> 9) / extent->cluster_sectors) % extent->l2_size;
714 ea2384d3 bellard
    cluster_offset = le32_to_cpu(l2_table[l2_index]);
715 630530a6 ths
716 ff1afc72 bellard
    if (!cluster_offset) {
717 ff1afc72 bellard
        if (!allocate)
718 ff1afc72 bellard
            return 0;
719 9949f97e Kevin Wolf
720 630530a6 ths
        // Avoid the L2 tables update for the images that have snapshots.
721 b3976d3c Fam Zheng
        cluster_offset = bdrv_getlength(extent->file);
722 b3976d3c Fam Zheng
        bdrv_truncate(
723 b3976d3c Fam Zheng
            extent->file,
724 b3976d3c Fam Zheng
            cluster_offset + (extent->cluster_sectors << 9)
725 b3976d3c Fam Zheng
        );
726 9949f97e Kevin Wolf
727 9949f97e Kevin Wolf
        cluster_offset >>= 9;
728 9949f97e Kevin Wolf
        tmp = cpu_to_le32(cluster_offset);
729 9949f97e Kevin Wolf
        l2_table[l2_index] = tmp;
730 630530a6 ths
731 630530a6 ths
        /* First of all we write grain itself, to avoid race condition
732 630530a6 ths
         * that may to corrupt the image.
733 630530a6 ths
         * This problem may occur because of insufficient space on host disk
734 630530a6 ths
         * or inappropriate VM shutdown.
735 630530a6 ths
         */
736 b3976d3c Fam Zheng
        if (get_whole_cluster(
737 b3976d3c Fam Zheng
                bs, extent, cluster_offset, offset, allocate) == -1)
738 5f4da8c0 ths
            return 0;
739 630530a6 ths
740 630530a6 ths
        if (m_data) {
741 630530a6 ths
            m_data->offset = tmp;
742 630530a6 ths
            m_data->l1_index = l1_index;
743 630530a6 ths
            m_data->l2_index = l2_index;
744 630530a6 ths
            m_data->l2_offset = l2_offset;
745 630530a6 ths
            m_data->valid = 1;
746 630530a6 ths
        }
747 ff1afc72 bellard
    }
748 ea2384d3 bellard
    cluster_offset <<= 9;
749 ea2384d3 bellard
    return cluster_offset;
750 ea2384d3 bellard
}
751 ea2384d3 bellard
752 b3976d3c Fam Zheng
static VmdkExtent *find_extent(BDRVVmdkState *s,
753 b3976d3c Fam Zheng
                                int64_t sector_num, VmdkExtent *start_hint)
754 b3976d3c Fam Zheng
{
755 b3976d3c Fam Zheng
    VmdkExtent *extent = start_hint;
756 b3976d3c Fam Zheng
757 b3976d3c Fam Zheng
    if (!extent) {
758 b3976d3c Fam Zheng
        extent = &s->extents[0];
759 b3976d3c Fam Zheng
    }
760 b3976d3c Fam Zheng
    while (extent < &s->extents[s->num_extents]) {
761 b3976d3c Fam Zheng
        if (sector_num < extent->end_sector) {
762 b3976d3c Fam Zheng
            return extent;
763 b3976d3c Fam Zheng
        }
764 b3976d3c Fam Zheng
        extent++;
765 b3976d3c Fam Zheng
    }
766 b3976d3c Fam Zheng
    return NULL;
767 b3976d3c Fam Zheng
}
768 b3976d3c Fam Zheng
769 5fafdf24 ths
static int vmdk_is_allocated(BlockDriverState *bs, int64_t sector_num,
770 ea2384d3 bellard
                             int nb_sectors, int *pnum)
771 ea2384d3 bellard
{
772 ea2384d3 bellard
    BDRVVmdkState *s = bs->opaque;
773 ea2384d3 bellard
774 b3976d3c Fam Zheng
    int64_t index_in_cluster, n, ret;
775 b3976d3c Fam Zheng
    uint64_t offset;
776 b3976d3c Fam Zheng
    VmdkExtent *extent;
777 b3976d3c Fam Zheng
778 b3976d3c Fam Zheng
    extent = find_extent(s, sector_num, NULL);
779 b3976d3c Fam Zheng
    if (!extent) {
780 b3976d3c Fam Zheng
        return 0;
781 b3976d3c Fam Zheng
    }
782 b3976d3c Fam Zheng
    if (extent->flat) {
783 b3976d3c Fam Zheng
        n = extent->end_sector - sector_num;
784 b3976d3c Fam Zheng
        ret = 1;
785 b3976d3c Fam Zheng
    } else {
786 b3976d3c Fam Zheng
        offset = get_cluster_offset(bs, extent, NULL, sector_num * 512, 0);
787 b3976d3c Fam Zheng
        index_in_cluster = sector_num % extent->cluster_sectors;
788 b3976d3c Fam Zheng
        n = extent->cluster_sectors - index_in_cluster;
789 b3976d3c Fam Zheng
        ret = offset ? 1 : 0;
790 b3976d3c Fam Zheng
    }
791 ea2384d3 bellard
    if (n > nb_sectors)
792 ea2384d3 bellard
        n = nb_sectors;
793 ea2384d3 bellard
    *pnum = n;
794 b3976d3c Fam Zheng
    return ret;
795 ea2384d3 bellard
}
796 ea2384d3 bellard
797 5fafdf24 ths
static int vmdk_read(BlockDriverState *bs, int64_t sector_num,
798 ea2384d3 bellard
                    uint8_t *buf, int nb_sectors)
799 ea2384d3 bellard
{
800 ea2384d3 bellard
    BDRVVmdkState *s = bs->opaque;
801 b3976d3c Fam Zheng
    int ret;
802 b3976d3c Fam Zheng
    uint64_t n, index_in_cluster;
803 b3976d3c Fam Zheng
    VmdkExtent *extent = NULL;
804 ea2384d3 bellard
    uint64_t cluster_offset;
805 5f4da8c0 ths
806 ea2384d3 bellard
    while (nb_sectors > 0) {
807 b3976d3c Fam Zheng
        extent = find_extent(s, sector_num, extent);
808 b3976d3c Fam Zheng
        if (!extent) {
809 b3976d3c Fam Zheng
            return -EIO;
810 b3976d3c Fam Zheng
        }
811 b3976d3c Fam Zheng
        cluster_offset = get_cluster_offset(
812 b3976d3c Fam Zheng
                            bs, extent, NULL, sector_num << 9, 0);
813 b3976d3c Fam Zheng
        index_in_cluster = sector_num % extent->cluster_sectors;
814 b3976d3c Fam Zheng
        n = extent->cluster_sectors - index_in_cluster;
815 ea2384d3 bellard
        if (n > nb_sectors)
816 ea2384d3 bellard
            n = nb_sectors;
817 ea2384d3 bellard
        if (!cluster_offset) {
818 5f4da8c0 ths
            // try to read from parent image, if exist
819 b171271a Kevin Wolf
            if (bs->backing_hd) {
820 5f4da8c0 ths
                if (!vmdk_is_cid_valid(bs))
821 5f4da8c0 ths
                    return -1;
822 b171271a Kevin Wolf
                ret = bdrv_read(bs->backing_hd, sector_num, buf, n);
823 5f4da8c0 ths
                if (ret < 0)
824 5f4da8c0 ths
                    return -1;
825 5f4da8c0 ths
            } else {
826 5f4da8c0 ths
                memset(buf, 0, 512 * n);
827 5f4da8c0 ths
            }
828 ea2384d3 bellard
        } else {
829 6511ef77 Kevin Wolf
            if(bdrv_pread(bs->file, cluster_offset + index_in_cluster * 512, buf, n * 512) != n * 512)
830 ea2384d3 bellard
                return -1;
831 ea2384d3 bellard
        }
832 ea2384d3 bellard
        nb_sectors -= n;
833 ea2384d3 bellard
        sector_num += n;
834 ea2384d3 bellard
        buf += n * 512;
835 ea2384d3 bellard
    }
836 ea2384d3 bellard
    return 0;
837 ea2384d3 bellard
}
838 ea2384d3 bellard
839 5fafdf24 ths
static int vmdk_write(BlockDriverState *bs, int64_t sector_num,
840 ea2384d3 bellard
                     const uint8_t *buf, int nb_sectors)
841 ea2384d3 bellard
{
842 ff1afc72 bellard
    BDRVVmdkState *s = bs->opaque;
843 b3976d3c Fam Zheng
    VmdkExtent *extent = NULL;
844 b3976d3c Fam Zheng
    int n;
845 b3976d3c Fam Zheng
    int64_t index_in_cluster;
846 ff1afc72 bellard
    uint64_t cluster_offset;
847 5f4da8c0 ths
    static int cid_update = 0;
848 b3976d3c Fam Zheng
    VmdkMetaData m_data;
849 ff1afc72 bellard
850 630530a6 ths
    if (sector_num > bs->total_sectors) {
851 630530a6 ths
        fprintf(stderr,
852 92868412 j_mayer
                "(VMDK) Wrong offset: sector_num=0x%" PRIx64
853 92868412 j_mayer
                " total_sectors=0x%" PRIx64 "\n",
854 630530a6 ths
                sector_num, bs->total_sectors);
855 630530a6 ths
        return -1;
856 630530a6 ths
    }
857 630530a6 ths
858 ff1afc72 bellard
    while (nb_sectors > 0) {
859 b3976d3c Fam Zheng
        extent = find_extent(s, sector_num, extent);
860 b3976d3c Fam Zheng
        if (!extent) {
861 b3976d3c Fam Zheng
            return -EIO;
862 b3976d3c Fam Zheng
        }
863 b3976d3c Fam Zheng
        cluster_offset = get_cluster_offset(
864 b3976d3c Fam Zheng
                                bs,
865 b3976d3c Fam Zheng
                                extent,
866 b3976d3c Fam Zheng
                                &m_data,
867 b3976d3c Fam Zheng
                                sector_num << 9, 1);
868 b3976d3c Fam Zheng
        if (!cluster_offset) {
869 ff1afc72 bellard
            return -1;
870 b3976d3c Fam Zheng
        }
871 b3976d3c Fam Zheng
        index_in_cluster = sector_num % extent->cluster_sectors;
872 b3976d3c Fam Zheng
        n = extent->cluster_sectors - index_in_cluster;
873 b3976d3c Fam Zheng
        if (n > nb_sectors) {
874 b3976d3c Fam Zheng
            n = nb_sectors;
875 b3976d3c Fam Zheng
        }
876 630530a6 ths
877 b3976d3c Fam Zheng
        if (bdrv_pwrite(bs->file,
878 b3976d3c Fam Zheng
                        cluster_offset + index_in_cluster * 512,
879 b3976d3c Fam Zheng
                        buf, n * 512)
880 b3976d3c Fam Zheng
                != n * 512) {
881 ff1afc72 bellard
            return -1;
882 b3976d3c Fam Zheng
        }
883 630530a6 ths
        if (m_data.valid) {
884 630530a6 ths
            /* update L2 tables */
885 b3976d3c Fam Zheng
            if (vmdk_L2update(extent, &m_data) == -1) {
886 630530a6 ths
                return -1;
887 b3976d3c Fam Zheng
            }
888 630530a6 ths
        }
889 ff1afc72 bellard
        nb_sectors -= n;
890 ff1afc72 bellard
        sector_num += n;
891 ff1afc72 bellard
        buf += n * 512;
892 5f4da8c0 ths
893 5f4da8c0 ths
        // update CID on the first write every time the virtual disk is opened
894 5f4da8c0 ths
        if (!cid_update) {
895 5f4da8c0 ths
            vmdk_write_cid(bs, time(NULL));
896 5f4da8c0 ths
            cid_update++;
897 5f4da8c0 ths
        }
898 ff1afc72 bellard
    }
899 ff1afc72 bellard
    return 0;
900 ea2384d3 bellard
}
901 ea2384d3 bellard
902 0e7e1989 Kevin Wolf
static int vmdk_create(const char *filename, QEMUOptionParameter *options)
903 8979b227 bellard
{
904 8979b227 bellard
    int fd, i;
905 8979b227 bellard
    VMDK4Header header;
906 8979b227 bellard
    uint32_t tmp, magic, grains, gd_size, gt_size, gt_count;
907 7ccfb2eb blueswir1
    static const char desc_template[] =
908 8979b227 bellard
        "# Disk DescriptorFile\n"
909 8979b227 bellard
        "version=1\n"
910 8979b227 bellard
        "CID=%x\n"
911 8979b227 bellard
        "parentCID=ffffffff\n"
912 8979b227 bellard
        "createType=\"monolithicSparse\"\n"
913 8979b227 bellard
        "\n"
914 8979b227 bellard
        "# Extent description\n"
915 7fd6d9fc blueswir1
        "RW %" PRId64 " SPARSE \"%s\"\n"
916 8979b227 bellard
        "\n"
917 8979b227 bellard
        "# The Disk Data Base \n"
918 8979b227 bellard
        "#DDB\n"
919 8979b227 bellard
        "\n"
920 ec36ba14 ths
        "ddb.virtualHWVersion = \"%d\"\n"
921 7fd6d9fc blueswir1
        "ddb.geometry.cylinders = \"%" PRId64 "\"\n"
922 8979b227 bellard
        "ddb.geometry.heads = \"16\"\n"
923 8979b227 bellard
        "ddb.geometry.sectors = \"63\"\n"
924 8979b227 bellard
        "ddb.adapterType = \"ide\"\n";
925 8979b227 bellard
    char desc[1024];
926 8979b227 bellard
    const char *real_filename, *temp_str;
927 0e7e1989 Kevin Wolf
    int64_t total_size = 0;
928 0e7e1989 Kevin Wolf
    const char *backing_file = NULL;
929 0e7e1989 Kevin Wolf
    int flags = 0;
930 1640366c Kirill A. Shutemov
    int ret;
931 0e7e1989 Kevin Wolf
932 0e7e1989 Kevin Wolf
    // Read out options
933 0e7e1989 Kevin Wolf
    while (options && options->name) {
934 0e7e1989 Kevin Wolf
        if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
935 0e7e1989 Kevin Wolf
            total_size = options->value.n / 512;
936 0e7e1989 Kevin Wolf
        } else if (!strcmp(options->name, BLOCK_OPT_BACKING_FILE)) {
937 0e7e1989 Kevin Wolf
            backing_file = options->value.s;
938 0e7e1989 Kevin Wolf
        } else if (!strcmp(options->name, BLOCK_OPT_COMPAT6)) {
939 0e7e1989 Kevin Wolf
            flags |= options->value.n ? BLOCK_FLAG_COMPAT6: 0;
940 0e7e1989 Kevin Wolf
        }
941 0e7e1989 Kevin Wolf
        options++;
942 0e7e1989 Kevin Wolf
    }
943 8979b227 bellard
944 8979b227 bellard
    /* XXX: add support for backing file */
945 5f4da8c0 ths
    if (backing_file) {
946 5f4da8c0 ths
        return vmdk_snapshot_create(filename, backing_file);
947 5f4da8c0 ths
    }
948 8979b227 bellard
949 8979b227 bellard
    fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
950 8979b227 bellard
              0644);
951 8979b227 bellard
    if (fd < 0)
952 b781cce5 Juan Quintela
        return -errno;
953 8979b227 bellard
    magic = cpu_to_be32(VMDK4_MAGIC);
954 8979b227 bellard
    memset(&header, 0, sizeof(header));
955 16372ff0 Alexander Graf
    header.version = 1;
956 16372ff0 Alexander Graf
    header.flags = 3; /* ?? */
957 16372ff0 Alexander Graf
    header.capacity = total_size;
958 16372ff0 Alexander Graf
    header.granularity = 128;
959 16372ff0 Alexander Graf
    header.num_gtes_per_gte = 512;
960 8979b227 bellard
961 8979b227 bellard
    grains = (total_size + header.granularity - 1) / header.granularity;
962 8979b227 bellard
    gt_size = ((header.num_gtes_per_gte * sizeof(uint32_t)) + 511) >> 9;
963 8979b227 bellard
    gt_count = (grains + header.num_gtes_per_gte - 1) / header.num_gtes_per_gte;
964 8979b227 bellard
    gd_size = (gt_count * sizeof(uint32_t) + 511) >> 9;
965 8979b227 bellard
966 8979b227 bellard
    header.desc_offset = 1;
967 8979b227 bellard
    header.desc_size = 20;
968 8979b227 bellard
    header.rgd_offset = header.desc_offset + header.desc_size;
969 8979b227 bellard
    header.gd_offset = header.rgd_offset + gd_size + (gt_size * gt_count);
970 8979b227 bellard
    header.grain_offset =
971 8979b227 bellard
       ((header.gd_offset + gd_size + (gt_size * gt_count) +
972 8979b227 bellard
         header.granularity - 1) / header.granularity) *
973 8979b227 bellard
        header.granularity;
974 8979b227 bellard
975 16372ff0 Alexander Graf
    /* swap endianness for all header fields */
976 16372ff0 Alexander Graf
    header.version = cpu_to_le32(header.version);
977 16372ff0 Alexander Graf
    header.flags = cpu_to_le32(header.flags);
978 16372ff0 Alexander Graf
    header.capacity = cpu_to_le64(header.capacity);
979 16372ff0 Alexander Graf
    header.granularity = cpu_to_le64(header.granularity);
980 16372ff0 Alexander Graf
    header.num_gtes_per_gte = cpu_to_le32(header.num_gtes_per_gte);
981 8979b227 bellard
    header.desc_offset = cpu_to_le64(header.desc_offset);
982 8979b227 bellard
    header.desc_size = cpu_to_le64(header.desc_size);
983 8979b227 bellard
    header.rgd_offset = cpu_to_le64(header.rgd_offset);
984 8979b227 bellard
    header.gd_offset = cpu_to_le64(header.gd_offset);
985 8979b227 bellard
    header.grain_offset = cpu_to_le64(header.grain_offset);
986 8979b227 bellard
987 8979b227 bellard
    header.check_bytes[0] = 0xa;
988 8979b227 bellard
    header.check_bytes[1] = 0x20;
989 8979b227 bellard
    header.check_bytes[2] = 0xd;
990 8979b227 bellard
    header.check_bytes[3] = 0xa;
991 3b46e624 ths
992 3b46e624 ths
    /* write all the data */
993 1640366c Kirill A. Shutemov
    ret = qemu_write_full(fd, &magic, sizeof(magic));
994 1640366c Kirill A. Shutemov
    if (ret != sizeof(magic)) {
995 b781cce5 Juan Quintela
        ret = -errno;
996 1640366c Kirill A. Shutemov
        goto exit;
997 1640366c Kirill A. Shutemov
    }
998 1640366c Kirill A. Shutemov
    ret = qemu_write_full(fd, &header, sizeof(header));
999 1640366c Kirill A. Shutemov
    if (ret != sizeof(header)) {
1000 b781cce5 Juan Quintela
        ret = -errno;
1001 1640366c Kirill A. Shutemov
        goto exit;
1002 1640366c Kirill A. Shutemov
    }
1003 8979b227 bellard
1004 16372ff0 Alexander Graf
    ret = ftruncate(fd, le64_to_cpu(header.grain_offset) << 9);
1005 1640366c Kirill A. Shutemov
    if (ret < 0) {
1006 b781cce5 Juan Quintela
        ret = -errno;
1007 1640366c Kirill A. Shutemov
        goto exit;
1008 1640366c Kirill A. Shutemov
    }
1009 8979b227 bellard
1010 8979b227 bellard
    /* write grain directory */
1011 8979b227 bellard
    lseek(fd, le64_to_cpu(header.rgd_offset) << 9, SEEK_SET);
1012 16372ff0 Alexander Graf
    for (i = 0, tmp = le64_to_cpu(header.rgd_offset) + gd_size;
1013 1640366c Kirill A. Shutemov
         i < gt_count; i++, tmp += gt_size) {
1014 1640366c Kirill A. Shutemov
        ret = qemu_write_full(fd, &tmp, sizeof(tmp));
1015 1640366c Kirill A. Shutemov
        if (ret != sizeof(tmp)) {
1016 b781cce5 Juan Quintela
            ret = -errno;
1017 1640366c Kirill A. Shutemov
            goto exit;
1018 1640366c Kirill A. Shutemov
        }
1019 1640366c Kirill A. Shutemov
    }
1020 3b46e624 ths
1021 8979b227 bellard
    /* write backup grain directory */
1022 8979b227 bellard
    lseek(fd, le64_to_cpu(header.gd_offset) << 9, SEEK_SET);
1023 16372ff0 Alexander Graf
    for (i = 0, tmp = le64_to_cpu(header.gd_offset) + gd_size;
1024 1640366c Kirill A. Shutemov
         i < gt_count; i++, tmp += gt_size) {
1025 1640366c Kirill A. Shutemov
        ret = qemu_write_full(fd, &tmp, sizeof(tmp));
1026 1640366c Kirill A. Shutemov
        if (ret != sizeof(tmp)) {
1027 b781cce5 Juan Quintela
            ret = -errno;
1028 1640366c Kirill A. Shutemov
            goto exit;
1029 1640366c Kirill A. Shutemov
        }
1030 1640366c Kirill A. Shutemov
    }
1031 8979b227 bellard
1032 8979b227 bellard
    /* compose the descriptor */
1033 8979b227 bellard
    real_filename = filename;
1034 8979b227 bellard
    if ((temp_str = strrchr(real_filename, '\\')) != NULL)
1035 8979b227 bellard
        real_filename = temp_str + 1;
1036 8979b227 bellard
    if ((temp_str = strrchr(real_filename, '/')) != NULL)
1037 8979b227 bellard
        real_filename = temp_str + 1;
1038 8979b227 bellard
    if ((temp_str = strrchr(real_filename, ':')) != NULL)
1039 8979b227 bellard
        real_filename = temp_str + 1;
1040 7ccfb2eb blueswir1
    snprintf(desc, sizeof(desc), desc_template, (unsigned int)time(NULL),
1041 7fd6d9fc blueswir1
             total_size, real_filename,
1042 7fd6d9fc blueswir1
             (flags & BLOCK_FLAG_COMPAT6 ? 6 : 4),
1043 7fd6d9fc blueswir1
             total_size / (int64_t)(63 * 16));
1044 8979b227 bellard
1045 8979b227 bellard
    /* write the descriptor */
1046 8979b227 bellard
    lseek(fd, le64_to_cpu(header.desc_offset) << 9, SEEK_SET);
1047 1640366c Kirill A. Shutemov
    ret = qemu_write_full(fd, desc, strlen(desc));
1048 1640366c Kirill A. Shutemov
    if (ret != strlen(desc)) {
1049 b781cce5 Juan Quintela
        ret = -errno;
1050 1640366c Kirill A. Shutemov
        goto exit;
1051 1640366c Kirill A. Shutemov
    }
1052 8979b227 bellard
1053 1640366c Kirill A. Shutemov
    ret = 0;
1054 1640366c Kirill A. Shutemov
exit:
1055 8979b227 bellard
    close(fd);
1056 1640366c Kirill A. Shutemov
    return ret;
1057 8979b227 bellard
}
1058 8979b227 bellard
1059 e2731add bellard
static void vmdk_close(BlockDriverState *bs)
1060 ea2384d3 bellard
{
1061 b3976d3c Fam Zheng
    vmdk_free_extents(bs);
1062 ea2384d3 bellard
}
1063 ea2384d3 bellard
1064 205ef796 Kevin Wolf
static int vmdk_flush(BlockDriverState *bs)
1065 7a6cba61 pbrook
{
1066 205ef796 Kevin Wolf
    return bdrv_flush(bs->file);
1067 7a6cba61 pbrook
}
1068 7a6cba61 pbrook
1069 0e7e1989 Kevin Wolf
1070 0e7e1989 Kevin Wolf
static QEMUOptionParameter vmdk_create_options[] = {
1071 db08adf5 Kevin Wolf
    {
1072 db08adf5 Kevin Wolf
        .name = BLOCK_OPT_SIZE,
1073 db08adf5 Kevin Wolf
        .type = OPT_SIZE,
1074 db08adf5 Kevin Wolf
        .help = "Virtual disk size"
1075 db08adf5 Kevin Wolf
    },
1076 db08adf5 Kevin Wolf
    {
1077 db08adf5 Kevin Wolf
        .name = BLOCK_OPT_BACKING_FILE,
1078 db08adf5 Kevin Wolf
        .type = OPT_STRING,
1079 db08adf5 Kevin Wolf
        .help = "File name of a base image"
1080 db08adf5 Kevin Wolf
    },
1081 db08adf5 Kevin Wolf
    {
1082 db08adf5 Kevin Wolf
        .name = BLOCK_OPT_COMPAT6,
1083 db08adf5 Kevin Wolf
        .type = OPT_FLAG,
1084 db08adf5 Kevin Wolf
        .help = "VMDK version 6 image"
1085 db08adf5 Kevin Wolf
    },
1086 0e7e1989 Kevin Wolf
    { NULL }
1087 0e7e1989 Kevin Wolf
};
1088 0e7e1989 Kevin Wolf
1089 5efa9d5a Anthony Liguori
static BlockDriver bdrv_vmdk = {
1090 e60f469c aurel32
    .format_name        = "vmdk",
1091 e60f469c aurel32
    .instance_size        = sizeof(BDRVVmdkState),
1092 e60f469c aurel32
    .bdrv_probe                = vmdk_probe,
1093 6511ef77 Kevin Wolf
    .bdrv_open      = vmdk_open,
1094 e60f469c aurel32
    .bdrv_read                = vmdk_read,
1095 e60f469c aurel32
    .bdrv_write                = vmdk_write,
1096 e60f469c aurel32
    .bdrv_close                = vmdk_close,
1097 e60f469c aurel32
    .bdrv_create        = vmdk_create,
1098 e60f469c aurel32
    .bdrv_flush                = vmdk_flush,
1099 e60f469c aurel32
    .bdrv_is_allocated        = vmdk_is_allocated,
1100 0e7e1989 Kevin Wolf
1101 0e7e1989 Kevin Wolf
    .create_options = vmdk_create_options,
1102 ea2384d3 bellard
};
1103 5efa9d5a Anthony Liguori
1104 5efa9d5a Anthony Liguori
static void bdrv_vmdk_init(void)
1105 5efa9d5a Anthony Liguori
{
1106 5efa9d5a Anthony Liguori
    bdrv_register(&bdrv_vmdk);
1107 5efa9d5a Anthony Liguori
}
1108 5efa9d5a Anthony Liguori
1109 5efa9d5a Anthony Liguori
block_init(bdrv_vmdk_init);