~jderose/ubuntu/raring/qemu/vde-again

« back to all changes in this revision

Viewing changes to debian/patches/91_security.patch

  • Committer: Bazaar Package Importer
  • Author(s): Aurelien Jarno, Aurelien Jarno
  • Date: 2009-03-22 10:13:17 UTC
  • mfrom: (1.2.1 upstream) (6.1.1 sid)
  • Revision ID: james.westby@ubuntu.com-20090322101317-iigjtnu5qil35dtb
Tags: 0.10.1-1
[ Aurelien Jarno ]
* New upstream stable release:
  - patches/80_stable-branch.patch: remove.
* debian/control: 
  - Remove depends on proll.
  - Move depends on device-tree-compiler to build-depends.
  - Bump Standards-Version to 3.8.1 (no changes).
* patches/82_qemu-img_decimal.patch: new patch from upstream to make
  qemu-img accept sizes with decimal values (closes: bug#501400).

Show diffs side-by-side

added added

removed removed

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