Solaris port (Ben Taylor)
[qemu] / block.c
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_info(void)
619 {
620     BlockDriverState *bs;
621
622     for (bs = bdrv_first; bs != NULL; bs = bs->next) {
623         term_printf("%s:", bs->device_name);
624         term_printf(" type=");
625         switch(bs->type) {
626         case BDRV_TYPE_HD:
627             term_printf("hd");
628             break;
629         case BDRV_TYPE_CDROM:
630             term_printf("cdrom");
631             break;
632         case BDRV_TYPE_FLOPPY:
633             term_printf("floppy");
634             break;
635         }
636         term_printf(" removable=%d", bs->removable);
637         if (bs->removable) {
638             term_printf(" locked=%d", bs->locked);
639         }
640         if (bs->inserted) {
641             term_printf(" file=%s", bs->filename);
642             if (bs->backing_file[0] != '\0')
643                 term_printf(" backing_file=%s", bs->backing_file);
644             term_printf(" ro=%d", bs->read_only);
645             term_printf(" drv=%s", bs->drv->format_name);
646             if (bs->encrypted)
647                 term_printf(" encrypted");
648         } else {
649             term_printf(" [not inserted]");
650         }
651         term_printf("\n");
652     }
653 }
654
655 /**************************************************************/
656 /* RAW block driver */
657
658 typedef struct BDRVRawState {
659     int fd;
660 } BDRVRawState;
661
662 static int raw_probe(const uint8_t *buf, int buf_size, const char *filename)
663 {
664     return 1; /* maybe */
665 }
666
667 static int raw_open(BlockDriverState *bs, const char *filename)
668 {
669     BDRVRawState *s = bs->opaque;
670     int fd;
671     int64_t size;
672 #ifdef _BSD
673     struct stat sb;
674 #endif
675 #ifdef __sun__
676     struct dk_minfo minfo;
677     int rv;
678 #endif
679
680     fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE);
681     if (fd < 0) {
682         fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
683         if (fd < 0)
684             return -1;
685         bs->read_only = 1;
686     }
687 #ifdef _BSD
688     if (!fstat(fd, &sb) && (S_IFCHR & sb.st_mode)) {
689 #ifdef DIOCGMEDIASIZE
690         if (ioctl(fd, DIOCGMEDIASIZE, (off_t *)&size))
691 #endif
692 #ifdef CONFIG_COCOA
693         size = LONG_LONG_MAX;
694 #else
695         size = lseek(fd, 0LL, SEEK_END);
696 #endif
697     } else
698 #endif
699 #ifdef __sun__
700     /*
701      * use the DKIOCGMEDIAINFO ioctl to read the size.
702      */
703     rv = ioctl ( fd, DKIOCGMEDIAINFO, &minfo );
704     if ( rv != -1 ) {
705         size = minfo.dki_lbsize * minfo.dki_capacity;
706     } else /* there are reports that lseek on some devices
707               fails, but irc discussion said that contingency
708               on contingency was overkill */
709 #endif
710     {
711         size = lseek(fd, 0, SEEK_END);
712     }
713 #ifdef _WIN32
714     /* On Windows hosts it can happen that we're unable to get file size
715        for CD-ROM raw device (it's inherent limitation of the CDFS driver). */
716     if (size == -1)
717         size = LONG_LONG_MAX;
718 #endif
719     bs->total_sectors = size / 512;
720     s->fd = fd;
721     return 0;
722 }
723
724 static int raw_read(BlockDriverState *bs, int64_t sector_num, 
725                     uint8_t *buf, int nb_sectors)
726 {
727     BDRVRawState *s = bs->opaque;
728     int ret;
729     
730     lseek(s->fd, sector_num * 512, SEEK_SET);
731     ret = read(s->fd, buf, nb_sectors * 512);
732     if (ret != nb_sectors * 512) 
733         return -1;
734     return 0;
735 }
736
737 static int raw_write(BlockDriverState *bs, int64_t sector_num, 
738                      const uint8_t *buf, int nb_sectors)
739 {
740     BDRVRawState *s = bs->opaque;
741     int ret;
742     
743     lseek(s->fd, sector_num * 512, SEEK_SET);
744     ret = write(s->fd, buf, nb_sectors * 512);
745     if (ret != nb_sectors * 512) 
746         return -1;
747     return 0;
748 }
749
750 static void raw_close(BlockDriverState *bs)
751 {
752     BDRVRawState *s = bs->opaque;
753     close(s->fd);
754 }
755
756 static int raw_create(const char *filename, int64_t total_size,
757                       const char *backing_file, int flags)
758 {
759     int fd;
760
761     if (flags || backing_file)
762         return -ENOTSUP;
763
764     fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE, 
765               0644);
766     if (fd < 0)
767         return -EIO;
768     ftruncate(fd, total_size * 512);
769     close(fd);
770     return 0;
771 }
772
773 BlockDriver bdrv_raw = {
774     "raw",
775     sizeof(BDRVRawState),
776     raw_probe,
777     raw_open,
778     raw_read,
779     raw_write,
780     raw_close,
781     raw_create,
782 };
783
784 void bdrv_init(void)
785 {
786     bdrv_register(&bdrv_raw);
787 #ifndef _WIN32
788     bdrv_register(&bdrv_cow);
789 #endif
790     bdrv_register(&bdrv_qcow);
791     bdrv_register(&bdrv_vmdk);
792     bdrv_register(&bdrv_cloop);
793     bdrv_register(&bdrv_dmg);
794     bdrv_register(&bdrv_bochs);
795     bdrv_register(&bdrv_vpc);
796     bdrv_register(&bdrv_vvfat);
797 }