Revision f66fd6c3 block/vmdk.c

b/block/vmdk.c
156 156
#define CHECK_CID 1
157 157

  
158 158
#define SECTOR_SIZE 512
159
#define DESC_SIZE 20*SECTOR_SIZE	// 20 sectors of 512 bytes each
160
#define HEADER_SIZE 512   			// first sector of 512 bytes
159
#define DESC_SIZE (20 * SECTOR_SIZE)    /* 20 sectors of 512 bytes each */
160
#define BUF_SIZE 4096
161
#define HEADER_SIZE 512                 /* first sector of 512 bytes */
161 162

  
162 163
static void vmdk_free_extents(BlockDriverState *bs)
163 164
{
......
243 244
    return 1;
244 245
}
245 246

  
246
static int vmdk_snapshot_create(const char *filename, const char *backing_file)
247
{
248
    int snp_fd, p_fd;
249
    int ret;
250
    uint32_t p_cid;
251
    char *p_name, *gd_buf, *rgd_buf;
252
    const char *real_filename, *temp_str;
253
    VMDK4Header header;
254
    uint32_t gde_entries, gd_size;
255
    int64_t gd_offset, rgd_offset, capacity, gt_size;
256
    char p_desc[DESC_SIZE], s_desc[DESC_SIZE], hdr[HEADER_SIZE];
257
    static const char desc_template[] =
258
    "# Disk DescriptorFile\n"
259
    "version=1\n"
260
    "CID=%x\n"
261
    "parentCID=%x\n"
262
    "createType=\"monolithicSparse\"\n"
263
    "parentFileNameHint=\"%s\"\n"
264
    "\n"
265
    "# Extent description\n"
266
    "RW %u SPARSE \"%s\"\n"
267
    "\n"
268
    "# The Disk Data Base \n"
269
    "#DDB\n"
270
    "\n";
271

  
272
    snp_fd = open(filename, O_RDWR | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE, 0644);
273
    if (snp_fd < 0)
274
        return -errno;
275
    p_fd = open(backing_file, O_RDONLY | O_BINARY | O_LARGEFILE);
276
    if (p_fd < 0) {
277
        close(snp_fd);
278
        return -errno;
279
    }
280

  
281
    /* read the header */
282
    if (lseek(p_fd, 0x0, SEEK_SET) == -1) {
283
        ret = -errno;
284
        goto fail;
285
    }
286
    if (read(p_fd, hdr, HEADER_SIZE) != HEADER_SIZE) {
287
        ret = -errno;
288
        goto fail;
289
    }
290

  
291
    /* write the header */
292
    if (lseek(snp_fd, 0x0, SEEK_SET) == -1) {
293
        ret = -errno;
294
        goto fail;
295
    }
296
    if (write(snp_fd, hdr, HEADER_SIZE) == -1) {
297
        ret = -errno;
298
        goto fail;
299
    }
300

  
301
    memset(&header, 0, sizeof(header));
302
    memcpy(&header,&hdr[4], sizeof(header)); // skip the VMDK4_MAGIC
303

  
304
    if (ftruncate(snp_fd, header.grain_offset << 9)) {
305
        ret = -errno;
306
        goto fail;
307
    }
308
    /* the descriptor offset = 0x200 */
309
    if (lseek(p_fd, 0x200, SEEK_SET) == -1) {
310
        ret = -errno;
311
        goto fail;
312
    }
313
    if (read(p_fd, p_desc, DESC_SIZE) != DESC_SIZE) {
314
        ret = -errno;
315
        goto fail;
316
    }
317

  
318
    if ((p_name = strstr(p_desc,"CID")) != NULL) {
319
        p_name += sizeof("CID");
320
        sscanf(p_name,"%x",&p_cid);
321
    }
322

  
323
    real_filename = filename;
324
    if ((temp_str = strrchr(real_filename, '\\')) != NULL)
325
        real_filename = temp_str + 1;
326
    if ((temp_str = strrchr(real_filename, '/')) != NULL)
327
        real_filename = temp_str + 1;
328
    if ((temp_str = strrchr(real_filename, ':')) != NULL)
329
        real_filename = temp_str + 1;
330

  
331
    snprintf(s_desc, sizeof(s_desc), desc_template, p_cid, p_cid, backing_file,
332
             (uint32_t)header.capacity, real_filename);
333

  
334
    /* write the descriptor */
335
    if (lseek(snp_fd, 0x200, SEEK_SET) == -1) {
336
        ret = -errno;
337
        goto fail;
338
    }
339
    if (write(snp_fd, s_desc, strlen(s_desc)) == -1) {
340
        ret = -errno;
341
        goto fail;
342
    }
343

  
344
    gd_offset = header.gd_offset * SECTOR_SIZE;     // offset of GD table
345
    rgd_offset = header.rgd_offset * SECTOR_SIZE;   // offset of RGD table
346
    capacity = header.capacity * SECTOR_SIZE;       // Extent size
347
    /*
348
     * Each GDE span 32M disk, means:
349
     * 512 GTE per GT, each GTE points to grain
350
     */
351
    gt_size = (int64_t)header.num_gtes_per_gte * header.granularity * SECTOR_SIZE;
352
    if (!gt_size) {
353
        ret = -EINVAL;
354
        goto fail;
355
    }
356
    gde_entries = (uint32_t)(capacity / gt_size);  // number of gde/rgde
357
    gd_size = gde_entries * sizeof(uint32_t);
358

  
359
    /* write RGD */
360
    rgd_buf = qemu_malloc(gd_size);
361
    if (lseek(p_fd, rgd_offset, SEEK_SET) == -1) {
362
        ret = -errno;
363
        goto fail_rgd;
364
    }
365
    if (read(p_fd, rgd_buf, gd_size) != gd_size) {
366
        ret = -errno;
367
        goto fail_rgd;
368
    }
369
    if (lseek(snp_fd, rgd_offset, SEEK_SET) == -1) {
370
        ret = -errno;
371
        goto fail_rgd;
372
    }
373
    if (write(snp_fd, rgd_buf, gd_size) == -1) {
374
        ret = -errno;
375
        goto fail_rgd;
376
    }
377

  
378
    /* write GD */
379
    gd_buf = qemu_malloc(gd_size);
380
    if (lseek(p_fd, gd_offset, SEEK_SET) == -1) {
381
        ret = -errno;
382
        goto fail_gd;
383
    }
384
    if (read(p_fd, gd_buf, gd_size) != gd_size) {
385
        ret = -errno;
386
        goto fail_gd;
387
    }
388
    if (lseek(snp_fd, gd_offset, SEEK_SET) == -1) {
389
        ret = -errno;
390
        goto fail_gd;
391
    }
392
    if (write(snp_fd, gd_buf, gd_size) == -1) {
393
        ret = -errno;
394
        goto fail_gd;
395
    }
396
    ret = 0;
397

  
398
fail_gd:
399
    qemu_free(gd_buf);
400
fail_rgd:
401
    qemu_free(rgd_buf);
402
fail:
403
    close(p_fd);
404
    close(snp_fd);
405
    return ret;
406
}
407

  
408 247
static int vmdk_parent_open(BlockDriverState *bs)
409 248
{
410 249
    char *p_name;
......
1058 897
    return 0;
1059 898
}
1060 899

  
1061
static int vmdk_create(const char *filename, QEMUOptionParameter *options)
900

  
901
static int vmdk_create_extent(const char *filename, int64_t filesize, bool flat)
1062 902
{
1063
    int fd, i;
903
    int ret, i;
904
    int fd = 0;
1064 905
    VMDK4Header header;
1065 906
    uint32_t tmp, magic, grains, gd_size, gt_size, gt_count;
1066
    static const char desc_template[] =
1067
        "# Disk DescriptorFile\n"
1068
        "version=1\n"
1069
        "CID=%x\n"
1070
        "parentCID=ffffffff\n"
1071
        "createType=\"monolithicSparse\"\n"
1072
        "\n"
1073
        "# Extent description\n"
1074
        "RW %" PRId64 " SPARSE \"%s\"\n"
1075
        "\n"
1076
        "# The Disk Data Base \n"
1077
        "#DDB\n"
1078
        "\n"
1079
        "ddb.virtualHWVersion = \"%d\"\n"
1080
        "ddb.geometry.cylinders = \"%" PRId64 "\"\n"
1081
        "ddb.geometry.heads = \"16\"\n"
1082
        "ddb.geometry.sectors = \"63\"\n"
1083
        "ddb.adapterType = \"ide\"\n";
1084
    char desc[1024];
1085
    const char *real_filename, *temp_str;
1086
    int64_t total_size = 0;
1087
    const char *backing_file = NULL;
1088
    int flags = 0;
1089
    int ret;
1090 907

  
1091
    // Read out options
1092
    while (options && options->name) {
1093
        if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
1094
            total_size = options->value.n / 512;
1095
        } else if (!strcmp(options->name, BLOCK_OPT_BACKING_FILE)) {
1096
            backing_file = options->value.s;
1097
        } else if (!strcmp(options->name, BLOCK_OPT_COMPAT6)) {
1098
            flags |= options->value.n ? BLOCK_FLAG_COMPAT6: 0;
1099
        }
1100
        options++;
908
    fd = open(
909
        filename,
910
        O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
911
        0644);
912
    if (fd < 0) {
913
        return -errno;
1101 914
    }
1102

  
1103
    /* XXX: add support for backing file */
1104
    if (backing_file) {
1105
        return vmdk_snapshot_create(filename, backing_file);
915
    if (flat) {
916
        ret = ftruncate(fd, filesize);
917
        if (ret < 0) {
918
            ret = -errno;
919
        }
920
        goto exit;
1106 921
    }
1107

  
1108
    fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
1109
              0644);
1110
    if (fd < 0)
1111
        return -errno;
1112 922
    magic = cpu_to_be32(VMDK4_MAGIC);
1113 923
    memset(&header, 0, sizeof(header));
1114 924
    header.version = 1;
1115 925
    header.flags = 3; /* ?? */
1116
    header.capacity = total_size;
926
    header.capacity = filesize / 512;
1117 927
    header.granularity = 128;
1118 928
    header.num_gtes_per_gte = 512;
1119 929

  
1120
    grains = (total_size + header.granularity - 1) / header.granularity;
930
    grains = (filesize / 512 + header.granularity - 1) / header.granularity;
1121 931
    gt_size = ((header.num_gtes_per_gte * sizeof(uint32_t)) + 511) >> 9;
1122
    gt_count = (grains + header.num_gtes_per_gte - 1) / header.num_gtes_per_gte;
932
    gt_count =
933
        (grains + header.num_gtes_per_gte - 1) / header.num_gtes_per_gte;
1123 934
    gd_size = (gt_count * sizeof(uint32_t) + 511) >> 9;
1124 935

  
1125 936
    header.desc_offset = 1;
......
1130 941
       ((header.gd_offset + gd_size + (gt_size * gt_count) +
1131 942
         header.granularity - 1) / header.granularity) *
1132 943
        header.granularity;
1133

  
1134 944
    /* swap endianness for all header fields */
1135 945
    header.version = cpu_to_le32(header.version);
1136 946
    header.flags = cpu_to_le32(header.flags);
......
1188 998
        }
