Statistics
| Branch: | Revision:

root / block-raw.c @ 57be54bb

History | View | Annotate | Download (32.7 kB)

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>
29

    
30
#ifndef QEMU_TOOL
31
#include "exec-all.h"
32
#endif
33

    
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
45

    
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
59

    
60
//#define DEBUG_FLOPPY
61

    
62
#define FTYPE_FILE   0
63
#define FTYPE_CD     1
64
#define FTYPE_FD     2
65

    
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
69

    
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;
82

    
83
static int fd_open(BlockDriverState *bs);
84

    
85
static int raw_open(BlockDriverState *bs, const char *filename, int flags)
86
{
87
    BDRVRawState *s = bs->opaque;
88
    int fd, open_flags, ret;
89

    
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;
99

    
100
    s->type = FTYPE_FILE;
101

    
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
}
112

    
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
*/
129

    
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;
135
    
136
    ret = fd_open(bs);
137
    if (ret < 0)
138
        return ret;
139

    
140
    lseek(s->fd, offset, SEEK_SET);
141
    ret = read(s->fd, buf, count);
142
    return ret;
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
    int ret;
150
    
151
    ret = fd_open(bs);
152
    if (ret < 0)
153
        return ret;
154

    
155
    lseek(s->fd, offset, SEEK_SET);
156
    ret = write(s->fd, buf, count);
157
    return ret;
158
}
159

    
160
/***********************************************************/
161
/* Unix AIO using POSIX AIO */
162

    
163
typedef struct RawAIOCB {
164
    BlockDriverAIOCB common;
165
    struct aiocb aiocb;
166
    struct RawAIOCB *next;
167
} RawAIOCB;
168

    
169
static int aio_sig_num = SIGUSR2;
170
static RawAIOCB *first_aio; /* AIO issued */
171
static int aio_initialized = 0;
172

    
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
}
188

    
189
void qemu_aio_init(void)
190
{
191
    struct sigaction act;
192

    
193
    aio_initialized = 1;
194
    
195
    sigfillset(&act.sa_mask);
196
    act.sa_flags = 0; /* do not restart syscalls to interrupt select() */
197
    act.sa_handler = aio_signal_handler;
198
    sigaction(aio_sig_num, &act, NULL);
199

    
200
#if defined(__GLIBC__) && defined(__linux__)
201
    {
202
        /* XXX: aio thread exit seems to hang on RedHat 9 and this init
203
           seems to fix the problem. */
204
        struct aioinit ai;
205
        memset(&ai, 0, sizeof(ai));
206
        ai.aio_threads = 1;
207
        ai.aio_num = 1;
208
        ai.aio_idle_time = 365 * 100000;
209
        aio_init(&ai);
210
    }
211
#endif
212
}
213

    
214
void qemu_aio_poll(void)
215
{
216
    RawAIOCB *acb, **pacb;
217
    int ret;
218

    
219
    for(;;) {
220
        pacb = &first_aio;
221
        for(;;) {
222
            acb = *pacb;
223
            if (!acb)
224
                goto the_end;
225
            ret = aio_error(&acb->aiocb);
226
            if (ret == ECANCELED) {
227
                /* remove the request */
228
                *pacb = acb->next;
229
                qemu_aio_release(acb);
230
            } else if (ret != EINPROGRESS) {
231
                /* end of aio */
232
                if (ret == 0) {
233
                    ret = aio_return(&acb->aiocb);
234
                    if (ret == acb->aiocb.aio_nbytes)
235
                        ret = 0;
236
                    else
237
                        ret = -EINVAL;
238
                } else {
239
                    ret = -ret;
240
                }
241
                /* remove the request */
242
                *pacb = acb->next;
243
                /* call the callback */
244
                acb->common.cb(acb->common.opaque, ret);
245
                qemu_aio_release(acb);
246
                break;
247
            } else {
248
                pacb = &acb->next;
249
            }
250
        }
251
    }
252
 the_end: ;
253
}
254

    
255
/* Wait for all IO requests to complete.  */
256
void qemu_aio_flush(void)
257
{
258
    qemu_aio_wait_start();
259
    qemu_aio_poll();
260
    while (first_aio) {
261
        qemu_aio_wait();
262
    }
263
    qemu_aio_wait_end();
264
}
265

    
266
/* wait until at least one AIO was handled */
267
static sigset_t wait_oset;
268

    
269
void qemu_aio_wait_start(void)
270
{
271
    sigset_t set;
272

    
273
    if (!aio_initialized)
274
        qemu_aio_init();
275
    sigemptyset(&set);
276
    sigaddset(&set, aio_sig_num);
277
    sigprocmask(SIG_BLOCK, &set, &wait_oset);
278
}
279

    
280
void qemu_aio_wait(void)
281
{
282
    sigset_t set;
283
    int nb_sigs;
284

    
285
#ifndef QEMU_TOOL
286
    if (qemu_bh_poll())
287
        return;
288
#endif
289
    sigemptyset(&set);
290
    sigaddset(&set, aio_sig_num);
291
    sigwait(&set, &nb_sigs);
292
    qemu_aio_poll();
293
}
294

    
295
void qemu_aio_wait_end(void)
296
{
297
    sigprocmask(SIG_SETMASK, &wait_oset, NULL);
298
}
299

    
300
static RawAIOCB *raw_aio_setup(BlockDriverState *bs,
301
        int64_t sector_num, uint8_t *buf, int nb_sectors,
302
        BlockDriverCompletionFunc *cb, void *opaque)
