root / block / cloop.c @ 1b1ed8dc
History | View | Annotate | Download (5.8 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 | 737e150e | Paolo Bonzini | #include "block/block_int.h" |
26 | 1de7afc9 | Paolo Bonzini | #include "qemu/module.h" |
27 | 3c56521b | bellard | #include <zlib.h> |
28 | 3c56521b | bellard | |
29 | 3c56521b | bellard | typedef struct BDRVCloopState { |
30 | 848c66e8 | Paolo Bonzini | CoMutex lock; |
31 | 3c56521b | bellard | uint32_t block_size; |
32 | 3c56521b | bellard | uint32_t n_blocks; |
33 | 5b47b7c3 | Dong Xu Wang | 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 | 5b47b7c3 | Dong Xu Wang | const char *magic_version_2_0 = "#!/bin/sh\n" |
44 | 5b47b7c3 | Dong Xu Wang | "#V2.0 Format\n"
|
45 | 5b47b7c3 | Dong Xu Wang | "modprobe cloop file=$0 && mount -r -t iso9660 /dev/cloop $1\n";
|
46 | 5b47b7c3 | Dong Xu Wang | int length = strlen(magic_version_2_0);
|
47 | 5b47b7c3 | Dong Xu Wang | if (length > buf_size) {
|
48 | 5b47b7c3 | Dong Xu Wang | length = buf_size; |
49 | 5b47b7c3 | Dong Xu Wang | } |
50 | 5b47b7c3 | Dong Xu Wang | if (!memcmp(magic_version_2_0, buf, length)) {
|
51 | 5b47b7c3 | Dong Xu Wang | return 2; |
52 | 5b47b7c3 | Dong Xu Wang | } |
53 | 3c56521b | bellard | return 0; |
54 | 3c56521b | bellard | } |
55 | 3c56521b | bellard | |
56 | 20be49e4 | Christoph Hellwig | static int cloop_open(BlockDriverState *bs, int flags) |
57 | 3c56521b | bellard | { |
58 | 3c56521b | bellard | BDRVCloopState *s = bs->opaque; |
59 | 5b47b7c3 | Dong Xu Wang | uint32_t offsets_size, max_compressed_block_size = 1, i;
|
60 | 3c56521b | bellard | |
61 | 3c56521b | bellard | bs->read_only = 1;
|
62 | 3c56521b | bellard | |
63 | 3c56521b | bellard | /* read header */
|
64 | 20be49e4 | Christoph Hellwig | if (bdrv_pread(bs->file, 128, &s->block_size, 4) < 4) { |
65 | c94304be | Christoph Hellwig | goto cloop_close;
|
66 | 3c56521b | bellard | } |
67 | c94304be | Christoph Hellwig | s->block_size = be32_to_cpu(s->block_size); |
68 | c94304be | Christoph Hellwig | |
69 | 20be49e4 | Christoph Hellwig | if (bdrv_pread(bs->file, 128 + 4, &s->n_blocks, 4) < 4) { |
70 | c94304be | Christoph Hellwig | goto cloop_close;
|
71 | c94304be | Christoph Hellwig | } |
72 | c94304be | Christoph Hellwig | s->n_blocks = be32_to_cpu(s->n_blocks); |
73 | 3c56521b | bellard | |
74 | 3c56521b | bellard | /* read offsets */
|
75 | c94304be | Christoph Hellwig | offsets_size = s->n_blocks * sizeof(uint64_t);
|
76 | 7267c094 | Anthony Liguori | s->offsets = g_malloc(offsets_size); |
77 | 20be49e4 | Christoph Hellwig | if (bdrv_pread(bs->file, 128 + 4 + 4, s->offsets, offsets_size) < |
78 | 20be49e4 | Christoph Hellwig | offsets_size) { |
79 | 5b47b7c3 | Dong Xu Wang | goto cloop_close;
|
80 | c94304be | Christoph Hellwig | } |
81 | 3c56521b | bellard | for(i=0;i<s->n_blocks;i++) { |
82 | 5b47b7c3 | Dong Xu Wang | s->offsets[i] = be64_to_cpu(s->offsets[i]); |
83 | 5b47b7c3 | Dong Xu Wang | if (i > 0) { |
84 | 5b47b7c3 | Dong Xu Wang | uint32_t size = s->offsets[i] - s->offsets[i - 1];
|
85 | 5b47b7c3 | Dong Xu Wang | if (size > max_compressed_block_size) {
|
86 | 5b47b7c3 | Dong Xu Wang | max_compressed_block_size = size; |
87 | 5b47b7c3 | Dong Xu Wang | } |
88 | 5b47b7c3 | Dong Xu Wang | } |
89 | 3c56521b | bellard | } |
90 | 3c56521b | bellard | |
91 | 3c56521b | bellard | /* initialize zlib engine */
|
92 | 5b47b7c3 | Dong Xu Wang | s->compressed_block = g_malloc(max_compressed_block_size + 1);
|
93 | 7267c094 | Anthony Liguori | s->uncompressed_block = g_malloc(s->block_size); |
94 | 5b47b7c3 | Dong Xu Wang | if (inflateInit(&s->zstream) != Z_OK) {
|
95 | 5b47b7c3 | Dong Xu Wang | goto cloop_close;
|
96 | 5b47b7c3 | Dong Xu Wang | } |
97 | 5b47b7c3 | Dong Xu Wang | s->current_block = s->n_blocks; |
98 | 3b46e624 | ths | |
99 | 3c56521b | bellard | s->sectors_per_block = s->block_size/512;
|
100 | 5b47b7c3 | Dong Xu Wang | bs->total_sectors = s->n_blocks * s->sectors_per_block; |
101 | 848c66e8 | Paolo Bonzini | qemu_co_mutex_init(&s->lock); |
102 | 3c56521b | bellard | return 0; |
103 | c94304be | Christoph Hellwig | |
104 | c94304be | Christoph Hellwig | cloop_close:
|
105 | c94304be | Christoph Hellwig | return -1; |
106 | 3c56521b | bellard | } |
107 | 3c56521b | bellard | |
108 | 20be49e4 | Christoph Hellwig | static inline int cloop_read_block(BlockDriverState *bs, int block_num) |
109 | 3c56521b | bellard | { |
110 | 20be49e4 | Christoph Hellwig | BDRVCloopState *s = bs->opaque; |
111 | 20be49e4 | Christoph Hellwig | |
112 | 5b47b7c3 | Dong Xu Wang | if (s->current_block != block_num) {
|
113 | 5b47b7c3 | Dong Xu Wang | int ret;
|
114 | 5b47b7c3 | Dong Xu Wang | uint32_t bytes = s->offsets[block_num + 1] - s->offsets[block_num];
|
115 | 3b46e624 | ths | |
116 | 20be49e4 | Christoph Hellwig | ret = bdrv_pread(bs->file, s->offsets[block_num], s->compressed_block, |
117 | 20be49e4 | Christoph Hellwig | bytes); |
118 | 5b47b7c3 | Dong Xu Wang | if (ret != bytes) {
|
119 | 3c56521b | bellard | return -1; |
120 | 5b47b7c3 | Dong Xu Wang | } |
121 | 5b47b7c3 | Dong Xu Wang | |
122 | 5b47b7c3 | Dong Xu Wang | s->zstream.next_in = s->compressed_block; |
123 | 5b47b7c3 | Dong Xu Wang | s->zstream.avail_in = bytes; |
124 | 5b47b7c3 | Dong Xu Wang | s->zstream.next_out = s->uncompressed_block; |
125 | 5b47b7c3 | Dong Xu Wang | s->zstream.avail_out = s->block_size; |
126 | 5b47b7c3 | Dong Xu Wang | ret = inflateReset(&s->zstream); |
127 | 5b47b7c3 | Dong Xu Wang | if (ret != Z_OK) {
|
128 | 5b47b7c3 | Dong Xu Wang | return -1; |
129 | 5b47b7c3 | Dong Xu Wang | } |
130 | 5b47b7c3 | Dong Xu Wang | ret = inflate(&s->zstream, Z_FINISH); |
131 | 5b47b7c3 | Dong Xu Wang | if (ret != Z_STREAM_END || s->zstream.total_out != s->block_size) {
|
132 | 5b47b7c3 | Dong Xu Wang | return -1; |
133 | 5b47b7c3 | Dong Xu Wang | } |
134 | 5fafdf24 | ths | |
135 | 5b47b7c3 | Dong Xu Wang | s->current_block = block_num; |
136 | 3c56521b | bellard | } |
137 | 3c56521b | bellard | return 0; |
138 | 3c56521b | bellard | } |
139 | 3c56521b | bellard | |
140 | 5fafdf24 | ths | static int cloop_read(BlockDriverState *bs, int64_t sector_num, |
141 | 3c56521b | bellard | uint8_t *buf, int nb_sectors)
|
142 | 3c56521b | bellard | { |
143 | 3c56521b | bellard | BDRVCloopState *s = bs->opaque; |
144 | 3c56521b | bellard | int i;
|
145 | 3c56521b | bellard | |
146 | 5b47b7c3 | Dong Xu Wang | for (i = 0; i < nb_sectors; i++) { |
147 | 5b47b7c3 | Dong Xu Wang | uint32_t sector_offset_in_block = |
148 | 5b47b7c3 | Dong Xu Wang | ((sector_num + i) % s->sectors_per_block), |
149 | 5b47b7c3 | Dong Xu Wang | block_num = (sector_num + i) / s->sectors_per_block; |
150 | 5b47b7c3 | Dong Xu Wang | if (cloop_read_block(bs, block_num) != 0) { |
151 | 5b47b7c3 | Dong Xu Wang | return -1; |
152 | 5b47b7c3 | Dong Xu Wang | } |
153 | 5b47b7c3 | Dong Xu Wang | memcpy(buf + i * 512,
|
154 | 5b47b7c3 | Dong Xu Wang | s->uncompressed_block + sector_offset_in_block * 512, 512); |
155 | 3c56521b | bellard | } |
156 | 3c56521b | bellard | return 0; |
157 | 3c56521b | bellard | } |
158 | 3c56521b | bellard | |
159 | 2914caa0 | Paolo Bonzini | static coroutine_fn int cloop_co_read(BlockDriverState *bs, int64_t sector_num, |
160 | 2914caa0 | Paolo Bonzini | uint8_t *buf, int nb_sectors)
|
161 | 2914caa0 | Paolo Bonzini | { |
162 | 2914caa0 | Paolo Bonzini | int ret;
|
163 | 2914caa0 | Paolo Bonzini | BDRVCloopState *s = bs->opaque; |
164 | 2914caa0 | Paolo Bonzini | qemu_co_mutex_lock(&s->lock); |
165 | 2914caa0 | Paolo Bonzini | ret = cloop_read(bs, sector_num, buf, nb_sectors); |
166 | 2914caa0 | Paolo Bonzini | qemu_co_mutex_unlock(&s->lock); |
167 | 2914caa0 | Paolo Bonzini | return ret;
|
168 | 2914caa0 | Paolo Bonzini | } |
169 | 2914caa0 | Paolo Bonzini | |
170 | 3c56521b | bellard | static void cloop_close(BlockDriverState *bs) |
171 | 3c56521b | bellard | { |
172 | 3c56521b | bellard | BDRVCloopState *s = bs->opaque; |
173 | 5b47b7c3 | Dong Xu Wang | if (s->n_blocks > 0) { |
174 | 756f51e4 | Dong Xu Wang | g_free(s->offsets); |
175 | 5b47b7c3 | Dong Xu Wang | } |
176 | 756f51e4 | Dong Xu Wang | g_free(s->compressed_block); |
177 | 756f51e4 | Dong Xu Wang | g_free(s->uncompressed_block); |
178 | 3c56521b | bellard | inflateEnd(&s->zstream); |
179 | 3c56521b | bellard | } |
180 | 3c56521b | bellard | |
181 | 5efa9d5a | Anthony Liguori | static BlockDriver bdrv_cloop = {
|
182 | 5b47b7c3 | Dong Xu Wang | .format_name = "cloop",
|
183 | 5b47b7c3 | Dong Xu Wang | .instance_size = sizeof(BDRVCloopState),
|
184 | 5b47b7c3 | Dong Xu Wang | .bdrv_probe = cloop_probe, |
185 | 5b47b7c3 | Dong Xu Wang | .bdrv_open = cloop_open, |
186 | 5b47b7c3 | Dong Xu Wang | .bdrv_read = cloop_co_read, |
187 | 5b47b7c3 | Dong Xu Wang | .bdrv_close = cloop_close, |
188 | 3c56521b | bellard | }; |
189 | 5efa9d5a | Anthony Liguori | |
190 | 5efa9d5a | Anthony Liguori | static void bdrv_cloop_init(void) |
191 | 5efa9d5a | Anthony Liguori | { |
192 | 5efa9d5a | Anthony Liguori | bdrv_register(&bdrv_cloop); |
193 | 5efa9d5a | Anthony Liguori | } |
194 | 5efa9d5a | Anthony Liguori | |
195 | 5efa9d5a | Anthony Liguori | block_init(bdrv_cloop_init); |