File:  [Qemu by Fabrice Bellard] / qemu / block-raw-win32.c
Revision 1.1: download - view: text, annotated - select for diffs
Tue Apr 24 16:47:32 2018 UTC (22 months ago) by root
CVS tags: MAIN, HEAD
Initial revision

    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: #ifndef QEMU_IMG
   26: #include "qemu-timer.h"
   27: #include "exec-all.h"
   28: #endif
   29: #include "block_int.h"
   30: #include <assert.h>
   31: #include <winioctl.h>
   32: 
   33: #define FTYPE_FILE 0
   34: #define FTYPE_CD     1
   35: #define FTYPE_HARDDISK 2
   36: 
   37: typedef struct BDRVRawState {
   38:     HANDLE hfile;
   39:     int type;
   40:     char drive_path[16]; /* format: "d:\" */
   41: } BDRVRawState;
   42: 
   43: typedef struct RawAIOCB {
   44:     BlockDriverAIOCB common;
   45:     HANDLE hEvent;
   46:     OVERLAPPED ov;
   47:     int count;
   48: } RawAIOCB;
   49: 
   50: int qemu_ftruncate64(int fd, int64_t length)
   51: {
   52:     LARGE_INTEGER li;
   53:     LONG high;
   54:     HANDLE h;
   55:     BOOL res;
   56: 
   57:     if ((GetVersion() & 0x80000000UL) && (length >> 32) != 0)
   58: 	return -1;
   59: 
   60:     h = (HANDLE)_get_osfhandle(fd);
   61: 
   62:     /* get current position, ftruncate do not change position */
   63:     li.HighPart = 0;
   64:     li.LowPart = SetFilePointer (h, 0, &li.HighPart, FILE_CURRENT);
   65:     if (li.LowPart == 0xffffffffUL && GetLastError() != NO_ERROR)
   66: 	return -1;
   67: 
   68:     high = length >> 32;
   69:     if (!SetFilePointer(h, (DWORD) length, &high, FILE_BEGIN))
   70: 	return -1;
   71:     res = SetEndOfFile(h);
   72: 
   73:     /* back to old position */
   74:     SetFilePointer(h, li.LowPart, &li.HighPart, FILE_BEGIN);
   75:     return res ? 0 : -1;
   76: }
   77: 
   78: static int set_sparse(int fd)
   79: {
   80:     DWORD returned;
   81:     return (int) DeviceIoControl((HANDLE)_get_osfhandle(fd), FSCTL_SET_SPARSE,
   82: 				 NULL, 0, NULL, 0, &returned, NULL);
   83: }
   84: 
   85: static int raw_open(BlockDriverState *bs, const char *filename, int flags)
   86: {
   87:     BDRVRawState *s = bs->opaque;
   88:     int access_flags, create_flags;
   89:     DWORD overlapped;
   90: 
   91:     s->type = FTYPE_FILE;
   92: 
   93:     if ((flags & BDRV_O_ACCESS) == O_RDWR) {
   94:         access_flags = GENERIC_READ | GENERIC_WRITE;
   95:     } else {
   96:         access_flags = GENERIC_READ;
   97:     }
   98:     if (flags & BDRV_O_CREAT) {
   99:         create_flags = CREATE_ALWAYS;
  100:     } else {
  101:         create_flags = OPEN_EXISTING;
  102:     }
  103: #ifdef QEMU_IMG
  104:     overlapped = FILE_ATTRIBUTE_NORMAL;
  105: #else
  106:     overlapped = FILE_FLAG_OVERLAPPED;
  107: #endif
  108:     if (flags & BDRV_O_DIRECT)
  109:         overlapped |= FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH;
  110:     s->hfile = CreateFile(filename, access_flags,
  111:                           FILE_SHARE_READ, NULL,
  112:                           create_flags, overlapped, NULL);
  113:     if (s->hfile == INVALID_HANDLE_VALUE) {
  114:         int err = GetLastError();
  115: 
  116:         if (err == ERROR_ACCESS_DENIED)
  117:             return -EACCES;
  118:         return -1;
  119:     }
  120:     return 0;
  121: }
  122: 
  123: static int raw_pread(BlockDriverState *bs, int64_t offset,
  124:                      uint8_t *buf, int count)
  125: {
  126:     BDRVRawState *s = bs->opaque;
  127:     OVERLAPPED ov;
  128:     DWORD ret_count;
  129:     int ret;
  130: 
  131:     memset(&ov, 0, sizeof(ov));
  132:     ov.Offset = offset;
  133:     ov.OffsetHigh = offset >> 32;
  134:     ret = ReadFile(s->hfile, buf, count, &ret_count, &ov);
  135:     if (!ret) {
  136:         ret = GetOverlappedResult(s->hfile, &ov, &ret_count, TRUE);
  137:         if (!ret)
  138:             return -EIO;
  139:         else
  140:             return ret_count;
  141:     }
  142:     return ret_count;
  143: }
  144: 
  145: static int raw_pwrite(BlockDriverState *bs, int64_t offset,
  146:                       const uint8_t *buf, int count)
  147: {
  148:     BDRVRawState *s = bs->opaque;
  149:     OVERLAPPED ov;
  150:     DWORD ret_count;
  151:     int ret;
  152: 
  153:     memset(&ov, 0, sizeof(ov));
  154:     ov.Offset = offset;
  155:     ov.OffsetHigh = offset >> 32;
  156:     ret = WriteFile(s->hfile, buf, count, &ret_count, &ov);
  157:     if (!ret) {
  158:         ret = GetOverlappedResult(s->hfile, &ov, &ret_count, TRUE);
  159:         if (!ret)
  160:             return -EIO;
  161:         else
  162:             return ret_count;
  163:     }
  164:     return ret_count;
  165: }
  166: 
  167: #if 0
  168: #ifndef QEMU_IMG
  169: static void raw_aio_cb(void *opaque)
  170: {
  171:     RawAIOCB *acb = opaque;
  172:     BlockDriverState *bs = acb->common.bs;
  173:     BDRVRawState *s = bs->opaque;
  174:     DWORD ret_count;
  175:     int ret;
  176: 
  177:     ret = GetOverlappedResult(s->hfile, &acb->ov, &ret_count, TRUE);
  178:     if (!ret || ret_count != acb->count) {
  179:         acb->common.cb(acb->common.opaque, -EIO);
  180:     } else {
  181:         acb->common.cb(acb->common.opaque, 0);
  182:     }
  183: }
  184: #endif
  185: 
  186: static RawAIOCB *raw_aio_setup(BlockDriverState *bs,
  187:         int64_t sector_num, uint8_t *buf, int nb_sectors,
  188:         BlockDriverCompletionFunc *cb, void *opaque)
  189: {
  190:     RawAIOCB *acb;
  191:     int64_t offset;
  192: 
  193:     acb = qemu_aio_get(bs, cb, opaque);
  194:     if (acb->hEvent) {
  195:         acb->hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  196:         if (!acb->hEvent) {
  197:             qemu_aio_release(acb);
  198:             return NULL;
  199:         }
  200:     }
  201:     memset(&acb->ov, 0, sizeof(acb->ov));
  202:     offset = sector_num * 512;
  203:     acb->ov.Offset = offset;
  204:     acb->ov.OffsetHigh = offset >> 32;
  205:     acb->ov.hEvent = acb->hEvent;
  206:     acb->count = nb_sectors * 512;
  207: #ifndef QEMU_IMG
  208:     qemu_add_wait_object(acb->ov.hEvent, raw_aio_cb, acb);
  209: #endif
  210:     return acb;
  211: }
  212: 
  213: static BlockDriverAIOCB *raw_aio_read(BlockDriverState *bs,
  214:         int64_t sector_num, uint8_t *buf, int nb_sectors,
  215:         BlockDriverCompletionFunc *cb, void *opaque)
  216: {
  217:     BDRVRawState *s = bs->opaque;
  218:     RawAIOCB *acb;
  219:     int ret;
  220: 
  221:     acb = raw_aio_setup(bs, sector_num, buf, nb_sectors, cb, opaque);
  222:     if (!acb)
  223:         return NULL;
  224:     ret = ReadFile(s->hfile, buf, acb->count, NULL, &acb->ov);
  225:     if (!ret) {
  226:         qemu_aio_release(acb);
  227:         return NULL;
  228:     }
  229: #ifdef QEMU_IMG
  230:     qemu_aio_release(acb);
  231: #endif
  232:     return (BlockDriverAIOCB *)acb;
  233: }
  234: 
  235: static BlockDriverAIOCB *raw_aio_write(BlockDriverState *bs,
  236:         int64_t sector_num, uint8_t *buf, int nb_sectors,
  237:         BlockDriverCompletionFunc *cb, void *opaque)
  238: {
  239:     BDRVRawState *s = bs->opaque;
  240:     RawAIOCB *acb;
  241:     int ret;
  242: 
  243:     acb = raw_aio_setup(bs, sector_num, buf, nb_sectors, cb, opaque);
  244:     if (!acb)
  245:         return NULL;
  246:     ret = WriteFile(s->hfile, buf, acb->count, NULL, &acb->ov);
  247:     if (!ret) {
  248:         qemu_aio_release(acb);
  249:         return NULL;
  250:     }
  251: #ifdef QEMU_IMG
  252:     qemu_aio_release(acb);
  253: #endif
  254:     return (BlockDriverAIOCB *)acb;
  255: }
  256: 
  257: static void raw_aio_cancel(BlockDriverAIOCB *blockacb)
  258: {
  259: #ifndef QEMU_IMG
  260:     RawAIOCB *acb = (RawAIOCB *)blockacb;
  261:     BlockDriverState *bs = acb->common.bs;
  262:     BDRVRawState *s = bs->opaque;
  263: 
  264:     qemu_del_wait_object(acb->ov.hEvent, raw_aio_cb, acb);
  265:     /* XXX: if more than one async I/O it is not correct */
  266:     CancelIo(s->hfile);
  267:     qemu_aio_release(acb);
  268: #endif
  269: }
  270: #endif /* #if 0 */
  271: 
  272: static void raw_flush(BlockDriverState *bs)
  273: {
  274:     BDRVRawState *s = bs->opaque;
  275:     FlushFileBuffers(s->hfile);
  276: }
  277: 
  278: static void raw_close(BlockDriverState *bs)
  279: {
  280:     BDRVRawState *s = bs->opaque;
  281:     CloseHandle(s->hfile);
  282: }
  283: 
  284: static int raw_truncate(BlockDriverState *bs, int64_t offset)
  285: {
  286:     BDRVRawState *s = bs->opaque;
  287:     DWORD low, high;
  288: 
  289:     low = offset;
  290:     high = offset >> 32;
  291:     if (!SetFilePointer(s->hfile, low, &high, FILE_BEGIN))
  292: 	return -EIO;
  293:     if (!SetEndOfFile(s->hfile))
  294:         return -EIO;
  295:     return 0;
  296: }
  297: 
  298: static int64_t raw_getlength(BlockDriverState *bs)
  299: {
  300:     BDRVRawState *s = bs->opaque;
  301:     LARGE_INTEGER l;
  302:     ULARGE_INTEGER available, total, total_free;
  303:     DISK_GEOMETRY_EX dg;
  304:     DWORD count;
  305:     BOOL status;
  306: 
  307:     switch(s->type) {
  308:     case FTYPE_FILE:
  309:         l.LowPart = GetFileSize(s->hfile, &l.HighPart);
  310:         if (l.LowPart == 0xffffffffUL && GetLastError() != NO_ERROR)
  311:             return -EIO;
  312:         break;
  313:     case FTYPE_CD:
  314:         if (!GetDiskFreeSpaceEx(s->drive_path, &available, &total, &total_free))
  315:             return -EIO;
  316:         l.QuadPart = total.QuadPart;
  317:         break;
  318:     case FTYPE_HARDDISK:
  319:         status = DeviceIoControl(s->hfile, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX,
  320:                                  NULL, 0, &dg, sizeof(dg), &count, NULL);
  321:         if (status != 0) {
  322:             l = dg.DiskSize;
  323:         }
  324:         break;
  325:     default:
  326:         return -EIO;
  327:     }
  328:     return l.QuadPart;
  329: }
  330: 
  331: static int raw_create(const char *filename, int64_t total_size,
  332:                       const char *backing_file, int flags)
  333: {
  334:     int fd;
  335: 
  336:     if (flags || backing_file)
  337:         return -ENOTSUP;
  338: 
  339:     fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
  340:               0644);
  341:     if (fd < 0)
  342:         return -EIO;
  343:     set_sparse(fd);
  344:     ftruncate(fd, total_size * 512);
  345:     close(fd);
  346:     return 0;
  347: }
  348: 
  349: void qemu_aio_init(void)
  350: {
  351: }
  352: 
  353: void qemu_aio_poll(void)
  354: {
  355: }
  356: 
  357: void qemu_aio_flush(void)
  358: {
  359: }
  360: 
  361: void qemu_aio_wait_start(void)
  362: {
  363: }
  364: 
  365: void qemu_aio_wait(void)
  366: {
  367: #ifndef QEMU_IMG
  368:     qemu_bh_poll();
  369: #endif
  370: }
  371: 
  372: void qemu_aio_wait_end(void)
  373: {
  374: }
  375: 
  376: BlockDriver bdrv_raw = {
  377:     "raw",
  378:     sizeof(BDRVRawState),
  379:     NULL, /* no probe for protocols */
  380:     raw_open,
  381:     NULL,
  382:     NULL,
  383:     raw_close,
  384:     raw_create,
  385:     raw_flush,
  386: 
  387: #if 0
  388:     .bdrv_aio_read = raw_aio_read,
  389:     .bdrv_aio_write = raw_aio_write,
  390:     .bdrv_aio_cancel = raw_aio_cancel,
  391:     .aiocb_size = sizeof(RawAIOCB);
  392: #endif
  393:     .protocol_name = "file",
  394:     .bdrv_pread = raw_pread,
  395:     .bdrv_pwrite = raw_pwrite,
  396:     .bdrv_truncate = raw_truncate,
  397:     .bdrv_getlength = raw_getlength,
  398: };
  399: 
  400: /***********************************************/
  401: /* host device */
  402: 
  403: static int find_cdrom(char *cdrom_name, int cdrom_name_size)
  404: {
  405:     char drives[256], *pdrv = drives;
  406:     UINT type;
  407: 
  408:     memset(drives, 0, sizeof(drives));
  409:     GetLogicalDriveStrings(sizeof(drives), drives);
  410:     while(pdrv[0] != '\0') {
  411:         type = GetDriveType(pdrv);
  412:         switch(type) {
  413:         case DRIVE_CDROM:
  414:             snprintf(cdrom_name, cdrom_name_size, "\\\\.\\%c:", pdrv[0]);
  415:             return 0;
  416:             break;
  417:         }
  418:         pdrv += lstrlen(pdrv) + 1;
  419:     }
  420:     return -1;
  421: }
  422: 
  423: static int find_device_type(BlockDriverState *bs, const char *filename)
  424: {
  425:     BDRVRawState *s = bs->opaque;
  426:     UINT type;
  427:     const char *p;
  428: 
  429:     if (strstart(filename, "\\\\.\\", &p) ||
  430:         strstart(filename, "//./", &p)) {
  431:         if (stristart(p, "PhysicalDrive", NULL))
  432:             return FTYPE_HARDDISK;
  433:         snprintf(s->drive_path, sizeof(s->drive_path), "%c:\\", p[0]);
  434:         type = GetDriveType(s->drive_path);
  435:         if (type == DRIVE_CDROM)
  436:             return FTYPE_CD;
  437:         else
  438:             return FTYPE_FILE;
  439:     } else {
  440:         return FTYPE_FILE;
  441:     }
  442: }
  443: 
  444: static int hdev_open(BlockDriverState *bs, const char *filename, int flags)
  445: {
  446:     BDRVRawState *s = bs->opaque;
  447:     int access_flags, create_flags;
  448:     DWORD overlapped;
  449:     char device_name[64];
  450: 
  451:     if (strstart(filename, "/dev/cdrom", NULL)) {
  452:         if (find_cdrom(device_name, sizeof(device_name)) < 0)
  453:             return -ENOENT;
  454:         filename = device_name;
  455:     } else {
  456:         /* transform drive letters into device name */
  457:         if (((filename[0] >= 'a' && filename[0] <= 'z') ||
  458:              (filename[0] >= 'A' && filename[0] <= 'Z')) &&
  459:             filename[1] == ':' && filename[2] == '\0') {
  460:             snprintf(device_name, sizeof(device_name), "\\\\.\\%c:", filename[0]);
  461:             filename = device_name;
  462:         }
  463:     }
  464:     s->type = find_device_type(bs, filename);
  465: 
  466:     if ((flags & BDRV_O_ACCESS) == O_RDWR) {
  467:         access_flags = GENERIC_READ | GENERIC_WRITE;
  468:     } else {
  469:         access_flags = GENERIC_READ;
  470:     }
  471:     create_flags = OPEN_EXISTING;
  472: 
  473: #ifdef QEMU_IMG
  474:     overlapped = FILE_ATTRIBUTE_NORMAL;
  475: #else
  476:     overlapped = FILE_FLAG_OVERLAPPED;
  477: #endif
  478:     if (flags & BDRV_O_DIRECT)
  479:         overlapped |= FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH;
  480:     s->hfile = CreateFile(filename, access_flags,
  481:                           FILE_SHARE_READ, NULL,
  482:                           create_flags, overlapped, NULL);
  483:     if (s->hfile == INVALID_HANDLE_VALUE) {
  484:         int err = GetLastError();
  485: 
  486:         if (err == ERROR_ACCESS_DENIED)
  487:             return -EACCES;
  488:         return -1;
  489:     }
  490:     return 0;
  491: }
  492: 
  493: #if 0
  494: /***********************************************/
  495: /* removable device additional commands */
  496: 
  497: static int raw_is_inserted(BlockDriverState *bs)
  498: {
  499:     return 1;
  500: }
  501: 
  502: static int raw_media_changed(BlockDriverState *bs)
  503: {
  504:     return -ENOTSUP;
  505: }
  506: 
  507: static int raw_eject(BlockDriverState *bs, int eject_flag)
  508: {
  509:     DWORD ret_count;
  510: 
  511:     if (s->type == FTYPE_FILE)
  512:         return -ENOTSUP;
  513:     if (eject_flag) {
  514:         DeviceIoControl(s->hfile, IOCTL_STORAGE_EJECT_MEDIA,
  515:                         NULL, 0, NULL, 0, &lpBytesReturned, NULL);
  516:     } else {
  517:         DeviceIoControl(s->hfile, IOCTL_STORAGE_LOAD_MEDIA,
  518:                         NULL, 0, NULL, 0, &lpBytesReturned, NULL);
  519:     }
  520: }
  521: 
  522: static int raw_set_locked(BlockDriverState *bs, int locked)
  523: {
  524:     return -ENOTSUP;
  525: }
  526: #endif
  527: 
  528: BlockDriver bdrv_host_device = {
  529:     "host_device",
  530:     sizeof(BDRVRawState),
  531:     NULL, /* no probe for protocols */
  532:     hdev_open,
  533:     NULL,
  534:     NULL,
  535:     raw_close,
  536:     NULL,
  537:     raw_flush,
  538: 
  539: #if 0
  540:     .bdrv_aio_read = raw_aio_read,
  541:     .bdrv_aio_write = raw_aio_write,
  542:     .bdrv_aio_cancel = raw_aio_cancel,
  543:     .aiocb_size = sizeof(RawAIOCB);
  544: #endif
  545:     .bdrv_pread = raw_pread,
  546:     .bdrv_pwrite = raw_pwrite,
  547:     .bdrv_getlength = raw_getlength,
  548: };

unix.superglobalmegacorp.com