root / block / cloop.c @ 5bc89ef6
History | View | Annotate | Download (5 kB)
1 | 3c56521b | bellard | /*
|
---|---|---|---|
2 | 585d0ed9 | bellard | * QEMU Block driver for CLOOP images
|
3 | 5fafdf24 | ths | *
|
4 | 3c56521b | bellard | * Copyright (c) 2004 Johannes E. Schindelin
|
5 | 5fafdf24 | ths | *
|
6 | 3c56521b | bellard | * Permission is hereby granted, free of charge, to any person obtaining a copy
|
7 | 3c56521b | bellard | * of this software and associated documentation files (the "Software"), to deal
|
8 | 3c56521b | bellard | * in the Software without restriction, including without limitation the rights
|
9 | 3c56521b | bellard | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
10 | 3c56521b | bellard | * copies of the Software, and to permit persons to whom the Software is
|
11 | 3c56521b | bellard | * furnished to do so, subject to the following conditions:
|
12 | 3c56521b | bellard | *
|
13 | 3c56521b | bellard | * The above copyright notice and this permission notice shall be included in
|
14 | 3c56521b | bellard | * all copies or substantial portions of the Software.
|
15 | 3c56521b | bellard | *
|
16 | 3c56521b | bellard | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
17 | 3c56521b | bellard | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
18 | 3c56521b | bellard | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
19 | 3c56521b | bellard | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
20 | 3c56521b | bellard | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
21 | 3c56521b | bellard | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
22 | 3c56521b | bellard | * THE SOFTWARE.
|
23 | 3c56521b | bellard | */
|
24 | faf07963 | pbrook | #include "qemu-common.h" |
25 | 3c56521b | bellard | #include "block_int.h" |
26 | 5efa9d5a | Anthony Liguori | #include "module.h" |
27 | 3c56521b | bellard | #include <zlib.h> |
28 | 3c56521b | bellard | |
29 | 3c56521b | bellard | typedef struct BDRVCloopState { |
30 | 3c56521b | bellard | int fd;
|
31 | 3c56521b | bellard | uint32_t block_size; |
32 | 3c56521b | bellard | uint32_t n_blocks; |
33 | 3c56521b | bellard | uint64_t* offsets; |
34 | 3c56521b | bellard | uint32_t sectors_per_block; |
35 | 3c56521b | bellard | uint32_t current_block; |
36 | 28a5c9c8 | bellard | uint8_t *compressed_block; |
37 | 28a5c9c8 | bellard | uint8_t *uncompressed_block; |
38 | 3c56521b | bellard | z_stream zstream; |
39 | 3c56521b | bellard | } BDRVCloopState; |
40 | 3c56521b | bellard | |
41 | 3c56521b | bellard | static int cloop_probe(const uint8_t *buf, int buf_size, const char *filename) |
42 | 3c56521b | bellard | { |
43 | 3c56521b | bellard | const char* magic_version_2_0="#!/bin/sh\n" |
44 | 3c56521b | bellard | "#V2.0 Format\n"
|
45 | 3c56521b | bellard | "modprobe cloop file=$0 && mount -r -t iso9660 /dev/cloop $1\n";
|
46 | 3c56521b | bellard | int length=strlen(magic_version_2_0);
|
47 | 3c56521b | bellard | if(length>buf_size)
|
48 | 3c56521b | bellard | length=buf_size; |
49 | 3c56521b | bellard | if(!memcmp(magic_version_2_0,buf,length))
|
50 | 3c56521b | bellard | return 2; |
51 | 3c56521b | bellard | return 0; |
52 | 3c56521b | bellard | } |
53 | 3c56521b | bellard | |
54 | 83f64091 | bellard | static int cloop_open(BlockDriverState *bs, const char *filename, int flags) |
55 | 3c56521b | bellard | { |
56 | 3c56521b | bellard | BDRVCloopState *s = bs->opaque; |
57 | 3c56521b | bellard | uint32_t offsets_size,max_compressed_block_size=1,i;
|
58 | 3c56521b | bellard | |
59 | 83f64091 | bellard | s->fd = open(filename, O_RDONLY | O_BINARY); |
60 | 3c56521b | bellard | if (s->fd < 0) |
61 | 83f64091 | bellard | return -errno;
|
62 | 3c56521b | bellard | bs->read_only = 1;
|
63 | 3c56521b | bellard | |
64 | 3c56521b | bellard | /* read header */
|
65 | 3c56521b | bellard | if(lseek(s->fd,128,SEEK_SET)<0) { |
66 | 3c56521b | bellard | cloop_close:
|
67 | 3c56521b | bellard | close(s->fd); |
68 | 3c56521b | bellard | return -1; |
69 | 3c56521b | bellard | } |
70 | 3c56521b | bellard | if(read(s->fd,&s->block_size,4)<4) |
71 | 3c56521b | bellard | goto cloop_close;
|
72 | 3c56521b | bellard | s->block_size=be32_to_cpu(s->block_size); |
73 | 3c56521b | bellard | if(read(s->fd,&s->n_blocks,4)<4) |
74 | 3c56521b | bellard | goto cloop_close;
|
75 | 3c56521b | bellard | s->n_blocks=be32_to_cpu(s->n_blocks); |
76 | 3c56521b | bellard | |
77 | 3c56521b | bellard | /* read offsets */
|
78 | 3c56521b | bellard | offsets_size=s->n_blocks*sizeof(uint64_t);
|
79 | 3ec88e80 | aliguori | s->offsets=(uint64_t*)qemu_malloc(offsets_size); |
80 | 3c56521b | bellard | if(read(s->fd,s->offsets,offsets_size)<offsets_size)
|
81 | 3c56521b | bellard | goto cloop_close;
|
82 | 3c56521b | bellard | for(i=0;i<s->n_blocks;i++) { |
83 | 3c56521b | bellard | s->offsets[i]=be64_to_cpu(s->offsets[i]); |
84 | 3c56521b | bellard | if(i>0) { |
85 | 3c56521b | bellard | uint32_t size=s->offsets[i]-s->offsets[i-1];
|
86 | 3c56521b | bellard | if(size>max_compressed_block_size)
|
87 | 3c56521b | bellard | max_compressed_block_size=size; |
88 | 3c56521b | bellard | } |
89 | 3c56521b | bellard | } |
90 | 3c56521b | bellard | |
91 | 3c56521b | bellard | /* initialize zlib engine */
|
92 | 3ec88e80 | aliguori | s->compressed_block = qemu_malloc(max_compressed_block_size+1);
|
93 | 3ec88e80 | aliguori | s->uncompressed_block = qemu_malloc(s->block_size); |
94 | 3c56521b | bellard | if(inflateInit(&s->zstream) != Z_OK)
|
95 | 3c56521b | bellard | goto cloop_close;
|
96 | 3c56521b | bellard | s->current_block=s->n_blocks; |
97 | 3b46e624 | ths | |
98 | 3c56521b | bellard | s->sectors_per_block = s->block_size/512;
|
99 | 3c56521b | bellard | bs->total_sectors = s->n_blocks*s->sectors_per_block; |
100 | 3c56521b | bellard | return 0; |
101 | 3c56521b | bellard | } |
102 | 3c56521b | bellard | |
103 | 3c56521b | bellard | static inline int cloop_read_block(BDRVCloopState *s,int block_num) |
104 | 3c56521b | bellard | { |
105 | 3c56521b | bellard | if(s->current_block != block_num) {
|
106 | 3c56521b | bellard | int ret;
|
107 | 3c56521b | bellard | uint32_t bytes = s->offsets[block_num+1]-s->offsets[block_num];
|
108 | 3b46e624 | ths | |
109 | 3c56521b | bellard | lseek(s->fd, s->offsets[block_num], SEEK_SET); |
110 | 3c56521b | bellard | ret = read(s->fd, s->compressed_block, bytes); |
111 | 5fafdf24 | ths | if (ret != bytes)
|
112 | 3c56521b | bellard | return -1; |
113 | 5fafdf24 | ths | |
114 | 3c56521b | bellard | s->zstream.next_in = s->compressed_block; |
115 | 3c56521b | bellard | s->zstream.avail_in = bytes; |
116 | 3c56521b | bellard | s->zstream.next_out = s->uncompressed_block; |
117 | 3c56521b | bellard | s->zstream.avail_out = s->block_size; |
118 | 3c56521b | bellard | ret = inflateReset(&s->zstream); |
119 | 3c56521b | bellard | if(ret != Z_OK)
|
120 | 3c56521b | bellard | return -1; |
121 | 3c56521b | bellard | ret = inflate(&s->zstream, Z_FINISH); |
122 | 3c56521b | bellard | if(ret != Z_STREAM_END || s->zstream.total_out != s->block_size)
|
123 | 3c56521b | bellard | return -1; |
124 | 5fafdf24 | ths | |
125 | 3c56521b | bellard | s->current_block = block_num; |
126 | 3c56521b | bellard | } |
127 | 3c56521b | bellard | return 0; |
128 | 3c56521b | bellard | } |
129 | 3c56521b | bellard | |
130 | 5fafdf24 | ths | static int cloop_read(BlockDriverState *bs, int64_t sector_num, |
131 | 3c56521b | bellard | uint8_t *buf, int nb_sectors)
|
132 | 3c56521b | bellard | { |
133 | 3c56521b | bellard | BDRVCloopState *s = bs->opaque; |
134 | 3c56521b | bellard | int i;
|
135 | 3c56521b | bellard | |
136 | 3c56521b | bellard | for(i=0;i<nb_sectors;i++) { |
137 | 3c56521b | bellard | uint32_t sector_offset_in_block=((sector_num+i)%s->sectors_per_block), |
138 | 3c56521b | bellard | block_num=(sector_num+i)/s->sectors_per_block; |
139 | 3c56521b | bellard | if(cloop_read_block(s, block_num) != 0) |
140 | 3c56521b | bellard | return -1; |
141 | 3c56521b | bellard | memcpy(buf+i*512,s->uncompressed_block+sector_offset_in_block*512,512); |
142 | 3c56521b | bellard | } |
143 | 3c56521b | bellard | return 0; |
144 | 3c56521b | bellard | } |
145 | 3c56521b | bellard | |
146 | 3c56521b | bellard | static void cloop_close(BlockDriverState *bs) |
147 | 3c56521b | bellard | { |
148 | 3c56521b | bellard | BDRVCloopState *s = bs->opaque; |
149 | 3c56521b | bellard | close(s->fd); |
150 | 585d0ed9 | bellard | if(s->n_blocks>0) |
151 | 585d0ed9 | bellard | free(s->offsets); |
152 | 3c56521b | bellard | free(s->compressed_block); |
153 | 3c56521b | bellard | free(s->uncompressed_block); |
154 | 3c56521b | bellard | inflateEnd(&s->zstream); |
155 | 3c56521b | bellard | } |
156 | 3c56521b | bellard | |
157 | 5efa9d5a | Anthony Liguori | static BlockDriver bdrv_cloop = {
|
158 | e60f469c | aurel32 | .format_name = "cloop",
|
159 | e60f469c | aurel32 | .instance_size = sizeof(BDRVCloopState),
|
160 | e60f469c | aurel32 | .bdrv_probe = cloop_probe, |
161 | e60f469c | aurel32 | .bdrv_open = cloop_open, |
162 | e60f469c | aurel32 | .bdrv_read = cloop_read, |
163 | e60f469c | aurel32 | .bdrv_close = cloop_close, |
164 | 3c56521b | bellard | }; |
165 | 5efa9d5a | Anthony Liguori | |
166 | 5efa9d5a | Anthony Liguori | static void bdrv_cloop_init(void) |
167 | 5efa9d5a | Anthony Liguori | { |
168 | 5efa9d5a | Anthony Liguori | bdrv_register(&bdrv_cloop); |
169 | 5efa9d5a | Anthony Liguori | } |
170 | 5efa9d5a | Anthony Liguori | |
171 | 5efa9d5a | Anthony Liguori | block_init(bdrv_cloop_init); |