Annotation of qemu/block/vmdk.c, revision 1.1.1.5

1.1       root        1: /*
                      2:  * Block driver for the VMDK format
                      3:  *
                      4:  * Copyright (c) 2004 Fabrice Bellard
                      5:  * Copyright (c) 2005 Filip Navara
                      6:  *
                      7:  * Permission is hereby granted, free of charge, to any person obtaining a copy
                      8:  * of this software and associated documentation files (the "Software"), to deal
                      9:  * in the Software without restriction, including without limitation the rights
                     10:  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
                     11:  * copies of the Software, and to permit persons to whom the Software is
                     12:  * furnished to do so, subject to the following conditions:
                     13:  *
                     14:  * The above copyright notice and this permission notice shall be included in
                     15:  * all copies or substantial portions of the Software.
                     16:  *
                     17:  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
                     18:  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
                     19:  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
                     20:  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
                     21:  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
                     22:  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
                     23:  * THE SOFTWARE.
                     24:  */
                     25: 
                     26: #include "qemu-common.h"
                     27: #include "block_int.h"
                     28: #include "module.h"
                     29: 
                     30: #define VMDK3_MAGIC (('C' << 24) | ('O' << 16) | ('W' << 8) | 'D')
                     31: #define VMDK4_MAGIC (('K' << 24) | ('D' << 16) | ('M' << 8) | 'V')
                     32: 
                     33: typedef struct {
                     34:     uint32_t version;
                     35:     uint32_t flags;
                     36:     uint32_t disk_sectors;
                     37:     uint32_t granularity;
                     38:     uint32_t l1dir_offset;
                     39:     uint32_t l1dir_size;
                     40:     uint32_t file_sectors;
                     41:     uint32_t cylinders;
                     42:     uint32_t heads;
                     43:     uint32_t sectors_per_track;
                     44: } VMDK3Header;
                     45: 
                     46: typedef struct {
                     47:     uint32_t version;
                     48:     uint32_t flags;
                     49:     int64_t capacity;
                     50:     int64_t granularity;
                     51:     int64_t desc_offset;
                     52:     int64_t desc_size;
                     53:     int32_t num_gtes_per_gte;
                     54:     int64_t rgd_offset;
                     55:     int64_t gd_offset;
                     56:     int64_t grain_offset;
                     57:     char filler[1];
                     58:     char check_bytes[4];
                     59: } __attribute__((packed)) VMDK4Header;
                     60: 
                     61: #define L2_CACHE_SIZE 16
                     62: 
1.1.1.5 ! root       63: typedef struct VmdkExtent {
        !            64:     BlockDriverState *file;
        !            65:     bool flat;
        !            66:     int64_t sectors;
        !            67:     int64_t end_sector;
        !            68:     int64_t flat_start_offset;
1.1       root       69:     int64_t l1_table_offset;
                     70:     int64_t l1_backup_table_offset;
                     71:     uint32_t *l1_table;
                     72:     uint32_t *l1_backup_table;
                     73:     unsigned int l1_size;
                     74:     uint32_t l1_entry_sectors;
                     75: 
                     76:     unsigned int l2_size;
                     77:     uint32_t *l2_cache;
                     78:     uint32_t l2_cache_offsets[L2_CACHE_SIZE];
                     79:     uint32_t l2_cache_counts[L2_CACHE_SIZE];
                     80: 
                     81:     unsigned int cluster_sectors;
1.1.1.5 ! root       82: } VmdkExtent;
        !            83: 
        !            84: typedef struct BDRVVmdkState {
        !            85:     int desc_offset;
        !            86:     bool cid_updated;
1.1       root       87:     uint32_t parent_cid;
1.1.1.5 ! root       88:     int num_extents;
        !            89:     /* Extent array with num_extents entries, ascend ordered by address */
        !            90:     VmdkExtent *extents;
1.1       root       91: } BDRVVmdkState;
                     92: 
                     93: typedef struct VmdkMetaData {
                     94:     uint32_t offset;
                     95:     unsigned int l1_index;
                     96:     unsigned int l2_index;
                     97:     unsigned int l2_offset;
                     98:     int valid;
                     99: } VmdkMetaData;
                    100: 
                    101: static int vmdk_probe(const uint8_t *buf, int buf_size, const char *filename)
                    102: {
                    103:     uint32_t magic;
                    104: 
1.1.1.5 ! root      105:     if (buf_size < 4) {
1.1       root      106:         return 0;
1.1.1.5 ! root      107:     }
1.1       root      108:     magic = be32_to_cpu(*(uint32_t *)buf);
                    109:     if (magic == VMDK3_MAGIC ||
1.1.1.5 ! root      110:         magic == VMDK4_MAGIC) {
1.1       root      111:         return 100;
1.1.1.5 ! root      112:     } else {
        !           113:         const char *p = (const char *)buf;
        !           114:         const char *end = p + buf_size;
        !           115:         while (p < end) {
        !           116:             if (*p == '#') {
        !           117:                 /* skip comment line */
        !           118:                 while (p < end && *p != '\n') {
        !           119:                     p++;
        !           120:                 }
        !           121:                 p++;
        !           122:                 continue;
        !           123:             }
        !           124:             if (*p == ' ') {
        !           125:                 while (p < end && *p == ' ') {
        !           126:                     p++;
        !           127:                 }
        !           128:                 /* skip '\r' if windows line endings used. */
        !           129:                 if (p < end && *p == '\r') {
        !           130:                     p++;
        !           131:                 }
        !           132:                 /* only accept blank lines before 'version=' line */
        !           133:                 if (p == end || *p != '\n') {
        !           134:                     return 0;
        !           135:                 }
        !           136:                 p++;
        !           137:                 continue;
        !           138:             }
        !           139:             if (end - p >= strlen("version=X\n")) {
        !           140:                 if (strncmp("version=1\n", p, strlen("version=1\n")) == 0 ||
        !           141:                     strncmp("version=2\n", p, strlen("version=2\n")) == 0) {
        !           142:                     return 100;
        !           143:                 }
        !           144:             }
        !           145:             if (end - p >= strlen("version=X\r\n")) {
        !           146:                 if (strncmp("version=1\r\n", p, strlen("version=1\r\n")) == 0 ||
        !           147:                     strncmp("version=2\r\n", p, strlen("version=2\r\n")) == 0) {
        !           148:                     return 100;
        !           149:                 }
        !           150:             }
        !           151:             return 0;
        !           152:         }
1.1       root      153:         return 0;
1.1.1.5 ! root      154:     }
1.1       root      155: }
                    156: 
                    157: #define CHECK_CID 1
                    158: 
                    159: #define SECTOR_SIZE 512
1.1.1.5 ! root      160: #define DESC_SIZE (20 * SECTOR_SIZE)    /* 20 sectors of 512 bytes each */
        !           161: #define BUF_SIZE 4096
        !           162: #define HEADER_SIZE 512                 /* first sector of 512 bytes */
        !           163: 
        !           164: static void vmdk_free_extents(BlockDriverState *bs)
        !           165: {
        !           166:     int i;
        !           167:     BDRVVmdkState *s = bs->opaque;
        !           168: 
        !           169:     for (i = 0; i < s->num_extents; i++) {
        !           170:         qemu_free(s->extents[i].l1_table);
        !           171:         qemu_free(s->extents[i].l2_cache);
        !           172:         qemu_free(s->extents[i].l1_backup_table);
        !           173:     }
        !           174:     qemu_free(s->extents);
        !           175: }
