Revision 019d6b8f
b/Makefile | ||
---|---|---|
64 | 64 |
# BLOCK_OBJS is code used by both qemu system emulation and qemu-img |
65 | 65 |
|
66 | 66 |
BLOCK_OBJS=cutils.o cache-utils.o qemu-malloc.o module.o |
67 |
BLOCK_OBJS+=block-cow.o block-qcow.o aes.o block-vmdk.o block-cloop.o
|
|
68 |
BLOCK_OBJS+=block-dmg.o block-bochs.o block-vpc.o block-vvfat.o
|
|
69 |
BLOCK_OBJS+=block-qcow2.o block-parallels.o block-nbd.o
|
|
67 |
BLOCK_OBJS+=block/cow.o block/qcow.o aes.o block/vmdk.o block/cloop.o
|
|
68 |
BLOCK_OBJS+=block/dmg.o block/bochs.o block/vpc.o block/vvfat.o
|
|
69 |
BLOCK_OBJS+=block/qcow2.o block/parallels.o block/nbd.o
|
|
70 | 70 |
BLOCK_OBJS+=nbd.o block.o aio.o |
71 | 71 |
|
72 | 72 |
ifdef CONFIG_WIN32 |
73 |
BLOCK_OBJS += block-raw-win32.o
|
|
73 |
BLOCK_OBJS += block/raw-win32.o
|
|
74 | 74 |
else |
75 | 75 |
ifdef CONFIG_AIO |
76 | 76 |
BLOCK_OBJS += posix-aio-compat.o |
77 | 77 |
endif |
78 |
BLOCK_OBJS += block-raw-posix.o
|
|
78 |
BLOCK_OBJS += block/raw-posix.o
|
|
79 | 79 |
endif |
80 | 80 |
|
81 | 81 |
###################################################################### |
... | ... | |
234 | 234 |
# avoid old build problems by removing potentially incorrect old files |
235 | 235 |
rm -f config.mak config.h op-i386.h opc-i386.h gen-op-i386.h op-arm.h opc-arm.h gen-op-arm.h |
236 | 236 |
rm -f *.o *.d *.a $(TOOLS) TAGS cscope.* *.pod *~ */*~ |
237 |
rm -f slirp/*.o slirp/*.d audio/*.o audio/*.d |
|
237 |
rm -f slirp/*.o slirp/*.d audio/*.o audio/*.d block/*.o block/*.d
|
|
238 | 238 |
$(MAKE) -C tests clean |
239 | 239 |
for d in $(TARGET_DIRS); do \ |
240 | 240 |
$(MAKE) -C $$d $@ || exit 1 ; \ |
... | ... | |
408 | 408 |
$(mandir)/man8/qemu-nbd.8 |
409 | 409 |
|
410 | 410 |
# Include automatically generated dependency files |
411 |
-include $(wildcard *.d audio/*.d slirp/*.d) |
|
411 |
-include $(wildcard *.d audio/*.d slirp/*.d block/*.d) |
/dev/null | ||
---|---|---|
1 |
/* |
|
2 |
* Block driver for the various disk image formats used by Bochs |
|
3 |
* Currently only for "growing" type in read-only mode |
|
4 |
* |
|
5 |
* Copyright (c) 2005 Alex Beregszaszi |
|
6 |
* |
|
7 |
* Permission is hereby granted, free of charge, to any person obtaining a copy |
|
8 |
* of this software and associated documentation files (the "Software"), to deal |
|
9 |
* in the Software without restriction, including without limitation the rights |
|
10 |
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
11 |
* copies of the Software, and to permit persons to whom the Software is |
|
12 |
* furnished to do so, subject to the following conditions: |
|
13 |
* |
|
14 |
* The above copyright notice and this permission notice shall be included in |
|
15 |
* all copies or substantial portions of the Software. |
|
16 |
* |
|
17 |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
18 |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
19 |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
|
20 |
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
21 |
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|
22 |
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|
23 |
* THE SOFTWARE. |
|
24 |
*/ |
|
25 |
#include "qemu-common.h" |
|
26 |
#include "block_int.h" |
|
27 |
#include "module.h" |
|
28 |
|
|
29 |
/**************************************************************/ |
|
30 |
|
|
31 |
#define HEADER_MAGIC "Bochs Virtual HD Image" |
|
32 |
#define HEADER_VERSION 0x00020000 |
|
33 |
#define HEADER_V1 0x00010000 |
|
34 |
#define HEADER_SIZE 512 |
|
35 |
|
|
36 |
#define REDOLOG_TYPE "Redolog" |
|
37 |
#define GROWING_TYPE "Growing" |
|
38 |
|
|
39 |
// not allocated: 0xffffffff |
|
40 |
|
|
41 |
// always little-endian |
|
42 |
struct bochs_header_v1 { |
|
43 |
char magic[32]; // "Bochs Virtual HD Image" |
|
44 |
char type[16]; // "Redolog" |
|
45 |
char subtype[16]; // "Undoable" / "Volatile" / "Growing" |
|
46 |
uint32_t version; |
|
47 |
uint32_t header; // size of header |
|
48 |
|
|
49 |
union { |
|
50 |
struct { |
|
51 |
uint32_t catalog; // num of entries |
|
52 |
uint32_t bitmap; // bitmap size |
|
53 |
uint32_t extent; // extent size |
|
54 |
uint64_t disk; // disk size |
|
55 |
char padding[HEADER_SIZE - 64 - 8 - 20]; |
|
56 |
} redolog; |
|
57 |
char padding[HEADER_SIZE - 64 - 8]; |
|
58 |
} extra; |
|
59 |
}; |
|
60 |
|
|
61 |
// always little-endian |
|
62 |
struct bochs_header { |
|
63 |
char magic[32]; // "Bochs Virtual HD Image" |
|
64 |
char type[16]; // "Redolog" |
|
65 |
char subtype[16]; // "Undoable" / "Volatile" / "Growing" |
|
66 |
uint32_t version; |
|
67 |
uint32_t header; // size of header |
|
68 |
|
|
69 |
union { |
|
70 |
struct { |
|
71 |
uint32_t catalog; // num of entries |
|
72 |
uint32_t bitmap; // bitmap size |
|
73 |
uint32_t extent; // extent size |
|
74 |
uint32_t reserved; // for ??? |
|
75 |
uint64_t disk; // disk size |
|
76 |
char padding[HEADER_SIZE - 64 - 8 - 24]; |
|
77 |
} redolog; |
|
78 |
char padding[HEADER_SIZE - 64 - 8]; |
|
79 |
} extra; |
|
80 |
}; |
|
81 |
|
|
82 |
typedef struct BDRVBochsState { |
|
83 |
int fd; |
|
84 |
|
|
85 |
uint32_t *catalog_bitmap; |
|
86 |
int catalog_size; |
|
87 |
|
|
88 |
int data_offset; |
|
89 |
|
|
90 |
int bitmap_blocks; |
|
91 |
int extent_blocks; |
|
92 |
int extent_size; |
|
93 |
} BDRVBochsState; |
|
94 |
|
|
95 |
static int bochs_probe(const uint8_t *buf, int buf_size, const char *filename) |
|
96 |
{ |
|
97 |
const struct bochs_header *bochs = (const void *)buf; |
|
98 |
|
|
99 |
if (buf_size < HEADER_SIZE) |
|
100 |
return 0; |
|
101 |
|
|
102 |
if (!strcmp(bochs->magic, HEADER_MAGIC) && |
|
103 |
!strcmp(bochs->type, REDOLOG_TYPE) && |
|
104 |
!strcmp(bochs->subtype, GROWING_TYPE) && |
|
105 |
((le32_to_cpu(bochs->version) == HEADER_VERSION) || |
|
106 |
(le32_to_cpu(bochs->version) == HEADER_V1))) |
|
107 |
return 100; |
|
108 |
|
|
109 |
return 0; |
|
110 |
} |
|
111 |
|
|
112 |
static int bochs_open(BlockDriverState *bs, const char *filename, int flags) |
|
113 |
{ |
|
114 |
BDRVBochsState *s = bs->opaque; |
|
115 |
int fd, i; |
|
116 |
struct bochs_header bochs; |
|
117 |
struct bochs_header_v1 header_v1; |
|
118 |
|
|
119 |
fd = open(filename, O_RDWR | O_BINARY); |
|
120 |
if (fd < 0) { |
|
121 |
fd = open(filename, O_RDONLY | O_BINARY); |
|
122 |
if (fd < 0) |
|
123 |
return -1; |
|
124 |
} |
|
125 |
|
|
126 |
bs->read_only = 1; // no write support yet |
|
127 |
|
|
128 |
s->fd = fd; |
|
129 |
|
|
130 |
if (read(fd, &bochs, sizeof(bochs)) != sizeof(bochs)) { |
|
131 |
goto fail; |
|
132 |
} |
|
133 |
|
|
134 |
if (strcmp(bochs.magic, HEADER_MAGIC) || |
|
135 |
strcmp(bochs.type, REDOLOG_TYPE) || |
|
136 |
strcmp(bochs.subtype, GROWING_TYPE) || |
|
137 |
((le32_to_cpu(bochs.version) != HEADER_VERSION) && |
|
138 |
(le32_to_cpu(bochs.version) != HEADER_V1))) { |
|
139 |
goto fail; |
|
140 |
} |
|
141 |
|
|
142 |
if (le32_to_cpu(bochs.version) == HEADER_V1) { |
|
143 |
memcpy(&header_v1, &bochs, sizeof(bochs)); |
|
144 |
bs->total_sectors = le64_to_cpu(header_v1.extra.redolog.disk) / 512; |
|
145 |
} else { |
|
146 |
bs->total_sectors = le64_to_cpu(bochs.extra.redolog.disk) / 512; |
|
147 |
} |
|
148 |
|
|
149 |
lseek(s->fd, le32_to_cpu(bochs.header), SEEK_SET); |
|
150 |
|
|
151 |
s->catalog_size = le32_to_cpu(bochs.extra.redolog.catalog); |
|
152 |
s->catalog_bitmap = qemu_malloc(s->catalog_size * 4); |
|
153 |
if (read(s->fd, s->catalog_bitmap, s->catalog_size * 4) != |
|
154 |
s->catalog_size * 4) |
|
155 |
goto fail; |
|
156 |
for (i = 0; i < s->catalog_size; i++) |
|
157 |
le32_to_cpus(&s->catalog_bitmap[i]); |
|
158 |
|
|
159 |
s->data_offset = le32_to_cpu(bochs.header) + (s->catalog_size * 4); |
|
160 |
|
|
161 |
s->bitmap_blocks = 1 + (le32_to_cpu(bochs.extra.redolog.bitmap) - 1) / 512; |
|
162 |
s->extent_blocks = 1 + (le32_to_cpu(bochs.extra.redolog.extent) - 1) / 512; |
|
163 |
|
|
164 |
s->extent_size = le32_to_cpu(bochs.extra.redolog.extent); |
|
165 |
|
|
166 |
return 0; |
|
167 |
fail: |
|
168 |
close(fd); |
|
169 |
return -1; |
|
170 |
} |
|
171 |
|
|
172 |
static inline int seek_to_sector(BlockDriverState *bs, int64_t sector_num) |
|
173 |
{ |
|
174 |
BDRVBochsState *s = bs->opaque; |
|
175 |
int64_t offset = sector_num * 512; |
|
176 |
int64_t extent_index, extent_offset, bitmap_offset, block_offset; |
|
177 |
char bitmap_entry; |
|
178 |
|
|
179 |
// seek to sector |
|
180 |
extent_index = offset / s->extent_size; |
|
181 |
extent_offset = (offset % s->extent_size) / 512; |
|
182 |
|
|
183 |
if (s->catalog_bitmap[extent_index] == 0xffffffff) |
|
184 |
{ |
|
185 |
// fprintf(stderr, "page not allocated [%x - %x:%x]\n", |
|
186 |
// sector_num, extent_index, extent_offset); |
|
187 |
return -1; // not allocated |
|
188 |
} |
|
189 |
|
|
190 |
bitmap_offset = s->data_offset + (512 * s->catalog_bitmap[extent_index] * |
|
191 |
(s->extent_blocks + s->bitmap_blocks)); |
|
192 |
block_offset = bitmap_offset + (512 * (s->bitmap_blocks + extent_offset)); |
|
193 |
|
|
194 |
// fprintf(stderr, "sect: %x [ext i: %x o: %x] -> %x bitmap: %x block: %x\n", |
|
195 |
// sector_num, extent_index, extent_offset, |
|
196 |
// le32_to_cpu(s->catalog_bitmap[extent_index]), |
|
197 |
// bitmap_offset, block_offset); |
|
198 |
|
|
199 |
// read in bitmap for current extent |
|
200 |
lseek(s->fd, bitmap_offset + (extent_offset / 8), SEEK_SET); |
|
201 |
|
|
202 |
read(s->fd, &bitmap_entry, 1); |
|
203 |
|
|
204 |
if (!((bitmap_entry >> (extent_offset % 8)) & 1)) |
|
205 |
{ |
|
206 |
// fprintf(stderr, "sector (%x) in bitmap not allocated\n", |
|
207 |
// sector_num); |
|
208 |
return -1; // not allocated |
|
209 |
} |
|
210 |
|
|
211 |
lseek(s->fd, block_offset, SEEK_SET); |
|
212 |
|
|
213 |
return 0; |
|
214 |
} |
|
215 |
|
|
216 |
static int bochs_read(BlockDriverState *bs, int64_t sector_num, |
|
217 |
uint8_t *buf, int nb_sectors) |
|
218 |
{ |
|
219 |
BDRVBochsState *s = bs->opaque; |
|
220 |
int ret; |
|
221 |
|
|
222 |
while (nb_sectors > 0) { |
|
223 |
if (!seek_to_sector(bs, sector_num)) |
|
224 |
{ |
|
225 |
ret = read(s->fd, buf, 512); |
|
226 |
if (ret != 512) |
|
227 |
return -1; |
|
228 |
} |
|
229 |
else |
|
230 |
memset(buf, 0, 512); |
|
231 |
nb_sectors--; |
|
232 |
sector_num++; |
|
233 |
buf += 512; |
|
234 |
} |
|
235 |
return 0; |
|
236 |
} |
|
237 |
|
|
238 |
static void bochs_close(BlockDriverState *bs) |
|
239 |
{ |
|
240 |
BDRVBochsState *s = bs->opaque; |
|
241 |
qemu_free(s->catalog_bitmap); |
|
242 |
close(s->fd); |
|
243 |
} |
|
244 |
|
|
245 |
static BlockDriver bdrv_bochs = { |
|
246 |
.format_name = "bochs", |
|
247 |
.instance_size = sizeof(BDRVBochsState), |
|
248 |
.bdrv_probe = bochs_probe, |
|
249 |
.bdrv_open = bochs_open, |
|
250 |
.bdrv_read = bochs_read, |
|
251 |
.bdrv_close = bochs_close, |
|
252 |
}; |
|
253 |
|
|
254 |
static void bdrv_bochs_init(void) |
|
255 |
{ |
|
256 |
bdrv_register(&bdrv_bochs); |
|
257 |
} |
|
258 |
|
|
259 |
block_init(bdrv_bochs_init); |
/dev/null | ||
---|---|---|
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 "module.h" |
|
27 |
#include <zlib.h> |
|
28 |
|
|
29 |
typedef struct BDRVCloopState { |
|
30 |
int fd; |
|
31 |
uint32_t block_size; |
|
32 |
uint32_t n_blocks; |
|
33 |
uint64_t* offsets; |
|
34 |
uint32_t sectors_per_block; |
|
35 |
uint32_t current_block; |
|
36 |
uint8_t *compressed_block; |
|
37 |
uint8_t *uncompressed_block; |
|
38 |
z_stream zstream; |
|
39 |
} BDRVCloopState; |
|
40 |
|
|
41 |
static int cloop_probe(const uint8_t *buf, int buf_size, const char *filename) |
|
42 |
{ |
|
43 |
const char* magic_version_2_0="#!/bin/sh\n" |
|
44 |
"#V2.0 Format\n" |
|
45 |
"modprobe cloop file=$0 && mount -r -t iso9660 /dev/cloop $1\n"; |
|
46 |
int length=strlen(magic_version_2_0); |
|
47 |
if(length>buf_size) |
|
48 |
length=buf_size; |
|
49 |
if(!memcmp(magic_version_2_0,buf,length)) |
|
50 |
return 2; |
|
51 |
return 0; |
|
52 |
} |
|
53 |
|
|
54 |
static int cloop_open(BlockDriverState *bs, const char *filename, int flags) |
|
55 |
{ |
|
56 |
BDRVCloopState *s = bs->opaque; |
|
57 |
uint32_t offsets_size,max_compressed_block_size=1,i; |
|
58 |
|
|
59 |
s->fd = open(filename, O_RDONLY | O_BINARY); |
|
60 |
if (s->fd < 0) |
|
61 |
return -errno; |
|
62 |
bs->read_only = 1; |
|
63 |
|
|
64 |
/* read header */ |
|
65 |
if(lseek(s->fd,128,SEEK_SET)<0) { |
|
66 |
cloop_close: |
|
67 |
close(s->fd); |
|
68 |
return -1; |
|
69 |
} |
|
70 |
if(read(s->fd,&s->block_size,4)<4) |
|
71 |
goto cloop_close; |
|
72 |
s->block_size=be32_to_cpu(s->block_size); |
|
73 |
if(read(s->fd,&s->n_blocks,4)<4) |
|
74 |
goto cloop_close; |
|
75 |
s->n_blocks=be32_to_cpu(s->n_blocks); |
|
76 |
|
|
77 |
/* read offsets */ |
|
78 |
offsets_size=s->n_blocks*sizeof(uint64_t); |
|
79 |
s->offsets=(uint64_t*)qemu_malloc(offsets_size); |
|
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 |
s->compressed_block = qemu_malloc(max_compressed_block_size+1); |
|
93 |
s->uncompressed_block = qemu_malloc(s->block_size); |
|
94 |
if(inflateInit(&s->zstream) != Z_OK) |
|
95 |
goto cloop_close; |
|
96 |
s->current_block=s->n_blocks; |
|
97 |
|
|
98 |
s->sectors_per_block = s->block_size/512; |
|
99 |
bs->total_sectors = s->n_blocks*s->sectors_per_block; |
|
100 |
return 0; |
|
101 |
} |
|
102 |
|
|
103 |
static inline int cloop_read_block(BDRVCloopState *s,int block_num) |
|
104 |
{ |
|
105 |
if(s->current_block != block_num) { |
|
106 |
int ret; |
|
107 |
uint32_t bytes = s->offsets[block_num+1]-s->offsets[block_num]; |
|
108 |
|
|
109 |
lseek(s->fd, s->offsets[block_num], SEEK_SET); |
|
110 |
ret = read(s->fd, s->compressed_block, bytes); |
|
111 |
if (ret != bytes) |
|
112 |
return -1; |
|
113 |
|
|
114 |
s->zstream.next_in = s->compressed_block; |
|
115 |
s->zstream.avail_in = bytes; |
|
116 |
s->zstream.next_out = s->uncompressed_block; |
|
117 |
s->zstream.avail_out = s->block_size; |
|
118 |
ret = inflateReset(&s->zstream); |
|
119 |
if(ret != Z_OK) |
|
120 |
return -1; |
|
121 |
ret = inflate(&s->zstream, Z_FINISH); |
|
122 |
if(ret != Z_STREAM_END || s->zstream.total_out != s->block_size) |
|
123 |
return -1; |
|
124 |
|
|
125 |
s->current_block = block_num; |
|
126 |
} |
|
127 |
return 0; |
|
128 |
} |
|
129 |
|
|
130 |
static int cloop_read(BlockDriverState *bs, int64_t sector_num, |
|
131 |
uint8_t *buf, int nb_sectors) |
|
132 |
{ |
|
133 |
BDRVCloopState *s = bs->opaque; |
|
134 |
int i; |
|
135 |
|
|
136 |
for(i=0;i<nb_sectors;i++) { |
|
137 |
uint32_t sector_offset_in_block=((sector_num+i)%s->sectors_per_block), |
|
138 |
block_num=(sector_num+i)/s->sectors_per_block; |
|
139 |
if(cloop_read_block(s, block_num) != 0) |
|
140 |
return -1; |
|
141 |
memcpy(buf+i*512,s->uncompressed_block+sector_offset_in_block*512,512); |
|
142 |
} |
|
143 |
return 0; |
|
144 |
} |
|
145 |
|
|
146 |
static void cloop_close(BlockDriverState *bs) |
|
147 |
{ |
|
148 |
BDRVCloopState *s = bs->opaque; |
|
149 |
close(s->fd); |
|
150 |
if(s->n_blocks>0) |
|
151 |
free(s->offsets); |
|
152 |
free(s->compressed_block); |
|
153 |
free(s->uncompressed_block); |
|
154 |
inflateEnd(&s->zstream); |
|
155 |
} |
|
156 |
|
|
157 |
static BlockDriver bdrv_cloop = { |
|
158 |
.format_name = "cloop", |
|
159 |
.instance_size = sizeof(BDRVCloopState), |
|
160 |
.bdrv_probe = cloop_probe, |
|
161 |
.bdrv_open = cloop_open, |
|
162 |
.bdrv_read = cloop_read, |
|
163 |
.bdrv_close = cloop_close, |
|
164 |
}; |
|
165 |
|
|
166 |
static void bdrv_cloop_init(void) |
|
167 |
{ |
|
168 |
bdrv_register(&bdrv_cloop); |
|
169 |
} |
|
170 |
|
|
171 |
block_init(bdrv_cloop_init); |
/dev/null | ||
---|---|---|
1 |
/* |
|
2 |
* Block driver for the COW format |
|
3 |
* |
|
4 |
* Copyright (c) 2004 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 |
#ifndef _WIN32 |
|
25 |
#include "qemu-common.h" |
|
26 |
#include "block_int.h" |
|
27 |
#include "module.h" |
|
28 |
#include <sys/mman.h> |
|
29 |
|
|
30 |
/**************************************************************/ |
|
31 |
/* COW block driver using file system holes */ |
|
32 |
|
|
33 |
/* user mode linux compatible COW file */ |
|
34 |
#define COW_MAGIC 0x4f4f4f4d /* MOOO */ |
|
35 |
#define COW_VERSION 2 |
|
36 |
|
|
37 |
struct cow_header_v2 { |
|
38 |
uint32_t magic; |
|
39 |
uint32_t version; |
|
40 |
char backing_file[1024]; |
|
41 |
int32_t mtime; |
|
42 |
uint64_t size; |
|
43 |
uint32_t sectorsize; |
|
44 |
}; |
|
45 |
|
|
46 |
typedef struct BDRVCowState { |
|
47 |
int fd; |
|
48 |
uint8_t *cow_bitmap; /* if non NULL, COW mappings are used first */ |
|
49 |
uint8_t *cow_bitmap_addr; /* mmap address of cow_bitmap */ |
|
50 |
int cow_bitmap_size; |
|
51 |
int64_t cow_sectors_offset; |
|
52 |
} BDRVCowState; |
|
53 |
|
|
54 |
static int cow_probe(const uint8_t *buf, int buf_size, const char *filename) |
|
55 |
{ |
|
56 |
const struct cow_header_v2 *cow_header = (const void *)buf; |
|
57 |
|
|
58 |
if (buf_size >= sizeof(struct cow_header_v2) && |
|
59 |
be32_to_cpu(cow_header->magic) == COW_MAGIC && |
|
60 |
be32_to_cpu(cow_header->version) == COW_VERSION) |
|
61 |
return 100; |
|
62 |
else |
|
63 |
return 0; |
|
64 |
} |
|
65 |
|
|
66 |
static int cow_open(BlockDriverState *bs, const char *filename, int flags) |
|
67 |
{ |
|
68 |
BDRVCowState *s = bs->opaque; |
|
69 |
int fd; |
|
70 |
struct cow_header_v2 cow_header; |
|
71 |
int64_t size; |
|
72 |
|
|
73 |
fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE); |
|
74 |
if (fd < 0) { |
|
75 |
fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE); |
|
76 |
if (fd < 0) |
|
77 |
return -1; |
|
78 |
} |
|
79 |
s->fd = fd; |
|
80 |
/* see if it is a cow image */ |
|
81 |
if (read(fd, &cow_header, sizeof(cow_header)) != sizeof(cow_header)) { |
|
82 |
goto fail; |
|
83 |
} |
|
84 |
|
|
85 |
if (be32_to_cpu(cow_header.magic) != COW_MAGIC || |
|
86 |
be32_to_cpu(cow_header.version) != COW_VERSION) { |
|
87 |
goto fail; |
|
88 |
} |
|
89 |
|
|
90 |
/* cow image found */ |
|
91 |
size = be64_to_cpu(cow_header.size); |
|
92 |
bs->total_sectors = size / 512; |
|
93 |
|
|
94 |
pstrcpy(bs->backing_file, sizeof(bs->backing_file), |
|
95 |
cow_header.backing_file); |
|
96 |
|
|
97 |
/* mmap the bitmap */ |
|
98 |
s->cow_bitmap_size = ((bs->total_sectors + 7) >> 3) + sizeof(cow_header); |
|
99 |
s->cow_bitmap_addr = (void *)mmap(get_mmap_addr(s->cow_bitmap_size), |
|
100 |
s->cow_bitmap_size, |
|
101 |
PROT_READ | PROT_WRITE, |
|
102 |
MAP_SHARED, s->fd, 0); |
|
103 |
if (s->cow_bitmap_addr == MAP_FAILED) |
|
104 |
goto fail; |
|
105 |
s->cow_bitmap = s->cow_bitmap_addr + sizeof(cow_header); |
|
106 |
s->cow_sectors_offset = (s->cow_bitmap_size + 511) & ~511; |
|
107 |
return 0; |
|
108 |
fail: |
|
109 |
close(fd); |
|
110 |
return -1; |
|
111 |
} |
|
112 |
|
|
113 |
static inline void cow_set_bit(uint8_t *bitmap, int64_t bitnum) |
|
114 |
{ |
|
115 |
bitmap[bitnum / 8] |= (1 << (bitnum%8)); |
|
116 |
} |
|
117 |
|
|
118 |
static inline int is_bit_set(const uint8_t *bitmap, int64_t bitnum) |
|
119 |
{ |
|
120 |
return !!(bitmap[bitnum / 8] & (1 << (bitnum%8))); |
|
121 |
} |
|
122 |
|
|
123 |
|
|
124 |
/* Return true if first block has been changed (ie. current version is |
|
125 |
* in COW file). Set the number of continuous blocks for which that |
|
126 |
* is true. */ |
|
127 |
static inline int is_changed(uint8_t *bitmap, |
|
128 |
int64_t sector_num, int nb_sectors, |
|
129 |
int *num_same) |
|
130 |
{ |
|
131 |
int changed; |
|
132 |
|
|
133 |
if (!bitmap || nb_sectors == 0) { |
|
134 |
*num_same = nb_sectors; |
|
135 |
return 0; |
|
136 |
} |
|
137 |
|
|
138 |
changed = is_bit_set(bitmap, sector_num); |
|
139 |
for (*num_same = 1; *num_same < nb_sectors; (*num_same)++) { |
|
140 |
if (is_bit_set(bitmap, sector_num + *num_same) != changed) |
|
141 |
break; |
|
142 |
} |
|
143 |
|
|
144 |
return changed; |
|
145 |
} |
|
146 |
|
|
147 |
static int cow_is_allocated(BlockDriverState *bs, int64_t sector_num, |
|
148 |
int nb_sectors, int *pnum) |
|
149 |
{ |
|
150 |
BDRVCowState *s = bs->opaque; |
|
151 |
return is_changed(s->cow_bitmap, sector_num, nb_sectors, pnum); |
|
152 |
} |
|
153 |
|
|
154 |
static int cow_read(BlockDriverState *bs, int64_t sector_num, |
|
155 |
uint8_t *buf, int nb_sectors) |
|
156 |
{ |
|
157 |
BDRVCowState *s = bs->opaque; |
|
158 |
int ret, n; |
|
159 |
|
|
160 |
while (nb_sectors > 0) { |
|
161 |
if (is_changed(s->cow_bitmap, sector_num, nb_sectors, &n)) { |
|
162 |
lseek(s->fd, s->cow_sectors_offset + sector_num * 512, SEEK_SET); |
|
163 |
ret = read(s->fd, buf, n * 512); |
|
164 |
if (ret != n * 512) |
|
165 |
return -1; |
|
166 |
} else { |
|
167 |
if (bs->backing_hd) { |
|
168 |
/* read from the base image */ |
|
169 |
ret = bdrv_read(bs->backing_hd, sector_num, buf, n); |
|
170 |
if (ret < 0) |
|
171 |
return -1; |
|
172 |
} else { |
|
173 |
memset(buf, 0, n * 512); |
|
174 |
} |
|
175 |
} |
|
176 |
nb_sectors -= n; |
|
177 |
sector_num += n; |
|
178 |
buf += n * 512; |
|
179 |
} |
|
180 |
return 0; |
|
181 |
} |
|
182 |
|
|
183 |
static int cow_write(BlockDriverState *bs, int64_t sector_num, |
|
184 |
const uint8_t *buf, int nb_sectors) |
|
185 |
{ |
|
186 |
BDRVCowState *s = bs->opaque; |
|
187 |
int ret, i; |
|
188 |
|
|
189 |
lseek(s->fd, s->cow_sectors_offset + sector_num * 512, SEEK_SET); |
|
190 |
ret = write(s->fd, buf, nb_sectors * 512); |
|
191 |
if (ret != nb_sectors * 512) |
|
192 |
return -1; |
|
193 |
for (i = 0; i < nb_sectors; i++) |
|
194 |
cow_set_bit(s->cow_bitmap, sector_num + i); |
|
195 |
return 0; |
|
196 |
} |
|
197 |
|
|
198 |
static void cow_close(BlockDriverState *bs) |
|
199 |
{ |
|
200 |
BDRVCowState *s = bs->opaque; |
|
201 |
munmap((void *)s->cow_bitmap_addr, s->cow_bitmap_size); |
|
202 |
close(s->fd); |
|
203 |
} |
|
204 |
|
|
205 |
static int cow_create(const char *filename, int64_t image_sectors, |
|
206 |
const char *image_filename, int flags) |
|
207 |
{ |
|
208 |
int fd, cow_fd; |
|
209 |
struct cow_header_v2 cow_header; |
|
210 |
struct stat st; |
|
211 |
|
|
212 |
if (flags) |
|
213 |
return -ENOTSUP; |
|
214 |
|
|
215 |
cow_fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, |
|
216 |
0644); |
|
217 |
if (cow_fd < 0) |
|
218 |
return -1; |
|
219 |
memset(&cow_header, 0, sizeof(cow_header)); |
|
220 |
cow_header.magic = cpu_to_be32(COW_MAGIC); |
|
221 |
cow_header.version = cpu_to_be32(COW_VERSION); |
|
222 |
if (image_filename) { |
|
223 |
/* Note: if no file, we put a dummy mtime */ |
|
224 |
cow_header.mtime = cpu_to_be32(0); |
|
225 |
|
|
226 |
fd = open(image_filename, O_RDONLY | O_BINARY); |
|
227 |
if (fd < 0) { |
|
228 |
close(cow_fd); |
|
229 |
goto mtime_fail; |
|
230 |
} |
|
231 |
if (fstat(fd, &st) != 0) { |
|
232 |
close(fd); |
|
233 |
goto mtime_fail; |
|
234 |
} |
|
235 |
close(fd); |
|
236 |
cow_header.mtime = cpu_to_be32(st.st_mtime); |
|
237 |
mtime_fail: |
|
238 |
pstrcpy(cow_header.backing_file, sizeof(cow_header.backing_file), |
|
239 |
image_filename); |
|
240 |
} |
|
241 |
cow_header.sectorsize = cpu_to_be32(512); |
|
242 |
cow_header.size = cpu_to_be64(image_sectors * 512); |
|
243 |
write(cow_fd, &cow_header, sizeof(cow_header)); |
|
244 |
/* resize to include at least all the bitmap */ |
|
245 |
ftruncate(cow_fd, sizeof(cow_header) + ((image_sectors + 7) >> 3)); |
|
246 |
close(cow_fd); |
|
247 |
return 0; |
|
248 |
} |
|
249 |
|
|
250 |
static void cow_flush(BlockDriverState *bs) |
|
251 |
{ |
|
252 |
BDRVCowState *s = bs->opaque; |
|
253 |
fsync(s->fd); |
|
254 |
} |
|
255 |
|
|
256 |
static BlockDriver bdrv_cow = { |
|
257 |
.format_name = "cow", |
|
258 |
.instance_size = sizeof(BDRVCowState), |
|
259 |
.bdrv_probe = cow_probe, |
|
260 |
.bdrv_open = cow_open, |
|
261 |
.bdrv_read = cow_read, |
|
262 |
.bdrv_write = cow_write, |
|
263 |
.bdrv_close = cow_close, |
|
264 |
.bdrv_create = cow_create, |
|
265 |
.bdrv_flush = cow_flush, |
|
266 |
.bdrv_is_allocated = cow_is_allocated, |
|
267 |
}; |
|
268 |
|
|
269 |
static void bdrv_cow_init(void) |
|
270 |
{ |
|
271 |
bdrv_register(&bdrv_cow); |
|
272 |
} |
|
273 |
|
|
274 |
block_init(bdrv_cow_init); |
|
275 |
#endif |
/dev/null | ||
---|---|---|
1 |
/* |
|
2 |
* QEMU Block driver for DMG 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 "bswap.h" |
|
27 |
#include "module.h" |
|
28 |
#include <zlib.h> |
|
29 |
|
|
30 |
typedef struct BDRVDMGState { |
|
31 |
int fd; |
|
32 |
|
|
33 |
/* each chunk contains a certain number of sectors, |
|
34 |
* offsets[i] is the offset in the .dmg file, |
|
35 |
* lengths[i] is the length of the compressed chunk, |
|
36 |
* sectors[i] is the sector beginning at offsets[i], |
|
37 |
* sectorcounts[i] is the number of sectors in that chunk, |
|
38 |
* the sectors array is ordered |
|
39 |
* 0<=i<n_chunks */ |
|
40 |
|
|
41 |
uint32_t n_chunks; |
|
42 |
uint32_t* types; |
|
43 |
uint64_t* offsets; |
|
44 |
uint64_t* lengths; |
|
45 |
uint64_t* sectors; |
|
46 |
uint64_t* sectorcounts; |
|
47 |
uint32_t current_chunk; |
|
48 |
uint8_t *compressed_chunk; |
|
49 |
uint8_t *uncompressed_chunk; |
|
50 |
z_stream zstream; |
|
51 |
} BDRVDMGState; |
|
52 |
|
|
53 |
static int dmg_probe(const uint8_t *buf, int buf_size, const char *filename) |
|
54 |
{ |
|
55 |
int len=strlen(filename); |
|
56 |
if(len>4 && !strcmp(filename+len-4,".dmg")) |
|
57 |
return 2; |
|
58 |
return 0; |
|
59 |
} |
|
60 |
|
|
61 |
static off_t read_off(int fd) |
|
62 |
{ |
|
63 |
uint64_t buffer; |
|
64 |
if(read(fd,&buffer,8)<8) |
|
65 |
return 0; |
|
66 |
return be64_to_cpu(buffer); |
|
67 |
} |
|
68 |
|
|
69 |
static off_t read_uint32(int fd) |
|
70 |
{ |
|
71 |
uint32_t buffer; |
|
72 |
if(read(fd,&buffer,4)<4) |
|
73 |
return 0; |
|
74 |
return be32_to_cpu(buffer); |
|
75 |
} |
|
76 |
|
|
77 |
static int dmg_open(BlockDriverState *bs, const char *filename, int flags) |
|
78 |
{ |
|
79 |
BDRVDMGState *s = bs->opaque; |
|
80 |
off_t info_begin,info_end,last_in_offset,last_out_offset; |
|
81 |
uint32_t count; |
|
82 |
uint32_t max_compressed_size=1,max_sectors_per_chunk=1,i; |
|
83 |
|
|
84 |
s->fd = open(filename, O_RDONLY | O_BINARY); |
|
85 |
if (s->fd < 0) |
|
86 |
return -errno; |
|
87 |
bs->read_only = 1; |
|
88 |
s->n_chunks = 0; |
|
89 |
s->offsets = s->lengths = s->sectors = s->sectorcounts = NULL; |
|
90 |
|
|
91 |
/* read offset of info blocks */ |
|
92 |
if(lseek(s->fd,-0x1d8,SEEK_END)<0) { |
|
93 |
dmg_close: |
|
94 |
close(s->fd); |
|
95 |
/* open raw instead */ |
|
96 |
bs->drv=bdrv_find_format("raw"); |
|
97 |
return bs->drv->bdrv_open(bs, filename, flags); |
|
98 |
} |
|
99 |
info_begin=read_off(s->fd); |
|
100 |
if(info_begin==0) |
|
101 |
goto dmg_close; |
|
102 |
if(lseek(s->fd,info_begin,SEEK_SET)<0) |
|
103 |
goto dmg_close; |
|
104 |
if(read_uint32(s->fd)!=0x100) |
|
105 |
goto dmg_close; |
|
106 |
if((count = read_uint32(s->fd))==0) |
|
107 |
goto dmg_close; |
|
108 |
info_end = info_begin+count; |
|
109 |
if(lseek(s->fd,0xf8,SEEK_CUR)<0) |
|
110 |
goto dmg_close; |
|
111 |
|
|
112 |
/* read offsets */ |
|
113 |
last_in_offset = last_out_offset = 0; |
|
114 |
while(lseek(s->fd,0,SEEK_CUR)<info_end) { |
|
115 |
uint32_t type; |
|
116 |
|
|
117 |
count = read_uint32(s->fd); |
|
118 |
if(count==0) |
|
119 |
goto dmg_close; |
|
120 |
type = read_uint32(s->fd); |
|
121 |
if(type!=0x6d697368 || count<244) |
|
122 |
lseek(s->fd,count-4,SEEK_CUR); |
|
123 |
else { |
|
124 |
int new_size, chunk_count; |
|
125 |
if(lseek(s->fd,200,SEEK_CUR)<0) |
|
126 |
goto dmg_close; |
|
127 |
chunk_count = (count-204)/40; |
|
128 |
new_size = sizeof(uint64_t) * (s->n_chunks + chunk_count); |
|
129 |
s->types = qemu_realloc(s->types, new_size/2); |
|
130 |
s->offsets = qemu_realloc(s->offsets, new_size); |
|
131 |
s->lengths = qemu_realloc(s->lengths, new_size); |
|
132 |
s->sectors = qemu_realloc(s->sectors, new_size); |
|
133 |
s->sectorcounts = qemu_realloc(s->sectorcounts, new_size); |
|
134 |
|
|
135 |
for(i=s->n_chunks;i<s->n_chunks+chunk_count;i++) { |
|
136 |
s->types[i] = read_uint32(s->fd); |
|
137 |
if(s->types[i]!=0x80000005 && s->types[i]!=1 && s->types[i]!=2) { |
|
138 |
if(s->types[i]==0xffffffff) { |
|
139 |
last_in_offset = s->offsets[i-1]+s->lengths[i-1]; |
|
140 |
last_out_offset = s->sectors[i-1]+s->sectorcounts[i-1]; |
|
141 |
} |
|
142 |
chunk_count--; |
|
143 |
i--; |
|
144 |
if(lseek(s->fd,36,SEEK_CUR)<0) |
|
145 |
goto dmg_close; |
|
146 |
continue; |
|
147 |
} |
|
148 |
read_uint32(s->fd); |
|
149 |
s->sectors[i] = last_out_offset+read_off(s->fd); |
|
150 |
s->sectorcounts[i] = read_off(s->fd); |
|
151 |
s->offsets[i] = last_in_offset+read_off(s->fd); |
|
152 |
s->lengths[i] = read_off(s->fd); |
|
153 |
if(s->lengths[i]>max_compressed_size) |
|
154 |
max_compressed_size = s->lengths[i]; |
|
155 |
if(s->sectorcounts[i]>max_sectors_per_chunk) |
|
156 |
max_sectors_per_chunk = s->sectorcounts[i]; |
|
157 |
} |
|
158 |
s->n_chunks+=chunk_count; |
|
159 |
} |
|
160 |
} |
|
161 |
|
|
162 |
/* initialize zlib engine */ |
|
163 |
s->compressed_chunk = qemu_malloc(max_compressed_size+1); |
|
164 |
s->uncompressed_chunk = qemu_malloc(512*max_sectors_per_chunk); |
|
165 |
if(inflateInit(&s->zstream) != Z_OK) |
|
166 |
goto dmg_close; |
|
167 |
|
|
168 |
s->current_chunk = s->n_chunks; |
|
169 |
|
|
170 |
return 0; |
|
171 |
} |
|
172 |
|
|
173 |
static inline int is_sector_in_chunk(BDRVDMGState* s, |
|
174 |
uint32_t chunk_num,int sector_num) |
|
175 |
{ |
|
176 |
if(chunk_num>=s->n_chunks || s->sectors[chunk_num]>sector_num || |
|
177 |
s->sectors[chunk_num]+s->sectorcounts[chunk_num]<=sector_num) |
|
178 |
return 0; |
|
179 |
else |
|
180 |
return -1; |
|
181 |
} |
|
182 |
|
|
183 |
static inline uint32_t search_chunk(BDRVDMGState* s,int sector_num) |
|
184 |
{ |
|
185 |
/* binary search */ |
|
186 |
uint32_t chunk1=0,chunk2=s->n_chunks,chunk3; |
|
187 |
while(chunk1!=chunk2) { |
|
188 |
chunk3 = (chunk1+chunk2)/2; |
|
189 |
if(s->sectors[chunk3]>sector_num) |
|
190 |
chunk2 = chunk3; |
|
191 |
else if(s->sectors[chunk3]+s->sectorcounts[chunk3]>sector_num) |
|
192 |
return chunk3; |
|
193 |
else |
|
194 |
chunk1 = chunk3; |
|
195 |
} |
|
196 |
return s->n_chunks; /* error */ |
|
197 |
} |
|
198 |
|
|
199 |
static inline int dmg_read_chunk(BDRVDMGState *s,int sector_num) |
|
200 |
{ |
|
201 |
if(!is_sector_in_chunk(s,s->current_chunk,sector_num)) { |
|
202 |
int ret; |
|
203 |
uint32_t chunk = search_chunk(s,sector_num); |
|
204 |
|
|
205 |
if(chunk>=s->n_chunks) |
|
206 |
return -1; |
|
207 |
|
|
208 |
s->current_chunk = s->n_chunks; |
|
209 |
switch(s->types[chunk]) { |
|
210 |
case 0x80000005: { /* zlib compressed */ |
|
211 |
int i; |
|
212 |
|
|
213 |
ret = lseek(s->fd, s->offsets[chunk], SEEK_SET); |
|
214 |
if(ret<0) |
|
215 |
return -1; |
|
216 |
|
|
217 |
/* we need to buffer, because only the chunk as whole can be |
|
218 |
* inflated. */ |
|
219 |
i=0; |
|
220 |
do { |
|
221 |
ret = read(s->fd, s->compressed_chunk+i, s->lengths[chunk]-i); |
|
222 |
if(ret<0 && errno==EINTR) |
|
223 |
ret=0; |
|
224 |
i+=ret; |
|
225 |
} while(ret>=0 && ret+i<s->lengths[chunk]); |
|
226 |
|
|
227 |
if (ret != s->lengths[chunk]) |
|
228 |
return -1; |
|
229 |
|
|
230 |
s->zstream.next_in = s->compressed_chunk; |
|
231 |
s->zstream.avail_in = s->lengths[chunk]; |
|
232 |
s->zstream.next_out = s->uncompressed_chunk; |
|
233 |
s->zstream.avail_out = 512*s->sectorcounts[chunk]; |
|
234 |
ret = inflateReset(&s->zstream); |
|
235 |
if(ret != Z_OK) |
|
236 |
return -1; |
|
237 |
ret = inflate(&s->zstream, Z_FINISH); |
|
238 |
if(ret != Z_STREAM_END || s->zstream.total_out != 512*s->sectorcounts[chunk]) |
|
239 |
return -1; |
|
240 |
break; } |
|
241 |
case 1: /* copy */ |
|
242 |
ret = read(s->fd, s->uncompressed_chunk, s->lengths[chunk]); |
|
243 |
if (ret != s->lengths[chunk]) |
|
244 |
return -1; |
|
245 |
break; |
|
246 |
case 2: /* zero */ |
|
247 |
memset(s->uncompressed_chunk, 0, 512*s->sectorcounts[chunk]); |
|
248 |
break; |
|
249 |
} |
|
250 |
s->current_chunk = chunk; |
|
251 |
} |
|
252 |
return 0; |
|
253 |
} |
|
254 |
|
|
255 |
static int dmg_read(BlockDriverState *bs, int64_t sector_num, |
|
256 |
uint8_t *buf, int nb_sectors) |
|
257 |
{ |
|
258 |
BDRVDMGState *s = bs->opaque; |
|
259 |
int i; |
|
260 |
|
|
261 |
for(i=0;i<nb_sectors;i++) { |
|
262 |
uint32_t sector_offset_in_chunk; |
|
263 |
if(dmg_read_chunk(s, sector_num+i) != 0) |
|
264 |
return -1; |
|
265 |
sector_offset_in_chunk = sector_num+i-s->sectors[s->current_chunk]; |
|
266 |
memcpy(buf+i*512,s->uncompressed_chunk+sector_offset_in_chunk*512,512); |
|
267 |
} |
|
268 |
return 0; |
|
269 |
} |
|
270 |
|
|
271 |
static void dmg_close(BlockDriverState *bs) |
|
272 |
{ |
|
273 |
BDRVDMGState *s = bs->opaque; |
|
274 |
close(s->fd); |
|
275 |
if(s->n_chunks>0) { |
|
276 |
free(s->types); |
|
277 |
free(s->offsets); |
|
278 |
free(s->lengths); |
|
279 |
free(s->sectors); |
|
280 |
free(s->sectorcounts); |
|
281 |
} |
|
282 |
free(s->compressed_chunk); |
|
283 |
free(s->uncompressed_chunk); |
|
284 |
inflateEnd(&s->zstream); |
|
285 |
} |
|
286 |
|
|
287 |
static BlockDriver bdrv_dmg = { |
|
288 |
.format_name = "dmg", |
|
289 |
.instance_size = sizeof(BDRVDMGState), |
|
290 |
.bdrv_probe = dmg_probe, |
|
291 |
.bdrv_open = dmg_open, |
|
292 |
.bdrv_read = dmg_read, |
|
293 |
.bdrv_close = dmg_close, |
|
294 |
}; |
|
295 |
|
|
296 |
static void bdrv_dmg_init(void) |
|
297 |
{ |
|
298 |
bdrv_register(&bdrv_dmg); |
|
299 |
} |
|
300 |
|
|
301 |
block_init(bdrv_dmg_init); |
/dev/null | ||
---|---|---|
1 |
/* |
|
2 |
* QEMU Block driver for NBD |
|
3 |
* |
|
4 |
* Copyright (C) 2008 Bull S.A.S. |
|
5 |
* Author: Laurent Vivier <Laurent.Vivier@bull.net> |
|
6 |
* |
|
7 |
* Some parts: |
|
8 |
* Copyright (C) 2007 Anthony Liguori <anthony@codemonkey.ws> |
|
9 |
* |
|
10 |
* Permission is hereby granted, free of charge, to any person obtaining a copy |
|
11 |
* of this software and associated documentation files (the "Software"), to deal |
|
12 |
* in the Software without restriction, including without limitation the rights |
|
13 |
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
14 |
* copies of the Software, and to permit persons to whom the Software is |
|
15 |
* furnished to do so, subject to the following conditions: |
|
16 |
* |
|
17 |
* The above copyright notice and this permission notice shall be included in |
|
18 |
* all copies or substantial portions of the Software. |
|
19 |
* |
|
20 |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
21 |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
22 |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
|
23 |
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
24 |
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|
25 |
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|
26 |
* THE SOFTWARE. |
|
27 |
*/ |
|
28 |
|
|
29 |
#include "qemu-common.h" |
|
30 |
#include "nbd.h" |
|
31 |
#include "module.h" |
|
32 |
|
|
33 |
#include <sys/types.h> |
|
34 |
#include <unistd.h> |
|
35 |
|
|
36 |
typedef struct BDRVNBDState { |
|
37 |
int sock; |
|
38 |
off_t size; |
|
39 |
size_t blocksize; |
|
40 |
} BDRVNBDState; |
|
41 |
|
|
42 |
static int nbd_open(BlockDriverState *bs, const char* filename, int flags) |
|
43 |
{ |
|
44 |
BDRVNBDState *s = bs->opaque; |
|
45 |
const char *host; |
|
46 |
const char *unixpath; |
|
47 |
int sock; |
|
48 |
off_t size; |
|
49 |
size_t blocksize; |
|
50 |
int ret; |
|
51 |
|
|
52 |
if ((flags & BDRV_O_CREAT)) |
|
53 |
return -EINVAL; |
|
54 |
|
|
55 |
if (!strstart(filename, "nbd:", &host)) |
|
56 |
return -EINVAL; |
|
57 |
|
|
58 |
if (strstart(host, "unix:", &unixpath)) { |
|
59 |
|
|
60 |
if (unixpath[0] != '/') |
|
61 |
return -EINVAL; |
|
62 |
|
|
63 |
sock = unix_socket_outgoing(unixpath); |
|
64 |
|
|
65 |
} else { |
|
66 |
uint16_t port; |
|
67 |
char *p, *r; |
|
68 |
char hostname[128]; |
|
69 |
|
|
70 |
pstrcpy(hostname, 128, host); |
|
71 |
|
|
72 |
p = strchr(hostname, ':'); |
|
73 |
if (p == NULL) |
|
74 |
return -EINVAL; |
|
75 |
|
|
76 |
*p = '\0'; |
|
77 |
p++; |
|
78 |
|
|
79 |
port = strtol(p, &r, 0); |
|
80 |
if (r == p) |
|
81 |
return -EINVAL; |
|
82 |
sock = tcp_socket_outgoing(hostname, port); |
|
83 |
} |
|
84 |
|
|
85 |
if (sock == -1) |
|
86 |
return -errno; |
|
87 |
|
|
88 |
ret = nbd_receive_negotiate(sock, &size, &blocksize); |
|
89 |
if (ret == -1) |
|
90 |
return -errno; |
|
91 |
|
|
92 |
s->sock = sock; |
|
93 |
s->size = size; |
|
94 |
s->blocksize = blocksize; |
|
95 |
|
|
96 |
return 0; |
|
97 |
} |
|
98 |
|
|
99 |
static int nbd_read(BlockDriverState *bs, int64_t sector_num, |
|
100 |
uint8_t *buf, int nb_sectors) |
|
101 |
{ |
|
102 |
BDRVNBDState *s = bs->opaque; |
|
103 |
struct nbd_request request; |
|
104 |
struct nbd_reply reply; |
|
105 |
|
|
106 |
request.type = NBD_CMD_READ; |
|
107 |
request.handle = (uint64_t)(intptr_t)bs; |
|
108 |
request.from = sector_num * 512;; |
|
109 |
request.len = nb_sectors * 512; |
|
110 |
|
|
111 |
if (nbd_send_request(s->sock, &request) == -1) |
|
112 |
return -errno; |
|
113 |
|
|
114 |
if (nbd_receive_reply(s->sock, &reply) == -1) |
|
115 |
return -errno; |
|
116 |
|
|
117 |
if (reply.error !=0) |
|
118 |
return -reply.error; |
|
119 |
|
|
120 |
if (reply.handle != request.handle) |
|
121 |
return -EIO; |
|
122 |
|
|
123 |
if (nbd_wr_sync(s->sock, buf, request.len, 1) != request.len) |
|
124 |
return -EIO; |
|
125 |
|
|
126 |
return 0; |
|
127 |
} |
|
128 |
|
|
129 |
static int nbd_write(BlockDriverState *bs, int64_t sector_num, |
|
130 |
const uint8_t *buf, int nb_sectors) |
|
131 |
{ |
|
132 |
BDRVNBDState *s = bs->opaque; |
|
133 |
struct nbd_request request; |
|
134 |
struct nbd_reply reply; |
|
135 |
|
|
136 |
request.type = NBD_CMD_WRITE; |
|
137 |
request.handle = (uint64_t)(intptr_t)bs; |
|
138 |
request.from = sector_num * 512;; |
|
139 |
request.len = nb_sectors * 512; |
|
140 |
|
|
141 |
if (nbd_send_request(s->sock, &request) == -1) |
|
142 |
return -errno; |
|
143 |
|
|
144 |
if (nbd_wr_sync(s->sock, (uint8_t*)buf, request.len, 0) != request.len) |
|
145 |
return -EIO; |
|
146 |
|
|
147 |
if (nbd_receive_reply(s->sock, &reply) == -1) |
|
148 |
return -errno; |
|
149 |
|
|
150 |
if (reply.error !=0) |
|
151 |
return -reply.error; |
|
152 |
|
|
153 |
if (reply.handle != request.handle) |
|
154 |
return -EIO; |
|
155 |
|
|
156 |
return 0; |
|
157 |
} |
|
158 |
|
|
159 |
static void nbd_close(BlockDriverState *bs) |
|
160 |
{ |
|
161 |
BDRVNBDState *s = bs->opaque; |
|
162 |
struct nbd_request request; |
|
163 |
|
|
164 |
request.type = NBD_CMD_DISC; |
|
165 |
request.handle = (uint64_t)(intptr_t)bs; |
|
166 |
request.from = 0; |
|
167 |
request.len = 0; |
|
168 |
nbd_send_request(s->sock, &request); |
|
169 |
|
|
170 |
close(s->sock); |
|
171 |
} |
|
172 |
|
|
173 |
static int64_t nbd_getlength(BlockDriverState *bs) |
|
174 |
{ |
|
175 |
BDRVNBDState *s = bs->opaque; |
|
176 |
|
|
177 |
return s->size; |
|
178 |
} |
|
179 |
|
|
180 |
static BlockDriver bdrv_nbd = { |
|
181 |
.format_name = "nbd", |
|
182 |
.instance_size = sizeof(BDRVNBDState), |
|
183 |
.bdrv_open = nbd_open, |
|
184 |
.bdrv_read = nbd_read, |
|
185 |
.bdrv_write = nbd_write, |
|
186 |
.bdrv_close = nbd_close, |
|
187 |
.bdrv_getlength = nbd_getlength, |
|
188 |
.protocol_name = "nbd", |
|
189 |
}; |
|
190 |
|
|
191 |
static void bdrv_nbd_init(void) |
|
192 |
{ |
|
193 |
bdrv_register(&bdrv_nbd); |
|
194 |
} |
|
195 |
|
|
196 |
block_init(bdrv_nbd_init); |
/dev/null | ||
---|---|---|
1 |
/* |
|
2 |
* Block driver for Parallels disk image format |
|
3 |
* |
|
4 |
* Copyright (c) 2007 Alex Beregszaszi |
|
5 |
* |
|
6 |
* This code is based on comparing different disk images created by Parallels. |
|
7 |
* |
|
8 |
* Permission is hereby granted, free of charge, to any person obtaining a copy |
|
9 |
* of this software and associated documentation files (the "Software"), to deal |
|
10 |
* in the Software without restriction, including without limitation the rights |
|
11 |
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
12 |
* copies of the Software, and to permit persons to whom the Software is |
|
13 |
* furnished to do so, subject to the following conditions: |
|
14 |
* |
|
15 |
* The above copyright notice and this permission notice shall be included in |
|
16 |
* all copies or substantial portions of the Software. |
|
17 |
* |
|
18 |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
19 |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
20 |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
|
21 |
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
22 |
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|
23 |
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|
24 |
* THE SOFTWARE. |
|
25 |
*/ |
|
26 |
#include "qemu-common.h" |
|
27 |
#include "block_int.h" |
|
28 |
#include "module.h" |
|
29 |
|
|
30 |
/**************************************************************/ |
|
31 |
|
|
32 |
#define HEADER_MAGIC "WithoutFreeSpace" |
|
33 |
#define HEADER_VERSION 2 |
|
34 |
#define HEADER_SIZE 64 |
|
35 |
|
|
36 |
// always little-endian |
|
37 |
struct parallels_header { |
|
38 |
char magic[16]; // "WithoutFreeSpace" |
|
39 |
uint32_t version; |
|
40 |
uint32_t heads; |
|
41 |
uint32_t cylinders; |
|
42 |
uint32_t tracks; |
|
43 |
uint32_t catalog_entries; |
|
44 |
uint32_t nb_sectors; |
|
45 |
char padding[24]; |
|
46 |
} __attribute__((packed)); |
|
47 |
|
|
48 |
typedef struct BDRVParallelsState { |
|
49 |
int fd; |
|
50 |
|
|
51 |
uint32_t *catalog_bitmap; |
|
52 |
int catalog_size; |
|
53 |
|
|
54 |
int tracks; |
|
55 |
} BDRVParallelsState; |
|
56 |
|
|
57 |
static int parallels_probe(const uint8_t *buf, int buf_size, const char *filename) |
|
58 |
{ |
|
59 |
const struct parallels_header *ph = (const void *)buf; |
|
60 |
|
|
61 |
if (buf_size < HEADER_SIZE) |
|
62 |
return 0; |
|
63 |
|
|
64 |
if (!memcmp(ph->magic, HEADER_MAGIC, 16) && |
|
65 |
(le32_to_cpu(ph->version) == HEADER_VERSION)) |
|
66 |
return 100; |
|
67 |
|
|
68 |
return 0; |
|
69 |
} |
|
70 |
|
|
71 |
static int parallels_open(BlockDriverState *bs, const char *filename, int flags) |
|
72 |
{ |
|
73 |
BDRVParallelsState *s = bs->opaque; |
|
74 |
int fd, i; |
|
75 |
struct parallels_header ph; |
|
76 |
|
|
77 |
fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE); |
|
78 |
if (fd < 0) { |
|
79 |
fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE); |
|
80 |
if (fd < 0) |
|
81 |
return -1; |
|
82 |
} |
|
83 |
|
|
84 |
bs->read_only = 1; // no write support yet |
|
85 |
|
|
86 |
s->fd = fd; |
|
87 |
|
|
88 |
if (read(fd, &ph, sizeof(ph)) != sizeof(ph)) |
|
89 |
goto fail; |
|
90 |
|
|
91 |
if (memcmp(ph.magic, HEADER_MAGIC, 16) || |
|
92 |
(le32_to_cpu(ph.version) != HEADER_VERSION)) { |
|
93 |
goto fail; |
|
94 |
} |
|
95 |
|
|
96 |
bs->total_sectors = le32_to_cpu(ph.nb_sectors); |
|
97 |
|
|
98 |
if (lseek(s->fd, 64, SEEK_SET) != 64) |
|
99 |
goto fail; |
|
100 |
|
|
101 |
s->tracks = le32_to_cpu(ph.tracks); |
|
102 |
|
|
103 |
s->catalog_size = le32_to_cpu(ph.catalog_entries); |
|
104 |
s->catalog_bitmap = qemu_malloc(s->catalog_size * 4); |
|
105 |
if (read(s->fd, s->catalog_bitmap, s->catalog_size * 4) != |
|
106 |
s->catalog_size * 4) |
|
107 |
goto fail; |
|
108 |
for (i = 0; i < s->catalog_size; i++) |
|
109 |
le32_to_cpus(&s->catalog_bitmap[i]); |
|
110 |
|
|
111 |
return 0; |
|
112 |
fail: |
|
113 |
if (s->catalog_bitmap) |
|
114 |
qemu_free(s->catalog_bitmap); |
|
115 |
close(fd); |
|
116 |
return -1; |
|
117 |
} |
|
118 |
|
|
119 |
static inline int seek_to_sector(BlockDriverState *bs, int64_t sector_num) |
|
120 |
{ |
|
121 |
BDRVParallelsState *s = bs->opaque; |
|
122 |
uint32_t index, offset, position; |
|
123 |
|
|
124 |
index = sector_num / s->tracks; |
|
125 |
offset = sector_num % s->tracks; |
|
126 |
|
|
127 |
// not allocated |
|
128 |
if ((index > s->catalog_size) || (s->catalog_bitmap[index] == 0)) |
|
129 |
return -1; |
|
130 |
|
|
131 |
position = (s->catalog_bitmap[index] + offset) * 512; |
|
132 |
|
|
133 |
// fprintf(stderr, "sector: %llx index=%x offset=%x pointer=%x position=%x\n", |
|
134 |
// sector_num, index, offset, s->catalog_bitmap[index], position); |
|
135 |
|
|
136 |
if (lseek(s->fd, position, SEEK_SET) != position) |
|
137 |
return -1; |
|
138 |
|
|
139 |
return 0; |
|
140 |
} |
|
141 |
|
|
142 |
static int parallels_read(BlockDriverState *bs, int64_t sector_num, |
|
143 |
uint8_t *buf, int nb_sectors) |
|
144 |
{ |
|
145 |
BDRVParallelsState *s = bs->opaque; |
|
146 |
|
|
147 |
while (nb_sectors > 0) { |
|
148 |
if (!seek_to_sector(bs, sector_num)) { |
|
149 |
if (read(s->fd, buf, 512) != 512) |
|
150 |
return -1; |
|
151 |
} else |
|
152 |
memset(buf, 0, 512); |
|
153 |
nb_sectors--; |
|
154 |
sector_num++; |
|
155 |
buf += 512; |
|
156 |
} |
|
157 |
return 0; |
|
158 |
} |
|
159 |
|
|
160 |
static void parallels_close(BlockDriverState *bs) |
|
161 |
{ |
|
162 |
BDRVParallelsState *s = bs->opaque; |
|
163 |
qemu_free(s->catalog_bitmap); |
|
164 |
close(s->fd); |
|
165 |
} |
|
166 |
|
|
167 |
static BlockDriver bdrv_parallels = { |
|
168 |
.format_name = "parallels", |
|
169 |
.instance_size = sizeof(BDRVParallelsState), |
|
170 |
.bdrv_probe = parallels_probe, |
|
171 |
.bdrv_open = parallels_open, |
|
172 |
.bdrv_read = parallels_read, |
|
173 |
.bdrv_close = parallels_close, |
|
174 |
}; |
|
175 |
|
|
176 |
static void bdrv_parallels_init(void) |
|
177 |
{ |
|
178 |
bdrv_register(&bdrv_parallels); |
|
179 |
} |
|
180 |
|
|
181 |
block_init(bdrv_parallels_init); |
/dev/null | ||
---|---|---|
1 |
/* |
|
2 |
* Block driver for the QCOW format |
|
3 |
* |
|
4 |
* Copyright (c) 2004-2006 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 "qemu-common.h" |
|
25 |
#include "block_int.h" |
Also available in: Unified diff