Statistics
| Branch: | Revision:

root / block.c @ beac80cd

History | View | Annotate | Download (21.2 kB)

1
/*
2
 * QEMU System Emulator block driver
3
 * 
4
 * Copyright (c) 2003 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

    
27
#ifdef _BSD
28
#include <sys/types.h>
29
#include <sys/stat.h>
30
#include <sys/ioctl.h>
31
#include <sys/queue.h>
32
#include <sys/disk.h>
33
#endif
34

    
35
#ifdef CONFIG_COCOA
36
#include <paths.h>
37
#include <sys/param.h>
38
#include <IOKit/IOKitLib.h>
39
#include <IOKit/IOBSD.h>
40
#include <IOKit/storage/IOMediaBSDClient.h>
41
#include <IOKit/storage/IOMedia.h>
42
#include <IOKit/storage/IOCDMedia.h>
43
//#include <IOKit/storage/IOCDTypes.h>
44
#include <CoreFoundation/CoreFoundation.h>
45
#endif
46

    
47
#ifdef __sun__
48
#include <sys/dkio.h>
49
#endif
50

    
51
static BlockDriverState *bdrv_first;
52
static BlockDriver *first_drv;
53

    
54
#ifdef CONFIG_COCOA
55
static kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator );
56
static kern_return_t GetBSDPath( io_iterator_t mediaIterator, char *bsdPath, CFIndex maxPathSize );
57

    
58
kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator )
59
{
60
    kern_return_t       kernResult; 
61
    mach_port_t     masterPort;
62
    CFMutableDictionaryRef  classesToMatch;
63

    
64
    kernResult = IOMasterPort( MACH_PORT_NULL, &masterPort );
65
    if ( KERN_SUCCESS != kernResult ) {
66
        printf( "IOMasterPort returned %d\n", kernResult );
67
    }
68
    
69
    classesToMatch = IOServiceMatching( kIOCDMediaClass ); 
70
    if ( classesToMatch == NULL ) {
71
        printf( "IOServiceMatching returned a NULL dictionary.\n" );
72
    } else {
73
    CFDictionarySetValue( classesToMatch, CFSTR( kIOMediaEjectableKey ), kCFBooleanTrue );
74
    }
75
    kernResult = IOServiceGetMatchingServices( masterPort, classesToMatch, mediaIterator );
76
    if ( KERN_SUCCESS != kernResult )
77
    {
78
        printf( "IOServiceGetMatchingServices returned %d\n", kernResult );
79
    }
80
    
81
    return kernResult;
82
}
83

    
84
kern_return_t GetBSDPath( io_iterator_t mediaIterator, char *bsdPath, CFIndex maxPathSize )
85
{
86
    io_object_t     nextMedia;
87
    kern_return_t   kernResult = KERN_FAILURE;
88
    *bsdPath = '\0';
89
    nextMedia = IOIteratorNext( mediaIterator );
90
    if ( nextMedia )
91
    {
92
        CFTypeRef   bsdPathAsCFString;
93
    bsdPathAsCFString = IORegistryEntryCreateCFProperty( nextMedia, CFSTR( kIOBSDNameKey ), kCFAllocatorDefault, 0 );
94
        if ( bsdPathAsCFString ) {
95
            size_t devPathLength;
96
            strcpy( bsdPath, _PATH_DEV );
97
            strcat( bsdPath, "r" );
98
            devPathLength = strlen( bsdPath );
99
            if ( CFStringGetCString( bsdPathAsCFString, bsdPath + devPathLength, maxPathSize - devPathLength, kCFStringEncodingASCII ) ) {
100
                kernResult = KERN_SUCCESS;
101
            }
102
            CFRelease( bsdPathAsCFString );
103
        }
104
        IOObjectRelease( nextMedia );
105
    }
106
    
107
    return kernResult;
108
}
109

    
110
#endif
111

    
112
void bdrv_register(BlockDriver *bdrv)
113
{
114
    bdrv->next = first_drv;
115
    first_drv = bdrv;
116
}
117

    
118
/* create a new block device (by default it is empty) */
119
BlockDriverState *bdrv_new(const char *device_name)
120
{
121
    BlockDriverState **pbs, *bs;
122

    
123
    bs = qemu_mallocz(sizeof(BlockDriverState));
124
    if(!bs)
125
        return NULL;
126
    pstrcpy(bs->device_name, sizeof(bs->device_name), device_name);
127
    if (device_name[0] != '\0') {
128
        /* insert at the end */
129
        pbs = &bdrv_first;
130
        while (*pbs != NULL)
131
            pbs = &(*pbs)->next;
132
        *pbs = bs;
133
    }
134
    return bs;
135
}
136

    
137
BlockDriver *bdrv_find_format(const char *format_name)
138
{
139
    BlockDriver *drv1;
140
    for(drv1 = first_drv; drv1 != NULL; drv1 = drv1->next) {
141
        if (!strcmp(drv1->format_name, format_name))
142
            return drv1;
143
    }
144
    return NULL;
145
}
146

    
147
int bdrv_create(BlockDriver *drv, 
148
                const char *filename, int64_t size_in_sectors,
149
                const char *backing_file, int flags)
