Statistics
| Branch: | Revision:

root / block / vmdk.c @ 7fa60fa3

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