2 * Block driver for RAW files (win32)
4 * Copyright (c) 2006 Fabrice Bellard
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:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
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
24 #include "qemu-common.h"
25 #include "qemu-timer.h"
26 #include "block_int.h"
33 #define FTYPE_HARDDISK 2
35 typedef struct BDRVRawState {
38 char drive_path[16]; /* format: "d:\" */
41 int qemu_ftruncate64(int fd, int64_t length)
49 if ((GetVersion() & 0x80000000UL) && (length >> 32) != 0)
52 h = (HANDLE)_get_osfhandle(fd);
54 /* get current position, ftruncate do not change position */
56 li.LowPart = SetFilePointer (h, 0, &li.HighPart, FILE_CURRENT);
57 if (li.LowPart == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) {
62 dw = SetFilePointer(h, (DWORD) length, &high, FILE_BEGIN);
63 if (dw == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) {
66 res = SetEndOfFile(h);
68 /* back to old position */
69 SetFilePointer(h, li.LowPart, &li.HighPart, FILE_BEGIN);
73 static int set_sparse(int fd)
76 return (int) DeviceIoControl((HANDLE)_get_osfhandle(fd), FSCTL_SET_SPARSE,
77 NULL, 0, NULL, 0, &returned, NULL);
80 static int raw_open(BlockDriverState *bs, const char *filename, int flags)
82 BDRVRawState *s = bs->opaque;
89 if (flags & BDRV_O_RDWR) {
90 access_flags = GENERIC_READ | GENERIC_WRITE;
92 access_flags = GENERIC_READ;
95 overlapped = FILE_ATTRIBUTE_NORMAL;
96 if (flags & BDRV_O_NOCACHE)
97 overlapped |= FILE_FLAG_NO_BUFFERING;
98 if (!(flags & BDRV_O_CACHE_WB))
99 overlapped |= FILE_FLAG_WRITE_THROUGH;
100 s->hfile = CreateFile(filename,
102 FILE_SHARE_READ, NULL,
103 OPEN_EXISTING, overlapped, NULL);
104 if (s->hfile == INVALID_HANDLE_VALUE) {
105 int err = GetLastError();
107 if (err == ERROR_ACCESS_DENIED)
114 int open_flags = O_BINARY;
115 open_flags &= ~O_ACCMODE;
116 if (flags & BDRV_O_RDWR) {
117 open_flags |= O_RDWR;
119 open_flags |= O_RDONLY;
122 /* Use O_DSYNC for write-through caching, no flags for write-back caching,
123 * and O_DIRECT for no caching. */
125 if ((flags & BDRV_O_NOCACHE)) {
126 open_flags |= O_DIRECT;
128 if (!(flags & BDRV_O_CACHE_WB)) {
129 open_flags |= O_DSYNC;
133 int ret = qemu_open(filename, open_flags, 0644);
135 error_report("raw_open failed(%d) \n", ret);
138 s->hfile = (HANDLE)_get_osfhandle(ret);
144 static int raw_read(BlockDriverState *bs, int64_t sector_num,
145 uint8_t *buf, int nb_sectors)
147 BDRVRawState *s = bs->opaque;
151 int64_t offset = sector_num * 512;
152 int count = nb_sectors * 512;
154 memset(&ov, 0, sizeof(ov));
156 ov.OffsetHigh = offset >> 32;
157 ret = ReadFile(s->hfile, buf, count, &ret_count, &ov);
160 if (ret_count == count)
165 static int raw_write(BlockDriverState *bs, int64_t sector_num,
166 const uint8_t *buf, int nb_sectors)
168 BDRVRawState *s = bs->opaque;
172 int64_t offset = sector_num * 512;
173 int count = nb_sectors * 512;
175 memset(&ov, 0, sizeof(ov));
177 ov.OffsetHigh = offset >> 32;
178 ret = WriteFile(s->hfile, buf, count, &ret_count, &ov);
181 if (ret_count == count)
186 static int raw_flush(BlockDriverState *bs)
188 BDRVRawState *s = bs->opaque;
191 ret = FlushFileBuffers(s->hfile);
199 static void raw_close(BlockDriverState *bs)
201 BDRVRawState *s = bs->opaque;
202 CloseHandle(s->hfile);
205 static int raw_truncate(BlockDriverState *bs, int64_t offset)
207 BDRVRawState *s = bs->opaque;
212 if (!SetFilePointer(s->hfile, low, &high, FILE_BEGIN))
214 if (!SetEndOfFile(s->hfile))
219 static int64_t raw_getlength(BlockDriverState *bs)
221 BDRVRawState *s = bs->opaque;
223 ULARGE_INTEGER available, total, total_free;
230 l.LowPart = GetFileSize(s->hfile, (PDWORD)&l.HighPart);
231 if (l.LowPart == 0xffffffffUL && GetLastError() != NO_ERROR)
235 if (!GetDiskFreeSpaceEx(s->drive_path, &available, &total, &total_free))
237 l.QuadPart = total.QuadPart;
240 status = DeviceIoControl(s->hfile, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX,
241 NULL, 0, &dg, sizeof(dg), &count, NULL);
252 static int64_t raw_get_allocated_file_size(BlockDriverState *bs)
254 typedef DWORD (WINAPI * get_compressed_t)(const char *filename,
256 get_compressed_t get_compressed;
258 const char *filename = bs->filename;
259 /* WinNT support GetCompressedFileSize to determine allocate size */
261 (get_compressed_t) GetProcAddress(GetModuleHandle("kernel32"),
262 "GetCompressedFileSizeA");
263 if (get_compressed) {
265 low = get_compressed(filename, &high);
266 if (low != 0xFFFFFFFFlu || GetLastError() == NO_ERROR) {
267 return (((int64_t) high) << 32) + low;
271 if (_stati64(filename, &st) < 0) {
277 static int raw_create(const char *filename, QEMUOptionParameter *options)
280 int64_t total_size = 0;
282 /* Read out options */
283 while (options && options->name) {
284 if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
285 total_size = options->value.n / 512;
290 fd = qemu_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
295 ftruncate(fd, total_size * 512);
300 static QEMUOptionParameter raw_create_options[] = {
302 .name = BLOCK_OPT_SIZE,
304 .help = "Virtual disk size"
309 static BlockDriver bdrv_file = {
310 .format_name = "file",
311 .protocol_name = "file",
312 .instance_size = sizeof(BDRVRawState),
313 .bdrv_file_open = raw_open,
314 .bdrv_close = raw_close,
315 .bdrv_create = raw_create,
317 .bdrv_read = raw_read,
318 .bdrv_write = raw_write,
319 .bdrv_co_flush_to_disk = raw_flush,
321 .bdrv_truncate = raw_truncate,
322 .bdrv_getlength = raw_getlength,
323 .bdrv_get_allocated_file_size
324 = raw_get_allocated_file_size,
326 .create_options = raw_create_options,
329 /***********************************************/
332 static int find_cdrom(char *cdrom_name, int cdrom_name_size)
334 char drives[256], *pdrv = drives;
337 memset(drives, 0, sizeof(drives));
338 GetLogicalDriveStrings(sizeof(drives), drives);
339 while(pdrv[0] != '\0') {
340 type = GetDriveType(pdrv);
343 snprintf(cdrom_name, cdrom_name_size, "\\\\.\\%c:", pdrv[0]);
347 pdrv += lstrlen(pdrv) + 1;
352 static int find_device_type(BlockDriverState *bs, const char *filename)
354 BDRVRawState *s = bs->opaque;
358 if (strstart(filename, "\\\\.\\", &p) ||
359 strstart(filename, "//./", &p)) {
360 if (stristart(p, "PhysicalDrive", NULL))
361 return FTYPE_HARDDISK;
362 snprintf(s->drive_path, sizeof(s->drive_path), "%c:\\", p[0]);
363 type = GetDriveType(s->drive_path);
365 case DRIVE_REMOVABLE:
367 return FTYPE_HARDDISK;
378 static int hdev_probe_device(const char *filename)
380 if (strstart(filename, "/dev/cdrom", NULL))
382 if (is_windows_drive(filename))
387 static int hdev_open(BlockDriverState *bs, const char *filename, int flags)
389 BDRVRawState *s = bs->opaque;
390 int access_flags, create_flags;
392 char device_name[64];
394 if (strstart(filename, "/dev/cdrom", NULL)) {
395 if (find_cdrom(device_name, sizeof(device_name)) < 0)
397 filename = device_name;
399 /* transform drive letters into device name */
400 if (((filename[0] >= 'a' && filename[0] <= 'z') ||
401 (filename[0] >= 'A' && filename[0] <= 'Z')) &&
402 filename[1] == ':' && filename[2] == '\0') {
403 snprintf(device_name, sizeof(device_name), "\\\\.\\%c:", filename[0]);
404 filename = device_name;
407 s->type = find_device_type(bs, filename);
410 if (flags & BDRV_O_RDWR) {
411 access_flags = GENERIC_READ | GENERIC_WRITE;
413 access_flags = GENERIC_READ;
415 create_flags = OPEN_EXISTING;
417 overlapped = FILE_ATTRIBUTE_NORMAL;
418 if (flags & BDRV_O_NOCACHE)
419 overlapped |= FILE_FLAG_NO_BUFFERING;
420 if (!(flags & BDRV_O_CACHE_WB))
421 overlapped |= FILE_FLAG_WRITE_THROUGH;
423 s->hfile = CreateFile(filename,
425 FILE_SHARE_READ, NULL,
426 create_flags, overlapped, NULL);
427 if (s->hfile == INVALID_HANDLE_VALUE) {
428 int err = GetLastError();
430 if (err == ERROR_ACCESS_DENIED)
437 s->hfile = CreateFile(g_win32_locale_filename_from_utf8(filename),
439 FILE_SHARE_READ, NULL,
440 create_flags, overlapped, NULL);
444 int open_flags = O_BINARY;
445 open_flags &= ~O_ACCMODE;
446 if (flags & BDRV_O_RDWR) {
447 open_flags |= O_RDWR;
449 open_flags |= O_RDONLY;
452 /* Use O_DSYNC for write-through caching, no flags for write-back caching,
453 * and O_DIRECT for no caching. */
455 if ((flags & BDRV_O_NOCACHE)) {
456 open_flags |= O_DIRECT;
458 if (!(flags & BDRV_O_CACHE_WB)) {
459 open_flags |= O_DSYNC;
463 int ret = qemu_open(filename, open_flags, 0644);
465 error_report("raw_open failed(%d) \n", ret);
468 s->hfile = (HANDLE)_get_osfhandle(ret);
474 static int hdev_has_zero_init(BlockDriverState *bs)
479 static BlockDriver bdrv_host_device = {
480 .format_name = "host_device",
481 .protocol_name = "host_device",
482 .instance_size = sizeof(BDRVRawState),
483 .bdrv_probe_device = hdev_probe_device,
484 .bdrv_file_open = hdev_open,
485 .bdrv_close = raw_close,
486 .bdrv_has_zero_init = hdev_has_zero_init,
488 .bdrv_read = raw_read,
489 .bdrv_write = raw_write,
490 .bdrv_co_flush_to_disk = raw_flush,
492 .bdrv_getlength = raw_getlength,
493 .bdrv_get_allocated_file_size
494 = raw_get_allocated_file_size,
497 static void bdrv_file_init(void)
499 bdrv_register(&bdrv_file);
500 bdrv_register(&bdrv_host_device);
503 block_init(bdrv_file_init);