150
{
151
    if (!drv->bdrv_create)
152
        return -ENOTSUP;
153
    return drv->bdrv_create(filename, size_in_sectors, backing_file, flags);
154
}
155

    
156
#ifdef _WIN32
157
void get_tmp_filename(char *filename, int size)
158
{
159
    char* p = strrchr(filename, '/');
160

    
161
    if (p == NULL)
162
        return;
163

    
164
    /* XXX: find a better function */
165
    tmpnam(p);
166
    *p = '/';
167
}
168
#else
169
void get_tmp_filename(char *filename, int size)
170
{
171
    int fd;
172
    /* XXX: race condition possible */
173
    pstrcpy(filename, size, "/tmp/vl.XXXXXX");
174
    fd = mkstemp(filename);
175
    close(fd);
176
}
177
#endif
178

    
179
/* XXX: force raw format if block or character device ? It would
180
   simplify the BSD case */
181
static BlockDriver *find_image_format(const char *filename)
182
{
183
    int fd, ret, score, score_max;
184
    BlockDriver *drv1, *drv;
185
    uint8_t *buf;
186
    size_t bufsize = 1024;
187

    
188
    fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
189
    if (fd < 0) {
190
        buf = NULL;
191
        ret = 0;
192
    } else {
193
#ifdef DIOCGSECTORSIZE
194
        {
195
            unsigned int sectorsize = 512;
196
            if (!ioctl(fd, DIOCGSECTORSIZE, &sectorsize) &&
197
                sectorsize > bufsize)
198
                bufsize = sectorsize;
199
        }
200
#endif
201
#ifdef CONFIG_COCOA
202
        u_int32_t   blockSize = 512;
203
        if ( !ioctl( fd, DKIOCGETBLOCKSIZE, &blockSize ) && blockSize > bufsize) {
204
            bufsize = blockSize;
205
        }
206
#endif
207
        buf = qemu_malloc(bufsize);
208
        if (!buf)
209
            return NULL;
210
        ret = read(fd, buf, bufsize);
211
        if (ret < 0) {
212
            close(fd);
213
            qemu_free(buf);
214
            return NULL;
215
        }
216
        close(fd);
217
    }
218
    
219
    drv = NULL;
220
    score_max = 0;
221
    for(drv1 = first_drv; drv1 != NULL; drv1 = drv1->next) {
222
        score = drv1->bdrv_probe(buf, ret, filename);
223
        if (score > score_max) {
224
            score_max = score;
225
            drv = drv1;
226
        }
227
    }
228
    qemu_free(buf);
229
    return drv;
230
}
231

    
232
int bdrv_open(BlockDriverState *bs, const char *filename, int snapshot)
233
{
234
#ifdef CONFIG_COCOA
235
    if ( strncmp( filename, "/dev/cdrom", 10 ) == 0 ) {
236
        kern_return_t kernResult;
237
        io_iterator_t mediaIterator;
238
        char bsdPath[ MAXPATHLEN ];
239
        int fd;
240
 
241
        kernResult = FindEjectableCDMedia( &mediaIterator );
242
        kernResult = GetBSDPath( mediaIterator, bsdPath, sizeof( bsdPath ) );
243
    
244
        if ( bsdPath[ 0 ] != '\0' ) {
245
            strcat(bsdPath,"s0");
246
            /* some CDs don't have a partition 0 */
247
            fd = open(bsdPath, O_RDONLY | O_BINARY | O_LARGEFILE);
248
            if (fd < 0) {
249
                bsdPath[strlen(bsdPath)-1] = '1';
250
            } else {
251
                close(fd);
252
            }
253
            filename = bsdPath;
254
        }
255
        
256
        if ( mediaIterator )
257
            IOObjectRelease( mediaIterator );
258
    }
259
#endif
260
    return bdrv_open2(bs, filename, snapshot, NULL);
261
}
262

    
263
int bdrv_open2(BlockDriverState *bs, const char *filename, int snapshot,
264
               BlockDriver *drv)
