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;
     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 
    108 static 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 
    129 static 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 
    150 static void raw_flush(BlockDriverState *bs)
    151 {
    152     BDRVRawState *s = bs->opaque;
    153     FlushFileBuffers(s->hfile);
    154 }
    155 
    156 static void raw_close(BlockDriverState *bs)
    157 {
    158     BDRVRawState *s = bs->opaque;
    159     CloseHandle(s->hfile);
    160 }
    161 
    162 static 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 
    176 static 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 
    209 static 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 
    232 static QEMUOptionParameter raw_create_options[] = {
    233     {
    234         .name = BLOCK_OPT_SIZE,
    235         .type = OPT_SIZE,
    236         .help = "Virtual disk size"
    237     },
    238     { NULL }
    239 };
    240 
    241 static 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 
    260 static 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 
    280 static 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 
    306 static 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 
    315 static 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 
    366 static int raw_is_inserted(BlockDriverState *bs)
    367 {
    368     return 1;
    369 }
    370 
    371 static int raw_media_changed(BlockDriverState *bs)
    372 {
    373     return -ENOTSUP;
    374 }
    375 
    376 static 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 
    391 static int raw_set_locked(BlockDriverState *bs, int locked)
    392 {
    393     return -ENOTSUP;
    394 }
    395 #endif
    396 
    397 static int hdev_has_zero_init(BlockDriverState *bs)
    398 {
    399     return 0;
    400 }
    401 
    402 static 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 
    417 static void bdrv_file_init(void)
    418 {
    419     bdrv_register(&bdrv_file);
    420     bdrv_register(&bdrv_host_device);
    421 }
    422 
    423 block_init(bdrv_file_init);
    424