1.1       root      176: 
                    177: static uint32_t vmdk_read_cid(BlockDriverState *bs, int parent)
                    178: {
                    179:     char desc[DESC_SIZE];
                    180:     uint32_t cid;
                    181:     const char *p_name, *cid_str;
                    182:     size_t cid_str_size;
1.1.1.5 ! root      183:     BDRVVmdkState *s = bs->opaque;
1.1       root      184: 
1.1.1.5 ! root      185:     if (bdrv_pread(bs->file, s->desc_offset, desc, DESC_SIZE) != DESC_SIZE) {
1.1       root      186:         return 0;
1.1.1.5 ! root      187:     }
1.1       root      188: 
                    189:     if (parent) {
                    190:         cid_str = "parentCID";
                    191:         cid_str_size = sizeof("parentCID");
                    192:     } else {
                    193:         cid_str = "CID";
                    194:         cid_str_size = sizeof("CID");
                    195:     }
                    196: 
1.1.1.5 ! root      197:     p_name = strstr(desc, cid_str);
        !           198:     if (p_name != NULL) {
1.1       root      199:         p_name += cid_str_size;
1.1.1.5 ! root      200:         sscanf(p_name, "%x", &cid);
1.1       root      201:     }
                    202: 
                    203:     return cid;
                    204: }
                    205: 
                    206: static int vmdk_write_cid(BlockDriverState *bs, uint32_t cid)
                    207: {
                    208:     char desc[DESC_SIZE], tmp_desc[DESC_SIZE];
                    209:     char *p_name, *tmp_str;
1.1.1.5 ! root      210:     BDRVVmdkState *s = bs->opaque;
1.1       root      211: 
1.1.1.5 ! root      212:     memset(desc, 0, sizeof(desc));
        !           213:     if (bdrv_pread(bs->file, s->desc_offset, desc, DESC_SIZE) != DESC_SIZE) {
        !           214:         return -EIO;
        !           215:     }
1.1       root      216: 
1.1.1.5 ! root      217:     tmp_str = strstr(desc, "parentCID");
1.1       root      218:     pstrcpy(tmp_desc, sizeof(tmp_desc), tmp_str);
1.1.1.5 ! root      219:     p_name = strstr(desc, "CID");
        !           220:     if (p_name != NULL) {
1.1       root      221:         p_name += sizeof("CID");
                    222:         snprintf(p_name, sizeof(desc) - (p_name - desc), "%x\n", cid);
                    223:         pstrcat(desc, sizeof(desc), tmp_desc);
                    224:     }
                    225: 
1.1.1.5 ! root      226:     if (bdrv_pwrite_sync(bs->file, s->desc_offset, desc, DESC_SIZE) < 0) {
        !           227:         return -EIO;
        !           228:     }
1.1       root      229:     return 0;
                    230: }
                    231: 
                    232: static int vmdk_is_cid_valid(BlockDriverState *bs)
                    233: {
                    234: #ifdef CHECK_CID
                    235:     BDRVVmdkState *s = bs->opaque;
                    236:     BlockDriverState *p_bs = bs->backing_hd;
                    237:     uint32_t cur_pcid;
                    238: 
                    239:     if (p_bs) {
1.1.1.5 ! root      240:         cur_pcid = vmdk_read_cid(p_bs, 0);
        !           241:         if (s->parent_cid != cur_pcid) {
        !           242:             /* CID not valid */
1.1       root      243:             return 0;
1.1.1.5 ! root      244:         }
1.1       root      245:     }
                    246: #endif
1.1.1.5 ! root      247:     /* CID valid */
1.1       root      248:     return 1;
                    249: }
                    250: 
1.1.1.5 ! root      251: static int vmdk_parent_open(BlockDriverState *bs)
1.1       root      252: {
1.1.1.5 ! root      253:     char *p_name;
        !           254:     char desc[DESC_SIZE + 1];
        !           255:     BDRVVmdkState *s = bs->opaque;
1.1       root      256: 
1.1.1.5 ! root      257:     desc[DESC_SIZE] = '\0';
        !           258:     if (bdrv_pread(bs->file, s->desc_offset, desc, DESC_SIZE) != DESC_SIZE) {
        !           259:         return -1;
1.1       root      260:     }
                    261: 
1.1.1.5 ! root      262:     p_name = strstr(desc, "parentFileNameHint");
        !           263:     if (p_name != NULL) {
        !           264:         char *end_name;
1.1       root      265: 
1.1.1.5 ! root      266:         p_name += sizeof("parentFileNameHint") + 1;
        !           267:         end_name = strchr(p_name, '\"');
        !           268:         if (end_name == NULL) {
        !           269:             return -1;
        !           270:         }
        !           271:         if ((end_name - p_name) > sizeof(bs->backing_file) - 1) {
        !           272:             return -1;
        !           273:         }
        !           274: 
        !           275:         pstrcpy(bs->backing_file, end_name - p_name + 1, p_name);
1.1.1.3   root      276:     }
1.1       root      277: 
1.1.1.5 ! root      278:     return 0;
        !           279: }
1.1       root      280: 
1.1.1.5 ! root      281: /* Create and append extent to the extent array. Return the added VmdkExtent
        !           282:  * address. return NULL if allocation failed. */
        !           283: static VmdkExtent *vmdk_add_extent(BlockDriverState *bs,
        !           284:                            BlockDriverState *file, bool flat, int64_t sectors,
        !           285:                            int64_t l1_offset, int64_t l1_backup_offset,
        !           286:                            uint32_t l1_size,
        !           287:                            int l2_size, unsigned int cluster_sectors)
        !           288: {
        !           289:     VmdkExtent *extent;
        !           290:     BDRVVmdkState *s = bs->opaque;
        !           291: 
        !           292:     s->extents = qemu_realloc(s->extents,
        !           293:                               (s->num_extents + 1) * sizeof(VmdkExtent));
        !           294:     extent = &s->extents[s->num_extents];
        !           295:     s->num_extents++;
        !           296: 
        !           297:     memset(extent, 0, sizeof(VmdkExtent));
        !           298:     extent->file = file;
        !           299:     extent->flat = flat;
        !           300:     extent->sectors = sectors;
        !           301:     extent->l1_table_offset = l1_offset;
        !           302:     extent->l1_backup_table_offset = l1_backup_offset;
        !           303:     extent->l1_size = l1_size;
        !           304:     extent->l1_entry_sectors = l2_size * cluster_sectors;
        !           305:     extent->l2_size = l2_size;
        !           306:     extent->cluster_sectors = cluster_sectors;
        !           307: 
        !           308:     if (s->num_extents > 1) {
        !           309:         extent->end_sector = (*(extent - 1)).end_sector + extent->sectors;
        !           310:     } else {
        !           311:         extent->end_sector = extent->sectors;
1.1.1.3   root      312:     }
1.1.1.5 ! root      313:     bs->total_sectors = extent->end_sector;
        !           314:     return extent;
        !           315: }
        !           316: 
        !           317: static int vmdk_init_tables(BlockDriverState *bs, VmdkExtent *extent)
        !           318: {
        !           319:     int ret;
        !           320:     int l1_size, i;
        !           321: 
        !           322:     /* read the L1 table */
        !           323:     l1_size = extent->l1_size * sizeof(uint32_t);
        !           324:     extent->l1_table = qemu_malloc(l1_size);
        !           325:     ret = bdrv_pread(extent->file,
        !           326:                     extent->l1_table_offset,
        !           327:                     extent->l1_table,
        !           328:                     l1_size);
        !           329:     if (ret < 0) {
        !           330:         goto fail_l1;
1.1.1.3   root      331:     }
1.1.1.5 ! root      332:     for (i = 0; i < extent->l1_size; i++) {
        !           333:         le32_to_cpus(&extent->l1_table[i]);
1.1.1.3   root      334:     }
1.1       root      335: 
1.1.1.5 ! root      336:     if (extent->l1_backup_table_offset) {
        !           337:         extent->l1_backup_table = qemu_malloc(l1_size);
        !           338:         ret = bdrv_pread(extent->file,
        !           339:                         extent->l1_backup_table_offset,
        !           340:                         extent->l1_backup_table,
        !           341:                         l1_size);
        !           342:         if (ret < 0) {
        !           343:             goto fail_l1b;
        !           344:         }
        !           345:         for (i = 0; i < extent->l1_size; i++) {
        !           346:             le32_to_cpus(&extent->l1_backup_table[i]);
        !           347:         }
1.1       root      348:     }
                    349: 
1.1.1.5 ! root      350:     extent->l2_cache =
        !           351:         qemu_malloc(extent->l2_size * L2_CACHE_SIZE * sizeof(uint32_t));
        !           352:     return 0;
        !           353:  fail_l1b:
        !           354:     qemu_free(extent->l1_backup_table);
        !           355:  fail_l1:
        !           356:     qemu_free(extent->l1_table);
        !           357:     return ret;
        !           358: }