303
{
304
    BDRVRawState *s = bs->opaque;
305
    RawAIOCB *acb;
306

    
307
    if (fd_open(bs) < 0)
308
        return NULL;
309

    
310
    acb = qemu_aio_get(bs, cb, opaque);
311
    if (!acb)
312
        return NULL;
313
    acb->aiocb.aio_fildes = s->fd;
314
    acb->aiocb.aio_sigevent.sigev_signo = aio_sig_num;
315
    acb->aiocb.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
316
    acb->aiocb.aio_buf = buf;
317
    acb->aiocb.aio_nbytes = nb_sectors * 512;
318
    acb->aiocb.aio_offset = sector_num * 512;
319
    acb->next = first_aio;
320
    first_aio = acb;
321
    return acb;
322
}
323

    
324
static BlockDriverAIOCB *raw_aio_read(BlockDriverState *bs,
325
        int64_t sector_num, uint8_t *buf, int nb_sectors,
326
        BlockDriverCompletionFunc *cb, void *opaque)
327
{
328
    RawAIOCB *acb;
329

    
330
    acb = raw_aio_setup(bs, sector_num, buf, nb_sectors, cb, opaque);
331
    if (!acb)
332
        return NULL;
333
    if (aio_read(&acb->aiocb) < 0) {
334
        qemu_aio_release(acb);
335
        return NULL;
336
    } 
337
    return &acb->common;
338
}
339

    
340
static BlockDriverAIOCB *raw_aio_write(BlockDriverState *bs,
341
        int64_t sector_num, const uint8_t *buf, int nb_sectors,
342
        BlockDriverCompletionFunc *cb, void *opaque)
343
{
344
    RawAIOCB *acb;
345

    
346
    acb = raw_aio_setup(bs, sector_num, (uint8_t*)buf, nb_sectors, cb, opaque);
347
    if (!acb)
348
        return NULL;
349
    if (aio_write(&acb->aiocb) < 0) {
350
        qemu_aio_release(acb);
351
        return NULL;
352
    } 
353
    return &acb->common;
354
}
355

    
356
static void raw_aio_cancel(BlockDriverAIOCB *blockacb)
357
{
358
    int ret;
359
    RawAIOCB *acb = (RawAIOCB *)blockacb;
360
    RawAIOCB **pacb;
361

    
362
    ret = aio_cancel(acb->aiocb.aio_fildes, &acb->aiocb);
363
    if (ret == AIO_NOTCANCELED) {
364
        /* fail safe: if the aio could not be canceled, we wait for
365
           it */
366
        while (aio_error(&acb->aiocb) == EINPROGRESS);
367
    }
368

    
369
    /* remove the callback from the queue */
370
    pacb = &first_aio;
371
    for(;;) {
372
        if (*pacb == NULL) {
373
            break;
374
        } else if (*pacb == acb) {
375
            *pacb = acb->next;
376
            qemu_aio_release(acb);
377
            break;
378
        }
379
        pacb = &acb->next;
380
    }
381
}
382

    
383
static void raw_close(BlockDriverState *bs)
384
{
385
    BDRVRawState *s = bs->opaque;
386
    if (s->fd >= 0) {
387
        close(s->fd);
388
        s->fd = -1;
389
    }
390
}
391

    
392
static int raw_truncate(BlockDriverState *bs, int64_t offset)
393
{
394
    BDRVRawState *s = bs->opaque;
395
    if (s->type != FTYPE_FILE)
396
        return -ENOTSUP;
397
    if (ftruncate(s->fd, offset) < 0)
398
        return -errno;
399
    return 0;
400
}
401

    
402
static int64_t  raw_getlength(BlockDriverState *bs)
403
{
404
    BDRVRawState *s = bs->opaque;
405
    int fd = s->fd;
406
    int64_t size;
407
#ifdef _BSD
408
    struct stat sb;
409
#endif
410
#ifdef __sun__
411
    struct dk_minfo minfo;
412
    int rv;
413
#endif
414
    int ret;
415

    
416
    ret = fd_open(bs);
417
    if (ret < 0)
418
        return ret;
419

    
420
#ifdef _BSD
421
    if (!fstat(fd, &sb) && (S_IFCHR & sb.st_mode)) {
422
#ifdef DIOCGMEDIASIZE
423
        if (ioctl(fd, DIOCGMEDIASIZE, (off_t *)&size))
424
#endif
425
#ifdef CONFIG_COCOA
426
        size = LONG_LONG_MAX;
427
#else
428
        size = lseek(fd, 0LL, SEEK_END);
429
#endif
430
    } else
431
#endif
432
#ifdef __sun__
433
    /*
434
     * use the DKIOCGMEDIAINFO ioctl to read the size.
435
     */
436
    rv = ioctl ( fd, DKIOCGMEDIAINFO, &minfo );
437
    if ( rv != -1 ) {
438
        size = minfo.dki_lbsize * minfo.dki_capacity;
439
    } else /* there are reports that lseek on some devices
440
              fails, but irc discussion said that contingency
441
              on contingency was overkill */
442
#endif
443
    {
444
        size = lseek(fd, 0, SEEK_END);
445
    }
446
    return size;
447
}
448

    
449
static int raw_create(const char *filename, int64_t total_size,
450
                      const char *backing_file, int flags)
451
{
452
    int fd;
453

    
454
    if (flags || backing_file)
455
        return -ENOTSUP;
456

    
457
    fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 
458
              0644);