1189 999
    }
1190 1000

  
1191
    /* compose the descriptor */
1192
    real_filename = filename;
1193
    if ((temp_str = strrchr(real_filename, '\\')) != NULL)
1194
        real_filename = temp_str + 1;
1195
    if ((temp_str = strrchr(real_filename, '/')) != NULL)
1196
        real_filename = temp_str + 1;
1197
    if ((temp_str = strrchr(real_filename, ':')) != NULL)
1198
        real_filename = temp_str + 1;
1199
    snprintf(desc, sizeof(desc), desc_template, (unsigned int)time(NULL),
1200
             total_size, real_filename,
1201
             (flags & BLOCK_FLAG_COMPAT6 ? 6 : 4),
1202
             total_size / (int64_t)(63 * 16));
1203

  
1204
    /* write the descriptor */
1205
    lseek(fd, le64_to_cpu(header.desc_offset) << 9, SEEK_SET);
1001
    ret = 0;
1002
 exit:
1003
    close(fd);
1004
    return ret;
1005
}
1006

  
1007
static int filename_decompose(const char *filename, char *path, char *prefix,
1008
        char *postfix, size_t buf_len)
1009
{
1010
    const char *p, *q;
1011

  
1012
    if (filename == NULL || !strlen(filename)) {
1013
        fprintf(stderr, "Vmdk: no filename provided.\n");
1014
        return -1;
1015
    }
1016
    p = strrchr(filename, '/');
1017
    if (p == NULL) {
1018
        p = strrchr(filename, '\\');
1019
    }
1020
    if (p == NULL) {
1021
        p = strrchr(filename, ':');
1022
    }
1023
    if (p != NULL) {
1024
        p++;
1025
        if (p - filename >= buf_len) {
1026
            return -1;
1027
        }
1028
        pstrcpy(path, p - filename + 1, filename);
1029
    } else {
1030
        p = filename;
1031
        path[0] = '\0';
1032
    }
1033
    q = strrchr(p, '.');
1034
    if (q == NULL) {
1035
        pstrcpy(prefix, buf_len, p);
1036
        postfix[0] = '\0';
1037
    } else {
1038
        if (q - p >= buf_len) {
1039
            return -1;
1040
        }
1041
        pstrcpy(prefix, q - p + 1, p);
1042
        pstrcpy(postfix, buf_len, q);
1043
    }
1044
    return 0;
1045
}
1046

  
1047
static int relative_path(char *dest, int dest_size,
1048
        const char *base, const char *target)