1.1       root      359: 
1.1.1.5 ! root      360: static int vmdk_open_vmdk3(BlockDriverState *bs, int flags)
        !           361: {
        !           362:     int ret;
        !           363:     uint32_t magic;
        !           364:     VMDK3Header header;
        !           365:     BDRVVmdkState *s = bs->opaque;
        !           366:     VmdkExtent *extent;
1.1       root      367: 
1.1.1.5 ! root      368:     s->desc_offset = 0x200;
        !           369:     ret = bdrv_pread(bs->file, sizeof(magic), &header, sizeof(header));
        !           370:     if (ret < 0) {
1.1       root      371:         goto fail;
1.1.1.3   root      372:     }
1.1.1.5 ! root      373:     extent = vmdk_add_extent(bs,
        !           374:                              bs->file, false,
        !           375:                              le32_to_cpu(header.disk_sectors),
        !           376:                              le32_to_cpu(header.l1dir_offset) << 9,
        !           377:                              0, 1 << 6, 1 << 9,
        !           378:                              le32_to_cpu(header.granularity));
        !           379:     ret = vmdk_init_tables(bs, extent);
        !           380:     if (ret) {
        !           381:         /* vmdk_init_tables cleans up on fail, so only free allocation of
        !           382:          * vmdk_add_extent here. */
1.1       root      383:         goto fail;
1.1.1.3   root      384:     }
1.1.1.5 ! root      385:     return 0;
        !           386:  fail:
        !           387:     vmdk_free_extents(bs);
        !           388:     return ret;
        !           389: }
1.1       root      390: 
1.1.1.5 ! root      391: static int vmdk_open_vmdk4(BlockDriverState *bs, int flags)
        !           392: {
        !           393:     int ret;
        !           394:     uint32_t magic;
        !           395:     uint32_t l1_size, l1_entry_sectors;
        !           396:     VMDK4Header header;
        !           397:     BDRVVmdkState *s = bs->opaque;
        !           398:     VmdkExtent *extent;
1.1       root      399: 
1.1.1.5 ! root      400:     s->desc_offset = 0x200;
        !           401:     ret = bdrv_pread(bs->file, sizeof(magic), &header, sizeof(header));
        !           402:     if (ret < 0) {
        !           403:         goto fail;
1.1.1.3   root      404:     }
1.1.1.5 ! root      405:     l1_entry_sectors = le32_to_cpu(header.num_gtes_per_gte)
        !           406:                         * le64_to_cpu(header.granularity);
        !           407:     l1_size = (le64_to_cpu(header.capacity) + l1_entry_sectors - 1)
        !           408:                 / l1_entry_sectors;
        !           409:     extent = vmdk_add_extent(bs, bs->file, false,
        !           410:                           le64_to_cpu(header.capacity),
        !           411:                           le64_to_cpu(header.gd_offset) << 9,
        !           412:                           le64_to_cpu(header.rgd_offset) << 9,
        !           413:                           l1_size,
        !           414:                           le32_to_cpu(header.num_gtes_per_gte),
        !           415:                           le64_to_cpu(header.granularity));
        !           416:     if (extent->l1_entry_sectors <= 0) {
        !           417:         ret = -EINVAL;
        !           418:         goto fail;
1.1.1.3   root      419:     }
1.1.1.5 ! root      420:     /* try to open parent images, if exist */
        !           421:     ret = vmdk_parent_open(bs);
        !           422:     if (ret) {
        !           423:         goto fail;
1.1.1.3   root      424:     }
1.1.1.5 ! root      425:     s->parent_cid = vmdk_read_cid(bs, 1);
        !           426:     ret = vmdk_init_tables(bs, extent);
        !           427:     if (ret) {
        !           428:         goto fail;
1.1.1.3   root      429:     }
1.1.1.5 ! root      430:     return 0;
        !           431:  fail:
        !           432:     vmdk_free_extents(bs);
        !           433:     return ret;
        !           434: }
1.1       root      435: 
1.1.1.5 ! root      436: /* find an option value out of descriptor file */
        !           437: static int vmdk_parse_description(const char *desc, const char *opt_name,
        !           438:         char *buf, int buf_size)
        !           439: {
        !           440:     char *opt_pos, *opt_end;
        !           441:     const char *end = desc + strlen(desc);
        !           442: 
        !           443:     opt_pos = strstr(desc, opt_name);
        !           444:     if (!opt_pos) {
        !           445:         return -1;
1.1.1.3   root      446:     }
1.1.1.5 ! root      447:     /* Skip "=\"" following opt_name */
        !           448:     opt_pos += strlen(opt_name) + 2;
        !           449:     if (opt_pos >= end) {
        !           450:         return -1;
1.1.1.3   root      451:     }
1.1.1.5 ! root      452:     opt_end = opt_pos;
        !           453:     while (opt_end < end && *opt_end != '"') {
        !           454:         opt_end++;
1.1.1.3   root      455:     }
1.1.1.5 ! root      456:     if (opt_end == end || buf_size < opt_end - opt_pos + 1) {
        !           457:         return -1;
1.1.1.3   root      458:     }
1.1.1.5 ! root      459:     pstrcpy(buf, opt_end - opt_pos + 1, opt_pos);
        !           460:     return 0;
1.1       root      461: }
                    462: 
1.1.1.5 ! root      463: static int vmdk_parse_extents(const char *desc, BlockDriverState *bs,
        !           464:         const char *desc_file_path)
1.1       root      465: {
1.1.1.5 ! root      466:     int ret;
        !           467:     char access[11];
        !           468:     char type[11];
        !           469:     char fname[512];
        !           470:     const char *p = desc;
        !           471:     int64_t sectors = 0;
        !           472:     int64_t flat_offset;
        !           473: 
        !           474:     while (*p) {
        !           475:         /* parse extent line:
        !           476:          * RW [size in sectors] FLAT "file-name.vmdk" OFFSET
        !           477:          * or
        !           478:          * RW [size in sectors] SPARSE "file-name.vmdk"
        !           479:          */
        !           480:         flat_offset = -1;
        !           481:         ret = sscanf(p, "%10s %" SCNd64 " %10s %511s %" SCNd64,
        !           482:                 access, &sectors, type, fname, &flat_offset);
        !           483:         if (ret < 4 || strcmp(access, "RW")) {
        !           484:             goto next_line;
        !           485:         } else if (!strcmp(type, "FLAT")) {
        !           486:             if (ret != 5 || flat_offset < 0) {
        !           487:                 return -EINVAL;
        !           488:             }
        !           489:         } else if (ret != 4) {
        !           490:             return -EINVAL;
        !           491:         }
1.1       root      492: 
1.1.1.5 ! root      493:         /* trim the quotation marks around */
        !           494:         if (fname[0] == '"') {
        !           495:             memmove(fname, fname + 1, strlen(fname));
        !           496:             if (strlen(fname) <= 1 || fname[strlen(fname) - 1] != '"') {
        !           497:                 return -EINVAL;
        !           498:             }
        !           499:             fname[strlen(fname) - 1] = '\0';
        !           500:         }
        !           501:         if (sectors <= 0 ||
        !           502:             (strcmp(type, "FLAT") && strcmp(type, "SPARSE")) ||
        !           503:             (strcmp(access, "RW"))) {
        !           504:             goto next_line;
        !           505:         }
1.1       root      506: 
1.1.1.5 ! root      507:         /* save to extents array */
        !           508:         if (!strcmp(type, "FLAT")) {
        !           509:             /* FLAT extent */
        !           510:             char extent_path[PATH_MAX];
        !           511:             BlockDriverState *extent_file;
        !           512:             VmdkExtent *extent;
        !           513: 
        !           514:             path_combine(extent_path, sizeof(extent_path),
        !           515:                     desc_file_path, fname);
        !           516:             ret = bdrv_file_open(&extent_file, extent_path, bs->open_flags);
        !           517:             if (ret) {
        !           518:                 return ret;
        !           519:             }
        !           520:             extent = vmdk_add_extent(bs, extent_file, true, sectors,
        !           521:                             0, 0, 0, 0, sectors);
        !           522:             extent->flat_start_offset = flat_offset;
        !           523:         } else {
        !           524:             /* SPARSE extent, not supported for now */
        !           525:             fprintf(stderr,
        !           526:                 "VMDK: Not supported extent type \"%s\""".\n", type);
        !           527:             return -ENOTSUP;
        !           528:         }
        !           529: next_line:
        !           530:         /* move to next line */
        !           531:         while (*p && *p != '\n') {
        !           532:             p++;
        !           533:         }
        !           534:         p++;
        !           535:     }
        !           536:     return 0;
        !           537: }
