1 /* 2 * Block driver for RAW files (win32) 3 * 4 * Copyright (c) 2006 Fabrice Bellard 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a copy 7 * of this software and associated documentation files (the "Software"), to deal 8 * in the Software without restriction, including without limitation the rights 9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 * copies of the Software, and to permit persons to whom the Software is 11 * furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in 14 * all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 * THE SOFTWARE. 23 */ 24 #include "qemu-common.h" 25 #include "qemu-timer.h" 26 #include "block_int.h" 27 #include "module.h" 28 #include <windows.h> 29 #include <winioctl.h> 30 31 #define FTYPE_FILE 0 32 #define FTYPE_CD 1 33 #define FTYPE_HARDDISK 2 34 35 typedef struct BDRVRawState { 36 HANDLE hfile; 37 int type; 38 char drive_path[16]; /* format: "d:\" */ 39 } BDRVRawState; 40 41 int qemu_ftruncate64(int fd, int64_t length) 42 { 43 LARGE_INTEGER li; 44 LONG high; 45 HANDLE h; 46 BOOL res; 47 48 if ((GetVersion() & 0x80000000UL) && (length >> 32) != 0) 49 return -1; 50 51 h = (HANDLE)_get_osfhandle(fd); 52 53 /* get current position, ftruncate do not change position */ 54 li.HighPart = 0; 55 li.LowPart = SetFilePointer (h, 0, &li.HighPart, FILE_CURRENT); 56 if (li.LowPart == 0xffffffffUL && GetLastError() != NO_ERROR) 57 return -1; 58 59 high = length >> 32; 60 if (!SetFilePointer(h, (DWORD) length, &high, FILE_BEGIN)) 61 return -1; 62 res = SetEndOfFile(h); 63 64 /* back to old position */ 65 SetFilePointer(h, li.LowPart, &li.HighPart, FILE_BEGIN); 66 return res ? 0 : -1; 67 } 68 69 static int set_sparse(int fd) 70 { 71 DWORD returned; 72 return (int) DeviceIoControl((HANDLE)_get_osfhandle(fd), FSCTL_SET_SPARSE, 73 NULL, 0, NULL, 0, &returned, NULL); 74 } 75 76 static int raw_open(BlockDriverState *bs, const char *filename, int flags) 77 { 78 BDRVRawState *s = bs->opaque; 79 int access_flags, create_flags; 80 DWORD overlapped; 81 82 s->type = FTYPE_FILE; 83 84 if ((flags & BDRV_O_ACCESS) == O_RDWR) { 85 access_flags = GENERIC_READ | GENERIC_WRITE; 86 } else { 87 access_flags = GENERIC_READ; 88 } 89 if (flags & BDRV_O_CREAT) { 90 create_flags = CREATE_ALWAYS; 91 } else { 92 create_flags = OPEN_EXISTING; 93 } 94 overlapped = FILE_ATTRIBUTE_NORMAL; 95 if ((flags & BDRV_O_NOCACHE)) 96 overlapped |= FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH; 97 else if (!(flags & BDRV_O_CACHE_WB)) 98 overlapped |= FILE_FLAG_WRITE_THROUGH; 99 s->hfile = CreateFile(filename, access_flags, 100 FILE_SHARE_READ, NULL, 101 create_flags, overlapped, NULL); 102 if (s->hfile == INVALID_HANDLE_VALUE) { 103 int err = GetLastError(); 104 105 if (err == ERROR_ACCESS_DENIED) 106 return -EACCES; 107 return -1; 108 } 109 return 0; 110 } 111 112 static int raw_read(BlockDriverState *bs, int64_t sector_num, 113 uint8_t *buf, int nb_sectors) 114 { 115 BDRVRawState *s = bs->opaque; 116 OVERLAPPED ov; 117 DWORD ret_count; 118 int ret; 119 int64_t offset = sector_num * 512; 120 int count = nb_sectors * 512; 121 122 memset(&ov, 0, sizeof(ov)); 123 ov.Offset = offset; 124 ov.OffsetHigh = offset >> 32; 125 ret = ReadFile(s->hfile, buf, count, &ret_count, &ov); 126 if (!ret) 127 return ret_count; 128 if (ret_count == count) 129 ret_count = 0; 130 return ret_count; 131 } 132 133 static int raw_write(BlockDriverState *bs, int64_t sector_num, 134 const uint8_t *buf, int nb_sectors) 135 { 136 BDRVRawState *s = bs->opaque; 137 OVERLAPPED ov; 138 DWORD ret_count; 139 int ret; 140 int64_t offset = sector_num * 512; 141 int count = nb_sectors * 512; 142 143 memset(&ov, 0, sizeof(ov)); 144 ov.Offset = offset; 145 ov.OffsetHigh = offset >> 32; 146 ret = WriteFile(s->hfile, buf, count, &ret_count, &ov); 147 if (!ret) 148 return ret_count; 149 if (ret_count == count) 150 ret_count = 0; 151 return ret_count; 152 } 153 154 static void raw_flush(BlockDriverState *bs) 155 { 156 BDRVRawState *s = bs->opaque; 157 FlushFileBuffers(s->hfile); 158 } 159 160 static void raw_close(BlockDriverState *bs) 161 { 162 BDRVRawState *s = bs->opaque; 163 CloseHandle(s->hfile); 164 } 165 166 static int raw_truncate(BlockDriverState *bs, int64_t offset) 167 { 168 BDRVRawState *s = bs->opaque; 169 LONG low, high; 170 171 low = offset; 172 high = offset >> 32; 173 if (!SetFilePointer(s->hfile, low, &high, FILE_BEGIN)) 174 return -EIO; 175 if (!SetEndOfFile(s->hfile)) 176 return -EIO; 177 return 0; 178 } 179 180 static int64_t raw_getlength(BlockDriverState *bs) 181 { 182 BDRVRawState *s = bs->opaque; 183 LARGE_INTEGER l; 184 ULARGE_INTEGER available, total, total_free; 185 DISK_GEOMETRY_EX dg; 186 DWORD count; 187 BOOL status; 188 189 switch(s->type) { 190 case FTYPE_FILE: 191 l.LowPart = GetFileSize(s->hfile, (PDWORD)&l.HighPart); 192 if (l.LowPart == 0xffffffffUL && GetLastError() != NO_ERROR) 193 return -EIO; 194 break; 195 case FTYPE_CD: 196 if (!GetDiskFreeSpaceEx(s->drive_path, &available, &total, &total_free)) 197 return -EIO; 198 l.QuadPart = total.QuadPart; 199 break; 200 case FTYPE_HARDDISK: 201 status = DeviceIoControl(s->hfile, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, 202 NULL, 0, &dg, sizeof(dg), &count, NULL); 203 if (status != 0) { 204 l = dg.DiskSize; 205 } 206 break; 207 default: 208 return -EIO; 209 } 210 return l.QuadPart; 211 } 212 213 static int raw_create(const char *filename, QEMUOptionParameter *options) 214 { 215 int fd; 216 int64_t total_size = 0; 217 218 /* Read out options */ 219 while (options && options->name) { 220 if (!strcmp(options->name, BLOCK_OPT_SIZE)) { 221 total_size = options->value.n / 512; 222 } 223 options++; 224 } 225 226 fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 227 0644); 228 if (fd < 0) 229 return -EIO; 230 set_sparse(fd); 231 ftruncate(fd, total_size * 512); 232 close(fd); 233 return 0; 234 } 235 236 static QEMUOptionParameter raw_create_options[] = { 237 { 238 .name = BLOCK_OPT_SIZE, 239 .type = OPT_SIZE, 240 .help = "Virtual disk size" 241 }, 242 { NULL } 243 }; 244 245 static BlockDriver bdrv_raw = { 246 .format_name = "raw", 247 .instance_size = sizeof(BDRVRawState), 248 .bdrv_open = raw_open, 249 .bdrv_close = raw_close, 250 .bdrv_create = raw_create, 251 .bdrv_flush = raw_flush, 252 .bdrv_read = raw_read, 253 .bdrv_write = raw_write, 254 .bdrv_truncate = raw_truncate, 255 .bdrv_getlength = raw_getlength, 256 257 .create_options = raw_create_options, 258 }; 259 260 /***********************************************/ 261 /* host device */ 262 263 static int find_cdrom(char *cdrom_name, int cdrom_name_size) 264 { 265 char drives[256], *pdrv = drives; 266 UINT type; 267 268 memset(drives, 0, sizeof(drives)); 269 GetLogicalDriveStrings(sizeof(drives), drives); 270 while(pdrv[0] != '\0') { 271 type = GetDriveType(pdrv); 272 switch(type) { 273 case DRIVE_CDROM: 274 snprintf(cdrom_name, cdrom_name_size, "\\\\.\\%c:", pdrv[0]); 275 return 0; 276 break; 277 } 278 pdrv += lstrlen(pdrv) + 1; 279 } 280 return -1; 281 } 282 283 static int find_device_type(BlockDriverState *bs, const char *filename) 284 { 285 BDRVRawState *s = bs->opaque; 286 UINT type; 287 const char *p; 288 289 if (strstart(filename, "\\\\.\\", &p) || 290 strstart(filename, "//./", &p)) { 291 if (stristart(p, "PhysicalDrive", NULL)) 292 return FTYPE_HARDDISK; 293 snprintf(s->drive_path, sizeof(s->drive_path), "%c:\\", p[0]); 294 type = GetDriveType(s->drive_path); 295 switch (type) { 296 case DRIVE_REMOVABLE: 297 case DRIVE_FIXED: 298 return FTYPE_HARDDISK; 299 case DRIVE_CDROM: 300 return FTYPE_CD; 301 default: 302 return FTYPE_FILE; 303 } 304 } else { 305 return FTYPE_FILE; 306 } 307 } 308 309 static int hdev_probe_device(const char *filename) 310 { 311 if (strstart(filename, "/dev/cdrom", NULL)) 312 return 100; 313 if (is_windows_drive(filename)) 314 return 100; 315 return 0; 316 } 317 318 static int hdev_open(BlockDriverState *bs, const char *filename, int flags) 319 { 320 BDRVRawState *s = bs->opaque; 321 int access_flags, create_flags; 322 DWORD overlapped; 323 char device_name[64]; 324 325 if (strstart(filename, "/dev/cdrom", NULL)) { 326 if (find_cdrom(device_name, sizeof(device_name)) < 0) 327 return -ENOENT; 328 filename = device_name; 329 } else { 330 /* transform drive letters into device name */ 331 if (((filename[0] >= 'a' && filename[0] <= 'z') || 332 (filename[0] >= 'A' && filename[0] <= 'Z')) && 333 filename[1] == ':' && filename[2] == '\0') { 334 snprintf(device_name, sizeof(device_name), "\\\\.\\%c:", filename[0]); 335 filename = device_name; 336 } 337 } 338 s->type = find_device_type(bs, filename); 339 340 if ((flags & BDRV_O_ACCESS) == O_RDWR) { 341 access_flags = GENERIC_READ | GENERIC_WRITE; 342 } else { 343 access_flags = GENERIC_READ; 344 } 345 create_flags = OPEN_EXISTING; 346 347 overlapped = FILE_ATTRIBUTE_NORMAL; 348 if ((flags & BDRV_O_NOCACHE)) 349 overlapped |= FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH; 350 else if (!(flags & BDRV_O_CACHE_WB)) 351 overlapped |= FILE_FLAG_WRITE_THROUGH; 352 s->hfile = CreateFile(filename, access_flags, 353 FILE_SHARE_READ, NULL, 354 create_flags, overlapped, NULL); 355 if (s->hfile == INVALID_HANDLE_VALUE) { 356 int err = GetLastError(); 357 358 if (err == ERROR_ACCESS_DENIED) 359 return -EACCES; 360 return -1; 361 } 362 return 0; 363 } 364 365 #if 0 366 /***********************************************/ 367 /* removable device additional commands */ 368 369 static int raw_is_inserted(BlockDriverState *bs) 370 { 371 return 1; 372 } 373 374 static int raw_media_changed(BlockDriverState *bs) 375 { 376 return -ENOTSUP; 377 } 378 379 static int raw_eject(BlockDriverState *bs, int eject_flag) 380 { 381 DWORD ret_count; 382 383 if (s->type == FTYPE_FILE) 384 return -ENOTSUP; 385 if (eject_flag) { 386 DeviceIoControl(s->hfile, IOCTL_STORAGE_EJECT_MEDIA, 387 NULL, 0, NULL, 0, &lpBytesReturned, NULL); 388 } else { 389 DeviceIoControl(s->hfile, IOCTL_STORAGE_LOAD_MEDIA, 390 NULL, 0, NULL, 0, &lpBytesReturned, NULL); 391 } 392 } 393 394 static int raw_set_locked(BlockDriverState *bs, int locked) 395 { 396 return -ENOTSUP; 397 } 398 #endif 399 400 static BlockDriver bdrv_host_device = { 401 .format_name = "host_device", 402 .instance_size = sizeof(BDRVRawState), 403 .bdrv_probe_device = hdev_probe_device, 404 .bdrv_open = hdev_open, 405 .bdrv_close = raw_close, 406 .bdrv_flush = raw_flush, 407 408 .bdrv_read = raw_read, 409 .bdrv_write = raw_write, 410 .bdrv_getlength = raw_getlength, 411 }; 412 413 static void bdrv_raw_init(void) 414 { 415 bdrv_register(&bdrv_raw); 416 bdrv_register(&bdrv_host_device); 417 } 418 419 block_init(bdrv_raw_init); 420