ia64/xen-unstable

view tools/ioemu/block-raw.c @ 15841:c5f735271e22

[IA64] Foreign p2m: Fix vti domain builder.

It should set arch_domain::convmem_end.

Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp>
author Alex Williamson <alex.williamson@hp.com>
date Thu Sep 06 13:48:43 2007 -0600 (2007-09-06)
parents ea52a66e43a8
children 5352a7cc4f2a
line source
1 /*
2 * Block driver for RAW files
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 "vl.h"
25 #include "block_int.h"
26 #include <assert.h>
27 #ifndef _WIN32
28 #include <aio.h>
30 #ifndef QEMU_TOOL
31 #include "exec-all.h"
32 #endif
34 #ifdef CONFIG_COCOA
35 #include <paths.h>
36 #include <sys/param.h>
37 #include <IOKit/IOKitLib.h>
38 #include <IOKit/IOBSD.h>
39 #include <IOKit/storage/IOMediaBSDClient.h>
40 #include <IOKit/storage/IOMedia.h>
41 #include <IOKit/storage/IOCDMedia.h>
42 //#include <IOKit/storage/IOCDTypes.h>
43 #include <CoreFoundation/CoreFoundation.h>
44 #endif
46 #ifdef __sun__
47 #define _POSIX_PTHREAD_SEMANTICS 1
48 #include <signal.h>
49 #include <sys/dkio.h>
50 #endif
51 #ifdef __linux__
52 #include <sys/ioctl.h>
53 #include <linux/cdrom.h>
54 #include <linux/fd.h>
55 #endif
56 #ifdef __FreeBSD__
57 #include <sys/disk.h>
58 #endif
60 //#define DEBUG_FLOPPY
62 #define FTYPE_FILE 0
63 #define FTYPE_CD 1
64 #define FTYPE_FD 2
66 /* if the FD is not accessed during that time (in ms), we try to
67 reopen it to see if the disk has been changed */
68 #define FD_OPEN_TIMEOUT 1000
70 typedef struct BDRVRawState {
71 int fd;
72 int type;
73 #if defined(__linux__)
74 /* linux floppy specific */
75 int fd_open_flags;
76 int64_t fd_open_time;
77 int64_t fd_error_time;
78 int fd_got_error;
79 int fd_media_changed;
80 #endif
81 } BDRVRawState;
83 static int fd_open(BlockDriverState *bs);
85 static int raw_open(BlockDriverState *bs, const char *filename, int flags)
86 {
87 BDRVRawState *s = bs->opaque;
88 int fd, open_flags, ret;
90 open_flags = O_BINARY;
91 if ((flags & BDRV_O_ACCESS) == O_RDWR) {
92 open_flags |= O_RDWR;
93 } else {
94 open_flags |= O_RDONLY;
95 bs->read_only = 1;
96 }
97 if (flags & BDRV_O_CREAT)
98 open_flags |= O_CREAT | O_TRUNC;
100 s->type = FTYPE_FILE;
102 fd = open(filename, open_flags, 0644);
103 if (fd < 0) {
104 ret = -errno;
105 if (ret == -EROFS)
106 ret = -EACCES;
107 return ret;
108 }
109 s->fd = fd;
110 return 0;
111 }
113 /* XXX: use host sector size if necessary with:
114 #ifdef DIOCGSECTORSIZE
115 {
116 unsigned int sectorsize = 512;
117 if (!ioctl(fd, DIOCGSECTORSIZE, &sectorsize) &&
118 sectorsize > bufsize)
119 bufsize = sectorsize;
120 }
121 #endif
122 #ifdef CONFIG_COCOA
123 u_int32_t blockSize = 512;
124 if ( !ioctl( fd, DKIOCGETBLOCKSIZE, &blockSize ) && blockSize > bufsize) {
125 bufsize = blockSize;
126 }
127 #endif
128 */
130 static int raw_pread(BlockDriverState *bs, int64_t offset,
131 uint8_t *buf, int count)
132 {
133 BDRVRawState *s = bs->opaque;
134 int ret;
136 ret = fd_open(bs);
137 if (ret < 0)
138 return ret;
140 lseek(s->fd, offset, SEEK_SET);
141 ret = read(s->fd, buf, count);
142 return ret;
143 }
145 static int raw_pwrite(BlockDriverState *bs, int64_t offset,
146 const uint8_t *buf, int count)
147 {
148 BDRVRawState *s = bs->opaque;
149 int ret;
151 ret = fd_open(bs);
152 if (ret < 0)
153 return ret;
155 lseek(s->fd, offset, SEEK_SET);
156 ret = write(s->fd, buf, count);
157 return ret;
158 }
160 /***********************************************************/
161 /* Unix AIO using POSIX AIO */
163 typedef struct RawAIOCB {
164 BlockDriverAIOCB common;
165 struct aiocb aiocb;
166 struct RawAIOCB *next;
167 } RawAIOCB;
169 const int aio_sig_num = SIGUSR2;
170 static RawAIOCB *first_aio; /* AIO issued */
171 static int aio_initialized = 0;
173 static void aio_signal_handler(int signum)
174 {
175 #ifndef QEMU_TOOL
176 CPUState *env = cpu_single_env;
177 if (env) {
178 /* stop the currently executing cpu because a timer occured */
179 cpu_interrupt(env, CPU_INTERRUPT_EXIT);
180 #ifdef USE_KQEMU
181 if (env->kqemu_enabled) {
182 kqemu_cpu_interrupt(env);
183 }
184 #endif
185 }
186 #endif
187 }
189 void qemu_aio_init(void)
190 {
191 struct sigaction act;
192 sigset_t set;
194 aio_initialized = 1;
196 /* Ensure aio_sig_num is not blocked */
197 sigemptyset(&set);
198 sigaddset(&set, aio_sig_num);
199 sigprocmask(SIG_UNBLOCK, &set, NULL);
201 sigfillset(&act.sa_mask);
202 act.sa_flags = 0; /* do not restart syscalls to interrupt select() */
203 act.sa_handler = aio_signal_handler;
204 sigaction(aio_sig_num, &act, NULL);
206 #if defined(__GLIBC__) && defined(__linux__)
207 {
208 /* XXX: aio thread exit seems to hang on RedHat 9 and this init
209 seems to fix the problem. */
210 struct aioinit ai;
211 memset(&ai, 0, sizeof(ai));
212 ai.aio_threads = 1;
213 ai.aio_num = 1;
214 ai.aio_idle_time = 365 * 100000;
215 aio_init(&ai);
216 }
217 #endif
218 }
220 void qemu_aio_poll(void)
221 {
222 RawAIOCB *acb, **pacb;
223 int ret;
225 for(;;) {
226 pacb = &first_aio;
227 for(;;) {
228 acb = *pacb;
229 if (!acb)
230 goto the_end;
231 ret = aio_error(&acb->aiocb);
232 if (ret == ECANCELED) {
233 /* remove the request */
234 *pacb = acb->next;
235 qemu_aio_release(acb);
236 } else if (ret != EINPROGRESS) {
237 /* end of aio */
238 if (ret == 0) {
239 ret = aio_return(&acb->aiocb);
240 if (ret == acb->aiocb.aio_nbytes)
241 ret = 0;
242 else
243 ret = -EINVAL;
244 } else {
245 ret = -ret;
246 }
247 /* remove the request */
248 *pacb = acb->next;
249 /* call the callback */
250 acb->common.cb(acb->common.opaque, ret);
251 qemu_aio_release(acb);
252 break;
253 } else {
254 pacb = &acb->next;
255 }
256 }
257 }
258 the_end: ;
259 }
261 /* Wait for all IO requests to complete. */
262 void qemu_aio_flush(void)
263 {
264 qemu_aio_wait_start();
265 qemu_aio_poll();
266 while (first_aio) {
267 qemu_aio_wait();
268 }
269 qemu_aio_wait_end();
270 }
272 /* wait until at least one AIO was handled */
273 static sigset_t wait_oset;
275 void qemu_aio_wait_start(void)
276 {
277 sigset_t set;
279 if (!aio_initialized)
280 qemu_aio_init();
281 sigemptyset(&set);
282 sigaddset(&set, aio_sig_num);
283 sigprocmask(SIG_BLOCK, &set, &wait_oset);
284 }
286 void qemu_aio_wait(void)
287 {
288 sigset_t set;
289 int nb_sigs;
291 #ifndef QEMU_TOOL
292 if (qemu_bh_poll())
293 return;
294 #endif
295 sigemptyset(&set);
296 sigaddset(&set, aio_sig_num);
297 sigwait(&set, &nb_sigs);
298 qemu_aio_poll();
299 }
301 void qemu_aio_wait_end(void)
302 {
303 sigprocmask(SIG_SETMASK, &wait_oset, NULL);
304 }
306 static RawAIOCB *raw_aio_setup(BlockDriverState *bs,
307 int64_t sector_num, uint8_t *buf, int nb_sectors,
308 BlockDriverCompletionFunc *cb, void *opaque)
309 {
310 BDRVRawState *s = bs->opaque;
311 RawAIOCB *acb;
313 if (fd_open(bs) < 0)
314 return NULL;
316 acb = qemu_aio_get(bs, cb, opaque);
317 if (!acb)
318 return NULL;
319 acb->aiocb.aio_fildes = s->fd;
320 acb->aiocb.aio_sigevent.sigev_signo = aio_sig_num;
321 acb->aiocb.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
322 acb->aiocb.aio_buf = buf;
323 acb->aiocb.aio_nbytes = nb_sectors * 512;
324 acb->aiocb.aio_offset = sector_num * 512;
325 acb->next = first_aio;
326 first_aio = acb;
327 return acb;
328 }
330 static BlockDriverAIOCB *raw_aio_read(BlockDriverState *bs,
331 int64_t sector_num, uint8_t *buf, int nb_sectors,
332 BlockDriverCompletionFunc *cb, void *opaque)
333 {
334 RawAIOCB *acb;
336 acb = raw_aio_setup(bs, sector_num, buf, nb_sectors, cb, opaque);
337 if (!acb)
338 return NULL;
339 if (aio_read(&acb->aiocb) < 0) {
340 qemu_aio_release(acb);
341 return NULL;
342 }
343 return &acb->common;
344 }
346 static BlockDriverAIOCB *raw_aio_write(BlockDriverState *bs,
347 int64_t sector_num, const uint8_t *buf, int nb_sectors,
348 BlockDriverCompletionFunc *cb, void *opaque)
349 {
350 RawAIOCB *acb;
352 acb = raw_aio_setup(bs, sector_num, (uint8_t*)buf, nb_sectors, cb, opaque);
353 if (!acb)
354 return NULL;
355 if (aio_write(&acb->aiocb) < 0) {
356 qemu_aio_release(acb);
357 return NULL;
358 }
359 return &acb->common;
360 }
362 static void raw_aio_cancel(BlockDriverAIOCB *blockacb)
363 {
364 int ret;
365 RawAIOCB *acb = (RawAIOCB *)blockacb;
366 RawAIOCB **pacb;
368 ret = aio_cancel(acb->aiocb.aio_fildes, &acb->aiocb);
369 if (ret == AIO_NOTCANCELED) {
370 /* fail safe: if the aio could not be canceled, we wait for
371 it */
372 while (aio_error(&acb->aiocb) == EINPROGRESS);
373 }
375 /* remove the callback from the queue */
376 pacb = &first_aio;
377 for(;;) {
378 if (*pacb == NULL) {
379 break;
380 } else if (*pacb == acb) {
381 *pacb = acb->next;
382 qemu_aio_release(acb);
383 break;
384 }
385 pacb = &acb->next;
386 }
387 }
389 static void raw_close(BlockDriverState *bs)
390 {
391 BDRVRawState *s = bs->opaque;
392 bs->total_sectors = 0;
393 if (s->fd >= 0) {
394 close(s->fd);
395 s->fd = -1;
396 }
397 }
399 static int raw_truncate(BlockDriverState *bs, int64_t offset)
400 {
401 BDRVRawState *s = bs->opaque;
402 if (s->type != FTYPE_FILE)
403 return -ENOTSUP;
404 if (ftruncate(s->fd, offset) < 0)
405 return -errno;
406 return 0;
407 }
409 static int64_t raw_getlength(BlockDriverState *bs)
410 {
411 BDRVRawState *s = bs->opaque;
412 int fd = s->fd;
413 int64_t size;
414 #ifdef _BSD
415 struct stat sb;
416 #endif
417 #ifdef __sun__
418 struct dk_minfo minfo;
419 int rv;
420 #endif
421 int ret;
423 ret = fd_open(bs);
424 if (ret < 0)
425 return ret;
427 #ifdef _BSD
428 if (!fstat(fd, &sb) && (S_IFCHR & sb.st_mode)) {
429 #ifdef DIOCGMEDIASIZE
430 if (ioctl(fd, DIOCGMEDIASIZE, (off_t *)&size))
431 #endif
432 #ifdef CONFIG_COCOA
433 size = LONG_LONG_MAX;
434 #else
435 size = lseek(fd, 0LL, SEEK_END);
436 #endif
437 } else
438 #endif
439 #ifdef __sun__
440 /*
441 * use the DKIOCGMEDIAINFO ioctl to read the size.
442 */
443 rv = ioctl ( fd, DKIOCGMEDIAINFO, &minfo );
444 if ( rv != -1 ) {
445 size = minfo.dki_lbsize * minfo.dki_capacity;
446 } else /* there are reports that lseek on some devices
447 fails, but irc discussion said that contingency
448 on contingency was overkill */
449 #endif
450 {
451 size = lseek(fd, 0, SEEK_END);
452 }
453 return size;
454 }
456 static int raw_create(const char *filename, int64_t total_size,
457 const char *backing_file, int flags)
458 {
459 int fd;
461 if (flags || backing_file)
462 return -ENOTSUP;
464 fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
465 0644);
466 if (fd < 0)
467 return -EIO;
468 ftruncate(fd, total_size * 512);
469 close(fd);
470 return 0;
471 }
473 static void raw_flush(BlockDriverState *bs)
474 {
475 BDRVRawState *s = bs->opaque;
476 fsync(s->fd);
477 }
479 BlockDriver bdrv_raw = {
480 "raw",
481 sizeof(BDRVRawState),
482 NULL, /* no probe for protocols */
483 raw_open,
484 NULL,
485 NULL,
486 raw_close,
487 raw_create,
488 raw_flush,
490 .bdrv_aio_read = raw_aio_read,
491 .bdrv_aio_write = raw_aio_write,
492 .bdrv_aio_cancel = raw_aio_cancel,
493 .aiocb_size = sizeof(RawAIOCB),
494 .protocol_name = "file",
495 .bdrv_pread = raw_pread,
496 .bdrv_pwrite = raw_pwrite,
497 .bdrv_truncate = raw_truncate,
498 .bdrv_getlength = raw_getlength,
499 };
501 /***********************************************/
502 /* host device */
504 #ifdef CONFIG_COCOA
505 static kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator );
506 static kern_return_t GetBSDPath( io_iterator_t mediaIterator, char *bsdPath, CFIndex maxPathSize );
508 kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator )
509 {
510 kern_return_t kernResult;
511 mach_port_t masterPort;
512 CFMutableDictionaryRef classesToMatch;
514 kernResult = IOMasterPort( MACH_PORT_NULL, &masterPort );
515 if ( KERN_SUCCESS != kernResult ) {
516 printf( "IOMasterPort returned %d\n", kernResult );
517 }
519 classesToMatch = IOServiceMatching( kIOCDMediaClass );
520 if ( classesToMatch == NULL ) {
521 printf( "IOServiceMatching returned a NULL dictionary.\n" );
522 } else {
523 CFDictionarySetValue( classesToMatch, CFSTR( kIOMediaEjectableKey ), kCFBooleanTrue );
524 }
525 kernResult = IOServiceGetMatchingServices( masterPort, classesToMatch, mediaIterator );
526 if ( KERN_SUCCESS != kernResult )
527 {
528 printf( "IOServiceGetMatchingServices returned %d\n", kernResult );
529 }
531 return kernResult;
532 }
534 kern_return_t GetBSDPath( io_iterator_t mediaIterator, char *bsdPath, CFIndex maxPathSize )
535 {
536 io_object_t nextMedia;
537 kern_return_t kernResult = KERN_FAILURE;
538 *bsdPath = '\0';
539 nextMedia = IOIteratorNext( mediaIterator );
540 if ( nextMedia )
541 {
542 CFTypeRef bsdPathAsCFString;
543 bsdPathAsCFString = IORegistryEntryCreateCFProperty( nextMedia, CFSTR( kIOBSDNameKey ), kCFAllocatorDefault, 0 );
544 if ( bsdPathAsCFString ) {
545 size_t devPathLength;
546 strcpy( bsdPath, _PATH_DEV );
547 strcat( bsdPath, "r" );
548 devPathLength = strlen( bsdPath );
549 if ( CFStringGetCString( bsdPathAsCFString, bsdPath + devPathLength, maxPathSize - devPathLength, kCFStringEncodingASCII ) ) {
550 kernResult = KERN_SUCCESS;
551 }
552 CFRelease( bsdPathAsCFString );
553 }
554 IOObjectRelease( nextMedia );
555 }
557 return kernResult;
558 }
560 #endif
562 static int hdev_open(BlockDriverState *bs, const char *filename, int flags)
563 {
564 BDRVRawState *s = bs->opaque;
565 int fd, open_flags, ret;
567 #ifdef CONFIG_COCOA
568 if (strstart(filename, "/dev/cdrom", NULL)) {
569 kern_return_t kernResult;
570 io_iterator_t mediaIterator;
571 char bsdPath[ MAXPATHLEN ];
572 int fd;
574 kernResult = FindEjectableCDMedia( &mediaIterator );
575 kernResult = GetBSDPath( mediaIterator, bsdPath, sizeof( bsdPath ) );
577 if ( bsdPath[ 0 ] != '\0' ) {
578 strcat(bsdPath,"s0");
579 /* some CDs don't have a partition 0 */
580 fd = open(bsdPath, O_RDONLY | O_BINARY | O_LARGEFILE);
581 if (fd < 0) {
582 bsdPath[strlen(bsdPath)-1] = '1';
583 } else {
584 close(fd);
585 }
586 filename = bsdPath;
587 }
589 if ( mediaIterator )
590 IOObjectRelease( mediaIterator );
591 }
592 #endif
593 open_flags = O_BINARY;
594 if ((flags & BDRV_O_ACCESS) == O_RDWR) {
595 open_flags |= O_RDWR;
596 } else {
597 open_flags |= O_RDONLY;
598 bs->read_only = 1;
599 }
601 s->type = FTYPE_FILE;
602 #if defined(__linux__)
603 if (strstart(filename, "/dev/cd", NULL)) {
604 /* open will not fail even if no CD is inserted */
605 open_flags |= O_NONBLOCK;
606 s->type = FTYPE_CD;
607 } else if (strstart(filename, "/dev/fd", NULL)) {
608 s->type = FTYPE_FD;
609 s->fd_open_flags = open_flags;
610 /* open will not fail even if no floppy is inserted */
611 open_flags |= O_NONBLOCK;
612 }
613 #endif
614 fd = open(filename, open_flags, 0644);
615 if (fd < 0) {
616 ret = -errno;
617 if (ret == -EROFS)
618 ret = -EACCES;
619 return ret;
620 }
621 s->fd = fd;
622 #if defined(__linux__)
623 /* close fd so that we can reopen it as needed */
624 if (s->type == FTYPE_FD) {
625 close(s->fd);
626 s->fd = -1;
627 s->fd_media_changed = 1;
628 }
629 #endif
630 return 0;
631 }
633 #if defined(__linux__) && !defined(QEMU_TOOL)
635 /* Note: we do not have a reliable method to detect if the floppy is
636 present. The current method is to try to open the floppy at every
637 I/O and to keep it opened during a few hundreds of ms. */
638 static int fd_open(BlockDriverState *bs)
639 {
640 BDRVRawState *s = bs->opaque;
641 int last_media_present;
643 if (s->type != FTYPE_FD)
644 return 0;
645 last_media_present = (s->fd >= 0);
646 if (s->fd >= 0 &&
647 (qemu_get_clock(rt_clock) - s->fd_open_time) >= FD_OPEN_TIMEOUT) {
648 close(s->fd);
649 s->fd = -1;
650 #ifdef DEBUG_FLOPPY
651 printf("Floppy closed\n");
652 #endif
653 }
654 if (s->fd < 0) {
655 if (s->fd_got_error &&
656 (qemu_get_clock(rt_clock) - s->fd_error_time) < FD_OPEN_TIMEOUT) {
657 #ifdef DEBUG_FLOPPY
658 printf("No floppy (open delayed)\n");
659 #endif
660 return -EIO;
661 }
662 s->fd = open(bs->filename, s->fd_open_flags);
663 if (s->fd < 0) {
664 s->fd_error_time = qemu_get_clock(rt_clock);
665 s->fd_got_error = 1;
666 if (last_media_present)
667 s->fd_media_changed = 1;
668 #ifdef DEBUG_FLOPPY
669 printf("No floppy\n");
670 #endif
671 return -EIO;
672 }
673 #ifdef DEBUG_FLOPPY
674 printf("Floppy opened\n");
675 #endif
676 }
677 if (!last_media_present)
678 s->fd_media_changed = 1;
679 s->fd_open_time = qemu_get_clock(rt_clock);
680 s->fd_got_error = 0;
681 return 0;
682 }
683 #else
684 static int fd_open(BlockDriverState *bs)
685 {
686 return 0;
687 }
688 #endif
690 #if defined(__linux__)
692 static int raw_is_inserted(BlockDriverState *bs)
693 {
694 BDRVRawState *s = bs->opaque;
695 int ret;
697 switch(s->type) {
698 case FTYPE_CD:
699 ret = ioctl(s->fd, CDROM_DRIVE_STATUS, CDSL_CURRENT);
700 if (ret == CDS_DISC_OK)
701 return 1;
702 else
703 return 0;
704 break;
705 case FTYPE_FD:
706 ret = fd_open(bs);
707 return (ret >= 0);
708 default:
709 return 1;
710 }
711 }
713 /* currently only used by fdc.c, but a CD version would be good too */
714 static int raw_media_changed(BlockDriverState *bs)
715 {
716 BDRVRawState *s = bs->opaque;
718 switch(s->type) {
719 case FTYPE_FD:
720 {
721 int ret;
722 /* XXX: we do not have a true media changed indication. It
723 does not work if the floppy is changed without trying
724 to read it */
725 fd_open(bs);
726 ret = s->fd_media_changed;
727 s->fd_media_changed = 0;
728 #ifdef DEBUG_FLOPPY
729 printf("Floppy changed=%d\n", ret);
730 #endif
731 return ret;
732 }
733 default:
734 return -ENOTSUP;
735 }
736 }
738 static int raw_eject(BlockDriverState *bs, int eject_flag)
739 {
740 BDRVRawState *s = bs->opaque;
742 switch(s->type) {
743 case FTYPE_CD:
744 if (eject_flag) {
745 if (ioctl (s->fd, CDROMEJECT, NULL) < 0)
746 perror("CDROMEJECT");
747 } else {
748 if (ioctl (s->fd, CDROMCLOSETRAY, NULL) < 0)
749 perror("CDROMEJECT");
750 }
751 break;
752 case FTYPE_FD:
753 {
754 int fd;
755 if (s->fd >= 0) {
756 close(s->fd);
757 s->fd = -1;
758 }
759 fd = open(bs->filename, s->fd_open_flags | O_NONBLOCK);
760 if (fd >= 0) {
761 if (ioctl(fd, FDEJECT, 0) < 0)
762 perror("FDEJECT");
763 close(fd);
764 }
765 }
766 break;
767 default:
768 return -ENOTSUP;
769 }
770 return 0;
771 }
773 static int raw_set_locked(BlockDriverState *bs, int locked)
774 {
775 BDRVRawState *s = bs->opaque;
777 switch(s->type) {
778 case FTYPE_CD:
779 if (ioctl (s->fd, CDROM_LOCKDOOR, locked) < 0) {
780 /* Note: an error can happen if the distribution automatically
781 mounts the CD-ROM */
782 // perror("CDROM_LOCKDOOR");
783 }
784 break;
785 default:
786 return -ENOTSUP;
787 }
788 return 0;
789 }
791 #else
793 static int raw_is_inserted(BlockDriverState *bs)
794 {
795 return 1;
796 }
798 static int raw_media_changed(BlockDriverState *bs)
799 {
800 return -ENOTSUP;
801 }
803 static int raw_eject(BlockDriverState *bs, int eject_flag)
804 {
805 return -ENOTSUP;
806 }
808 static int raw_set_locked(BlockDriverState *bs, int locked)
809 {
810 return -ENOTSUP;
811 }
813 #endif /* !linux */
815 BlockDriver bdrv_host_device = {
816 "host_device",
817 sizeof(BDRVRawState),
818 NULL, /* no probe for protocols */
819 hdev_open,
820 NULL,
821 NULL,
822 raw_close,
823 NULL,
824 raw_flush,
826 .bdrv_aio_read = raw_aio_read,
827 .bdrv_aio_write = raw_aio_write,
828 .bdrv_aio_cancel = raw_aio_cancel,
829 .aiocb_size = sizeof(RawAIOCB),
830 .bdrv_pread = raw_pread,
831 .bdrv_pwrite = raw_pwrite,
832 .bdrv_getlength = raw_getlength,
834 /* removable device support */
835 .bdrv_is_inserted = raw_is_inserted,
836 .bdrv_media_changed = raw_media_changed,
837 .bdrv_eject = raw_eject,
838 .bdrv_set_locked = raw_set_locked,
839 };
841 #else /* _WIN32 */
843 /* XXX: use another file ? */
844 #include <winioctl.h>
846 #define FTYPE_FILE 0
847 #define FTYPE_CD 1
848 #define FTYPE_HARDDISK 2
850 typedef struct BDRVRawState {
851 HANDLE hfile;
852 int type;
853 char drive_path[16]; /* format: "d:\" */
854 } BDRVRawState;
856 typedef struct RawAIOCB {
857 BlockDriverAIOCB common;
858 HANDLE hEvent;
859 OVERLAPPED ov;
860 int count;
861 } RawAIOCB;
863 int qemu_ftruncate64(int fd, int64_t length)
864 {
865 LARGE_INTEGER li;
866 LONG high;
867 HANDLE h;
868 BOOL res;
870 if ((GetVersion() & 0x80000000UL) && (length >> 32) != 0)
871 return -1;
873 h = (HANDLE)_get_osfhandle(fd);
875 /* get current position, ftruncate do not change position */
876 li.HighPart = 0;
877 li.LowPart = SetFilePointer (h, 0, &li.HighPart, FILE_CURRENT);
878 if (li.LowPart == 0xffffffffUL && GetLastError() != NO_ERROR)
879 return -1;
881 high = length >> 32;
882 if (!SetFilePointer(h, (DWORD) length, &high, FILE_BEGIN))
883 return -1;
884 res = SetEndOfFile(h);
886 /* back to old position */
887 SetFilePointer(h, li.LowPart, &li.HighPart, FILE_BEGIN);
888 return res ? 0 : -1;
889 }
891 static int set_sparse(int fd)
892 {
893 DWORD returned;
894 return (int) DeviceIoControl((HANDLE)_get_osfhandle(fd), FSCTL_SET_SPARSE,
895 NULL, 0, NULL, 0, &returned, NULL);
896 }
898 static int raw_open(BlockDriverState *bs, const char *filename, int flags)
899 {
900 BDRVRawState *s = bs->opaque;
901 int access_flags, create_flags;
902 DWORD overlapped;
904 s->type = FTYPE_FILE;
906 if ((flags & BDRV_O_ACCESS) == O_RDWR) {
907 access_flags = GENERIC_READ | GENERIC_WRITE;
908 } else {
909 access_flags = GENERIC_READ;
910 }
911 if (flags & BDRV_O_CREAT) {
912 create_flags = CREATE_ALWAYS;
913 } else {
914 create_flags = OPEN_EXISTING;
915 }
916 #ifdef QEMU_TOOL
917 overlapped = FILE_ATTRIBUTE_NORMAL;
918 #else
919 overlapped = FILE_FLAG_OVERLAPPED;
920 #endif
921 s->hfile = CreateFile(filename, access_flags,
922 FILE_SHARE_READ, NULL,
923 create_flags, overlapped, NULL);
924 if (s->hfile == INVALID_HANDLE_VALUE) {
925 int err = GetLastError();
927 if (err == ERROR_ACCESS_DENIED)
928 return -EACCES;
929 return -1;
930 }
931 return 0;
932 }
934 static int raw_pread(BlockDriverState *bs, int64_t offset,
935 uint8_t *buf, int count)
936 {
937 BDRVRawState *s = bs->opaque;
938 OVERLAPPED ov;
939 DWORD ret_count;
940 int ret;
942 memset(&ov, 0, sizeof(ov));
943 ov.Offset = offset;
944 ov.OffsetHigh = offset >> 32;
945 ret = ReadFile(s->hfile, buf, count, &ret_count, &ov);
946 if (!ret) {
947 ret = GetOverlappedResult(s->hfile, &ov, &ret_count, TRUE);
948 if (!ret)
949 return -EIO;
950 else
951 return ret_count;
952 }
953 return ret_count;
954 }
956 static int raw_pwrite(BlockDriverState *bs, int64_t offset,
957 const uint8_t *buf, int count)
958 {
959 BDRVRawState *s = bs->opaque;
960 OVERLAPPED ov;
961 DWORD ret_count;
962 int ret;
964 memset(&ov, 0, sizeof(ov));
965 ov.Offset = offset;
966 ov.OffsetHigh = offset >> 32;
967 ret = WriteFile(s->hfile, buf, count, &ret_count, &ov);
968 if (!ret) {
969 ret = GetOverlappedResult(s->hfile, &ov, &ret_count, TRUE);
970 if (!ret)
971 return -EIO;
972 else
973 return ret_count;
974 }
975 return ret_count;
976 }
978 #if 0
979 #ifndef QEMU_TOOL
980 static void raw_aio_cb(void *opaque)
981 {
982 RawAIOCB *acb = opaque;
983 BlockDriverState *bs = acb->common.bs;
984 BDRVRawState *s = bs->opaque;
985 DWORD ret_count;
986 int ret;
988 ret = GetOverlappedResult(s->hfile, &acb->ov, &ret_count, TRUE);
989 if (!ret || ret_count != acb->count) {
990 acb->common.cb(acb->common.opaque, -EIO);
991 } else {
992 acb->common.cb(acb->common.opaque, 0);
993 }
994 }
995 #endif
997 static RawAIOCB *raw_aio_setup(BlockDriverState *bs,
998 int64_t sector_num, uint8_t *buf, int nb_sectors,
999 BlockDriverCompletionFunc *cb, void *opaque)
1001 RawAIOCB *acb;
1002 int64_t offset;
1004 acb = qemu_aio_get(bs, cb, opaque);
1005 if (acb->hEvent) {
1006 acb->hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
1007 if (!acb->hEvent) {
1008 qemu_aio_release(acb);
1009 return NULL;
1012 memset(&acb->ov, 0, sizeof(acb->ov));
1013 offset = sector_num * 512;
1014 acb->ov.Offset = offset;
1015 acb->ov.OffsetHigh = offset >> 32;
1016 acb->ov.hEvent = acb->hEvent;
1017 acb->count = nb_sectors * 512;
1018 #ifndef QEMU_TOOL
1019 qemu_add_wait_object(acb->ov.hEvent, raw_aio_cb, acb);
1020 #endif
1021 return acb;
1024 static BlockDriverAIOCB *raw_aio_read(BlockDriverState *bs,
1025 int64_t sector_num, uint8_t *buf, int nb_sectors,
1026 BlockDriverCompletionFunc *cb, void *opaque)
1028 BDRVRawState *s = bs->opaque;
1029 RawAIOCB *acb;
1030 int ret;
1032 acb = raw_aio_setup(bs, sector_num, buf, nb_sectors, cb, opaque);
1033 if (!acb)
1034 return NULL;
1035 ret = ReadFile(s->hfile, buf, acb->count, NULL, &acb->ov);
1036 if (!ret) {
1037 qemu_aio_release(acb);
1038 return NULL;
1040 #ifdef QEMU_TOOL
1041 qemu_aio_release(acb);
1042 #endif
1043 return (BlockDriverAIOCB *)acb;
1046 static BlockDriverAIOCB *raw_aio_write(BlockDriverState *bs,
1047 int64_t sector_num, uint8_t *buf, int nb_sectors,
1048 BlockDriverCompletionFunc *cb, void *opaque)
1050 BDRVRawState *s = bs->opaque;
1051 RawAIOCB *acb;
1052 int ret;
1054 acb = raw_aio_setup(bs, sector_num, buf, nb_sectors, cb, opaque);
1055 if (!acb)
1056 return NULL;
1057 ret = WriteFile(s->hfile, buf, acb->count, NULL, &acb->ov);
1058 if (!ret) {
1059 qemu_aio_release(acb);
1060 return NULL;
1062 #ifdef QEMU_TOOL
1063 qemu_aio_release(acb);
1064 #endif
1065 return (BlockDriverAIOCB *)acb;
1068 static void raw_aio_cancel(BlockDriverAIOCB *blockacb)
1070 #ifndef QEMU_TOOL
1071 RawAIOCB *acb = (RawAIOCB *)blockacb;
1072 BlockDriverState *bs = acb->common.bs;
1073 BDRVRawState *s = bs->opaque;
1075 qemu_del_wait_object(acb->ov.hEvent, raw_aio_cb, acb);
1076 /* XXX: if more than one async I/O it is not correct */
1077 CancelIo(s->hfile);
1078 qemu_aio_release(acb);
1079 #endif
1081 #endif /* #if 0 */
1083 static void raw_flush(BlockDriverState *bs)
1085 BDRVRawState *s = bs->opaque;
1086 FlushFileBuffers(s->hfile);
1089 static void raw_close(BlockDriverState *bs)
1091 BDRVRawState *s = bs->opaque;
1092 CloseHandle(s->hfile);
1095 static int raw_truncate(BlockDriverState *bs, int64_t offset)
1097 BDRVRawState *s = bs->opaque;
1098 DWORD low, high;
1100 low = offset;
1101 high = offset >> 32;
1102 if (!SetFilePointer(s->hfile, low, &high, FILE_BEGIN))
1103 return -EIO;
1104 if (!SetEndOfFile(s->hfile))
1105 return -EIO;
1106 return 0;
1109 static int64_t raw_getlength(BlockDriverState *bs)
1111 BDRVRawState *s = bs->opaque;
1112 LARGE_INTEGER l;
1113 ULARGE_INTEGER available, total, total_free;
1114 DISK_GEOMETRY dg;
1115 DWORD count;
1116 BOOL status;
1118 switch(s->type) {
1119 case FTYPE_FILE:
1120 l.LowPart = GetFileSize(s->hfile, &l.HighPart);
1121 if (l.LowPart == 0xffffffffUL && GetLastError() != NO_ERROR)
1122 return -EIO;
1123 break;
1124 case FTYPE_CD:
1125 if (!GetDiskFreeSpaceEx(s->drive_path, &available, &total, &total_free))
1126 return -EIO;
1127 l.QuadPart = total.QuadPart;
1128 break;
1129 case FTYPE_HARDDISK:
1130 status = DeviceIoControl(s->hfile, IOCTL_DISK_GET_DRIVE_GEOMETRY,
1131 NULL, 0, &dg, sizeof(dg), &count, NULL);
1132 if (status != FALSE) {
1133 l.QuadPart = dg.Cylinders.QuadPart * dg.TracksPerCylinder
1134 * dg.SectorsPerTrack * dg.BytesPerSector;
1136 break;
1137 default:
1138 return -EIO;
1140 return l.QuadPart;
1143 static int raw_create(const char *filename, int64_t total_size,
1144 const char *backing_file, int flags)
1146 int fd;
1148 if (flags || backing_file)
1149 return -ENOTSUP;
1151 fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
1152 0644);
1153 if (fd < 0)
1154 return -EIO;
1155 set_sparse(fd);
1156 ftruncate(fd, total_size * 512);
1157 close(fd);
1158 return 0;
1161 void qemu_aio_init(void)
1165 void qemu_aio_poll(void)
1169 void qemu_aio_flush(void)
1173 void qemu_aio_wait_start(void)
1177 void qemu_aio_wait(void)
1179 #ifndef QEMU_TOOL
1180 qemu_bh_poll();
1181 #endif
1184 void qemu_aio_wait_end(void)
1188 BlockDriver bdrv_raw = {
1189 "raw",
1190 sizeof(BDRVRawState),
1191 NULL, /* no probe for protocols */
1192 raw_open,
1193 NULL,
1194 NULL,
1195 raw_close,
1196 raw_create,
1197 raw_flush,
1199 #if 0
1200 .bdrv_aio_read = raw_aio_read,
1201 .bdrv_aio_write = raw_aio_write,
1202 .bdrv_aio_cancel = raw_aio_cancel,
1203 .aiocb_size = sizeof(RawAIOCB);
1204 #endif
1205 .protocol_name = "file",
1206 .bdrv_pread = raw_pread,
1207 .bdrv_pwrite = raw_pwrite,
1208 .bdrv_truncate = raw_truncate,
1209 .bdrv_getlength = raw_getlength,
1210 };
1212 /***********************************************/
1213 /* host device */
1215 static int find_cdrom(char *cdrom_name, int cdrom_name_size)
1217 char drives[256], *pdrv = drives;
1218 UINT type;
1220 memset(drives, 0, sizeof(drives));
1221 GetLogicalDriveStrings(sizeof(drives), drives);
1222 while(pdrv[0] != '\0') {
1223 type = GetDriveType(pdrv);
1224 switch(type) {
1225 case DRIVE_CDROM:
1226 snprintf(cdrom_name, cdrom_name_size, "\\\\.\\%c:", pdrv[0]);
1227 return 0;
1228 break;
1230 pdrv += lstrlen(pdrv) + 1;
1232 return -1;
1235 static int find_device_type(BlockDriverState *bs, const char *filename)
1237 BDRVRawState *s = bs->opaque;
1238 UINT type;
1239 const char *p;
1241 if (strstart(filename, "\\\\.\\", &p) ||
1242 strstart(filename, "//./", &p)) {
1243 if (stristart(p, "PhysicalDrive", NULL))
1244 return FTYPE_HARDDISK;
1245 snprintf(s->drive_path, sizeof(s->drive_path), "%c:\\", p[0]);
1246 type = GetDriveType(s->drive_path);
1247 if (type == DRIVE_CDROM)
1248 return FTYPE_CD;
1249 else
1250 return FTYPE_FILE;
1251 } else {
1252 return FTYPE_FILE;
1256 static int hdev_open(BlockDriverState *bs, const char *filename, int flags)
1258 BDRVRawState *s = bs->opaque;
1259 int access_flags, create_flags;
1260 DWORD overlapped;
1261 char device_name[64];
1263 if (strstart(filename, "/dev/cdrom", NULL)) {
1264 if (find_cdrom(device_name, sizeof(device_name)) < 0)
1265 return -ENOENT;
1266 filename = device_name;
1267 } else {
1268 /* transform drive letters into device name */
1269 if (((filename[0] >= 'a' && filename[0] <= 'z') ||
1270 (filename[0] >= 'A' && filename[0] <= 'Z')) &&
1271 filename[1] == ':' && filename[2] == '\0') {
1272 snprintf(device_name, sizeof(device_name), "\\\\.\\%c:", filename[0]);
1273 filename = device_name;
1276 s->type = find_device_type(bs, filename);
1278 if ((flags & BDRV_O_ACCESS) == O_RDWR) {
1279 access_flags = GENERIC_READ | GENERIC_WRITE;
1280 } else {
1281 access_flags = GENERIC_READ;
1283 create_flags = OPEN_EXISTING;
1285 #ifdef QEMU_TOOL
1286 overlapped = FILE_ATTRIBUTE_NORMAL;
1287 #else
1288 overlapped = FILE_FLAG_OVERLAPPED;
1289 #endif
1290 s->hfile = CreateFile(filename, access_flags,
1291 FILE_SHARE_READ, NULL,
1292 create_flags, overlapped, NULL);
1293 if (s->hfile == INVALID_HANDLE_VALUE) {
1294 int err = GetLastError();
1296 if (err == ERROR_ACCESS_DENIED)
1297 return -EACCES;
1298 return -1;
1300 return 0;
1303 #if 0
1304 /***********************************************/
1305 /* removable device additionnal commands */
1307 static int raw_is_inserted(BlockDriverState *bs)
1309 return 1;
1312 static int raw_media_changed(BlockDriverState *bs)
1314 return -ENOTSUP;
1317 static int raw_eject(BlockDriverState *bs, int eject_flag)
1319 DWORD ret_count;
1321 if (s->type == FTYPE_FILE)
1322 return -ENOTSUP;
1323 if (eject_flag) {
1324 DeviceIoControl(s->hfile, IOCTL_STORAGE_EJECT_MEDIA,
1325 NULL, 0, NULL, 0, &lpBytesReturned, NULL);
1326 } else {
1327 DeviceIoControl(s->hfile, IOCTL_STORAGE_LOAD_MEDIA,
1328 NULL, 0, NULL, 0, &lpBytesReturned, NULL);
1332 static int raw_set_locked(BlockDriverState *bs, int locked)
1334 return -ENOTSUP;
1336 #endif
1338 BlockDriver bdrv_host_device = {
1339 "host_device",
1340 sizeof(BDRVRawState),
1341 NULL, /* no probe for protocols */
1342 hdev_open,
1343 NULL,
1344 NULL,
1345 raw_close,
1346 NULL,
1347 raw_flush,
1349 #if 0
1350 .bdrv_aio_read = raw_aio_read,
1351 .bdrv_aio_write = raw_aio_write,
1352 .bdrv_aio_cancel = raw_aio_cancel,
1353 .aiocb_size = sizeof(RawAIOCB);
1354 #endif
1355 .bdrv_pread = raw_pread,
1356 .bdrv_pwrite = raw_pwrite,
1357 .bdrv_getlength = raw_getlength,
1358 };
1359 #endif /* _WIN32 */