1.1       root      538: 
1.1.1.5 ! root      539: static int vmdk_open_desc_file(BlockDriverState *bs, int flags)
        !           540: {
        !           541:     int ret;
        !           542:     char buf[2048];
        !           543:     char ct[128];
        !           544:     BDRVVmdkState *s = bs->opaque;
1.1       root      545: 
1.1.1.5 ! root      546:     ret = bdrv_pread(bs->file, 0, buf, sizeof(buf));
        !           547:     if (ret < 0) {
        !           548:         return ret;
        !           549:     }
        !           550:     buf[2047] = '\0';
        !           551:     if (vmdk_parse_description(buf, "createType", ct, sizeof(ct))) {
        !           552:         return -EINVAL;
        !           553:     }
        !           554:     if (strcmp(ct, "monolithicFlat")) {
        !           555:         fprintf(stderr,
        !           556:                 "VMDK: Not supported image type \"%s\""".\n", ct);
        !           557:         return -ENOTSUP;
        !           558:     }
        !           559:     s->desc_offset = 0;
        !           560:     ret = vmdk_parse_extents(buf, bs, bs->file->filename);
        !           561:     if (ret) {
        !           562:         return ret;
1.1       root      563:     }
                    564: 
1.1.1.5 ! root      565:     /* try to open parent images, if exist */
        !           566:     if (vmdk_parent_open(bs)) {
        !           567:         qemu_free(s->extents);
        !           568:         return -EINVAL;
        !           569:     }
        !           570:     s->parent_cid = vmdk_read_cid(bs, 1);
1.1       root      571:     return 0;
                    572: }
                    573: 
1.1.1.3   root      574: static int vmdk_open(BlockDriverState *bs, int flags)
1.1       root      575: {
                    576:     uint32_t magic;
                    577: 
1.1.1.5 ! root      578:     if (bdrv_pread(bs->file, 0, &magic, sizeof(magic)) != sizeof(magic)) {
        !           579:         return -EIO;
        !           580:     }
1.1       root      581: 
                    582:     magic = be32_to_cpu(magic);
                    583:     if (magic == VMDK3_MAGIC) {
1.1.1.5 ! root      584:         return vmdk_open_vmdk3(bs, flags);
1.1       root      585:     } else if (magic == VMDK4_MAGIC) {
1.1.1.5 ! root      586:         return vmdk_open_vmdk4(bs, flags);
1.1       root      587:     } else {
1.1.1.5 ! root      588:         return vmdk_open_desc_file(bs, flags);
1.1       root      589:     }
                    590: }
                    591: 
1.1.1.5 ! root      592: static int get_whole_cluster(BlockDriverState *bs,
        !           593:                 VmdkExtent *extent,
        !           594:                 uint64_t cluster_offset,
        !           595:                 uint64_t offset,
        !           596:                 bool allocate)
1.1       root      597: {
1.1.1.5 ! root      598:     /* 128 sectors * 512 bytes each = grain size 64KB */
        !           599:     uint8_t  whole_grain[extent->cluster_sectors * 512];
1.1       root      600: 
1.1.1.5 ! root      601:     /* we will be here if it's first write on non-exist grain(cluster).
        !           602:      * try to read from parent image, if exist */
1.1       root      603:     if (bs->backing_hd) {
1.1.1.2   root      604:         int ret;
1.1       root      605: 
1.1.1.5 ! root      606:         if (!vmdk_is_cid_valid(bs)) {
1.1       root      607:             return -1;
1.1.1.5 ! root      608:         }
1.1       root      609: 
1.1.1.5 ! root      610:         /* floor offset to cluster */
        !           611:         offset -= offset % (extent->cluster_sectors * 512);
1.1.1.2   root      612:         ret = bdrv_read(bs->backing_hd, offset >> 9, whole_grain,
1.1.1.5 ! root      613:                 extent->cluster_sectors);
1.1.1.2   root      614:         if (ret < 0) {
                    615:             return -1;
                    616:         }
1.1       root      617: 
1.1.1.5 ! root      618:         /* Write grain only into the active image */
        !           619:         ret = bdrv_write(extent->file, cluster_offset, whole_grain,
        !           620:                 extent->cluster_sectors);
1.1.1.2   root      621:         if (ret < 0) {
                    622:             return -1;
1.1       root      623:         }
                    624:     }
                    625:     return 0;
                    626: }
                    627: 
1.1.1.5 ! root      628: static int vmdk_L2update(VmdkExtent *extent, VmdkMetaData *m_data)
1.1       root      629: {
                    630:     /* update L2 table */
1.1.1.5 ! root      631:     if (bdrv_pwrite_sync(
        !           632:                 extent->file,
        !           633:                 ((int64_t)m_data->l2_offset * 512)
        !           634:                     + (m_data->l2_index * sizeof(m_data->offset)),
        !           635:                 &(m_data->offset),
        !           636:                 sizeof(m_data->offset)
        !           637:             ) < 0) {
1.1       root      638:         return -1;
1.1.1.5 ! root      639:     }
1.1       root      640:     /* update backup L2 table */
1.1.1.5 ! root      641:     if (extent->l1_backup_table_offset != 0) {
        !           642:         m_data->l2_offset = extent->l1_backup_table[m_data->l1_index];
        !           643:         if (bdrv_pwrite_sync(
        !           644:                     extent->file,
        !           645:                     ((int64_t)m_data->l2_offset * 512)
        !           646:                         + (m_data->l2_index * sizeof(m_data->offset)),
        !           647:                     &(m_data->offset), sizeof(m_data->offset)
        !           648:                 ) < 0) {
1.1       root      649:             return -1;
1.1.1.5 ! root      650:         }
1.1       root      651:     }
                    652: 
                    653:     return 0;
                    654: }
                    655: 
1.1.1.5 ! root      656: static int get_cluster_offset(BlockDriverState *bs,
        !           657:                                     VmdkExtent *extent,
        !           658:                                     VmdkMetaData *m_data,
        !           659:                                     uint64_t offset,
        !           660:                                     int allocate,
        !           661:                                     uint64_t *cluster_offset)