1049
{
1050
    int i = 0;
1051
    int n = 0;
1052
    const char *p, *q;
1053
#ifdef _WIN32
1054
    const char *sep = "\\";
1055
#else
1056
    const char *sep = "/";
1057
#endif
1058

  
1059
    if (!(dest && base && target)) {
1060
        return -1;
1061
    }
1062
    if (path_is_absolute(target)) {
1063
        dest[dest_size - 1] = '\0';
1064
        strncpy(dest, target, dest_size - 1);
1065
        return 0;
1066
    }
1067
    while (base[i] == target[i]) {
1068
        i++;
1069
    }
1070
    p = &base[i];
1071
    q = &target[i];
1072
    while (*p) {
1073
        if (*p == *sep) {
1074
            n++;
1075
        }
1076
        p++;
1077
    }
1078
    dest[0] = '\0';
1079
    for (; n; n--) {
1080
        pstrcat(dest, dest_size, "..");
1081
        pstrcat(dest, dest_size, sep);
1082
    }
1083
    pstrcat(dest, dest_size, q);
1084
    return 0;
1085
}
1086

  
1087
static int vmdk_create(const char *filename, QEMUOptionParameter *options)
1088
{
1089
    int fd, idx = 0;
1090
    char desc[BUF_SIZE];
1091
    int64_t total_size = 0, filesize;
1092
    const char *backing_file = NULL;
1093
    const char *fmt = NULL;
1094
    int flags = 0;
1095
    int ret = 0;
1096
    bool flat, split;
1097
    char ext_desc_lines[BUF_SIZE] = "";
1098
    char path[PATH_MAX], prefix[PATH_MAX], postfix[PATH_MAX];
1099
    const int64_t split_size = 0x80000000;  /* VMDK has constant split size */
1100
    const char *desc_extent_line;
1101
    char parent_desc_line[BUF_SIZE] = "";
1102
    uint32_t parent_cid = 0xffffffff;
1103
    const char desc_template[] =
1104
        "# Disk DescriptorFile\n"
1105
        "version=1\n"
1106
        "CID=%x\n"
1107
        "parentCID=%x\n"
1108
        "createType=\"%s\"\n"
1109
        "%s"
1110
        "\n"
1111
        "# Extent description\n"
1112
        "%s"
1113
        "\n"
1114
        "# The Disk Data Base\n"
1115
        "#DDB\n"
1116
        "\n"
1117
        "ddb.virtualHWVersion = \"%d\"\n"
1118
        "ddb.geometry.cylinders = \"%" PRId64 "\"\n"
1119
        "ddb.geometry.heads = \"16\"\n"
1120
        "ddb.geometry.sectors = \"63\"\n"
1121
        "ddb.adapterType = \"ide\"\n";
1122

  
1123
    if (filename_decompose(filename, path, prefix, postfix, PATH_MAX)) {
1124
        return -EINVAL;
1125
    }
1126
    /* Read out options */
1127
    while (options && options->name) {
1128
        if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
1129
            total_size = options->value.n;
1130
        } else if (!strcmp(options->name, BLOCK_OPT_BACKING_FILE)) {
1131
            backing_file = options->value.s;
1132
        } else if (!strcmp(options->name, BLOCK_OPT_COMPAT6)) {
1133
            flags |= options->value.n ? BLOCK_FLAG_COMPAT6 : 0;
1134
        } else if (!strcmp(options->name, BLOCK_OPT_SUBFMT)) {
1135
            fmt = options->value.s;
1136
        }
1137
        options++;
1138
    }