265
{
266
    int ret;
267
    char tmp_filename[1024];
268
    
269
    bs->read_only = 0;
270
    bs->is_temporary = 0;
271
    bs->encrypted = 0;
272

    
273
    if (snapshot) {
274
        BlockDriverState *bs1;
275
        int64_t total_size;
276
        
277
        /* if snapshot, we create a temporary backing file and open it
278
           instead of opening 'filename' directly */
279

    
280
        /* if there is a backing file, use it */
281
        bs1 = bdrv_new("");
282
        if (!bs1) {
283
            return -1;
284
        }
285
        if (bdrv_open(bs1, filename, 0) < 0) {
286
            bdrv_delete(bs1);
287
            return -1;
288
        }
289
        total_size = bs1->total_sectors;
290
        bdrv_delete(bs1);
291
        
292
        get_tmp_filename(tmp_filename, sizeof(tmp_filename));
293
        /* XXX: use cow for linux as it is more efficient ? */
294
        if (bdrv_create(&bdrv_qcow, tmp_filename, 
295
                        total_size, filename, 0) < 0) {
296
            return -1;
297
        }
298
        filename = tmp_filename;
299
        bs->is_temporary = 1;
300
    }
301

    
302
    pstrcpy(bs->filename, sizeof(bs->filename), filename);
303
    if (!drv) {
304
        drv = find_image_format(filename);
305
        if (!drv)
306
            return -1;
307
    }
308
    bs->drv = drv;
309
    bs->opaque = qemu_mallocz(drv->instance_size);
310
    if (bs->opaque == NULL && drv->instance_size > 0)
311
        return -1;
312
    
313
    ret = drv->bdrv_open(bs, filename);
314
    if (ret < 0) {
315
        qemu_free(bs->opaque);
316
        return -1;
317
    }
318
#ifndef _WIN32
319
    if (bs->is_temporary) {
320
        unlink(filename);
321
    }
322
#endif
323
    if (bs->backing_file[0] != '\0' && drv->bdrv_is_allocated) {
324
        /* if there is a backing file, use it */
325
        bs->backing_hd = bdrv_new("");
326
        if (!bs->backing_hd) {
327
        fail:
328
            bdrv_close(bs);
329
            return -1;
330
        }
331
        if (bdrv_open(bs->backing_hd, bs->backing_file, 0) < 0)
332
            goto fail;
333
    }
334

    
335
    bs->inserted = 1;
336

    
337
    /* call the change callback */
338
    if (bs->change_cb)
339
        bs->change_cb(bs->change_opaque);
340

    
341
    return 0;
342
}
343

    
344
void bdrv_close(BlockDriverState *bs)
345
{
346
    if (bs->inserted) {
347
        if (bs->backing_hd)
348
            bdrv_delete(bs->backing_hd);
349
        bs->drv->bdrv_close(bs);
350
        qemu_free(bs->opaque);
351
#ifdef _WIN32
352
        if (bs->is_temporary) {
353
            unlink(bs->filename);
354
        }
355
#endif
356
        bs->opaque = NULL;
357
        bs->drv = NULL;
358
        bs->inserted = 0;
359

    
360
        /* call the change callback */
361
        if (bs->change_cb)
362
            bs->change_cb(bs->change_opaque);
363
    }
364
}
365

    
366
void bdrv_delete(BlockDriverState *bs)
367
{
368
    /* XXX: remove the driver list */
369
    bdrv_close(bs);
370
    qemu_free(bs);
371
}
372

    
373
/* commit COW file into the raw image */
374
int bdrv_commit(BlockDriverState *bs)
375
{
376
    int64_t i;
377
    int n, j;
378
    unsigned char sector[512];
379

    
380
    if (!bs->inserted)
381
        return -ENOENT;
382

    
383
    if (bs->read_only) {
384
        return -EACCES;
385
    }
386

    
387
    if (!bs->backing_hd) {
388
        return -ENOTSUP;
389
    }
390

    
391
    for (i = 0; i < bs->total_sectors;) {
392
        if (bs->drv->bdrv_is_allocated(bs, i, 65536, &n)) {
393
            for(j = 0; j < n; j++) {
394
                if (bdrv_read(bs, i, sector, 1) != 0) {
395
                    return -EIO;
396
                }
397

    
398
                if (bdrv_write(bs->backing_hd, i, sector, 1) != 0) {
399
                    return -EIO;
400
                }
401
                i++;
402
            }
403
        } else {
404
            i += n;
405
        }
406
    }
407

    
408
    if (bs->drv->bdrv_make_empty)
409
        return bs->drv->bdrv_make_empty(bs);
410

    
411
    return 0;
412
}
413

    
414
/* return -1 if error */
415
int bdrv_read(BlockDriverState *bs, int64_t sector_num, 
416
              uint8_t *buf, int nb_sectors)