459
    if (fd < 0)
460
        return -EIO;
461
    ftruncate(fd, total_size * 512);
462
    close(fd);
463
    return 0;
464
}
465

    
466
static void raw_flush(BlockDriverState *bs)
467
{
468
    BDRVRawState *s = bs->opaque;
469
    fsync(s->fd);
470
}
471

    
472
BlockDriver bdrv_raw = {
473
    "raw",
474
    sizeof(BDRVRawState),
475
    NULL, /* no probe for protocols */
476
    raw_open,
477
    NULL,
478
    NULL,
479
    raw_close,
480
    raw_create,
481
    raw_flush,
482
    
483
    .bdrv_aio_read = raw_aio_read,
484
    .bdrv_aio_write = raw_aio_write,
485
    .bdrv_aio_cancel = raw_aio_cancel,
486
    .aiocb_size = sizeof(RawAIOCB),
487
    .protocol_name = "file",
488
    .bdrv_pread = raw_pread,
489
    .bdrv_pwrite = raw_pwrite,
490
    .bdrv_truncate = raw_truncate,
491
    .bdrv_getlength = raw_getlength,
492
};
493

    
494
/***********************************************/
495
/* host device */
496

    
497
#ifdef CONFIG_COCOA
498
static kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator );
499
static kern_return_t GetBSDPath( io_iterator_t mediaIterator, char *bsdPath, CFIndex maxPathSize );
500

    
501
kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator )
502
{
503
    kern_return_t       kernResult; 
504
    mach_port_t     masterPort;
505
    CFMutableDictionaryRef  classesToMatch;
506

    
507
    kernResult = IOMasterPort( MACH_PORT_NULL, &masterPort );
508
    if ( KERN_SUCCESS != kernResult ) {
509
        printf( "IOMasterPort returned %d\n", kernResult );
510
    }
511
    
512
    classesToMatch = IOServiceMatching( kIOCDMediaClass ); 
513
    if ( classesToMatch == NULL ) {
514
        printf( "IOServiceMatching returned a NULL dictionary.\n" );
515
    } else {
516
    CFDictionarySetValue( classesToMatch, CFSTR( kIOMediaEjectableKey ), kCFBooleanTrue );
517
    }
518
    kernResult = IOServiceGetMatchingServices( masterPort, classesToMatch, mediaIterator );
519
    if ( KERN_SUCCESS != kernResult )
520
    {
521
        printf( "IOServiceGetMatchingServices returned %d\n", kernResult );
522
    }
523
    
524
    return kernResult;
525
}
526

    
527
kern_return_t GetBSDPath( io_iterator_t mediaIterator, char *bsdPath, CFIndex maxPathSize )
528
{
529
    io_object_t     nextMedia;
530
    kern_return_t   kernResult = KERN_FAILURE;
531
    *bsdPath = '\0';
532
    nextMedia = IOIteratorNext( mediaIterator );
533
    if ( nextMedia )
534
    {
535
        CFTypeRef   bsdPathAsCFString;
536
    bsdPathAsCFString = IORegistryEntryCreateCFProperty( nextMedia, CFSTR( kIOBSDNameKey ), kCFAllocatorDefault, 0 );
537
        if ( bsdPathAsCFString ) {
538
            size_t devPathLength;
539
            strcpy( bsdPath, _PATH_DEV );
540
            strcat( bsdPath, "r" );
541
            devPathLength = strlen( bsdPath );
542
            if ( CFStringGetCString( bsdPathAsCFString, bsdPath + devPathLength, maxPathSize - devPathLength, kCFStringEncodingASCII ) ) {
543
                kernResult = KERN_SUCCESS;
544
            }
545
            CFRelease( bsdPathAsCFString );
546
        }
547
        IOObjectRelease( nextMedia );
548
    }
549
    
550
    return kernResult;
551
}
552

    
553
#endif
554

    
555
static int hdev_open(BlockDriverState *bs, const char *filename, int flags)
556
{
557
    BDRVRawState *s = bs->opaque;
558
    int fd, open_flags, ret;
559

    
560
#ifdef CONFIG_COCOA
561
    if (strstart(filename, "/dev/cdrom", NULL)) {
562
        kern_return_t kernResult;
563
        io_iterator_t mediaIterator;
564
        char bsdPath[ MAXPATHLEN ];
565
        int fd;
566
 
567
        kernResult = FindEjectableCDMedia( &mediaIterator );
568
        kernResult = GetBSDPath( mediaIterator, bsdPath, sizeof( bsdPath ) );
569
    
570
        if ( bsdPath[ 0 ] != '\0' ) {
571
            strcat(bsdPath,"s0");
572
            /* some CDs don't have a partition 0 */
573
            fd = open(bsdPath, O_RDONLY | O_BINARY | O_LARGEFILE);
574
            if (fd < 0) {
575
                bsdPath[strlen(bsdPath)-1] = '1';
576
            } else {
577
                close(fd);
578
            }
579
            filename = bsdPath;
580
        }
581
        
582
        if ( mediaIterator )
583
            IOObjectRelease( mediaIterator );
584
    }
585
#endif
586
    open_flags = O_BINARY;
587
    if ((flags & BDRV_O_ACCESS) == O_RDWR) {
588
        open_flags |= O_RDWR;
589
    } else {
590
        open_flags |= O_RDONLY;
591
        bs->read_only = 1;
592
    }
593

    
594
    s->type = FTYPE_FILE;
595
#if defined(__linux__)
596
    if (strstart(filename, "/dev/cd", NULL)) {
597
        /* open will not fail even if no CD is inserted */
598
        open_flags |= O_NONBLOCK;
599
        s->type = FTYPE_CD;
600
    } else if (strstart(filename, "/dev/fd", NULL)) {
601
        s->type = FTYPE_FD;
602
        s->fd_open_flags = open_flags;
603
        /* open will not fail even if no floppy is inserted */
604
        open_flags |= O_NONBLOCK;
605
    }
606
#endif
607
    fd = open(filename, open_flags, 0644);
608
    if (fd < 0) {
609
        ret = -errno;
610
        if (ret == -EROFS)
611
            ret = -EACCES;
612
        return ret;
613
    }
614
    s->fd = fd;
615
#if defined(__linux__)
616
    /* close fd so that we can reopen it as needed */
617
    if (s->type == FTYPE_FD) {
618
        close(s->fd);
619
        s->fd = -1;
620
        s->fd_media_changed = 1;
621
    }
622
#endif
623
    return 0;
624
}
625

    
626
#if defined(__linux__) && !defined(QEMU_TOOL)
627

    
628
/* Note: we do not have a reliable method to detect if the floppy is
629
   present. The current method is to try to open the floppy at every
630
   I/O and to keep it opened during a few hundreds of ms. */
