Home | History | Annotate | Download | only in block
      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