417
{
418
    int ret, n;
419
    BlockDriver *drv = bs->drv;
420

    
421
    if (!bs->inserted)
422
        return -1;
423

    
424
    while (nb_sectors > 0) {
425
        if (sector_num == 0 && bs->boot_sector_enabled) {
426
            memcpy(buf, bs->boot_sector_data, 512);
427
            n = 1;
428
        } else if (bs->backing_hd) {
429
            if (drv->bdrv_is_allocated(bs, sector_num, nb_sectors, &n)) {
430
                ret = drv->bdrv_read(bs, sector_num, buf, n);
431
                if (ret < 0)
432
                    return -1;
433
            } else {
434
                /* read from the base image */
435
                ret = bdrv_read(bs->backing_hd, sector_num, buf, n);
436
                if (ret < 0)
437
                    return -1;
438
            }
439
        } else {
440
            ret = drv->bdrv_read(bs, sector_num, buf, nb_sectors);
441
            if (ret < 0)
442
                return -1;
443
            /* no need to loop */
444
            break;
445
        }
446
        nb_sectors -= n;
447
        sector_num += n;
448
        buf += n * 512;
449
    }
450
    return 0;
451
}
452

    
453
/* return -1 if error */
454
int bdrv_write(BlockDriverState *bs, int64_t sector_num, 
455
               const uint8_t *buf, int nb_sectors)
456
{
457
    if (!bs->inserted)
458
        return -1;
459
    if (bs->read_only)
460
        return -1;
461
    if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) {
462
        memcpy(bs->boot_sector_data, buf, 512);   
463
    }
464
    return bs->drv->bdrv_write(bs, sector_num, buf, nb_sectors);
465
}
466

    
467
void bdrv_get_geometry(BlockDriverState *bs, int64_t *nb_sectors_ptr)
468
{
469
    *nb_sectors_ptr = bs->total_sectors;
470
}
471

    
472
/* force a given boot sector. */
473
void bdrv_set_boot_sector(BlockDriverState *bs, const uint8_t *data, int size)
474
{
475
    bs->boot_sector_enabled = 1;
476
    if (size > 512)
477
        size = 512;
478
    memcpy(bs->boot_sector_data, data, size);
479
    memset(bs->boot_sector_data + size, 0, 512 - size);
480
}
481

    
482
void bdrv_set_geometry_hint(BlockDriverState *bs, 
483
                            int cyls, int heads, int secs)
