|
1 /* |
|
2 * QEMU Block driver for CLOOP images |
|
3 * |
|
4 * Copyright (c) 2004 Johannes E. Schindelin |
|
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 "qemu-common.h" |
|
25 #include "block_int.h" |
|
26 #include <zlib.h> |
|
27 |
|
28 typedef struct BDRVCloopState { |
|
29 int fd; |
|
30 uint32_t block_size; |
|
31 uint32_t n_blocks; |
|
32 uint64_t* offsets; |
|
33 uint32_t sectors_per_block; |
|
34 uint32_t current_block; |
|
35 uint8_t *compressed_block; |
|
36 uint8_t *uncompressed_block; |
|
37 z_stream zstream; |
|
38 } BDRVCloopState; |
|
39 |
|
40 static int cloop_probe(const uint8_t *buf, int buf_size, const char *filename) |
|
41 { |
|
42 const char* magic_version_2_0="#!/bin/sh\n" |
|
43 "#V2.0 Format\n" |
|
44 "modprobe cloop file=$0 && mount -r -t iso9660 /dev/cloop $1\n"; |
|
45 int length=strlen(magic_version_2_0); |
|
46 if(length>buf_size) |
|
47 length=buf_size; |
|
48 if(!memcmp(magic_version_2_0,buf,length)) |
|
49 return 2; |
|
50 return 0; |
|
51 } |
|
52 |
|
53 static int cloop_open(BlockDriverState *bs, const char *filename, int flags) |
|
54 { |
|
55 BDRVCloopState *s = bs->opaque; |
|
56 uint32_t offsets_size,max_compressed_block_size=1,i; |
|
57 |
|
58 s->fd = open(filename, O_RDONLY | O_BINARY); |
|
59 if (s->fd < 0) |
|
60 return -errno; |
|
61 bs->read_only = 1; |
|
62 |
|
63 /* read header */ |
|
64 if(lseek(s->fd,128,SEEK_SET)<0) { |
|
65 cloop_close: |
|
66 close(s->fd); |
|
67 return -1; |
|
68 } |
|
69 if(read(s->fd,&s->block_size,4)<4) |
|
70 goto cloop_close; |
|
71 s->block_size=be32_to_cpu(s->block_size); |
|
72 if(read(s->fd,&s->n_blocks,4)<4) |
|
73 goto cloop_close; |
|
74 s->n_blocks=be32_to_cpu(s->n_blocks); |
|
75 |
|
76 /* read offsets */ |
|
77 offsets_size=s->n_blocks*sizeof(uint64_t); |
|
78 if(!(s->offsets=(uint64_t*)malloc(offsets_size))) |
|
79 goto cloop_close; |
|
80 if(read(s->fd,s->offsets,offsets_size)<offsets_size) |
|
81 goto cloop_close; |
|
82 for(i=0;i<s->n_blocks;i++) { |
|
83 s->offsets[i]=be64_to_cpu(s->offsets[i]); |
|
84 if(i>0) { |
|
85 uint32_t size=s->offsets[i]-s->offsets[i-1]; |
|
86 if(size>max_compressed_block_size) |
|
87 max_compressed_block_size=size; |
|
88 } |
|
89 } |
|
90 |
|
91 /* initialize zlib engine */ |
|
92 if(!(s->compressed_block = malloc(max_compressed_block_size+1))) |
|
93 goto cloop_close; |
|
94 if(!(s->uncompressed_block = malloc(s->block_size))) |
|
95 goto cloop_close; |
|
96 if(inflateInit(&s->zstream) != Z_OK) |
|
97 goto cloop_close; |
|
98 s->current_block=s->n_blocks; |
|
99 |
|
100 s->sectors_per_block = s->block_size/512; |
|
101 bs->total_sectors = s->n_blocks*s->sectors_per_block; |
|
102 return 0; |
|
103 } |
|
104 |
|
105 static inline int cloop_read_block(BDRVCloopState *s,int block_num) |
|
106 { |
|
107 if(s->current_block != block_num) { |
|
108 int ret; |
|
109 uint32_t bytes = s->offsets[block_num+1]-s->offsets[block_num]; |
|
110 |
|
111 lseek(s->fd, s->offsets[block_num], SEEK_SET); |
|
112 ret = read(s->fd, s->compressed_block, bytes); |
|
113 if (ret != bytes) |
|
114 return -1; |
|
115 |
|
116 s->zstream.next_in = s->compressed_block; |
|
117 s->zstream.avail_in = bytes; |
|
118 s->zstream.next_out = s->uncompressed_block; |
|
119 s->zstream.avail_out = s->block_size; |
|
120 ret = inflateReset(&s->zstream); |
|
121 if(ret != Z_OK) |
|
122 return -1; |
|
123 ret = inflate(&s->zstream, Z_FINISH); |
|
124 if(ret != Z_STREAM_END || s->zstream.total_out != s->block_size) |
|
125 return -1; |
|
126 |
|
127 s->current_block = block_num; |
|
128 } |
|
129 return 0; |
|
130 } |
|
131 |
|
132 static int cloop_read(BlockDriverState *bs, int64_t sector_num, |
|
133 uint8_t *buf, int nb_sectors) |
|
134 { |
|
135 BDRVCloopState *s = bs->opaque; |
|
136 int i; |
|
137 |
|
138 for(i=0;i<nb_sectors;i++) { |
|
139 uint32_t sector_offset_in_block=((sector_num+i)%s->sectors_per_block), |
|
140 block_num=(sector_num+i)/s->sectors_per_block; |
|
141 if(cloop_read_block(s, block_num) != 0) |
|
142 return -1; |
|
143 memcpy(buf+i*512,s->uncompressed_block+sector_offset_in_block*512,512); |
|
144 } |
|
145 return 0; |
|
146 } |
|
147 |
|
148 static void cloop_close(BlockDriverState *bs) |
|
149 { |
|
150 BDRVCloopState *s = bs->opaque; |
|
151 close(s->fd); |
|
152 if(s->n_blocks>0) |
|
153 free(s->offsets); |
|
154 free(s->compressed_block); |
|
155 free(s->uncompressed_block); |
|
156 inflateEnd(&s->zstream); |
|
157 } |
|
158 |
|
159 BlockDriver bdrv_cloop = { |
|
160 "cloop", |
|
161 sizeof(BDRVCloopState), |
|
162 cloop_probe, |
|
163 cloop_open, |
|
164 cloop_read, |
|
165 NULL, |
|
166 cloop_close, |
|
167 }; |