1.1       root      662: {
                    663:     unsigned int l1_index, l2_offset, l2_index;
                    664:     int min_index, i, j;
                    665:     uint32_t min_count, *l2_table, tmp = 0;
                    666: 
1.1.1.5 ! root      667:     if (m_data) {
1.1       root      668:         m_data->valid = 0;
1.1.1.5 ! root      669:     }
        !           670:     if (extent->flat) {
        !           671:         *cluster_offset = extent->flat_start_offset;
1.1       root      672:         return 0;
1.1.1.5 ! root      673:     }
        !           674: 
        !           675:     l1_index = (offset >> 9) / extent->l1_entry_sectors;
        !           676:     if (l1_index >= extent->l1_size) {
        !           677:         return -1;
        !           678:     }
        !           679:     l2_offset = extent->l1_table[l1_index];
        !           680:     if (!l2_offset) {
        !           681:         return -1;
        !           682:     }
        !           683:     for (i = 0; i < L2_CACHE_SIZE; i++) {
        !           684:         if (l2_offset == extent->l2_cache_offsets[i]) {
1.1       root      685:             /* increment the hit count */
1.1.1.5 ! root      686:             if (++extent->l2_cache_counts[i] == 0xffffffff) {
        !           687:                 for (j = 0; j < L2_CACHE_SIZE; j++) {
        !           688:                     extent->l2_cache_counts[j] >>= 1;
1.1       root      689:                 }
                    690:             }
1.1.1.5 ! root      691:             l2_table = extent->l2_cache + (i * extent->l2_size);
1.1       root      692:             goto found;
                    693:         }
                    694:     }
                    695:     /* not found: load a new entry in the least used one */
                    696:     min_index = 0;
                    697:     min_count = 0xffffffff;
1.1.1.5 ! root      698:     for (i = 0; i < L2_CACHE_SIZE; i++) {
        !           699:         if (extent->l2_cache_counts[i] < min_count) {
        !           700:             min_count = extent->l2_cache_counts[i];
1.1       root      701:             min_index = i;
                    702:         }
                    703:     }
1.1.1.5 ! root      704:     l2_table = extent->l2_cache + (min_index * extent->l2_size);
        !           705:     if (bdrv_pread(
        !           706:                 extent->file,
        !           707:                 (int64_t)l2_offset * 512,
        !           708:                 l2_table,
        !           709:                 extent->l2_size * sizeof(uint32_t)
        !           710:             ) != extent->l2_size * sizeof(uint32_t)) {
        !           711:         return -1;
        !           712:     }
1.1       root      713: 
1.1.1.5 ! root      714:     extent->l2_cache_offsets[min_index] = l2_offset;
        !           715:     extent->l2_cache_counts[min_index] = 1;
1.1       root      716:  found:
1.1.1.5 ! root      717:     l2_index = ((offset >> 9) / extent->cluster_sectors) % extent->l2_size;
        !           718:     *cluster_offset = le32_to_cpu(l2_table[l2_index]);
1.1       root      719: 
1.1.1.5 ! root      720:     if (!*cluster_offset) {
        !           721:         if (!allocate) {
        !           722:             return -1;
        !           723:         }
1.1.1.3   root      724: 
1.1.1.5 ! root      725:         /* Avoid the L2 tables update for the images that have snapshots. */
        !           726:         *cluster_offset = bdrv_getlength(extent->file);
        !           727:         bdrv_truncate(
        !           728:             extent->file,
        !           729:             *cluster_offset + (extent->cluster_sectors << 9)
        !           730:         );
1.1.1.3   root      731: 
1.1.1.5 ! root      732:         *cluster_offset >>= 9;
        !           733:         tmp = cpu_to_le32(*cluster_offset);
1.1.1.3   root      734:         l2_table[l2_index] = tmp;
                    735: 
1.1       root      736:         /* First of all we write grain itself, to avoid race condition
                    737:          * that may to corrupt the image.
                    738:          * This problem may occur because of insufficient space on host disk
                    739:          * or inappropriate VM shutdown.
                    740:          */
1.1.1.5 ! root      741:         if (get_whole_cluster(
        !           742:                 bs, extent, *cluster_offset, offset, allocate) == -1) {
        !           743:             return -1;
        !           744:         }
1.1       root      745: 
                    746:         if (m_data) {
                    747:             m_data->offset = tmp;
                    748:             m_data->l1_index = l1_index;
                    749:             m_data->l2_index = l2_index;
                    750:             m_data->l2_offset = l2_offset;
                    751:             m_data->valid = 1;
                    752:         }
                    753:     }
1.1.1.5 ! root      754:     *cluster_offset <<= 9;
        !           755:     return 0;
        !           756: }
        !           757: 
        !           758: static VmdkExtent *find_extent(BDRVVmdkState *s,
        !           759:                                 int64_t sector_num, VmdkExtent *start_hint)
        !           760: {
        !           761:     VmdkExtent *extent = start_hint;
        !           762: 
        !           763:     if (!extent) {
        !           764:         extent = &s->extents[0];
        !           765:     }
        !           766:     while (extent < &s->extents[s->num_extents]) {
        !           767:         if (sector_num < extent->end_sector) {
        !           768:             return extent;
        !           769:         }
        !           770:         extent++;
        !           771:     }
        !           772:     return NULL;
1.1       root      773: }
                    774: 
                    775: static int vmdk_is_allocated(BlockDriverState *bs, int64_t sector_num,
                    776:                              int nb_sectors, int *pnum)
                    777: {
                    778:     BDRVVmdkState *s = bs->opaque;
1.1.1.5 ! root      779:     int64_t index_in_cluster, n, ret;
        !           780:     uint64_t offset;
        !           781:     VmdkExtent *extent;
1.1       root      782: 
1.1.1.5 ! root      783:     extent = find_extent(s, sector_num, NULL);
        !           784:     if (!extent) {
        !           785:         return 0;
        !           786:     }
        !           787:     ret = get_cluster_offset(bs, extent, NULL,
        !           788:                             sector_num * 512, 0, &offset);
        !           789:     /* get_cluster_offset returning 0 means success */
        !           790:     ret = !ret;
        !           791: 
        !           792:     index_in_cluster = sector_num % extent->cluster_sectors;
        !           793:     n = extent->cluster_sectors - index_in_cluster;
        !           794:     if (n > nb_sectors) {
1.1       root      795:         n = nb_sectors;
1.1.1.5 ! root      796:     }
1.1       root      797:     *pnum = n;
1.1.1.5 ! root      798:     return ret;
1.1       root      799: }
                    800: 
                    801: static int vmdk_read(BlockDriverState *bs, int64_t sector_num,
                    802:                     uint8_t *buf, int nb_sectors)
                    803: {
                    804:     BDRVVmdkState *s = bs->opaque;
1.1.1.5 ! root      805:     int ret;
        !           806:     uint64_t n, index_in_cluster;
        !           807:     VmdkExtent *extent = NULL;
1.1       root      808:     uint64_t cluster_offset;
                    809: 
                    810:     while (nb_sectors > 0) {
1.1.1.5 ! root      811:         extent = find_extent(s, sector_num, extent);
        !           812:         if (!extent) {
        !           813:             return -EIO;
        !           814:         }
        !           815:         ret = get_cluster_offset(
        !           816:                             bs, extent, NULL,
        !           817:                             sector_num << 9, 0, &cluster_offset);
        !           818:         index_in_cluster = sector_num % extent->cluster_sectors;
        !           819:         n = extent->cluster_sectors - index_in_cluster;
        !           820:         if (n > nb_sectors) {
1.1       root      821:             n = nb_sectors;
1.1.1.5 ! root      822:         }
        !           823:         if (ret) {
        !           824:             /* if not allocated, try to read from parent image, if exist */
1.1       root      825:             if (bs->backing_hd) {
1.1.1.5 ! root      826:                 if (!vmdk_is_cid_valid(bs)) {
        !           827:                     return -EINVAL;
        !           828:                 }
1.1       root      829:                 ret = bdrv_read(bs->backing_hd, sector_num, buf, n);
1.1.1.5 ! root      830:                 if (ret < 0) {
        !           831:                     return ret;
        !           832:                 }
1.1       root      833:             } else {
                    834:                 memset(buf, 0, 512 * n);
                    835:             }
                    836:         } else {
1.1.1.5 ! root      837:             ret = bdrv_pread(extent->file,
        !           838:                             cluster_offset + index_in_cluster * 512,
        !           839:                             buf, n * 512);
        !           840:             if (ret < 0) {
        !           841:                 return ret;
        !           842:             }
1.1       root      843:         }
                    844:         nb_sectors -= n;
                    845:         sector_num += n;
                    846:         buf += n * 512;
                    847:     }
                    848:     return 0;
                    849: }
                    850: 
                    851: static int vmdk_write(BlockDriverState *bs, int64_t sector_num,
                    852:                      const uint8_t *buf, int nb_sectors)
                    853: {
                    854:     BDRVVmdkState *s = bs->opaque;
1.1.1.5 ! root      855:     VmdkExtent *extent = NULL;
        !           856:     int n, ret;
        !           857:     int64_t index_in_cluster;
1.1       root      858:     uint64_t cluster_offset;
1.1.1.5 ! root      859:     VmdkMetaData m_data;
1.1       root      860: 
                    861:     if (sector_num > bs->total_sectors) {
                    862:         fprintf(stderr,
                    863:                 "(VMDK) Wrong offset: sector_num=0x%" PRIx64
                    864:                 " total_sectors=0x%" PRIx64 "\n",
                    865:                 sector_num, bs->total_sectors);
1.1.1.5 ! root      866:         return -EIO;
1.1       root      867:     }
                    868: 
                    869:     while (nb_sectors > 0) {
1.1.1.5 ! root      870:         extent = find_extent(s, sector_num, extent);
        !           871:         if (!extent) {
        !           872:             return -EIO;
        !           873:         }
        !           874:         ret = get_cluster_offset(
        !           875:                                 bs,
        !           876:                                 extent,
        !           877:                                 &m_data,
        !           878:                                 sector_num << 9, 1,
        !           879:                                 &cluster_offset);
        !           880:         if (ret) {
        !           881:             return -EINVAL;
        !           882:         }
        !           883:         index_in_cluster = sector_num % extent->cluster_sectors;
        !           884:         n = extent->cluster_sectors - index_in_cluster;
        !           885:         if (n > nb_sectors) {
1.1       root      886:             n = nb_sectors;
1.1.1.5 ! root      887:         }
1.1       root      888: 
1.1.1.5 ! root      889:         ret = bdrv_pwrite(extent->file,
        !           890:                         cluster_offset + index_in_cluster * 512,
        !           891:                         buf,
        !           892:                         n * 512);
        !           893:         if (ret < 0) {
        !           894:             return ret;
        !           895:         }
1.1       root      896:         if (m_data.valid) {
                    897:             /* update L2 tables */
1.1.1.5 ! root      898:             if (vmdk_L2update(extent, &m_data) == -1) {
        !           899:                 return -EIO;
        !           900:             }
1.1       root      901:         }
                    902:         nb_sectors -= n;
                    903:         sector_num += n;
                    904:         buf += n * 512;
                    905: 
1.1.1.5 ! root      906:         /* update CID on the first write every time the virtual disk is
        !           907:          * opened */
        !           908:         if (!s->cid_updated) {
1.1       root      909:             vmdk_write_cid(bs, time(NULL));
1.1.1.5 ! root      910:             s->cid_updated = true;
1.1       root      911:         }
                    912:     }
                    913:     return 0;
                    914: }
                    915: 