484
{
485
    bs->cyls = cyls;
486
    bs->heads = heads;
487
    bs->secs = secs;
488
}
489

    
490
void bdrv_set_type_hint(BlockDriverState *bs, int type)
491
{
492
    bs->type = type;
493
    bs->removable = ((type == BDRV_TYPE_CDROM ||
494
                      type == BDRV_TYPE_FLOPPY));
495
}
496

    
497
void bdrv_set_translation_hint(BlockDriverState *bs, int translation)
498
{
499
    bs->translation = translation;
500
}
501

    
502
void bdrv_get_geometry_hint(BlockDriverState *bs, 
503
                            int *pcyls, int *pheads, int *psecs)
504
{
505
    *pcyls = bs->cyls;
506
    *pheads = bs->heads;
507
    *psecs = bs->secs;
508
}
509

    
510
int bdrv_get_type_hint(BlockDriverState *bs)
511
{
512
    return bs->type;
513
}
514

    
515
int bdrv_get_translation_hint(BlockDriverState *bs)
516
{
517
    return bs->translation;
518
}
519

    
520
int bdrv_is_removable(BlockDriverState *bs)
521
{
522
    return bs->removable;
523
}
524

    
525
int bdrv_is_read_only(BlockDriverState *bs)
526
{
527
    return bs->read_only;
528
}
529

    
530
int bdrv_is_inserted(BlockDriverState *bs)
531
{
532
    return bs->inserted;
533
}
534

    
535
int bdrv_is_locked(BlockDriverState *bs)
536
{
537
    return bs->locked;
538
}
539

    
540
void bdrv_set_locked(BlockDriverState *bs, int locked)
541
{
542
    bs->locked = locked;
543
}
544

    
545
void bdrv_set_change_cb(BlockDriverState *bs, 
546
                        void (*change_cb)(void *opaque), void *opaque)
547
{
548
    bs->change_cb = change_cb;
549
    bs->change_opaque = opaque;
550
}
551

    
552
int bdrv_is_encrypted(BlockDriverState *bs)
553
{
554
    if (bs->backing_hd && bs->backing_hd->encrypted)
555
        return 1;
556
    return bs->encrypted;
557
}
558

    
559
int bdrv_set_key(BlockDriverState *bs, const char *key)
560
{
561
    int ret;
562
    if (bs->backing_hd && bs->backing_hd->encrypted) {
563
        ret = bdrv_set_key(bs->backing_hd, key);
564
        if (ret < 0)
565
            return ret;
566
        if (!bs->encrypted)
567
            return 0;
568
    }
569
    if (!bs->encrypted || !bs->drv || !bs->drv->bdrv_set_key)
570
        return -1;
571
    return bs->drv->bdrv_set_key(bs, key);
572
}
573

    
574
void bdrv_get_format(BlockDriverState *bs, char *buf, int buf_size)
575
{
576
    if (!bs->inserted || !bs->drv) {
577
        buf[0] = '\0';
578
    } else {
579
        pstrcpy(buf, buf_size, bs->drv->format_name);
580
    }
581
}
582

    
583
void bdrv_iterate_format(void (*it)(void *opaque, const char *name), 
584
                         void *opaque)
