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 35typedef struct BDRVRawState { 36 HANDLE hfile; 37 int type; 38 char drive_path[16]; /* format: "d:\" */ 39} BDRVRawState; 40 41int 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 69static 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 76static int raw_open(BlockDriverState *bs, const char *filename, int flags) 77{ 78 BDRVRawState *s = bs->opaque; 79 int access_flags; 80 DWORD overlapped; 81 82 s->type = FTYPE_FILE; 83 84 if (flags & BDRV_O_RDWR) { 85 access_flags = GENERIC_READ | GENERIC_WRITE; 86 } else { 87 access_flags = GENERIC_READ; 88 } 89 90 overlapped = FILE_ATTRIBUTE_NORMAL; 91 if ((flags & BDRV_O_NOCACHE)) 92 overlapped |= FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH; 93 else if (!(flags & BDRV_O_CACHE_WB)) 94 overlapped |= FILE_FLAG_WRITE_THROUGH; 95 s->hfile = CreateFile(filename, access_flags, 96 FILE_SHARE_READ, NULL, 97 OPEN_EXISTING, overlapped, NULL); 98 if (s->hfile == INVALID_HANDLE_VALUE) { 99 int err = GetLastError(); 100 101 if (err == ERROR_ACCESS_DENIED) 102 return -EACCES; 103 return -1; 104 } 105 return 0; 106} 107 108static int raw_read(BlockDriverState *bs, int64_t sector_num, 109 uint8_t *buf, int nb_sectors) 110{ 111 BDRVRawState *s = bs->opaque; 112 OVERLAPPED ov; 113 DWORD ret_count; 114 int ret; 115 int64_t offset = sector_num * 512; 116 int count = nb_sectors * 512; 117 118 memset(&ov, 0, sizeof(ov)); 119 ov.Offset = offset; 120 ov.OffsetHigh = offset >> 32; 121 ret = ReadFile(s->hfile, buf, count, &ret_count, &ov); 122 if (!ret) 123 return ret_count; 124 if (ret_count == count) 125 ret_count = 0; 126 return ret_count; 127} 128 129static int raw_write(BlockDriverState *bs, int64_t sector_num, 130 const uint8_t *buf, int nb_sectors) 131{ 132 BDRVRawState *s = bs->opaque; 133 OVERLAPPED ov; 134 DWORD ret_count; 135 int ret; 136 int64_t offset = sector_num * 512; 137 int count = nb_sectors * 512; 138 139 memset(&ov, 0, sizeof(ov)); 140 ov.Offset = offset; 141 ov.OffsetHigh = offset >> 32; 142 ret = WriteFile(s->hfile, buf, count, &ret_count, &ov); 143 if (!ret) 144 return ret_count; 145 if (ret_count == count) 146 ret_count = 0; 147 return ret_count; 148} 149 150static void raw_flush(BlockDriverState *bs) 151{ 152 BDRVRawState *s = bs->opaque; 153 FlushFileBuffers(s->hfile); 154} 155 156static void raw_close(BlockDriverState *bs) 157{ 158 BDRVRawState *s = bs->opaque; 159 CloseHandle(s->hfile); 160} 161 162static int raw_truncate(BlockDriverState *bs, int64_t offset) 163{ 164 BDRVRawState *s = bs->opaque; 165 LONG low, high; 166 167 low = offset; 168 high = offset >> 32; 169 if (!SetFilePointer(s->hfile, low, &high, FILE_BEGIN)) 170 return -EIO; 171 if (!SetEndOfFile(s->hfile)) 172 return -EIO; 173 return 0; 174} 175 176static int64_t raw_getlength(BlockDriverState *bs) 177{ 178 BDRVRawState *s = bs->opaque; 179 LARGE_INTEGER l; 180 ULARGE_INTEGER available, total, total_free; 181 DISK_GEOMETRY_EX dg; 182 DWORD count; 183 BOOL status; 184 185 switch(s->type) { 186 case FTYPE_FILE: 187 l.LowPart = GetFileSize(s->hfile, (PDWORD)&l.HighPart); 188 if (l.LowPart == 0xffffffffUL && GetLastError() != NO_ERROR) 189 return -EIO; 190 break; 191 case FTYPE_CD: 192 if (!GetDiskFreeSpaceEx(s->drive_path, &available, &total, &total_free)) 193 return -EIO; 194 l.QuadPart = total.QuadPart; 195 break; 196 case FTYPE_HARDDISK: 197 status = DeviceIoControl(s->hfile, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, 198 NULL, 0, &dg, sizeof(dg), &count, NULL); 199 if (status != 0) { 200 l = dg.DiskSize; 201 } 202 break; 203 default: 204 return -EIO; 205 } 206 return l.QuadPart; 207} 208 209static int raw_create(const char *filename, QEMUOptionParameter *options) 210{ 211 int fd; 212 int64_t total_size = 0; 213 214 /* Read out options */ 215 while (options && options->name) { 216 if (!strcmp(options->name, BLOCK_OPT_SIZE)) { 217 total_size = options->value.n / 512; 218 } 219 options++; 220 } 221 222 fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 223 0644); 224 if (fd < 0) 225 return -EIO; 226 set_sparse(fd); 227 ftruncate(fd, total_size * 512); 228 close(fd); 229 return 0; 230} 231 232static QEMUOptionParameter raw_create_options[] = { 233 { 234 .name = BLOCK_OPT_SIZE, 235 .type = OPT_SIZE, 236 .help = "Virtual disk size" 237 }, 238 { NULL } 239}; 240 241static BlockDriver bdrv_file = { 242 .format_name = "file", 243 .protocol_name = "file", 244 .instance_size = sizeof(BDRVRawState), 245 .bdrv_file_open = raw_open, 246 .bdrv_close = raw_close, 247 .bdrv_create = raw_create, 248 .bdrv_flush = raw_flush, 249 .bdrv_read = raw_read, 250 .bdrv_write = raw_write, 251 .bdrv_truncate = raw_truncate, 252 .bdrv_getlength = raw_getlength, 253 254 .create_options = raw_create_options, 255}; 256 257/***********************************************/ 258/* host device */ 259 260static int find_cdrom(char *cdrom_name, int cdrom_name_size) 261{ 262 char drives[256], *pdrv = drives; 263 UINT type; 264 265 memset(drives, 0, sizeof(drives)); 266 GetLogicalDriveStrings(sizeof(drives), drives); 267 while(pdrv[0] != '\0') { 268 type = GetDriveType(pdrv); 269 switch(type) { 270 case DRIVE_CDROM: 271 snprintf(cdrom_name, cdrom_name_size, "\\\\.\\%c:", pdrv[0]); 272 return 0; 273 break; 274 } 275 pdrv += lstrlen(pdrv) + 1; 276 } 277 return -1; 278} 279 280static int find_device_type(BlockDriverState *bs, const char *filename) 281{ 282 BDRVRawState *s = bs->opaque; 283 UINT type; 284 const char *p; 285 286 if (strstart(filename, "\\\\.\\", &p) || 287 strstart(filename, "//./", &p)) { 288 if (stristart(p, "PhysicalDrive", NULL)) 289 return FTYPE_HARDDISK; 290 snprintf(s->drive_path, sizeof(s->drive_path), "%c:\\", p[0]); 291 type = GetDriveType(s->drive_path); 292 switch (type) { 293 case DRIVE_REMOVABLE: 294 case DRIVE_FIXED: 295 return FTYPE_HARDDISK; 296 case DRIVE_CDROM: 297 return FTYPE_CD; 298 default: 299 return FTYPE_FILE; 300 } 301 } else { 302 return FTYPE_FILE; 303 } 304} 305 306static int hdev_probe_device(const char *filename) 307{ 308 if (strstart(filename, "/dev/cdrom", NULL)) 309 return 100; 310 if (is_windows_drive(filename)) 311 return 100; 312 return 0; 313} 314 315static int hdev_open(BlockDriverState *bs, const char *filename, int flags) 316{ 317 BDRVRawState *s = bs->opaque; 318 int access_flags, create_flags; 319 DWORD overlapped; 320 char device_name[64]; 321 322 if (strstart(filename, "/dev/cdrom", NULL)) { 323 if (find_cdrom(device_name, sizeof(device_name)) < 0) 324 return -ENOENT; 325 filename = device_name; 326 } else { 327 /* transform drive letters into device name */ 328 if (((filename[0] >= 'a' && filename[0] <= 'z') || 329 (filename[0] >= 'A' && filename[0] <= 'Z')) && 330 filename[1] == ':' && filename[2] == '\0') { 331 snprintf(device_name, sizeof(device_name), "\\\\.\\%c:", filename[0]); 332 filename = device_name; 333 } 334 } 335 s->type = find_device_type(bs, filename); 336 337 if (flags & BDRV_O_RDWR) { 338 access_flags = GENERIC_READ | GENERIC_WRITE; 339 } else { 340 access_flags = GENERIC_READ; 341 } 342 create_flags = OPEN_EXISTING; 343 344 overlapped = FILE_ATTRIBUTE_NORMAL; 345 if ((flags & BDRV_O_NOCACHE)) 346 overlapped |= FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH; 347 else if (!(flags & BDRV_O_CACHE_WB)) 348 overlapped |= FILE_FLAG_WRITE_THROUGH; 349 s->hfile = CreateFile(filename, access_flags, 350 FILE_SHARE_READ, NULL, 351 create_flags, overlapped, NULL); 352 if (s->hfile == INVALID_HANDLE_VALUE) { 353 int err = GetLastError(); 354 355 if (err == ERROR_ACCESS_DENIED) 356 return -EACCES; 357 return -1; 358 } 359 return 0; 360} 361 362#if 0 363/***********************************************/ 364/* removable device additional commands */ 365 366static int raw_is_inserted(BlockDriverState *bs) 367{ 368 return 1; 369} 370 371static int raw_media_changed(BlockDriverState *bs) 372{ 373 return -ENOTSUP; 374} 375 376static int raw_eject(BlockDriverState *bs, int eject_flag) 377{ 378 DWORD ret_count; 379 380 if (s->type == FTYPE_FILE) 381 return -ENOTSUP; 382 if (eject_flag) { 383 DeviceIoControl(s->hfile, IOCTL_STORAGE_EJECT_MEDIA, 384 NULL, 0, NULL, 0, &lpBytesReturned, NULL); 385 } else { 386 DeviceIoControl(s->hfile, IOCTL_STORAGE_LOAD_MEDIA, 387 NULL, 0, NULL, 0, &lpBytesReturned, NULL); 388 } 389} 390 391static int raw_set_locked(BlockDriverState *bs, int locked) 392{ 393 return -ENOTSUP; 394} 395#endif 396 397static int hdev_has_zero_init(BlockDriverState *bs) 398{ 399 return 0; 400} 401 402static BlockDriver bdrv_host_device = { 403 .format_name = "host_device", 404 .protocol_name = "host_device", 405 .instance_size = sizeof(BDRVRawState), 406 .bdrv_probe_device = hdev_probe_device, 407 .bdrv_file_open = hdev_open, 408 .bdrv_close = raw_close, 409 .bdrv_flush = raw_flush, 410 .bdrv_has_zero_init = hdev_has_zero_init, 411 412 .bdrv_read = raw_read, 413 .bdrv_write = raw_write, 414 .bdrv_getlength = raw_getlength, 415}; 416 417static void bdrv_file_init(void) 418{ 419 bdrv_register(&bdrv_file); 420 bdrv_register(&bdrv_host_device); 421} 422 423block_init(bdrv_file_init); 424