631
static int fd_open(BlockDriverState *bs)
632
{
633
    BDRVRawState *s = bs->opaque;
634
    int last_media_present;
635

    
636
    if (s->type != FTYPE_FD)
637
        return 0;
638
    last_media_present = (s->fd >= 0);
639
    if (s->fd >= 0 && 
640
        (qemu_get_clock(rt_clock) - s->fd_open_time) >= FD_OPEN_TIMEOUT) {
641
        close(s->fd);
642
        s->fd = -1;
643
#ifdef DEBUG_FLOPPY
644
        printf("Floppy closed\n");
645
#endif
646
    }
647
    if (s->fd < 0) {
648
        if (s->fd_got_error && 
649
            (qemu_get_clock(rt_clock) - s->fd_error_time) < FD_OPEN_TIMEOUT) {
650
#ifdef DEBUG_FLOPPY
651
            printf("No floppy (open delayed)\n");
652
#endif
653
            return -EIO;
654
        }
655
        s->fd = open(bs->filename, s->fd_open_flags);
656
        if (s->fd < 0) {
657
            s->fd_error_time = qemu_get_clock(rt_clock);
658
            s->fd_got_error = 1;
659
            if (last_media_present)
660
                s->fd_media_changed = 1;
661
#ifdef DEBUG_FLOPPY
662
            printf("No floppy\n");
663
#endif
664
            return -EIO;
665
        }
666
#ifdef DEBUG_FLOPPY
667
        printf("Floppy opened\n");
668
#endif
669
    }
670
    if (!last_media_present)
671
        s->fd_media_changed = 1;
672
    s->fd_open_time = qemu_get_clock(rt_clock);
673
    s->fd_got_error = 0;
674
    return 0;
675
}
676
#else
677
static int fd_open(BlockDriverState *bs)
678
{
679
    return 0;
680
}
681
#endif
682

    
683
#if defined(__linux__)
684

    
685
static int raw_is_inserted(BlockDriverState *bs)
686
{
687
    BDRVRawState *s = bs->opaque;
688
    int ret;
689

    
690
    switch(s->type) {
691
    case FTYPE_CD:
692
        ret = ioctl(s->fd, CDROM_DRIVE_STATUS, CDSL_CURRENT);
693
        if (ret == CDS_DISC_OK)
694
            return 1;
695
        else
696
            return 0;
697
        break;
698
    case FTYPE_FD:
699
        ret = fd_open(bs);
700
        return (ret >= 0);
701
    default:
702
        return 1;
703
    }
704
}
705

    
706
/* currently only used by fdc.c, but a CD version would be good too */
707
static int raw_media_changed(BlockDriverState *bs)
708
{
709
    BDRVRawState *s = bs->opaque;
710

    
711
    switch(s->type) {
712
    case FTYPE_FD:
713
        {
714
            int ret;
715
            /* XXX: we do not have a true media changed indication. It
716
               does not work if the floppy is changed without trying
717
               to read it */
718
            fd_open(bs);
719
            ret = s->fd_media_changed;
720
            s->fd_media_changed = 0;
721
#ifdef DEBUG_FLOPPY
722
            printf("Floppy changed=%d\n", ret);
723
#endif
724
            return ret;
725
        }
726
    default:
727
        return -ENOTSUP;
728
    }
729
}
730

    
731
static int raw_eject(BlockDriverState *bs, int eject_flag)
732
{
733
    BDRVRawState *s = bs->opaque;
734

    
735
    switch(s->type) {
736
    case FTYPE_CD:
737
        if (eject_flag) {
738
            if (ioctl (s->fd, CDROMEJECT, NULL) < 0)
739
                perror("CDROMEJECT");
740
        } else {
741
            if (ioctl (s->fd, CDROMCLOSETRAY, NULL) < 0)
742
                perror("CDROMEJECT");
743
        }
744
        break;
745
    case FTYPE_FD:
746
        {
747
            int fd;
748
            if (s->fd >= 0) {
749
                close(s->fd);
750
                s->fd = -1;
751
            }
752
            fd = open(bs->filename, s->fd_open_flags | O_NONBLOCK);
753
            if (fd >= 0) {
754
                if (ioctl(fd, FDEJECT, 0) < 0)
755
                    perror("FDEJECT");
756
                close(fd);
757
            }
758
        }
759
        break;
760
    default:
761
        return -ENOTSUP;
762
    }
763
    return 0;
764
}
765

    
766
static int raw_set_locked(BlockDriverState *bs, int locked)
767
{
768
    BDRVRawState *s = bs->opaque;
769

    
770
    switch(s->type) {
771
    case FTYPE_CD:
772
        if (ioctl (s->fd, CDROM_LOCKDOOR, locked) < 0) {
773
            /* Note: an error can happen if the distribution automatically
774
               mounts the CD-ROM */
775
            //        perror("CDROM_LOCKDOOR");
776
        }
777
        break;
778
    default:
779
        return -ENOTSUP;
780
    }
781
    return 0;
782
}
783

    
784
#else
785

    
786
static int raw_is_inserted(BlockDriverState *bs)
787
{
788
    return 1;
789
}
790

    
791
static int raw_media_changed(BlockDriverState *bs)
792
{
793
    return -ENOTSUP;
794
}
795

    
796
static int raw_eject(BlockDriverState *bs, int eject_flag)
797
{
798
    return -ENOTSUP;
799
}
800

    
801
static int raw_set_locked(BlockDriverState *bs, int locked)
802
{
803
    return -ENOTSUP;
804
}
805

    
806
#endif /* !linux */
807

    
808
BlockDriver bdrv_host_device = {
809
    "host_device",
810
    sizeof(BDRVRawState),
811
    NULL, /* no probe for protocols */
812
    hdev_open,
813
    NULL,
814
    NULL,
815
    raw_close,
816
    NULL,
817
    raw_flush,
818
    
819
    .bdrv_aio_read = raw_aio_read,
820
    .bdrv_aio_write = raw_aio_write,
821
    .bdrv_aio_cancel = raw_aio_cancel,
822
    .aiocb_size = sizeof(RawAIOCB),
823
    .bdrv_pread = raw_pread,
824
    .bdrv_pwrite = raw_pwrite,
825
    .bdrv_getlength = raw_getlength,
826

    
827
    /* removable device support */
828
    .bdrv_is_inserted = raw_is_inserted,
829
    .bdrv_media_changed = raw_media_changed,
830
    .bdrv_eject = raw_eject,
831
    .bdrv_set_locked = raw_set_locked,
832
};
833

    
834
#else /* _WIN32 */
835

    
836
/* XXX: use another file ? */
837
#include <winioctl.h>
838

    
839
#define FTYPE_FILE 0
840
#define FTYPE_CD     1
841
#define FTYPE_HARDDISK 2
842

    
843
typedef struct BDRVRawState {
844
    HANDLE hfile;
845
    int type;
846
    char drive_path[16]; /* format: "d:\" */
847
} BDRVRawState;
848

    
849
typedef struct RawAIOCB {
850
    BlockDriverAIOCB common;
851
    HANDLE hEvent;
852
    OVERLAPPED ov;
853
    int count;
854
} RawAIOCB;
855

    
856
int qemu_ftruncate64(int fd, int64_t length)
857
{
858
    LARGE_INTEGER li;
859
    LONG high;
860
    HANDLE h;
861
    BOOL res;
862

    
863
    if ((GetVersion() & 0x80000000UL) && (length >> 32) != 0)
864
        return -1;
865

    
866
    h = (HANDLE)_get_osfhandle(fd);
867

    
868
    /* get current position, ftruncate do not change position */
869
    li.HighPart = 0;
870
    li.LowPart = SetFilePointer (h, 0, &li.HighPart, FILE_CURRENT);
871
    if (li.LowPart == 0xffffffffUL && GetLastError() != NO_ERROR)
872
        return -1;
873

    
874
    high = length >> 32;
875
    if (!SetFilePointer(h, (DWORD) length, &high, FILE_BEGIN))
876
        return -1;
877
    res = SetEndOfFile(h);
878

    
879
    /* back to old position */
880
    SetFilePointer(h, li.LowPart, &li.HighPart, FILE_BEGIN);
881
    return res ? 0 : -1;
882
}
883

    
884
static int set_sparse(int fd)
885
{
886
    DWORD returned;
887
    return (int) DeviceIoControl((HANDLE)_get_osfhandle(fd), FSCTL_SET_SPARSE,
888
                                 NULL, 0, NULL, 0, &returned, NULL);
889
}
890

    
891
static int raw_open(BlockDriverState *bs, const char *filename, int flags)
892
{
893
    BDRVRawState *s = bs->opaque;
894
    int access_flags, create_flags;
895
    DWORD overlapped;
896

    
897
    s->type = FTYPE_FILE;
898

    
899
    if ((flags & BDRV_O_ACCESS) == O_RDWR) {
900
        access_flags = GENERIC_READ | GENERIC_WRITE;
901
    } else {
902
        access_flags = GENERIC_READ;
903
    }
904
    if (flags & BDRV_O_CREAT) {
905
        create_flags = CREATE_ALWAYS;
906
    } else {
907
        create_flags = OPEN_EXISTING;
908
    }
909
#ifdef QEMU_TOOL
910
    overlapped = FILE_ATTRIBUTE_NORMAL;
911
#else
912
    overlapped = FILE_FLAG_OVERLAPPED;
913
#endif
914
    s->hfile = CreateFile(filename, access_flags, 
915
                          FILE_SHARE_READ, NULL,
916
                          create_flags, overlapped, NULL);
917
    if (s->hfile == INVALID_HANDLE_VALUE) {
918
        int err = GetLastError();
919

    
920
        if (err == ERROR_ACCESS_DENIED)
921
            return -EACCES;
922
        return -1;
923
    }
924
    return 0;
925
}
926

    
927
static int raw_pread(BlockDriverState *bs, int64_t offset, 
928
                     uint8_t *buf, int count)