1.1.1.5 ! root      916: 
        !           917: static int vmdk_create_extent(const char *filename, int64_t filesize, bool flat)
1.1       root      918: {
1.1.1.5 ! root      919:     int ret, i;
        !           920:     int fd = 0;
1.1       root      921:     VMDK4Header header;
                    922:     uint32_t tmp, magic, grains, gd_size, gt_size, gt_count;
                    923: 
1.1.1.5 ! root      924:     fd = open(
        !           925:         filename,
        !           926:         O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
        !           927:         0644);
        !           928:     if (fd < 0) {
        !           929:         return -errno;
1.1       root      930:     }
1.1.1.5 ! root      931:     if (flat) {
        !           932:         ret = ftruncate(fd, filesize);
        !           933:         if (ret < 0) {
        !           934:             ret = -errno;
        !           935:         }
        !           936:         goto exit;
1.1       root      937:     }
                    938:     magic = cpu_to_be32(VMDK4_MAGIC);
                    939:     memset(&header, 0, sizeof(header));
1.1.1.5 ! root      940:     header.version = 1;
        !           941:     header.flags = 3; /* ?? */
        !           942:     header.capacity = filesize / 512;
        !           943:     header.granularity = 128;
        !           944:     header.num_gtes_per_gte = 512;
1.1       root      945: 
1.1.1.5 ! root      946:     grains = (filesize / 512 + header.granularity - 1) / header.granularity;
1.1       root      947:     gt_size = ((header.num_gtes_per_gte * sizeof(uint32_t)) + 511) >> 9;
1.1.1.5 ! root      948:     gt_count =
        !           949:         (grains + header.num_gtes_per_gte - 1) / header.num_gtes_per_gte;
1.1       root      950:     gd_size = (gt_count * sizeof(uint32_t) + 511) >> 9;
                    951: 
                    952:     header.desc_offset = 1;
                    953:     header.desc_size = 20;
                    954:     header.rgd_offset = header.desc_offset + header.desc_size;
                    955:     header.gd_offset = header.rgd_offset + gd_size + (gt_size * gt_count);
                    956:     header.grain_offset =
                    957:        ((header.gd_offset + gd_size + (gt_size * gt_count) +
                    958:          header.granularity - 1) / header.granularity) *
                    959:         header.granularity;
1.1.1.5 ! root      960:     /* swap endianness for all header fields */
        !           961:     header.version = cpu_to_le32(header.version);
        !           962:     header.flags = cpu_to_le32(header.flags);
        !           963:     header.capacity = cpu_to_le64(header.capacity);
        !           964:     header.granularity = cpu_to_le64(header.granularity);
        !           965:     header.num_gtes_per_gte = cpu_to_le32(header.num_gtes_per_gte);
1.1       root      966:     header.desc_offset = cpu_to_le64(header.desc_offset);
                    967:     header.desc_size = cpu_to_le64(header.desc_size);
                    968:     header.rgd_offset = cpu_to_le64(header.rgd_offset);
                    969:     header.gd_offset = cpu_to_le64(header.gd_offset);
                    970:     header.grain_offset = cpu_to_le64(header.grain_offset);
                    971: 
                    972:     header.check_bytes[0] = 0xa;
                    973:     header.check_bytes[1] = 0x20;
                    974:     header.check_bytes[2] = 0xd;
                    975:     header.check_bytes[3] = 0xa;
                    976: 
                    977:     /* write all the data */
1.1.1.3   root      978:     ret = qemu_write_full(fd, &magic, sizeof(magic));
                    979:     if (ret != sizeof(magic)) {
                    980:         ret = -errno;
                    981:         goto exit;
                    982:     }
                    983:     ret = qemu_write_full(fd, &header, sizeof(header));
                    984:     if (ret != sizeof(header)) {
                    985:         ret = -errno;
                    986:         goto exit;
                    987:     }
1.1       root      988: 
1.1.1.5 ! root      989:     ret = ftruncate(fd, le64_to_cpu(header.grain_offset) << 9);
1.1.1.3   root      990:     if (ret < 0) {
                    991:         ret = -errno;
                    992:         goto exit;
                    993:     }
1.1       root      994: 
                    995:     /* write grain directory */
                    996:     lseek(fd, le64_to_cpu(header.rgd_offset) << 9, SEEK_SET);
1.1.1.5 ! root      997:     for (i = 0, tmp = le64_to_cpu(header.rgd_offset) + gd_size;
1.1.1.3   root      998:          i < gt_count; i++, tmp += gt_size) {
                    999:         ret = qemu_write_full(fd, &tmp, sizeof(tmp));
                   1000:         if (ret != sizeof(tmp)) {
                   1001:             ret = -errno;
                   1002:             goto exit;
                   1003:         }
                   1004:     }
1.1       root     1005: 
                   1006:     /* write backup grain directory */
                   1007:     lseek(fd, le64_to_cpu(header.gd_offset) << 9, SEEK_SET);
1.1.1.5 ! root     1008:     for (i = 0, tmp = le64_to_cpu(header.gd_offset) + gd_size;
1.1.1.3   root     1009:          i < gt_count; i++, tmp += gt_size) {
                   1010:         ret = qemu_write_full(fd, &tmp, sizeof(tmp));
                   1011:         if (ret != sizeof(tmp)) {
                   1012:             ret = -errno;
                   1013:             goto exit;
                   1014:         }
                   1015:     }
1.1       root     1016: 
1.1.1.5 ! root     1017:     ret = 0;
        !          1018:  exit:
        !          1019:     close(fd);
        !          1020:     return ret;
        !          1021: }
        !          1022: 
        !          1023: static int filename_decompose(const char *filename, char *path, char *prefix,
        !          1024:         char *postfix, size_t buf_len)
        !          1025: {
        !          1026:     const char *p, *q;
        !          1027: 
        !          1028:     if (filename == NULL || !strlen(filename)) {
        !          1029:         fprintf(stderr, "Vmdk: no filename provided.\n");
        !          1030:         return -1;
        !          1031:     }
        !          1032:     p = strrchr(filename, '/');
        !          1033:     if (p == NULL) {
        !          1034:         p = strrchr(filename, '\\');
        !          1035:     }
        !          1036:     if (p == NULL) {
        !          1037:         p = strrchr(filename, ':');
        !          1038:     }
        !          1039:     if (p != NULL) {
        !          1040:         p++;
        !          1041:         if (p - filename >= buf_len) {
        !          1042:             return -1;
        !          1043:         }
        !          1044:         pstrcpy(path, p - filename + 1, filename);
        !          1045:     } else {
        !          1046:         p = filename;
        !          1047:         path[0] = '\0';
        !          1048:     }
        !          1049:     q = strrchr(p, '.');
        !          1050:     if (q == NULL) {
        !          1051:         pstrcpy(prefix, buf_len, p);
        !          1052:         postfix[0] = '\0';
        !          1053:     } else {
        !          1054:         if (q - p >= buf_len) {
        !          1055:             return -1;
        !          1056:         }
        !          1057:         pstrcpy(prefix, q - p + 1, p);
        !          1058:         pstrcpy(postfix, buf_len, q);
        !          1059:     }
        !          1060:     return 0;
        !          1061: }
        !          1062: 
        !          1063: static int relative_path(char *dest, int dest_size,
        !          1064:         const char *base, const char *target)
        !          1065: {
        !          1066:     int i = 0;
        !          1067:     int n = 0;
        !          1068:     const char *p, *q;
        !          1069: #ifdef _WIN32
        !          1070:     const char *sep = "\\";
        !          1071: #else
        !          1072:     const char *sep = "/";
        !          1073: #endif
        !          1074: 
        !          1075:     if (!(dest && base && target)) {
        !          1076:         return -1;
        !          1077:     }
        !          1078:     if (path_is_absolute(target)) {
        !          1079:         dest[dest_size - 1] = '\0';
        !          1080:         strncpy(dest, target, dest_size - 1);
        !          1081:         return 0;
        !          1082:     }
        !          1083:     while (base[i] == target[i]) {
        !          1084:         i++;
        !          1085:     }
        !          1086:     p = &base[i];
        !          1087:     q = &target[i];
        !          1088:     while (*p) {
        !          1089:         if (*p == *sep) {
        !          1090:             n++;
        !          1091:         }
        !          1092:         p++;
        !          1093:     }
        !          1094:     dest[0] = '\0';
        !          1095:     for (; n; n--) {
        !          1096:         pstrcat(dest, dest_size, "..");
        !          1097:         pstrcat(dest, dest_size, sep);
        !          1098:     }
        !          1099:     pstrcat(dest, dest_size, q);
        !          1100:     return 0;
        !          1101: }
        !          1102: 
        !          1103: static int vmdk_create(const char *filename, QEMUOptionParameter *options)
        !          1104: {
        !          1105:     int fd, idx = 0;
        !          1106:     char desc[BUF_SIZE];
        !          1107:     int64_t total_size = 0, filesize;
        !          1108:     const char *backing_file = NULL;
        !          1109:     const char *fmt = NULL;
        !          1110:     int flags = 0;
        !          1111:     int ret = 0;
        !          1112:     bool flat, split;
        !          1113:     char ext_desc_lines[BUF_SIZE] = "";
        !          1114:     char path[PATH_MAX], prefix[PATH_MAX], postfix[PATH_MAX];
        !          1115:     const int64_t split_size = 0x80000000;  /* VMDK has constant split size */
        !          1116:     const char *desc_extent_line;
        !          1117:     char parent_desc_line[BUF_SIZE] = "";
        !          1118:     uint32_t parent_cid = 0xffffffff;
        !          1119:     const char desc_template[] =
        !          1120:         "# Disk DescriptorFile\n"
        !          1121:         "version=1\n"
        !          1122:         "CID=%x\n"
        !          1123:         "parentCID=%x\n"
        !          1124:         "createType=\"%s\"\n"
        !          1125:         "%s"
        !          1126:         "\n"
        !          1127:         "# Extent description\n"
        !          1128:         "%s"
        !          1129:         "\n"
        !          1130:         "# The Disk Data Base\n"
        !          1131:         "#DDB\n"
        !          1132:         "\n"
        !          1133:         "ddb.virtualHWVersion = \"%d\"\n"
        !          1134:         "ddb.geometry.cylinders = \"%" PRId64 "\"\n"
        !          1135:         "ddb.geometry.heads = \"16\"\n"
        !          1136:         "ddb.geometry.sectors = \"63\"\n"
        !          1137:         "ddb.adapterType = \"ide\"\n";
1.1       root     1138: 
1.1.1.5 ! root     1139:     if (filename_decompose(filename, path, prefix, postfix, PATH_MAX)) {
        !          1140:         return -EINVAL;
        !          1141:     }
        !          1142:     /* Read out options */
        !          1143:     while (options && options->name) {
        !          1144:         if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
        !          1145:             total_size = options->value.n;
        !          1146:         } else if (!strcmp(options->name, BLOCK_OPT_BACKING_FILE)) {
        !          1147:             backing_file = options->value.s;
        !          1148:         } else if (!strcmp(options->name, BLOCK_OPT_COMPAT6)) {
        !          1149:             flags |= options->value.n ? BLOCK_FLAG_COMPAT6 : 0;
        !          1150:         } else if (!strcmp(options->name, BLOCK_OPT_SUBFMT)) {
        !          1151:             fmt = options->value.s;
        !          1152:         }
        !          1153:         options++;
        !          1154:     }
        !          1155:     if (!fmt) {
        !          1156:         /* Default format to monolithicSparse */
        !          1157:         fmt = "monolithicSparse";
        !          1158:     } else if (strcmp(fmt, "monolithicFlat") &&
        !          1159:                strcmp(fmt, "monolithicSparse") &&
        !          1160:                strcmp(fmt, "twoGbMaxExtentSparse") &&
        !          1161:                strcmp(fmt, "twoGbMaxExtentFlat")) {
        !          1162:         fprintf(stderr, "VMDK: Unknown subformat: %s\n", fmt);
        !          1163:         return -EINVAL;
        !          1164:     }
        !          1165:     split = !(strcmp(fmt, "twoGbMaxExtentFlat") &&
        !          1166:               strcmp(fmt, "twoGbMaxExtentSparse"));
        !          1167:     flat = !(strcmp(fmt, "monolithicFlat") &&
        !          1168:              strcmp(fmt, "twoGbMaxExtentFlat"));
        !          1169:     if (flat) {
        !          1170:         desc_extent_line = "RW %lld FLAT \"%s\" 0\n";
        !          1171:     } else {
        !          1172:         desc_extent_line = "RW %lld SPARSE \"%s\"\n";
        !          1173:     }
        !          1174:     if (flat && backing_file) {
        !          1175:         /* not supporting backing file for flat image */
        !          1176:         return -ENOTSUP;
        !          1177:     }
        !          1178:     if (backing_file) {
        !          1179:         char parent_filename[PATH_MAX];
        !          1180:         BlockDriverState *bs = bdrv_new("");
        !          1181:         ret = bdrv_open(bs, backing_file, 0, NULL);
        !          1182:         if (ret != 0) {
        !          1183:             bdrv_delete(bs);
        !          1184:             return ret;
        !          1185:         }
        !          1186:         if (strcmp(bs->drv->format_name, "vmdk")) {
        !          1187:             bdrv_delete(bs);
        !          1188:             return -EINVAL;
        !          1189:         }
        !          1190:         filesize = bdrv_getlength(bs);
        !          1191:         parent_cid = vmdk_read_cid(bs, 0);
        !          1192:         bdrv_delete(bs);
        !          1193:         relative_path(parent_filename, sizeof(parent_filename),
        !          1194:                       filename, backing_file);
        !          1195:         snprintf(parent_desc_line, sizeof(parent_desc_line),
        !          1196:                 "parentFileNameHint=\"%s\"", parent_filename);
        !          1197:     }
        !          1198: 
        !          1199:     /* Create extents */
        !          1200:     filesize = total_size;
        !          1201:     while (filesize > 0) {
        !          1202:         char desc_line[BUF_SIZE];
        !          1203:         char ext_filename[PATH_MAX];
        !          1204:         char desc_filename[PATH_MAX];
        !          1205:         int64_t size = filesize;
        !          1206: 
        !          1207:         if (split && size > split_size) {
        !          1208:             size = split_size;
        !          1209:         }
        !          1210:         if (split) {
        !          1211:             snprintf(desc_filename, sizeof(desc_filename), "%s-%c%03d%s",
        !          1212:                     prefix, flat ? 'f' : 's', ++idx, postfix);
        !          1213:         } else if (flat) {
        !          1214:             snprintf(desc_filename, sizeof(desc_filename), "%s-flat%s",
        !          1215:                     prefix, postfix);
        !          1216:         } else {
        !          1217:             snprintf(desc_filename, sizeof(desc_filename), "%s%s",
        !          1218:                     prefix, postfix);
        !          1219:         }
        !          1220:         snprintf(ext_filename, sizeof(ext_filename), "%s%s",
        !          1221:                 path, desc_filename);
        !          1222: 
        !          1223:         if (vmdk_create_extent(ext_filename, size, flat)) {
        !          1224:             return -EINVAL;
        !          1225:         }
        !          1226:         filesize -= size;
        !          1227: 
        !          1228:         /* Format description line */
        !          1229:         snprintf(desc_line, sizeof(desc_line),
        !          1230:                     desc_extent_line, size / 512, desc_filename);
        !          1231:         pstrcat(ext_desc_lines, sizeof(ext_desc_lines), desc_line);
        !          1232:     }
        !          1233:     /* generate descriptor file */
        !          1234:     snprintf(desc, sizeof(desc), desc_template,
        !          1235:             (unsigned int)time(NULL),
        !          1236:             parent_cid,
        !          1237:             fmt,
        !          1238:             parent_desc_line,
        !          1239:             ext_desc_lines,
        !          1240:             (flags & BLOCK_FLAG_COMPAT6 ? 6 : 4),
        !          1241:             total_size / (int64_t)(63 * 16 * 512));
        !          1242:     if (split || flat) {
        !          1243:         fd = open(
        !          1244:                 filename,
        !          1245:                 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
        !          1246:                 0644);
        !          1247:     } else {
        !          1248:         fd = open(
        !          1249:                 filename,
        !          1250:                 O_WRONLY | O_BINARY | O_LARGEFILE,
        !          1251:                 0644);
        !          1252:     }
        !          1253:     if (fd < 0) {
        !          1254:         return -errno;
        !          1255:     }
        !          1256:     /* the descriptor offset = 0x200 */
        !          1257:     if (!split && !flat && 0x200 != lseek(fd, 0x200, SEEK_SET)) {
        !          1258:         ret = -errno;
        !          1259:         goto exit;
        !          1260:     }
