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