929
{
930
    BDRVRawState *s = bs->opaque;
931
    OVERLAPPED ov;
932
    DWORD ret_count;
933
    int ret;
934
    
935
    memset(&ov, 0, sizeof(ov));
936
    ov.Offset = offset;
937
    ov.OffsetHigh = offset >> 32;
938
    ret = ReadFile(s->hfile, buf, count, &ret_count, &ov);
939
    if (!ret) {
940
        ret = GetOverlappedResult(s->hfile, &ov, &ret_count, TRUE);
941
        if (!ret)
942
            return -EIO;
943
        else
944
            return ret_count;
945
    }
946
    return ret_count;
947
}
948

    
949
static int raw_pwrite(BlockDriverState *bs, int64_t offset, 
950
                      const uint8_t *buf, int count)
951
{
952
    BDRVRawState *s = bs->opaque;
953
    OVERLAPPED ov;
954
    DWORD ret_count;
955
    int ret;
956
    
957
    memset(&ov, 0, sizeof(ov));
958
    ov.Offset = offset;
959
    ov.OffsetHigh = offset >> 32;
960
    ret = WriteFile(s->hfile, buf, count, &ret_count, &ov);
961
    if (!ret) {
962
        ret = GetOverlappedResult(s->hfile, &ov, &ret_count, TRUE);
963
        if (!ret)
964
            return -EIO;
965
        else
966
            return ret_count;
967
    }
968
    return ret_count;
969
}
970

    
971
#if 0
972
#ifndef QEMU_TOOL
973
static void raw_aio_cb(void *opaque)
974
{
975
    RawAIOCB *acb = opaque;
976
    BlockDriverState *bs = acb->common.bs;
977
    BDRVRawState *s = bs->opaque;
978
    DWORD ret_count;
979
    int ret;
980

981
    ret = GetOverlappedResult(s->hfile, &acb->ov, &ret_count, TRUE);
982
    if (!ret || ret_count != acb->count) {
983
        acb->common.cb(acb->common.opaque, -EIO);
984
    } else {
985
        acb->common.cb(acb->common.opaque, 0);
986
    }
987
}
988
#endif
989

    
990
static RawAIOCB *raw_aio_setup(BlockDriverState *bs,
991
        int64_t sector_num, uint8_t *buf, int nb_sectors,
992
        BlockDriverCompletionFunc *cb, void *opaque)
