1 /* 2 * Copyright 2007, Marcus Overhagen. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 */ 5 #include <sys/types.h> 6 #include <sys/stat.h> 7 #include <fcntl.h> 8 #include <unistd.h> 9 #include <stdarg.h> 10 #include <errno.h> 11 #include <getopt.h> 12 #include <stdio.h> 13 #include <stdlib.h> 14 #include <string.h> 15 16 #include "vmdkimage.h" 17 18 19 static void 20 print_usage() 21 { 22 printf("\n"); 23 printf("vmdkimage\n"); 24 printf("\n"); 25 printf("usage: vmdkimage -i <imagesize> -h <headersize> [-c] [-H] [-f] " 26 "<file>\n"); 27 printf(" -i, --imagesize size of raw partition image file\n"); 28 printf(" -h, --headersize size of the vmdk header to write\n"); 29 printf(" -f, --file the raw partition image file\n"); 30 printf(" -c, --clear-image set the image content to zero\n"); 31 printf(" -H, --header-only write only the header\n"); 32 exit(EXIT_FAILURE); 33 } 34 35 36 int 37 main(int argc, char *argv[]) 38 { 39 uint64 headersize = 0; 40 uint64 imagesize = 0; 41 const char *file = NULL; 42 bool headerOnly = false; 43 bool clearImage = false; 44 45 if (sizeof(SparseExtentHeader) != 512) { 46 fprintf(stderr, "compilation error: struct size is %u byte\n", 47 (unsigned)sizeof(SparseExtentHeader)); 48 exit(EXIT_FAILURE); 49 } 50 51 while (1) { 52 int c; 53 static struct option long_options[] = 54 { 55 {"headersize", required_argument, 0, 'h'}, 56 {"imagesize", required_argument, 0, 'i'}, 57 {"file", required_argument, 0, 'f'}, 58 {"clear-image", no_argument, 0, 'c'}, 59 {"header-only", no_argument, 0, 'H'}, 60 {0, 0, 0, 0} 61 }; 62 63 opterr = 0; /* don't print errors */ 64 c = getopt_long(argc, argv, "h:i:cHf:", long_options, NULL); 65 if (c == -1) 66 break; 67 68 switch (c) { 69 case 'h': 70 headersize = strtoull(optarg, NULL, 10); 71 if (strchr(optarg, 'G') || strchr(optarg, 'g')) 72 headersize *= 1024 * 1024 * 1024; 73 else if (strchr(optarg, 'M') || strchr(optarg, 'm')) 74 headersize *= 1024 * 1024; 75 else if (strchr(optarg, 'K') || strchr(optarg, 'k')) 76 headersize *= 1024; 77 break; 78 79 case 'i': 80 imagesize = strtoull(optarg, NULL, 10); 81 if (strchr(optarg, 'G') || strchr(optarg, 'g')) 82 imagesize *= 1024 * 1024 * 1024; 83 else if (strchr(optarg, 'M') || strchr(optarg, 'm')) 84 imagesize *= 1024 * 1024; 85 else if (strchr(optarg, 'K') || strchr(optarg, 'k')) 86 imagesize *= 1024; 87 break; 88 89 case 'f': 90 file = optarg; 91 break; 92 93 case 'c': 94 clearImage = true; 95 break; 96 97 case 'H': 98 headerOnly = true; 99 break; 100 101 default: 102 print_usage(); 103 } 104 } 105 106 if (file == NULL && optind == argc - 1) 107 file = argv[optind]; 108 109 if (!headersize || !imagesize || !file) 110 print_usage(); 111 112 char desc[512]; 113 SparseExtentHeader header; 114 115 if (headersize < sizeof(desc) + sizeof(header)) { 116 fprintf(stderr, "Error: header size must be at least %u byte\n", 117 (unsigned)(sizeof(desc) + sizeof(header))); 118 exit(EXIT_FAILURE); 119 } 120 121 if (headersize % 512) { 122 fprintf(stderr, "Error: header size must be a multiple of 512 bytes\n"); 123 exit(EXIT_FAILURE); 124 } 125 126 if (imagesize % 512) { 127 fprintf(stderr, "Error: image size must be a multiple of 512 bytes\n"); 128 exit(EXIT_FAILURE); 129 } 130 131 // arbitrary 1 GB limitation 132 if (headersize > 0x40000000u) { 133 fprintf(stderr, "Error: header size too large\n"); 134 exit(EXIT_FAILURE); 135 } 136 137 // arbitrary 2 GB limitation 138 if (imagesize > 0x80000000u) { 139 fprintf(stderr, "Error: image size too large\n"); 140 exit(EXIT_FAILURE); 141 } 142 143 const char *name = strrchr(file, '/'); 144 name = name ? (name + 1) : file; 145 146 // printf("headersize %llu\n", headersize); 147 // printf("imagesize %llu\n", imagesize); 148 // printf("file %s\n", file); 149 150 uint64 sectors; 151 uint64 heads; 152 uint64 cylinders; 153 154 // TODO: fixme! 155 sectors = 63; 156 heads = 16; 157 cylinders = imagesize / (sectors * heads * 512); 158 while (cylinders > 1024) { 159 cylinders /= 2; 160 heads *= 2; 161 } 162 off_t actualImageSize = (off_t)cylinders * sectors * heads * 512; 163 164 memset(desc, 0, sizeof(desc)); 165 memset(&header, 0, sizeof(header)); 166 167 header.magicNumber = SPARSE_MAGICNUMBER; 168 header.version = 1; 169 header.flags = 1; 170 header.capacity = 0; 171 header.grainSize = 16; 172 header.descriptorOffset = 1; 173 header.descriptorSize = sizeof(desc) / 512; 174 header.numGTEsPerGT = 512; 175 header.rgdOffset = 0; 176 header.gdOffset = 0; 177 header.overHead = headersize / 512; 178 header.uncleanShutdown = 0; 179 header.singleEndLineChar = '\n'; 180 header.nonEndLineChar = ' '; 181 header.doubleEndLineChar1 = '\r'; 182 header.doubleEndLineChar2 = '\n'; 183 184 strcat(desc, 185 "# Disk Descriptor File\n" 186 "version=1\n" 187 "CID=fffffffe\n" 188 "parentCID=ffffffff\n" 189 "createType=\"monolithicFlat\"\n"); 190 sprintf(desc + strlen(desc), 191 "# Extent Description\n" 192 "RW %llu FLAT \"%s\" %llu\n", 193 actualImageSize / 512, name, headersize / 512); 194 sprintf(desc + strlen(desc), 195 "# Disk Data Base\n" 196 "ddb.toolsVersion = \"0\"\n" 197 "ddb.virtualHWVersion = \"3\"\n" 198 "ddb.geometry.sectors = \"%llu\"\n" 199 "ddb.adapterType = \"ide\"\n" 200 "ddb.geometry.heads = \"%llu\"\n" 201 "ddb.geometry.cylinders = \"%llu\"\n", 202 sectors, heads, cylinders); 203 204 int fd = open(file, O_RDWR | O_CREAT, 0666); 205 if (fd < 0) { 206 fprintf(stderr, "Error: couldn't open file %s (%s)\n", file, 207 strerror(errno)); 208 exit(EXIT_FAILURE); 209 } 210 if (sizeof(header) != write(fd, &header, sizeof(header))) 211 goto write_err; 212 213 if (sizeof(desc) != write(fd, desc, sizeof(desc))) 214 goto write_err; 215 216 headersize--; 217 if (headersize != (uint64)lseek(fd, headersize, SEEK_SET)) 218 goto write_err; 219 220 if (1 != write(fd, "", 1)) 221 goto write_err; 222 223 if (!headerOnly) { 224 if (clearImage && ftruncate(fd, headersize) != 0 225 || ftruncate(fd, actualImageSize + headersize) != 0) { 226 fprintf(stderr, "Error: resizing file %s failed (%s)\n", file, 227 strerror(errno)); 228 exit(EXIT_FAILURE); 229 } 230 } 231 232 close(fd); 233 return 0; 234 235 write_err: 236 fprintf(stderr, "Error: writing file %s failed (%s)\n", file, 237 strerror(errno)); 238 close(fd); 239 exit(EXIT_FAILURE); 240 } 241