585
{
586
    BlockDriver *drv;
587

    
588
    for (drv = first_drv; drv != NULL; drv = drv->next) {
589
        it(opaque, drv->format_name);
590
    }
591
}
592

    
593
BlockDriverState *bdrv_find(const char *name)
594
{
595
    BlockDriverState *bs;
596

    
597
    for (bs = bdrv_first; bs != NULL; bs = bs->next) {
598
        if (!strcmp(name, bs->device_name))
599
            return bs;
600
    }
601
    return NULL;
602
}
603

    
604
void bdrv_iterate(void (*it)(void *opaque, const char *name), void *opaque)
605
{
606
    BlockDriverState *bs;
607

    
608
    for (bs = bdrv_first; bs != NULL; bs = bs->next) {
609
        it(opaque, bs->device_name);
610
    }
611
}
612

    
613
const char *bdrv_get_device_name(BlockDriverState *bs)
614
{
615
    return bs->device_name;
616
}
617

    
618
void bdrv_flush(BlockDriverState *bs)
619
{
620
    if (bs->drv->bdrv_flush)
621
        bs->drv->bdrv_flush(bs);
622
    if (bs->backing_hd)
623
        bdrv_flush(bs->backing_hd);
624
}
625

    
626
void bdrv_info(void)
627
{
628
    BlockDriverState *bs;
629

    
630
    for (bs = bdrv_first; bs != NULL; bs = bs->next) {
631
        term_printf("%s:", bs->device_name);
632
        term_printf(" type=");
633
        switch(bs->type) {
634
        case BDRV_TYPE_HD:
635
            term_printf("hd");
636
            break;
637
        case BDRV_TYPE_CDROM:
638
            term_printf("cdrom");
639
            break;
640
        case BDRV_TYPE_FLOPPY:
641
            term_printf("floppy");
642
            break;
643
        }
644
        term_printf(" removable=%d", bs->removable);
645
        if (bs->removable) {
646
            term_printf(" locked=%d", bs->locked);
647
        }
648
        if (bs->inserted) {
649
            term_printf(" file=%s", bs->filename);
650
            if (bs->backing_file[0] != '\0')
651
                term_printf(" backing_file=%s", bs->backing_file);
652
            term_printf(" ro=%d", bs->read_only);
653
            term_printf(" drv=%s", bs->drv->format_name);
654
            if (bs->encrypted)
655
                term_printf(" encrypted");
656
        } else {
657
            term_printf(" [not inserted]");
658
        }
659
        term_printf("\n");
660
    }
661
}
662

    
663
/**************************************************************/
664
/* RAW block driver */
665

    
666
typedef struct BDRVRawState {
667
    int fd;
668
} BDRVRawState;
669

    
670
static int raw_probe(const uint8_t *buf, int buf_size, const char *filename)
671
{
672
    return 1; /* maybe */
673
}
674

    
675
static int raw_open(BlockDriverState *bs, const char *filename)
676
{
677
    BDRVRawState *s = bs->opaque;
678
    int fd;
679
    int64_t size;
680
#ifdef _BSD
681
    struct stat sb;
682
#endif
683
#ifdef __sun__
684
    struct dk_minfo minfo;
685
    int rv;
686
#endif
687

    
688
    fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE);
689
    if (fd < 0) {
690
        fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
691
        if (fd < 0)
692
            return -1;
693
        bs->read_only = 1;
694
    }
695
#ifdef _BSD
696
    if (!fstat(fd, &sb) && (S_IFCHR & sb.st_mode)) {
697
#ifdef DIOCGMEDIASIZE
698
        if (ioctl(fd, DIOCGMEDIASIZE, (off_t *)&size))
699
#endif
700
#ifdef CONFIG_COCOA
701
        size = LONG_LONG_MAX;
702
#else
703
        size = lseek(fd, 0LL, SEEK_END);
704
#endif
705
    } else
706
#endif
707
#ifdef __sun__
708
    /*
709
     * use the DKIOCGMEDIAINFO ioctl to read the size.
710
     */
711
    rv = ioctl ( fd, DKIOCGMEDIAINFO, &minfo );
712
    if ( rv != -1 ) {
713
        size = minfo.dki_lbsize * minfo.dki_capacity;
714
    } else /* there are reports that lseek on some devices
715
              fails, but irc discussion said that contingency
716
              on contingency was overkill */
717
#endif
718
    {
719
        size = lseek(fd, 0, SEEK_END);
720
    }
721
#ifdef _WIN32
722
    /* On Windows hosts it can happen that we're unable to get file size
723
       for CD-ROM raw device (it's inherent limitation of the CDFS driver). */
724
    if (size == -1)
725
        size = LONG_LONG_MAX;
726
#endif
727
    bs->total_sectors = size / 512;
728
    s->fd = fd;
729
    return 0;
730
}
731

    
732
static int raw_read(BlockDriverState *bs, int64_t sector_num, 
733
                    uint8_t *buf, int nb_sectors)