993
{
994
    RawAIOCB *acb;
995
    int64_t offset;
996

    
997
    acb = qemu_aio_get(bs, cb, opaque);
998
    if (acb->hEvent) {
999
        acb->hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
1000
        if (!acb->hEvent) {
1001
            qemu_aio_release(acb);
1002
            return NULL;
1003
        }
1004
    }
1005
    memset(&acb->ov, 0, sizeof(acb->ov));
1006
    offset = sector_num * 512;
1007
    acb->ov.Offset = offset;
1008
    acb->ov.OffsetHigh = offset >> 32;
1009
    acb->ov.hEvent = acb->hEvent;
1010
    acb->count = nb_sectors * 512;
1011
#ifndef QEMU_TOOL
1012
    qemu_add_wait_object(acb->ov.hEvent, raw_aio_cb, acb);
1013
#endif
1014
    return acb;
1015
}
1016

    
1017
static BlockDriverAIOCB *raw_aio_read(BlockDriverState *bs,
1018
        int64_t sector_num, uint8_t *buf, int nb_sectors,
1019
        BlockDriverCompletionFunc *cb, void *opaque)
1020
{
1021
    BDRVRawState *s = bs->opaque;
1022
    RawAIOCB *acb;
1023
    int ret;
1024

    
1025
    acb = raw_aio_setup(bs, sector_num, buf, nb_sectors, cb, opaque);
1026
    if (!acb)
1027
        return NULL;
1028
    ret = ReadFile(s->hfile, buf, acb->count, NULL, &acb->ov);
1029
    if (!ret) {
1030
        qemu_aio_release(acb);
1031
        return NULL;
1032
    }
1033
#ifdef QEMU_TOOL
1034
    qemu_aio_release(acb);
1035
#endif
1036
    return (BlockDriverAIOCB *)acb;
1037
}
1038

    
1039
static BlockDriverAIOCB *raw_aio_write(BlockDriverState *bs,
1040
        int64_t sector_num, uint8_t *buf, int nb_sectors,
1041
        BlockDriverCompletionFunc *cb, void *opaque)