1.1.1.3   root     1261:     ret = qemu_write_full(fd, desc, strlen(desc));
                   1262:     if (ret != strlen(desc)) {
                   1263:         ret = -errno;
                   1264:         goto exit;
                   1265:     }
                   1266:     ret = 0;
                   1267: exit:
1.1       root     1268:     close(fd);
1.1.1.3   root     1269:     return ret;
1.1       root     1270: }
                   1271: 
                   1272: static void vmdk_close(BlockDriverState *bs)
                   1273: {
1.1.1.5 ! root     1274:     vmdk_free_extents(bs);
1.1       root     1275: }
                   1276: 
1.1.1.4   root     1277: static int vmdk_flush(BlockDriverState *bs)
1.1       root     1278: {
1.1.1.5 ! root     1279:     int i, ret, err;
        !          1280:     BDRVVmdkState *s = bs->opaque;
        !          1281: 
        !          1282:     ret = bdrv_flush(bs->file);
        !          1283:     for (i = 0; i < s->num_extents; i++) {
        !          1284:         err = bdrv_flush(s->extents[i].file);
        !          1285:         if (err < 0) {
        !          1286:             ret = err;
        !          1287:         }
        !          1288:     }
        !          1289:     return ret;
1.1       root     1290: }
                   1291: 