1139
    if (!fmt) {
1140
        /* Default format to monolithicSparse */
1141
        fmt = "monolithicSparse";
1142
    } else if (strcmp(fmt, "monolithicFlat") &&
1143
               strcmp(fmt, "monolithicSparse") &&
1144
               strcmp(fmt, "twoGbMaxExtentSparse") &&
1145
               strcmp(fmt, "twoGbMaxExtentFlat")) {
1146
        fprintf(stderr, "VMDK: Unknown subformat: %s\n", fmt);
1147
        return -EINVAL;
1148
    }
1149
    split = !(strcmp(fmt, "twoGbMaxExtentFlat") &&
1150
              strcmp(fmt, "twoGbMaxExtentSparse"));
1151
    flat = !(strcmp(fmt, "monolithicFlat") &&
1152
             strcmp(fmt, "twoGbMaxExtentFlat"));
1153
    if (flat) {
1154
        desc_extent_line = "RW %lld FLAT \"%s\" 0\n";
1155
    } else {
1156
        desc_extent_line = "RW %lld SPARSE \"%s\"\n";
1157
    }
1158
    if (flat && backing_file) {
1159
        /* not supporting backing file for flat image */
1160
        return -ENOTSUP;
1161
    }
1162
    if (backing_file) {
1163
        char parent_filename[PATH_MAX];
1164
        BlockDriverState *bs = bdrv_new("");
1165
        ret = bdrv_open(bs, backing_file, 0, NULL);
1166
        if (ret != 0) {
1167
            bdrv_delete(bs);
1168
            return ret;
1169
        }
1170
        if (strcmp(bs->drv->format_name, "vmdk")) {
1171
            bdrv_delete(bs);
1172
            return -EINVAL;
1173
        }
1174
        filesize = bdrv_getlength(bs);
1175
        parent_cid = vmdk_read_cid(bs, 0);
1176
        bdrv_delete(bs);
1177
        relative_path(parent_filename, sizeof(parent_filename),
1178
                      filename, backing_file);
1179
        snprintf(parent_desc_line, sizeof(parent_desc_line),
1180
                "parentFileNameHint=\"%s\"", parent_filename);
1181
    }