1042
{
1043
    BDRVRawState *s = bs->opaque;
1044
    RawAIOCB *acb;
1045
    int ret;
1046

    
1047
    acb = raw_aio_setup(bs, sector_num, buf, nb_sectors, cb, opaque);
1048
    if (!acb)
1049
        return NULL;
1050
    ret = WriteFile(s->hfile, buf, acb->count, NULL, &acb->ov);
1051
    if (!ret) {
1052
        qemu_aio_release(acb);
1053
        return NULL;
1054
    }
1055
#ifdef QEMU_TOOL
1056
    qemu_aio_release(acb);
1057
#endif
1058
    return (BlockDriverAIOCB *)acb;
1059
}
1060

    
1061
static void raw_aio_cancel(BlockDriverAIOCB *blockacb)
1062
{
1063
#ifndef QEMU_TOOL
1064
    RawAIOCB *acb = (RawAIOCB *)blockacb;
1065
    BlockDriverState *bs = acb->common.bs;
1066
    BDRVRawState *s = bs->opaque;
1067

    
1068
    qemu_del_wait_object(acb->ov.hEvent, raw_aio_cb, acb);
1069
    /* XXX: if more than one async I/O it is not correct */
1070
    CancelIo(s->hfile);
1071
    qemu_aio_release(acb);
1072
#endif
1073
}
1074
#endif /* #if 0 */
1075

    
1076
static void raw_flush(BlockDriverState *bs)
1077
{
1078
    BDRVRawState *s = bs->opaque;
1079
    FlushFileBuffers(s->hfile);
1080
}
1081

    
1082
static void raw_close(BlockDriverState *bs)
1083
{
1084
    BDRVRawState *s = bs->opaque;
1085
    CloseHandle(s->hfile);
1086
}
1087

    
1088
static int raw_truncate(BlockDriverState *bs, int64_t offset)
1089
{
1090
    BDRVRawState *s = bs->opaque;
1091
    DWORD low, high;
1092

    
1093
    low = offset;
1094
    high = offset >> 32;
1095
    if (!SetFilePointer(s->hfile, low, &high, FILE_BEGIN))
1096
        return -EIO;
1097
    if (!SetEndOfFile(s->hfile))
1098
        return -EIO;
1099
    return 0;
1100
}
1101

    
1102
static int64_t raw_getlength(BlockDriverState *bs)
1103
{
1104
    BDRVRawState *s = bs->opaque;
1105
    LARGE_INTEGER l;
1106
    ULARGE_INTEGER available, total, total_free; 
1107
    DISK_GEOMETRY dg;
1108
    DWORD count;
1109
    BOOL status;
1110

    
1111
    switch(s->type) {
1112
    case FTYPE_FILE:
1113
        l.LowPart = GetFileSize(s->hfile, &l.HighPart);
1114
        if (l.LowPart == 0xffffffffUL && GetLastError() != NO_ERROR)
1115
            return -EIO;
1116
        break;
1117
    case FTYPE_CD:
1118
        if (!GetDiskFreeSpaceEx(s->drive_path, &available, &total, &total_free))
1119
            return -EIO;
1120
        l.QuadPart = total.QuadPart;
1121
        break;
1122
    case FTYPE_HARDDISK:
1123
        status = DeviceIoControl(s->hfile, IOCTL_DISK_GET_DRIVE_GEOMETRY,
1124
                                 NULL, 0, &dg, sizeof(dg), &count, NULL);
1125
        if (status != FALSE) {
1126
            l.QuadPart = dg.Cylinders.QuadPart * dg.TracksPerCylinder
1127
                * dg.SectorsPerTrack * dg.BytesPerSector;
1128
        }
1129
        break;
1130
    default:
1131
        return -EIO;
1132
    }
1133
    return l.QuadPart;
1134
}
1135

    
1136
static int raw_create(const char *filename, int64_t total_size,
1137
                      const char *backing_file, int flags)
1138
{
1139
    int fd;
1140

    
1141
    if (flags || backing_file)
1142
        return -ENOTSUP;
1143

    
1144
    fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 
1145
              0644);
1146
    if (fd < 0)
1147
        return -EIO;
1148
    set_sparse(fd);
1149
    ftruncate(fd, total_size * 512);
1150
    close(fd);
1151
    return 0;