734
{
735
    BDRVRawState *s = bs->opaque;
736
    int ret;
737
    
738
    lseek(s->fd, sector_num * 512, SEEK_SET);
739
    ret = read(s->fd, buf, nb_sectors * 512);
740
    if (ret != nb_sectors * 512) 
741
        return -1;
742
    return 0;
743
}
744

    
745
static int raw_write(BlockDriverState *bs, int64_t sector_num, 
746
                     const uint8_t *buf, int nb_sectors)
747
{
748
    BDRVRawState *s = bs->opaque;
749
    int ret;
750
    
751
    lseek(s->fd, sector_num * 512, SEEK_SET);
752
    ret = write(s->fd, buf, nb_sectors * 512);
753
    if (ret != nb_sectors * 512) 
754
        return -1;
755
    return 0;
756
}
757

    
758
static void raw_close(BlockDriverState *bs)
759
{
760
    BDRVRawState *s = bs->opaque;
761
    close(s->fd);
762
}
763

    
764
#ifdef _WIN32
765
#include <windows.h>
766
#include <winioctl.h>
767

    
768
int qemu_ftruncate64(int fd, int64_t length)
769
{
770
    LARGE_INTEGER li;
771
    LONG high;
772
    HANDLE h;
773
    BOOL res;
774

    
775
    if ((GetVersion() & 0x80000000UL) && (length >> 32) != 0)
776
        return -1;
777

    
778
    h = (HANDLE)_get_osfhandle(fd);
779

    
780
    /* get current position, ftruncate do not change position */
781
    li.HighPart = 0;
782
    li.LowPart = SetFilePointer (h, 0, &li.HighPart, FILE_CURRENT);
783
    if (li.LowPart == 0xffffffffUL && GetLastError() != NO_ERROR)
784
        return -1;
785

    
786
    high = length >> 32;
787
    if (!SetFilePointer(h, (DWORD) length, &high, FILE_BEGIN))
788
        return -1;
789
    res = SetEndOfFile(h);
790

    
791
    /* back to old position */
792
    SetFilePointer(h, li.LowPart, &li.HighPart, FILE_BEGIN);
793
    return res ? 0 : -1;
794
}
795

    
796
static int set_sparse(int fd)
797
{
798
    DWORD returned;
799
    return (int) DeviceIoControl((HANDLE)_get_osfhandle(fd), FSCTL_SET_SPARSE,
800
                                 NULL, 0, NULL, 0, &returned, NULL);
801
}
802
#else
803
static inline int set_sparse(int fd)
804
{
805
    return 1;
806
}
807
#endif
808

    
809
static int raw_create(const char *filename, int64_t total_size,
810
                      const char *backing_file, int flags)
811
{
812
    int fd;
813

    
814
    if (flags || backing_file)
815
        return -ENOTSUP;
816

    
817
    fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE, 
818
              0644);
819
    if (fd < 0)
820
        return -EIO;
821
    set_sparse(fd);
822
    ftruncate(fd, total_size * 512);
823
    close(fd);
824
    return 0;
825
}
826

    
827
static void raw_flush(BlockDriverState *bs)
828
{
829
    BDRVRawState *s = bs->opaque;
830
    fsync(s->fd);
831
}
832

    
833
BlockDriver bdrv_raw = {
834
    "raw",
835
    sizeof(BDRVRawState),
836
    raw_probe,
837
    raw_open,
838
    raw_read,
839
    raw_write,
840
    raw_close,
841
    raw_create,
842
    raw_flush,
843
};
844

    
845
void bdrv_init(void)
846
{
847
    bdrv_register(&bdrv_raw);
848
#ifndef _WIN32
849
    bdrv_register(&bdrv_cow);
850
#endif
851
    bdrv_register(&bdrv_qcow);
852
    bdrv_register(&bdrv_vmdk);
853
    bdrv_register(&bdrv_cloop);
854
    bdrv_register(&bdrv_dmg);
855
    bdrv_register(&bdrv_bochs);
856
    bdrv_register(&bdrv_vpc);
857
    bdrv_register(&bdrv_vvfat);
858
}