Statistics
| Branch: | Revision:

root / block / vmdk.c @ 333c574d

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