1152
}
1153

    
1154
void qemu_aio_init(void)
1155
{
1156
}
1157

    
1158
void qemu_aio_poll(void)
1159
{
1160
}
1161

    
1162
void qemu_aio_flush(void)
1163
{
1164
}
1165

    
1166
void qemu_aio_wait_start(void)
1167
{
1168
}
1169

    
1170
void qemu_aio_wait(void)
1171
{
1172
#ifndef QEMU_TOOL
1173
    qemu_bh_poll();
1174
#endif
1175
}
1176

    
1177
void qemu_aio_wait_end(void)
1178
{
1179
}
1180

    
1181
BlockDriver bdrv_raw = {
1182
    "raw",
1183
    sizeof(BDRVRawState),
1184
    NULL, /* no probe for protocols */
1185
    raw_open,
1186
    NULL,
1187
    NULL,
1188
    raw_close,
1189
    raw_create,
1190
    raw_flush,
1191
    
1192
#if 0
1193
    .bdrv_aio_read = raw_aio_read,
1194
    .bdrv_aio_write = raw_aio_write,
1195
    .bdrv_aio_cancel = raw_aio_cancel,
1196
    .aiocb_size = sizeof(RawAIOCB);
1197
#endif
1198
    .protocol_name = "file",
1199
    .bdrv_pread = raw_pread,
1200
    .bdrv_pwrite = raw_pwrite,
1201
    .bdrv_truncate = raw_truncate,
1202
    .bdrv_getlength = raw_getlength,
1203
};
1204

    
1205
/***********************************************/
1206
/* host device */
1207

    
1208
static int find_cdrom(char *cdrom_name, int cdrom_name_size)
1209
{
1210
    char drives[256], *pdrv = drives;
1211
    UINT type;
1212

    
1213
    memset(drives, 0, sizeof(drives));
1214
    GetLogicalDriveStrings(sizeof(drives), drives);
1215
    while(pdrv[0] != '\0') {
1216
        type = GetDriveType(pdrv);
1217
        switch(type) {
1218
        case DRIVE_CDROM:
1219
            snprintf(cdrom_name, cdrom_name_size, "\\\\.\\%c:", pdrv[0]);
1220
            return 0;
1221
            break;
1222
        }
1223
        pdrv += lstrlen(pdrv) + 1;
1224
    }
1225
    return -1;
1226
}
1227

    
1228
static int find_device_type(BlockDriverState *bs, const char *filename)
1229
{
1230
    BDRVRawState *s = bs->opaque;
1231
    UINT type;
1232
    const char *p;
1233

    
1234
    if (strstart(filename, "\\\\.\\", &p) ||
1235
        strstart(filename, "//./", &p)) {
1236
        if (stristart(p, "PhysicalDrive", NULL))
1237
            return FTYPE_HARDDISK;
1238
        snprintf(s->drive_path, sizeof(s->drive_path), "%c:\\", p[0]);
1239
        type = GetDriveType(s->drive_path);
1240
        if (type == DRIVE_CDROM)
1241
            return FTYPE_CD;
1242
        else
1243
            return FTYPE_FILE;
1244
    } else {
1245
        return FTYPE_FILE;
1246
    }
1247
}
1248

    
1249
static int hdev_open(BlockDriverState *bs, const char *filename, int flags)
1250
{
1251
    BDRVRawState *s = bs->opaque;
1252
    int access_flags, create_flags;
1253
    DWORD overlapped;
1254
    char device_name[64];
1255

    
1256
    if (strstart(filename, "/dev/cdrom", NULL)) {
1257
        if (find_cdrom(device_name, sizeof(device_name)) < 0)
1258
            return -ENOENT;
1259
        filename = device_name;
1260
    } else {
1261
        /* transform drive letters into device name */
1262
        if (((filename[0] >= 'a' && filename[0] <= 'z') ||
1263
             (filename[0] >= 'A' && filename[0] <= 'Z')) &&
1264
            filename[1] == ':' && filename[2] == '\0') {
1265
            snprintf(device_name, sizeof(device_name), "\\\\.\\%c:", filename[0]);
1266
            filename = device_name;
1267
        }
1268
    }
1269
    s->type = find_device_type(bs, filename);
1270
    
1271
    if ((flags & BDRV_O_ACCESS) == O_RDWR) {
1272
        access_flags = GENERIC_READ | GENERIC_WRITE;
1273
    } else {
1274
        access_flags = GENERIC_READ;
1275
    }
1276
    create_flags = OPEN_EXISTING;
1277

    
1278
#ifdef QEMU_TOOL
1279
    overlapped = FILE_ATTRIBUTE_NORMAL;
1280
#else
1281
    overlapped = FILE_FLAG_OVERLAPPED;
1282
#endif
1283
    s->hfile = CreateFile(filename, access_flags, 
1284
                          FILE_SHARE_READ, NULL,
1285
                          create_flags, overlapped, NULL);
1286
    if (s->hfile == INVALID_HANDLE_VALUE) {
1287
        int err = GetLastError();
1288

    
1289
        if (err == ERROR_ACCESS_DENIED)
1290
            return -EACCES;
1291
        return -1;
1292
    }
1293
    return 0;
1294
}
1295

    
1296
#if 0
1297
/***********************************************/
1298
/* removable device additionnal commands */
1299

1300
static int raw_is_inserted(BlockDriverState *bs)
1301
{
1302
    return 1;
1303
}
1304

1305
static int raw_media_changed(BlockDriverState *bs)
1306
{
1307
    return -ENOTSUP;
1308
}
1309

1310
static int raw_eject(BlockDriverState *bs, int eject_flag)
1311
{
1312
    DWORD ret_count;
1313

1314
    if (s->type == FTYPE_FILE)
1315
        return -ENOTSUP;
1316
    if (eject_flag) {
1317
        DeviceIoControl(s->hfile, IOCTL_STORAGE_EJECT_MEDIA, 
1318
                        NULL, 0, NULL, 0, &lpBytesReturned, NULL);
1319
    } else {
1320
        DeviceIoControl(s->hfile, IOCTL_STORAGE_LOAD_MEDIA, 
1321
                        NULL, 0, NULL, 0, &lpBytesReturned, NULL);
1322
    }
1323
}
1324

1325
static int raw_set_locked(BlockDriverState *bs, int locked)
1326
{
1327
    return -ENOTSUP;
1328
}
1329
#endif
1330

    
1331
BlockDriver bdrv_host_device = {
1332
    "host_device",
1333
    sizeof(BDRVRawState),
1334
    NULL, /* no probe for protocols */
1335
    hdev_open,
1336
    NULL,
1337
    NULL,
1338
    raw_close,
1339
    NULL,
1340
    raw_flush,
1341
    
1342
#if 0
1343
    .bdrv_aio_read = raw_aio_read,
1344
    .bdrv_aio_write = raw_aio_write,
1345
    .bdrv_aio_cancel = raw_aio_cancel,
1346
    .aiocb_size = sizeof(RawAIOCB);
1347
#endif
1348
    .bdrv_pread = raw_pread,
1349
    .bdrv_pwrite = raw_pwrite,
1350
    .bdrv_getlength = raw_getlength,
1351
};
1352
#endif /* _WIN32 */