xref: /openbmc/qemu/block.c (revision ea2384d36e1e5f6dfd44b748d290762181c38350)
1fc01f7e7Sbellard /*
2fc01f7e7Sbellard  * QEMU System Emulator block driver
3fc01f7e7Sbellard  *
4fc01f7e7Sbellard  * Copyright (c) 2003 Fabrice Bellard
5fc01f7e7Sbellard  *
6fc01f7e7Sbellard  * Permission is hereby granted, free of charge, to any person obtaining a copy
7fc01f7e7Sbellard  * of this software and associated documentation files (the "Software"), to deal
8fc01f7e7Sbellard  * in the Software without restriction, including without limitation the rights
9fc01f7e7Sbellard  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10fc01f7e7Sbellard  * copies of the Software, and to permit persons to whom the Software is
11fc01f7e7Sbellard  * furnished to do so, subject to the following conditions:
12fc01f7e7Sbellard  *
13fc01f7e7Sbellard  * The above copyright notice and this permission notice shall be included in
14fc01f7e7Sbellard  * all copies or substantial portions of the Software.
15fc01f7e7Sbellard  *
16fc01f7e7Sbellard  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17fc01f7e7Sbellard  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18fc01f7e7Sbellard  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19fc01f7e7Sbellard  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20fc01f7e7Sbellard  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21fc01f7e7Sbellard  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22fc01f7e7Sbellard  * THE SOFTWARE.
23fc01f7e7Sbellard  */
24fc01f7e7Sbellard #include "vl.h"
25*ea2384d3Sbellard #include "block_int.h"
26fc01f7e7Sbellard 
27b338082bSbellard static BlockDriverState *bdrv_first;
28*ea2384d3Sbellard static BlockDriver *first_drv;
29*ea2384d3Sbellard 
30*ea2384d3Sbellard void bdrv_register(BlockDriver *bdrv)
31*ea2384d3Sbellard {
32*ea2384d3Sbellard     bdrv->next = first_drv;
33*ea2384d3Sbellard     first_drv = bdrv;
34*ea2384d3Sbellard }
35b338082bSbellard 
36b338082bSbellard /* create a new block device (by default it is empty) */
37b338082bSbellard BlockDriverState *bdrv_new(const char *device_name)
38fc01f7e7Sbellard {
39b338082bSbellard     BlockDriverState **pbs, *bs;
40b338082bSbellard 
41b338082bSbellard     bs = qemu_mallocz(sizeof(BlockDriverState));
42b338082bSbellard     if(!bs)
43b338082bSbellard         return NULL;
44b338082bSbellard     pstrcpy(bs->device_name, sizeof(bs->device_name), device_name);
45*ea2384d3Sbellard     if (device_name[0] != '\0') {
46b338082bSbellard         /* insert at the end */
47b338082bSbellard         pbs = &bdrv_first;
48b338082bSbellard         while (*pbs != NULL)
49b338082bSbellard             pbs = &(*pbs)->next;
50b338082bSbellard         *pbs = bs;
51*ea2384d3Sbellard     }
52b338082bSbellard     return bs;
53b338082bSbellard }
54b338082bSbellard 
55*ea2384d3Sbellard BlockDriver *bdrv_find_format(const char *format_name)
56*ea2384d3Sbellard {
57*ea2384d3Sbellard     BlockDriver *drv1;
58*ea2384d3Sbellard     for(drv1 = first_drv; drv1 != NULL; drv1 = drv1->next) {
59*ea2384d3Sbellard         if (!strcmp(drv1->format_name, format_name))
60*ea2384d3Sbellard             return drv1;
61*ea2384d3Sbellard     }
62*ea2384d3Sbellard     return NULL;
63*ea2384d3Sbellard }
64*ea2384d3Sbellard 
65*ea2384d3Sbellard int bdrv_create(BlockDriver *drv,
66*ea2384d3Sbellard                 const char *filename, int64_t size_in_sectors,
67*ea2384d3Sbellard                 const char *backing_file, int flags)
68*ea2384d3Sbellard {
69*ea2384d3Sbellard     if (!drv->bdrv_create)
70*ea2384d3Sbellard         return -ENOTSUP;
71*ea2384d3Sbellard     return drv->bdrv_create(filename, size_in_sectors, backing_file, flags);
72*ea2384d3Sbellard }
73*ea2384d3Sbellard 
74*ea2384d3Sbellard /* XXX: race condition possible */
75*ea2384d3Sbellard static void get_tmp_filename(char *filename, int size)
76*ea2384d3Sbellard {
77*ea2384d3Sbellard     int fd;
78*ea2384d3Sbellard     pstrcpy(filename, size, "/tmp/vl.XXXXXX");
79*ea2384d3Sbellard     fd = mkstemp(filename);
80*ea2384d3Sbellard     close(fd);
81*ea2384d3Sbellard }
82*ea2384d3Sbellard 
83*ea2384d3Sbellard static BlockDriver *find_image_format(const char *filename)
84*ea2384d3Sbellard {
85*ea2384d3Sbellard     int fd, ret, score, score_max;
86*ea2384d3Sbellard     BlockDriver *drv1, *drv;
87*ea2384d3Sbellard     uint8_t buf[1024];
88*ea2384d3Sbellard 
89*ea2384d3Sbellard     fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
90*ea2384d3Sbellard     if (fd < 0)
91*ea2384d3Sbellard         return NULL;
92*ea2384d3Sbellard     ret = read(fd, buf, sizeof(buf));
93*ea2384d3Sbellard     if (ret < 0) {
94*ea2384d3Sbellard         close(fd);
95*ea2384d3Sbellard         return NULL;
96*ea2384d3Sbellard     }
97*ea2384d3Sbellard     close(fd);
98*ea2384d3Sbellard 
99*ea2384d3Sbellard     drv = NULL;
100*ea2384d3Sbellard     score_max = 0;
101*ea2384d3Sbellard     for(drv1 = first_drv; drv1 != NULL; drv1 = drv1->next) {
102*ea2384d3Sbellard         score = drv1->bdrv_probe(buf, ret, filename);
103*ea2384d3Sbellard         if (score > score_max) {
104*ea2384d3Sbellard             score_max = score;
105*ea2384d3Sbellard             drv = drv1;
106*ea2384d3Sbellard         }
107*ea2384d3Sbellard     }
108*ea2384d3Sbellard     return drv;
109*ea2384d3Sbellard }
110*ea2384d3Sbellard 
111b338082bSbellard int bdrv_open(BlockDriverState *bs, const char *filename, int snapshot)
112b338082bSbellard {
113*ea2384d3Sbellard     return bdrv_open2(bs, filename, snapshot, NULL);
114*ea2384d3Sbellard }
115*ea2384d3Sbellard 
116*ea2384d3Sbellard int bdrv_open2(BlockDriverState *bs, const char *filename, int snapshot,
117*ea2384d3Sbellard                BlockDriver *drv)
118*ea2384d3Sbellard {
119*ea2384d3Sbellard     int ret;
120*ea2384d3Sbellard     char tmp_filename[1024];
121fc01f7e7Sbellard 
1220849bf08Sbellard     bs->read_only = 0;
123*ea2384d3Sbellard     bs->is_temporary = 0;
124*ea2384d3Sbellard     bs->encrypted = 0;
12533e3963eSbellard 
12633e3963eSbellard     if (snapshot) {
127*ea2384d3Sbellard         BlockDriverState *bs1;
128*ea2384d3Sbellard         int64_t total_size;
12933e3963eSbellard 
130*ea2384d3Sbellard         /* if snapshot, we create a temporary backing file and open it
131*ea2384d3Sbellard            instead of opening 'filename' directly */
132*ea2384d3Sbellard 
133*ea2384d3Sbellard         /* if there is a backing file, use it */
134*ea2384d3Sbellard         bs1 = bdrv_new("");
135*ea2384d3Sbellard         if (!bs1) {
136*ea2384d3Sbellard             return -1;
137*ea2384d3Sbellard         }
138*ea2384d3Sbellard         if (bdrv_open(bs1, filename, 0) < 0) {
139*ea2384d3Sbellard             bdrv_delete(bs1);
140*ea2384d3Sbellard             return -1;
141*ea2384d3Sbellard         }
142*ea2384d3Sbellard         total_size = bs1->total_sectors;
143*ea2384d3Sbellard         bdrv_delete(bs1);
144*ea2384d3Sbellard 
145*ea2384d3Sbellard         get_tmp_filename(tmp_filename, sizeof(tmp_filename));
146*ea2384d3Sbellard         /* XXX: use cow for linux as it is more efficient ? */
147*ea2384d3Sbellard         if (bdrv_create(&bdrv_qcow, tmp_filename,
148*ea2384d3Sbellard                         total_size, filename, 0) < 0) {
149*ea2384d3Sbellard             return -1;
150*ea2384d3Sbellard         }
151*ea2384d3Sbellard         filename = tmp_filename;
152*ea2384d3Sbellard         bs->is_temporary = 1;
153*ea2384d3Sbellard     }
154*ea2384d3Sbellard 
155*ea2384d3Sbellard     pstrcpy(bs->filename, sizeof(bs->filename), filename);
156*ea2384d3Sbellard     if (!drv) {
157*ea2384d3Sbellard         drv = find_image_format(filename);
158*ea2384d3Sbellard         if (!drv)
159*ea2384d3Sbellard             return -1;
160*ea2384d3Sbellard     }
161*ea2384d3Sbellard     bs->drv = drv;
162*ea2384d3Sbellard     bs->opaque = qemu_mallocz(drv->instance_size);
163*ea2384d3Sbellard     if (bs->opaque == NULL && drv->instance_size > 0)
164*ea2384d3Sbellard         return -1;
165*ea2384d3Sbellard 
166*ea2384d3Sbellard     ret = drv->bdrv_open(bs, filename);
167*ea2384d3Sbellard     if (ret < 0) {
168*ea2384d3Sbellard         qemu_free(bs->opaque);
169*ea2384d3Sbellard         return -1;
170*ea2384d3Sbellard     }
171*ea2384d3Sbellard #ifndef _WIN32
172*ea2384d3Sbellard     if (bs->is_temporary) {
173*ea2384d3Sbellard         unlink(filename);
17433e3963eSbellard     }
17567b915a5Sbellard #endif
176*ea2384d3Sbellard     if (bs->backing_file[0] != '\0' && drv->bdrv_is_allocated) {
177*ea2384d3Sbellard         /* if there is a backing file, use it */
178*ea2384d3Sbellard         bs->backing_hd = bdrv_new("");
179*ea2384d3Sbellard         if (!bs->backing_hd) {
180*ea2384d3Sbellard         fail:
181*ea2384d3Sbellard             bdrv_close(bs);
182*ea2384d3Sbellard             return -1;
183*ea2384d3Sbellard         }
184*ea2384d3Sbellard         if (bdrv_open(bs->backing_hd, bs->backing_file, 0) < 0)
185*ea2384d3Sbellard             goto fail;
186*ea2384d3Sbellard     }
18733e3963eSbellard 
188b338082bSbellard     bs->inserted = 1;
189b338082bSbellard 
190b338082bSbellard     /* call the change callback */
191b338082bSbellard     if (bs->change_cb)
192b338082bSbellard         bs->change_cb(bs->change_opaque);
193b338082bSbellard 
194b338082bSbellard     return 0;
195fc01f7e7Sbellard }
196fc01f7e7Sbellard 
197fc01f7e7Sbellard void bdrv_close(BlockDriverState *bs)
198fc01f7e7Sbellard {
199b338082bSbellard     if (bs->inserted) {
200*ea2384d3Sbellard         if (bs->backing_hd)
201*ea2384d3Sbellard             bdrv_delete(bs->backing_hd);
202*ea2384d3Sbellard         bs->drv->bdrv_close(bs);
203*ea2384d3Sbellard         qemu_free(bs->opaque);
204*ea2384d3Sbellard #ifdef _WIN32
205*ea2384d3Sbellard         if (bs->is_temporary) {
206*ea2384d3Sbellard             unlink(bs->filename);
207*ea2384d3Sbellard         }
20867b915a5Sbellard #endif
209*ea2384d3Sbellard         bs->opaque = NULL;
210*ea2384d3Sbellard         bs->drv = NULL;
211b338082bSbellard         bs->inserted = 0;
212b338082bSbellard 
213b338082bSbellard         /* call the change callback */
214b338082bSbellard         if (bs->change_cb)
215b338082bSbellard             bs->change_cb(bs->change_opaque);
216b338082bSbellard     }
217b338082bSbellard }
218b338082bSbellard 
219b338082bSbellard void bdrv_delete(BlockDriverState *bs)
220b338082bSbellard {
221*ea2384d3Sbellard     /* XXX: remove the driver list */
222b338082bSbellard     bdrv_close(bs);
223b338082bSbellard     qemu_free(bs);
224fc01f7e7Sbellard }
225fc01f7e7Sbellard 
22633e3963eSbellard /* commit COW file into the raw image */
22733e3963eSbellard int bdrv_commit(BlockDriverState *bs)
22833e3963eSbellard {
22933e3963eSbellard     int64_t i;
230*ea2384d3Sbellard     int n, j;
231*ea2384d3Sbellard     unsigned char sector[512];
23233e3963eSbellard 
233b338082bSbellard     if (!bs->inserted)
234*ea2384d3Sbellard         return -ENOENT;
23533e3963eSbellard 
23633e3963eSbellard     if (bs->read_only) {
237*ea2384d3Sbellard 	return -EACCES;
23833e3963eSbellard     }
23933e3963eSbellard 
240*ea2384d3Sbellard     if (!bs->backing_hd) {
241*ea2384d3Sbellard 	return -ENOTSUP;
242*ea2384d3Sbellard     }
243*ea2384d3Sbellard 
244*ea2384d3Sbellard     for (i = 0; i < bs->total_sectors;) {
245*ea2384d3Sbellard         if (bs->drv->bdrv_is_allocated(bs, i, 65536, &n)) {
246*ea2384d3Sbellard             for(j = 0; j < n; j++) {
24733e3963eSbellard                 if (bdrv_read(bs, i, sector, 1) != 0) {
248*ea2384d3Sbellard                     return -EIO;
24933e3963eSbellard                 }
25033e3963eSbellard 
251*ea2384d3Sbellard                 if (bdrv_write(bs->backing_hd, i, sector, 1) != 0) {
252*ea2384d3Sbellard                     return -EIO;
25333e3963eSbellard                 }
254*ea2384d3Sbellard                 i++;
255*ea2384d3Sbellard 	    }
256*ea2384d3Sbellard 	} else {
257*ea2384d3Sbellard             i += n;
25833e3963eSbellard         }
25933e3963eSbellard     }
26033e3963eSbellard     return 0;
26133e3963eSbellard }
26233e3963eSbellard 
263fc01f7e7Sbellard /* return -1 if error */
264fc01f7e7Sbellard int bdrv_read(BlockDriverState *bs, int64_t sector_num,
265fc01f7e7Sbellard               uint8_t *buf, int nb_sectors)
266fc01f7e7Sbellard {
267*ea2384d3Sbellard     int ret, n;
268*ea2384d3Sbellard     BlockDriver *drv = bs->drv;
269fc01f7e7Sbellard 
270b338082bSbellard     if (!bs->inserted)
271b338082bSbellard         return -1;
272b338082bSbellard 
27333e3963eSbellard     while (nb_sectors > 0) {
274*ea2384d3Sbellard         if (sector_num == 0 && bs->boot_sector_enabled) {
275cf98951bSbellard             memcpy(buf, bs->boot_sector_data, 512);
276cf98951bSbellard             n = 1;
277*ea2384d3Sbellard         } else if (bs->backing_hd) {
278*ea2384d3Sbellard             if (drv->bdrv_is_allocated(bs, sector_num, nb_sectors, &n)) {
279*ea2384d3Sbellard                 ret = drv->bdrv_read(bs, sector_num, buf, n);
280*ea2384d3Sbellard                 if (ret < 0)
281*ea2384d3Sbellard                     return -1;
28233e3963eSbellard             } else {
283*ea2384d3Sbellard                 /* read from the base image */
284*ea2384d3Sbellard                 ret = bdrv_read(bs->backing_hd, sector_num, buf, n);
285*ea2384d3Sbellard                 if (ret < 0)
286fc01f7e7Sbellard                     return -1;
28733e3963eSbellard             }
288*ea2384d3Sbellard         } else {
289*ea2384d3Sbellard             ret = drv->bdrv_read(bs, sector_num, buf, nb_sectors);
290*ea2384d3Sbellard             if (ret < 0)
291*ea2384d3Sbellard                 return -1;
292*ea2384d3Sbellard             /* no need to loop */
293*ea2384d3Sbellard             break;
29433e3963eSbellard         }
29533e3963eSbellard         nb_sectors -= n;
29633e3963eSbellard         sector_num += n;
29733e3963eSbellard         buf += n * 512;
29833e3963eSbellard     }
299fc01f7e7Sbellard     return 0;
300fc01f7e7Sbellard }
301fc01f7e7Sbellard 
302fc01f7e7Sbellard /* return -1 if error */
303fc01f7e7Sbellard int bdrv_write(BlockDriverState *bs, int64_t sector_num,
304fc01f7e7Sbellard                const uint8_t *buf, int nb_sectors)
305fc01f7e7Sbellard {
306b338082bSbellard     if (!bs->inserted)
307b338082bSbellard         return -1;
3080849bf08Sbellard     if (bs->read_only)
3090849bf08Sbellard         return -1;
310*ea2384d3Sbellard     return bs->drv->bdrv_write(bs, sector_num, buf, nb_sectors);
311fc01f7e7Sbellard }
312fc01f7e7Sbellard 
313fc01f7e7Sbellard void bdrv_get_geometry(BlockDriverState *bs, int64_t *nb_sectors_ptr)
314fc01f7e7Sbellard {
315fc01f7e7Sbellard     *nb_sectors_ptr = bs->total_sectors;
316fc01f7e7Sbellard }
317cf98951bSbellard 
318cf98951bSbellard /* force a given boot sector. */
319cf98951bSbellard void bdrv_set_boot_sector(BlockDriverState *bs, const uint8_t *data, int size)
320cf98951bSbellard {
321cf98951bSbellard     bs->boot_sector_enabled = 1;
322cf98951bSbellard     if (size > 512)
323cf98951bSbellard         size = 512;
324cf98951bSbellard     memcpy(bs->boot_sector_data, data, size);
325cf98951bSbellard     memset(bs->boot_sector_data + size, 0, 512 - size);
326cf98951bSbellard }
327b338082bSbellard 
328b338082bSbellard void bdrv_set_geometry_hint(BlockDriverState *bs,
329b338082bSbellard                             int cyls, int heads, int secs)
330b338082bSbellard {
331b338082bSbellard     bs->cyls = cyls;
332b338082bSbellard     bs->heads = heads;
333b338082bSbellard     bs->secs = secs;
334b338082bSbellard }
335b338082bSbellard 
336b338082bSbellard void bdrv_set_type_hint(BlockDriverState *bs, int type)
337b338082bSbellard {
338b338082bSbellard     bs->type = type;
339b338082bSbellard     bs->removable = ((type == BDRV_TYPE_CDROM ||
340b338082bSbellard                       type == BDRV_TYPE_FLOPPY));
341b338082bSbellard }
342b338082bSbellard 
343b338082bSbellard void bdrv_get_geometry_hint(BlockDriverState *bs,
344b338082bSbellard                             int *pcyls, int *pheads, int *psecs)
345b338082bSbellard {
346b338082bSbellard     *pcyls = bs->cyls;
347b338082bSbellard     *pheads = bs->heads;
348b338082bSbellard     *psecs = bs->secs;
349b338082bSbellard }
350b338082bSbellard 
351b338082bSbellard int bdrv_get_type_hint(BlockDriverState *bs)
352b338082bSbellard {
353b338082bSbellard     return bs->type;
354b338082bSbellard }
355b338082bSbellard 
356b338082bSbellard int bdrv_is_removable(BlockDriverState *bs)
357b338082bSbellard {
358b338082bSbellard     return bs->removable;
359b338082bSbellard }
360b338082bSbellard 
361b338082bSbellard int bdrv_is_read_only(BlockDriverState *bs)
362b338082bSbellard {
363b338082bSbellard     return bs->read_only;
364b338082bSbellard }
365b338082bSbellard 
366b338082bSbellard int bdrv_is_inserted(BlockDriverState *bs)
367b338082bSbellard {
368b338082bSbellard     return bs->inserted;
369b338082bSbellard }
370b338082bSbellard 
371b338082bSbellard int bdrv_is_locked(BlockDriverState *bs)
372b338082bSbellard {
373b338082bSbellard     return bs->locked;
374b338082bSbellard }
375b338082bSbellard 
376b338082bSbellard void bdrv_set_locked(BlockDriverState *bs, int locked)
377b338082bSbellard {
378b338082bSbellard     bs->locked = locked;
379b338082bSbellard }
380b338082bSbellard 
381b338082bSbellard void bdrv_set_change_cb(BlockDriverState *bs,
382b338082bSbellard                         void (*change_cb)(void *opaque), void *opaque)
383b338082bSbellard {
384b338082bSbellard     bs->change_cb = change_cb;
385b338082bSbellard     bs->change_opaque = opaque;
386b338082bSbellard }
387b338082bSbellard 
388*ea2384d3Sbellard int bdrv_is_encrypted(BlockDriverState *bs)
389*ea2384d3Sbellard {
390*ea2384d3Sbellard     if (bs->backing_hd && bs->backing_hd->encrypted)
391*ea2384d3Sbellard         return 1;
392*ea2384d3Sbellard     return bs->encrypted;
393*ea2384d3Sbellard }
394*ea2384d3Sbellard 
395*ea2384d3Sbellard int bdrv_set_key(BlockDriverState *bs, const char *key)
396*ea2384d3Sbellard {
397*ea2384d3Sbellard     int ret;
398*ea2384d3Sbellard     if (bs->backing_hd && bs->backing_hd->encrypted) {
399*ea2384d3Sbellard         ret = bdrv_set_key(bs->backing_hd, key);
400*ea2384d3Sbellard         if (ret < 0)
401*ea2384d3Sbellard             return ret;
402*ea2384d3Sbellard         if (!bs->encrypted)
403*ea2384d3Sbellard             return 0;
404*ea2384d3Sbellard     }
405*ea2384d3Sbellard     if (!bs->encrypted || !bs->drv || !bs->drv->bdrv_set_key)
406*ea2384d3Sbellard         return -1;
407*ea2384d3Sbellard     return bs->drv->bdrv_set_key(bs, key);
408*ea2384d3Sbellard }
409*ea2384d3Sbellard 
410*ea2384d3Sbellard void bdrv_get_format(BlockDriverState *bs, char *buf, int buf_size)
411*ea2384d3Sbellard {
412*ea2384d3Sbellard     if (!bs->inserted || !bs->drv) {
413*ea2384d3Sbellard         buf[0] = '\0';
414*ea2384d3Sbellard     } else {
415*ea2384d3Sbellard         pstrcpy(buf, buf_size, bs->drv->format_name);
416*ea2384d3Sbellard     }
417*ea2384d3Sbellard }
418*ea2384d3Sbellard 
419*ea2384d3Sbellard void bdrv_iterate_format(void (*it)(void *opaque, const char *name),
420*ea2384d3Sbellard                          void *opaque)
421*ea2384d3Sbellard {
422*ea2384d3Sbellard     BlockDriver *drv;
423*ea2384d3Sbellard 
424*ea2384d3Sbellard     for (drv = first_drv; drv != NULL; drv = drv->next) {
425*ea2384d3Sbellard         it(opaque, drv->format_name);
426*ea2384d3Sbellard     }
427*ea2384d3Sbellard }
428*ea2384d3Sbellard 
429b338082bSbellard BlockDriverState *bdrv_find(const char *name)
430b338082bSbellard {
431b338082bSbellard     BlockDriverState *bs;
432b338082bSbellard 
433b338082bSbellard     for (bs = bdrv_first; bs != NULL; bs = bs->next) {
434b338082bSbellard         if (!strcmp(name, bs->device_name))
435b338082bSbellard             return bs;
436b338082bSbellard     }
437b338082bSbellard     return NULL;
438b338082bSbellard }
439b338082bSbellard 
44081d0912dSbellard void bdrv_iterate(void (*it)(void *opaque, const char *name), void *opaque)
44181d0912dSbellard {
44281d0912dSbellard     BlockDriverState *bs;
44381d0912dSbellard 
44481d0912dSbellard     for (bs = bdrv_first; bs != NULL; bs = bs->next) {
44581d0912dSbellard         it(opaque, bs->device_name);
44681d0912dSbellard     }
44781d0912dSbellard }
44881d0912dSbellard 
449*ea2384d3Sbellard const char *bdrv_get_device_name(BlockDriverState *bs)
450*ea2384d3Sbellard {
451*ea2384d3Sbellard     return bs->device_name;
452*ea2384d3Sbellard }
453*ea2384d3Sbellard 
454b338082bSbellard void bdrv_info(void)
455b338082bSbellard {
456b338082bSbellard     BlockDriverState *bs;
457b338082bSbellard 
458b338082bSbellard     for (bs = bdrv_first; bs != NULL; bs = bs->next) {
459b338082bSbellard         term_printf("%s:", bs->device_name);
460b338082bSbellard         term_printf(" type=");
461b338082bSbellard         switch(bs->type) {
462b338082bSbellard         case BDRV_TYPE_HD:
463b338082bSbellard             term_printf("hd");
464b338082bSbellard             break;
465b338082bSbellard         case BDRV_TYPE_CDROM:
466b338082bSbellard             term_printf("cdrom");
467b338082bSbellard             break;
468b338082bSbellard         case BDRV_TYPE_FLOPPY:
469b338082bSbellard             term_printf("floppy");
470b338082bSbellard             break;
471b338082bSbellard         }
472b338082bSbellard         term_printf(" removable=%d", bs->removable);
473b338082bSbellard         if (bs->removable) {
474b338082bSbellard             term_printf(" locked=%d", bs->locked);
475b338082bSbellard         }
476b338082bSbellard         if (bs->inserted) {
477b338082bSbellard             term_printf(" file=%s", bs->filename);
478*ea2384d3Sbellard             if (bs->backing_file[0] != '\0')
479*ea2384d3Sbellard                 term_printf(" backing_file=%s", bs->backing_file);
480b338082bSbellard             term_printf(" ro=%d", bs->read_only);
481*ea2384d3Sbellard             term_printf(" drv=%s", bs->drv->format_name);
482*ea2384d3Sbellard             if (bs->encrypted)
483*ea2384d3Sbellard                 term_printf(" encrypted");
484b338082bSbellard         } else {
485b338082bSbellard             term_printf(" [not inserted]");
486b338082bSbellard         }
487b338082bSbellard         term_printf("\n");
488b338082bSbellard     }
489b338082bSbellard }
490*ea2384d3Sbellard 
491*ea2384d3Sbellard 
492*ea2384d3Sbellard /**************************************************************/
493*ea2384d3Sbellard /* RAW block driver */
494*ea2384d3Sbellard 
495*ea2384d3Sbellard typedef struct BDRVRawState {
496*ea2384d3Sbellard     int fd;
497*ea2384d3Sbellard } BDRVRawState;
498*ea2384d3Sbellard 
499*ea2384d3Sbellard static int raw_probe(const uint8_t *buf, int buf_size, const char *filename)
500*ea2384d3Sbellard {
501*ea2384d3Sbellard     return 1; /* maybe */
502*ea2384d3Sbellard }
503*ea2384d3Sbellard 
504*ea2384d3Sbellard static int raw_open(BlockDriverState *bs, const char *filename)
505*ea2384d3Sbellard {
506*ea2384d3Sbellard     BDRVRawState *s = bs->opaque;
507*ea2384d3Sbellard     int fd;
508*ea2384d3Sbellard     int64_t size;
509*ea2384d3Sbellard 
510*ea2384d3Sbellard     fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE);
511*ea2384d3Sbellard     if (fd < 0) {
512*ea2384d3Sbellard         fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
513*ea2384d3Sbellard         if (fd < 0)
514*ea2384d3Sbellard             return -1;
515*ea2384d3Sbellard         bs->read_only = 1;
516*ea2384d3Sbellard     }
517*ea2384d3Sbellard     size = lseek64(fd, 0, SEEK_END);
518*ea2384d3Sbellard     bs->total_sectors = size / 512;
519*ea2384d3Sbellard     s->fd = fd;
520*ea2384d3Sbellard     return 0;
521*ea2384d3Sbellard }
522*ea2384d3Sbellard 
523*ea2384d3Sbellard static int raw_read(BlockDriverState *bs, int64_t sector_num,
524*ea2384d3Sbellard                     uint8_t *buf, int nb_sectors)
525*ea2384d3Sbellard {
526*ea2384d3Sbellard     BDRVRawState *s = bs->opaque;
527*ea2384d3Sbellard     int ret;
528*ea2384d3Sbellard 
529*ea2384d3Sbellard     lseek64(s->fd, sector_num * 512, SEEK_SET);
530*ea2384d3Sbellard     ret = read(s->fd, buf, nb_sectors * 512);
531*ea2384d3Sbellard     if (ret != nb_sectors * 512)
532*ea2384d3Sbellard         return -1;
533*ea2384d3Sbellard     return 0;
534*ea2384d3Sbellard }
535*ea2384d3Sbellard 
536*ea2384d3Sbellard static int raw_write(BlockDriverState *bs, int64_t sector_num,
537*ea2384d3Sbellard                      const uint8_t *buf, int nb_sectors)
538*ea2384d3Sbellard {
539*ea2384d3Sbellard     BDRVRawState *s = bs->opaque;
540*ea2384d3Sbellard     int ret;
541*ea2384d3Sbellard 
542*ea2384d3Sbellard     lseek64(s->fd, sector_num * 512, SEEK_SET);
543*ea2384d3Sbellard     ret = write(s->fd, buf, nb_sectors * 512);
544*ea2384d3Sbellard     if (ret != nb_sectors * 512)
545*ea2384d3Sbellard         return -1;
546*ea2384d3Sbellard     return 0;
547*ea2384d3Sbellard }
548*ea2384d3Sbellard 
549*ea2384d3Sbellard static int raw_close(BlockDriverState *bs)
550*ea2384d3Sbellard {
551*ea2384d3Sbellard     BDRVRawState *s = bs->opaque;
552*ea2384d3Sbellard     close(s->fd);
553*ea2384d3Sbellard }
554*ea2384d3Sbellard 
555*ea2384d3Sbellard static int raw_create(const char *filename, int64_t total_size,
556*ea2384d3Sbellard                       const char *backing_file, int flags)
557*ea2384d3Sbellard {
558*ea2384d3Sbellard     int fd;
559*ea2384d3Sbellard 
560*ea2384d3Sbellard     if (flags || backing_file)
561*ea2384d3Sbellard         return -ENOTSUP;
562*ea2384d3Sbellard 
563*ea2384d3Sbellard     fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
564*ea2384d3Sbellard               0644);
565*ea2384d3Sbellard     if (fd < 0)
566*ea2384d3Sbellard         return -EIO;
567*ea2384d3Sbellard     ftruncate64(fd, total_size * 512);
568*ea2384d3Sbellard     close(fd);
569*ea2384d3Sbellard     return 0;
570*ea2384d3Sbellard }
571*ea2384d3Sbellard 
572*ea2384d3Sbellard BlockDriver bdrv_raw = {
573*ea2384d3Sbellard     "raw",
574*ea2384d3Sbellard     sizeof(BDRVRawState),
575*ea2384d3Sbellard     raw_probe,
576*ea2384d3Sbellard     raw_open,
577*ea2384d3Sbellard     raw_read,
578*ea2384d3Sbellard     raw_write,
579*ea2384d3Sbellard     raw_close,
580*ea2384d3Sbellard     raw_create,
581*ea2384d3Sbellard };
582*ea2384d3Sbellard 
583*ea2384d3Sbellard void bdrv_init(void)
584*ea2384d3Sbellard {
585*ea2384d3Sbellard     bdrv_register(&bdrv_raw);
586*ea2384d3Sbellard #ifndef _WIN32
587*ea2384d3Sbellard     bdrv_register(&bdrv_cow);
588*ea2384d3Sbellard #endif
589*ea2384d3Sbellard     bdrv_register(&bdrv_qcow);
590*ea2384d3Sbellard     bdrv_register(&bdrv_vmdk);
591*ea2384d3Sbellard }
592