1.1.1.5 ! root     1292: static int64_t vmdk_get_allocated_file_size(BlockDriverState *bs)
        !          1293: {
        !          1294:     int i;
        !          1295:     int64_t ret = 0;
        !          1296:     int64_t r;
        !          1297:     BDRVVmdkState *s = bs->opaque;
        !          1298: 
        !          1299:     ret = bdrv_get_allocated_file_size(bs->file);
        !          1300:     if (ret < 0) {
        !          1301:         return ret;
        !          1302:     }
        !          1303:     for (i = 0; i < s->num_extents; i++) {
        !          1304:         if (s->extents[i].file == bs->file) {
        !          1305:             continue;
        !          1306:         }
        !          1307:         r = bdrv_get_allocated_file_size(s->extents[i].file);
        !          1308:         if (r < 0) {
        !          1309:             return r;
        !          1310:         }
        !          1311:         ret += r;
        !          1312:     }
        !          1313:     return ret;
        !          1314: }
1.1       root     1315: 
                   1316: static QEMUOptionParameter vmdk_create_options[] = {
                   1317:     {
                   1318:         .name = BLOCK_OPT_SIZE,
                   1319:         .type = OPT_SIZE,
                   1320:         .help = "Virtual disk size"
                   1321:     },
                   1322:     {
                   1323:         .name = BLOCK_OPT_BACKING_FILE,
                   1324:         .type = OPT_STRING,
                   1325:         .help = "File name of a base image"
                   1326:     },
                   1327:     {
                   1328:         .name = BLOCK_OPT_COMPAT6,
                   1329:         .type = OPT_FLAG,
                   1330:         .help = "VMDK version 6 image"
                   1331:     },
1.1.1.5 ! root     1332:     {
        !          1333:         .name = BLOCK_OPT_SUBFMT,
        !          1334:         .type = OPT_STRING,
        !          1335:         .help =
        !          1336:             "VMDK flat extent format, can be one of "
        !          1337:             "{monolithicSparse (default) | monolithicFlat | twoGbMaxExtentSparse | twoGbMaxExtentFlat} "
        !          1338:     },
1.1       root     1339:     { NULL }
                   1340: };
                   1341: 
                   1342: static BlockDriver bdrv_vmdk = {
1.1.1.5 ! root     1343:     .format_name    = "vmdk",
        !          1344:     .instance_size  = sizeof(BDRVVmdkState),
        !          1345:     .bdrv_probe     = vmdk_probe,
1.1.1.3   root     1346:     .bdrv_open      = vmdk_open,
1.1.1.5 ! root     1347:     .bdrv_read      = vmdk_read,
        !          1348:     .bdrv_write     = vmdk_write,
        !          1349:     .bdrv_close     = vmdk_close,
        !          1350:     .bdrv_create    = vmdk_create,
        !          1351:     .bdrv_flush     = vmdk_flush,
        !          1352:     .bdrv_is_allocated  = vmdk_is_allocated,
        !          1353:     .bdrv_get_allocated_file_size  = vmdk_get_allocated_file_size,
1.1       root     1354: 
                   1355:     .create_options = vmdk_create_options,
                   1356: };
                   1357: 
                   1358: static void bdrv_vmdk_init(void)
                   1359: {
                   1360:     bdrv_register(&bdrv_vmdk);
                   1361: }
                   1362: 
                   1363: block_init(bdrv_vmdk_init);

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.