1182

  
1183
    /* Create extents */
1184
    filesize = total_size;
1185
    while (filesize > 0) {
1186
        char desc_line[BUF_SIZE];
1187
        char ext_filename[PATH_MAX];
1188
        char desc_filename[PATH_MAX];
1189
        int64_t size = filesize;
1190

  
1191
        if (split && size > split_size) {
1192
            size = split_size;
1193
        }
1194
        if (split) {
1195
            snprintf(desc_filename, sizeof(desc_filename), "%s-%c%03d%s",
1196
                    prefix, flat ? 'f' : 's', ++idx, postfix);
1197
        } else if (flat) {
1198
            snprintf(desc_filename, sizeof(desc_filename), "%s-flat%s",
1199
                    prefix, postfix);
1200
        } else {
1201
            snprintf(desc_filename, sizeof(desc_filename), "%s%s",
1202
                    prefix, postfix);
1203
        }
1204
        snprintf(ext_filename, sizeof(ext_filename), "%s%s",
1205
                path, desc_filename);
1206

  
1207
        if (vmdk_create_extent(ext_filename, size, flat)) {
1208
            return -EINVAL;
1209
        }
1210
        filesize -= size;
1211

  
1212
        /* Format description line */
1213
        snprintf(desc_line, sizeof(desc_line),
1214
                    desc_extent_line, size / 512, desc_filename);
1215
        pstrcat(ext_desc_lines, sizeof(ext_desc_lines), desc_line);
1216
    }
1217
    /* generate descriptor file */
1218
    snprintf(desc, sizeof(desc), desc_template,
1219
            (unsigned int)time(NULL),
1220
            parent_cid,
1221
            fmt,
1222
            parent_desc_line,
1223
            ext_desc_lines,
1224
            (flags & BLOCK_FLAG_COMPAT6 ? 6 : 4),
1225
            total_size / (int64_t)(63 * 16 * 512));
1226
    if (split || flat) {
1227
        fd = open(
1228
                filename,
1229
                O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
1230
                0644);
1231
    } else {
1232
        fd = open(
1233
                filename,
1234
                O_WRONLY | O_BINARY | O_LARGEFILE,
1235
                0644);
1236
    }
1237
    if (fd < 0) {
1238
        return -errno;
1239
    }
1240
    /* the descriptor offset = 0x200 */
1241
    if (!split && !flat && 0x200 != lseek(fd, 0x200, SEEK_SET)) {
1242
        ret = -errno;
1243
        goto exit;
1244
    }
1206 1245
    ret = qemu_write_full(fd, desc, strlen(desc));
1207 1246
    if (ret != strlen(desc)) {
1208 1247
        ret = -errno;
1209 1248
        goto exit;
1210 1249
    }
1211

  
1212 1250
    ret = 0;
1213 1251
exit:
1214 1252
    close(fd);
......
1252 1290
        .type = OPT_FLAG,
1253 1291
        .help = "VMDK version 6 image"
1254 1292
    },
1293
    {
1294
        .name = BLOCK_OPT_SUBFMT,
1295
        .type = OPT_STRING,
1296
        .help =
1297
            "VMDK flat extent format, can be one of "
1298
            "{monolithicSparse (default) | monolithicFlat | twoGbMaxExtentSparse | twoGbMaxExtentFlat} "
1299
    },
1255 1300
    { NULL }
1256 1301
};
1257 1302

  

Also available in: Unified diff