Commit ea2384d36e1e5f6dfd44b748d290762181c38350
1 parent
e4d4fe3c
new disk image layer
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1037 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
7 changed files
with
2372 additions
and
410 deletions
block-cow.c
0 → 100644
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 "vl.h" | |
26 | +#include "block_int.h" | |
27 | +#include <sys/mman.h> | |
28 | + | |
29 | +/**************************************************************/ | |
30 | +/* COW block driver using file system holes */ | |
31 | + | |
32 | +/* user mode linux compatible COW file */ | |
33 | +#define COW_MAGIC 0x4f4f4f4d /* MOOO */ | |
34 | +#define COW_VERSION 2 | |
35 | + | |
36 | +struct cow_header_v2 { | |
37 | + uint32_t magic; | |
38 | + uint32_t version; | |
39 | + char backing_file[1024]; | |
40 | + int32_t mtime; | |
41 | + uint64_t size; | |
42 | + uint32_t sectorsize; | |
43 | +}; | |
44 | + | |
45 | +typedef struct BDRVCowState { | |
46 | + int fd; | |
47 | + uint8_t *cow_bitmap; /* if non NULL, COW mappings are used first */ | |
48 | + uint8_t *cow_bitmap_addr; /* mmap address of cow_bitmap */ | |
49 | + int cow_bitmap_size; | |
50 | + int64_t cow_sectors_offset; | |
51 | +} BDRVCowState; | |
52 | + | |
53 | +static int cow_probe(const uint8_t *buf, int buf_size, const char *filename) | |
54 | +{ | |
55 | + const struct cow_header_v2 *cow_header = (const void *)buf; | |
56 | + | |
57 | + if (be32_to_cpu(cow_header->magic) == COW_MAGIC && | |
58 | + be32_to_cpu(cow_header->version) == COW_VERSION) | |
59 | + return 100; | |
60 | + else | |
61 | + return 0; | |
62 | +} | |
63 | + | |
64 | +static int cow_open(BlockDriverState *bs, const char *filename) | |
65 | +{ | |
66 | + BDRVCowState *s = bs->opaque; | |
67 | + int fd; | |
68 | + struct cow_header_v2 cow_header; | |
69 | + int64_t size; | |
70 | + | |
71 | + fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE); | |
72 | + if (fd < 0) { | |
73 | + fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE); | |
74 | + if (fd < 0) | |
75 | + return -1; | |
76 | + } | |
77 | + s->fd = fd; | |
78 | + /* see if it is a cow image */ | |
79 | + if (read(fd, &cow_header, sizeof(cow_header)) != sizeof(cow_header)) { | |
80 | + goto fail; | |
81 | + } | |
82 | + | |
83 | + if (be32_to_cpu(cow_header.magic) != COW_MAGIC || | |
84 | + be32_to_cpu(cow_header.version) != COW_VERSION) { | |
85 | + goto fail; | |
86 | + } | |
87 | + | |
88 | + /* cow image found */ | |
89 | + size = be64_to_cpu(cow_header.size); | |
90 | + bs->total_sectors = size / 512; | |
91 | + | |
92 | + pstrcpy(bs->backing_file, sizeof(bs->backing_file), | |
93 | + cow_header.backing_file); | |
94 | + | |
95 | +#if 0 | |
96 | + if (cow_header.backing_file[0] != '\0') { | |
97 | + if (stat(cow_header.backing_file, &st) != 0) { | |
98 | + fprintf(stderr, "%s: could not find original disk image '%s'\n", filename, cow_header.backing_file); | |
99 | + goto fail; | |
100 | + } | |
101 | + if (st.st_mtime != be32_to_cpu(cow_header.mtime)) { | |
102 | + fprintf(stderr, "%s: original raw disk image '%s' does not match saved timestamp\n", filename, cow_header.backing_file); | |
103 | + goto fail; | |
104 | + } | |
105 | + fd = open(cow_header.backing_file, O_RDONLY | O_LARGEFILE); | |
106 | + if (fd < 0) | |
107 | + goto fail; | |
108 | + bs->fd = fd; | |
109 | + } | |
110 | +#endif | |
111 | + /* mmap the bitmap */ | |
112 | + s->cow_bitmap_size = ((bs->total_sectors + 7) >> 3) + sizeof(cow_header); | |
113 | + s->cow_bitmap_addr = mmap(get_mmap_addr(s->cow_bitmap_size), | |
114 | + s->cow_bitmap_size, | |
115 | + PROT_READ | PROT_WRITE, | |
116 | + MAP_SHARED, s->fd, 0); | |
117 | + if (s->cow_bitmap_addr == MAP_FAILED) | |
118 | + goto fail; | |
119 | + s->cow_bitmap = s->cow_bitmap_addr + sizeof(cow_header); | |
120 | + s->cow_sectors_offset = (s->cow_bitmap_size + 511) & ~511; | |
121 | + return 0; | |
122 | + fail: | |
123 | + close(fd); | |
124 | + return -1; | |
125 | +} | |
126 | + | |
127 | +static inline void set_bit(uint8_t *bitmap, int64_t bitnum) | |
128 | +{ | |
129 | + bitmap[bitnum / 8] |= (1 << (bitnum%8)); | |
130 | +} | |
131 | + | |
132 | +static inline int is_bit_set(const uint8_t *bitmap, int64_t bitnum) | |
133 | +{ | |
134 | + return !!(bitmap[bitnum / 8] & (1 << (bitnum%8))); | |
135 | +} | |
136 | + | |
137 | + | |
138 | +/* Return true if first block has been changed (ie. current version is | |
139 | + * in COW file). Set the number of continuous blocks for which that | |
140 | + * is true. */ | |
141 | +static inline int is_changed(uint8_t *bitmap, | |
142 | + int64_t sector_num, int nb_sectors, | |
143 | + int *num_same) | |
144 | +{ | |
145 | + int changed; | |
146 | + | |
147 | + if (!bitmap || nb_sectors == 0) { | |
148 | + *num_same = nb_sectors; | |
149 | + return 0; | |
150 | + } | |
151 | + | |
152 | + changed = is_bit_set(bitmap, sector_num); | |
153 | + for (*num_same = 1; *num_same < nb_sectors; (*num_same)++) { | |
154 | + if (is_bit_set(bitmap, sector_num + *num_same) != changed) | |
155 | + break; | |
156 | + } | |
157 | + | |
158 | + return changed; | |
159 | +} | |
160 | + | |
161 | +static int cow_is_allocated(BlockDriverState *bs, int64_t sector_num, | |
162 | + int nb_sectors, int *pnum) | |
163 | +{ | |
164 | + BDRVCowState *s = bs->opaque; | |
165 | + return is_changed(s->cow_bitmap, sector_num, nb_sectors, pnum); | |
166 | +} | |
167 | + | |
168 | +static int cow_read(BlockDriverState *bs, int64_t sector_num, | |
169 | + uint8_t *buf, int nb_sectors) | |
170 | +{ | |
171 | + BDRVCowState *s = bs->opaque; | |
172 | + int ret, n; | |
173 | + | |
174 | + while (nb_sectors > 0) { | |
175 | + if (is_changed(s->cow_bitmap, sector_num, nb_sectors, &n)) { | |
176 | + lseek64(s->fd, s->cow_sectors_offset + sector_num * 512, SEEK_SET); | |
177 | + ret = read(s->fd, buf, n * 512); | |
178 | + if (ret != n * 512) | |
179 | + return -1; | |
180 | + } else { | |
181 | + memset(buf, 0, n * 512); | |
182 | + } | |
183 | + nb_sectors -= n; | |
184 | + sector_num += n; | |
185 | + buf += n * 512; | |
186 | + } | |
187 | + return 0; | |
188 | +} | |
189 | + | |
190 | +static int cow_write(BlockDriverState *bs, int64_t sector_num, | |
191 | + const uint8_t *buf, int nb_sectors) | |
192 | +{ | |
193 | + BDRVCowState *s = bs->opaque; | |
194 | + int ret, i; | |
195 | + | |
196 | + lseek64(s->fd, s->cow_sectors_offset + sector_num * 512, SEEK_SET); | |
197 | + ret = write(s->fd, buf, nb_sectors * 512); | |
198 | + if (ret != nb_sectors * 512) | |
199 | + return -1; | |
200 | + for (i = 0; i < nb_sectors; i++) | |
201 | + set_bit(s->cow_bitmap, sector_num + i); | |
202 | + return 0; | |
203 | +} | |
204 | + | |
205 | +static int cow_close(BlockDriverState *bs) | |
206 | +{ | |
207 | + BDRVCowState *s = bs->opaque; | |
208 | + munmap(s->cow_bitmap_addr, s->cow_bitmap_size); | |
209 | + close(s->fd); | |
210 | +} | |
211 | + | |
212 | +static int cow_create(const char *filename, int64_t image_sectors, | |
213 | + const char *image_filename, int flags) | |
214 | +{ | |
215 | + int fd, cow_fd; | |
216 | + struct cow_header_v2 cow_header; | |
217 | + struct stat st; | |
218 | + | |
219 | + if (flags) | |
220 | + return -ENOTSUP; | |
221 | + | |
222 | + cow_fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE, | |
223 | + 0644); | |
224 | + if (cow_fd < 0) | |
225 | + return -1; | |
226 | + memset(&cow_header, 0, sizeof(cow_header)); | |
227 | + cow_header.magic = cpu_to_be32(COW_MAGIC); | |
228 | + cow_header.version = cpu_to_be32(COW_VERSION); | |
229 | + if (image_filename) { | |
230 | + fd = open(image_filename, O_RDONLY | O_BINARY); | |
231 | + if (fd < 0) { | |
232 | + close(cow_fd); | |
233 | + return -1; | |
234 | + } | |
235 | + if (fstat(fd, &st) != 0) { | |
236 | + close(fd); | |
237 | + return -1; | |
238 | + } | |
239 | + close(fd); | |
240 | + cow_header.mtime = cpu_to_be32(st.st_mtime); | |
241 | + realpath(image_filename, cow_header.backing_file); | |
242 | + } | |
243 | + cow_header.sectorsize = cpu_to_be32(512); | |
244 | + cow_header.size = cpu_to_be64(image_sectors * 512); | |
245 | + write(cow_fd, &cow_header, sizeof(cow_header)); | |
246 | + /* resize to include at least all the bitmap */ | |
247 | + ftruncate(cow_fd, sizeof(cow_header) + ((image_sectors + 7) >> 3)); | |
248 | + close(cow_fd); | |
249 | + return 0; | |
250 | +} | |
251 | + | |
252 | +BlockDriver bdrv_cow = { | |
253 | + "cow", | |
254 | + sizeof(BDRVCowState), | |
255 | + cow_probe, | |
256 | + cow_open, | |
257 | + cow_read, | |
258 | + cow_write, | |
259 | + cow_close, | |
260 | + cow_create, | |
261 | + cow_is_allocated, | |
262 | +}; | |
263 | +#endif | ... | ... |
block-qcow.c
0 → 100644
1 | +/* | |
2 | + * Block driver for the QCOW 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 | +#include "vl.h" | |
25 | +#include "block_int.h" | |
26 | +#include "zlib.h" | |
27 | +#include "aes.h" | |
28 | + | |
29 | +/**************************************************************/ | |
30 | +/* QEMU COW block driver with compression and encryption support */ | |
31 | + | |
32 | +#define QCOW_MAGIC (('Q' << 24) | ('F' << 16) | ('I' << 8) | 0xfb) | |
33 | +#define QCOW_VERSION 1 | |
34 | + | |
35 | +#define QCOW_CRYPT_NONE 0 | |
36 | +#define QCOW_CRYPT_AES 1 | |
37 | + | |
38 | +#define QCOW_OFLAG_COMPRESSED (1LL << 63) | |
39 | + | |
40 | +typedef struct QCowHeader { | |
41 | + uint32_t magic; | |
42 | + uint32_t version; | |
43 | + uint64_t backing_file_offset; | |
44 | + uint32_t backing_file_size; | |
45 | + uint32_t mtime; | |
46 | + uint64_t size; /* in bytes */ | |
47 | + uint8_t cluster_bits; | |
48 | + uint8_t l2_bits; | |
49 | + uint32_t crypt_method; | |
50 | + uint64_t l1_table_offset; | |
51 | +} QCowHeader; | |
52 | + | |
53 | +#define L2_CACHE_SIZE 16 | |
54 | + | |
55 | +typedef struct BDRVQcowState { | |
56 | + int fd; | |
57 | + int cluster_bits; | |
58 | + int cluster_size; | |
59 | + int cluster_sectors; | |
60 | + int l2_bits; | |
61 | + int l2_size; | |
62 | + int l1_size; | |
63 | + uint64_t cluster_offset_mask; | |
64 | + uint64_t l1_table_offset; | |
65 | + uint64_t *l1_table; | |
66 | + uint64_t *l2_cache; | |
67 | + uint64_t l2_cache_offsets[L2_CACHE_SIZE]; | |
68 | + uint32_t l2_cache_counts[L2_CACHE_SIZE]; | |
69 | + uint8_t *cluster_cache; | |
70 | + uint8_t *cluster_data; | |
71 | + uint64_t cluster_cache_offset; | |
72 | + uint32_t crypt_method; /* current crypt method, 0 if no key yet */ | |
73 | + uint32_t crypt_method_header; | |
74 | + AES_KEY aes_encrypt_key; | |
75 | + AES_KEY aes_decrypt_key; | |
76 | +} BDRVQcowState; | |
77 | + | |
78 | +static int decompress_cluster(BDRVQcowState *s, uint64_t cluster_offset); | |
79 | + | |
80 | +static int qcow_probe(const uint8_t *buf, int buf_size, const char *filename) | |
81 | +{ | |
82 | + const QCowHeader *cow_header = (const void *)buf; | |
83 | + | |
84 | + if (be32_to_cpu(cow_header->magic) == QCOW_MAGIC && | |
85 | + be32_to_cpu(cow_header->version) == QCOW_VERSION) | |
86 | + return 100; | |
87 | + else | |
88 | + return 0; | |
89 | +} | |
90 | + | |
91 | +static int qcow_open(BlockDriverState *bs, const char *filename) | |
92 | +{ | |
93 | + BDRVQcowState *s = bs->opaque; | |
94 | + int fd, len, i, shift; | |
95 | + QCowHeader header; | |
96 | + | |
97 | + fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE); | |
98 | + if (fd < 0) { | |
99 | + fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE); | |
100 | + if (fd < 0) | |
101 | + return -1; | |
102 | + } | |
103 | + s->fd = fd; | |
104 | + if (read(fd, &header, sizeof(header)) != sizeof(header)) | |
105 | + goto fail; | |
106 | + be32_to_cpus(&header.magic); | |
107 | + be32_to_cpus(&header.version); | |
108 | + be64_to_cpus(&header.backing_file_offset); | |
109 | + be32_to_cpus(&header.backing_file_size); | |
110 | + be32_to_cpus(&header.mtime); | |
111 | + be64_to_cpus(&header.size); | |
112 | + be32_to_cpus(&header.crypt_method); | |
113 | + be64_to_cpus(&header.l1_table_offset); | |
114 | + | |
115 | + if (header.magic != QCOW_MAGIC || header.version != QCOW_VERSION) | |
116 | + goto fail; | |
117 | + if (header.size <= 1 || header.cluster_bits < 9) | |
118 | + goto fail; | |
119 | + if (header.crypt_method > QCOW_CRYPT_AES) | |
120 | + goto fail; | |
121 | + s->crypt_method_header = header.crypt_method; | |
122 | + if (s->crypt_method_header) | |
123 | + bs->encrypted = 1; | |
124 | + s->cluster_bits = header.cluster_bits; | |
125 | + s->cluster_size = 1 << s->cluster_bits; | |
126 | + s->cluster_sectors = 1 << (s->cluster_bits - 9); | |
127 | + s->l2_bits = header.l2_bits; | |
128 | + s->l2_size = 1 << s->l2_bits; | |
129 | + bs->total_sectors = header.size / 512; | |
130 | + s->cluster_offset_mask = (1LL << (63 - s->cluster_bits)) - 1; | |
131 | + | |
132 | + /* read the level 1 table */ | |
133 | + shift = s->cluster_bits + s->l2_bits; | |
134 | + s->l1_size = (header.size + (1LL << shift) - 1) >> shift; | |
135 | + | |
136 | + s->l1_table_offset = header.l1_table_offset; | |
137 | + s->l1_table = qemu_malloc(s->l1_size * sizeof(uint64_t)); | |
138 | + if (!s->l1_table) | |
139 | + goto fail; | |
140 | + lseek64(fd, s->l1_table_offset, SEEK_SET); | |
141 | + if (read(fd, s->l1_table, s->l1_size * sizeof(uint64_t)) != | |
142 | + s->l1_size * sizeof(uint64_t)) | |
143 | + goto fail; | |
144 | + for(i = 0;i < s->l1_size; i++) { | |
145 | + be64_to_cpus(&s->l1_table[i]); | |
146 | + } | |
147 | + /* alloc L2 cache */ | |
148 | + s->l2_cache = qemu_malloc(s->l2_size * L2_CACHE_SIZE * sizeof(uint64_t)); | |
149 | + if (!s->l2_cache) | |
150 | + goto fail; | |
151 | + s->cluster_cache = qemu_malloc(s->cluster_size); | |
152 | + if (!s->cluster_cache) | |
153 | + goto fail; | |
154 | + s->cluster_data = qemu_malloc(s->cluster_size); | |
155 | + if (!s->cluster_data) | |
156 | + goto fail; | |
157 | + s->cluster_cache_offset = -1; | |
158 | + | |
159 | + /* read the backing file name */ | |
160 | + if (header.backing_file_offset != 0) { | |
161 | + len = header.backing_file_size; | |
162 | + if (len > 1023) | |
163 | + len = 1023; | |
164 | + lseek64(fd, header.backing_file_offset, SEEK_SET); | |
165 | + if (read(fd, bs->backing_file, len) != len) | |
166 | + goto fail; | |
167 | + bs->backing_file[len] = '\0'; | |
168 | + } | |
169 | + return 0; | |
170 | + | |
171 | + fail: | |
172 | + qemu_free(s->l1_table); | |
173 | + qemu_free(s->l2_cache); | |
174 | + qemu_free(s->cluster_cache); | |
175 | + qemu_free(s->cluster_data); | |
176 | + close(fd); | |
177 | + return -1; | |
178 | +} | |
179 | + | |
180 | +static int qcow_set_key(BlockDriverState *bs, const char *key) | |
181 | +{ | |
182 | + BDRVQcowState *s = bs->opaque; | |
183 | + uint8_t keybuf[16]; | |
184 | + int len, i; | |
185 | + | |
186 | + memset(keybuf, 0, 16); | |
187 | + len = strlen(key); | |
188 | + if (len > 16) | |
189 | + len = 16; | |
190 | + /* XXX: we could compress the chars to 7 bits to increase | |
191 | + entropy */ | |
192 | + for(i = 0;i < len;i++) { | |
193 | + keybuf[i] = key[i]; | |
194 | + } | |
195 | + s->crypt_method = s->crypt_method_header; | |
196 | + | |
197 | + if (AES_set_encrypt_key(keybuf, 128, &s->aes_encrypt_key) != 0) | |
198 | + return -1; | |
199 | + if (AES_set_decrypt_key(keybuf, 128, &s->aes_decrypt_key) != 0) | |
200 | + return -1; | |
201 | +#if 0 | |
202 | + /* test */ | |
203 | + { | |
204 | + uint8_t in[16]; | |
205 | + uint8_t out[16]; | |
206 | + uint8_t tmp[16]; | |
207 | + for(i=0;i<16;i++) | |
208 | + in[i] = i; | |
209 | + AES_encrypt(in, tmp, &s->aes_encrypt_key); | |
210 | + AES_decrypt(tmp, out, &s->aes_decrypt_key); | |
211 | + for(i = 0; i < 16; i++) | |
212 | + printf(" %02x", tmp[i]); | |
213 | + printf("\n"); | |
214 | + for(i = 0; i < 16; i++) | |
215 | + printf(" %02x", out[i]); | |
216 | + printf("\n"); | |
217 | + } | |
218 | +#endif | |
219 | + return 0; | |
220 | +} | |
221 | + | |
222 | +/* The crypt function is compatible with the linux cryptoloop | |
223 | + algorithm for < 4 GB images. NOTE: out_buf == in_buf is | |
224 | + supported */ | |
225 | +static void encrypt_sectors(BDRVQcowState *s, int64_t sector_num, | |
226 | + uint8_t *out_buf, const uint8_t *in_buf, | |
227 | + int nb_sectors, int enc, | |
228 | + const AES_KEY *key) | |
229 | +{ | |
230 | + union { | |
231 | + uint64_t ll[2]; | |
232 | + uint8_t b[16]; | |
233 | + } ivec; | |
234 | + int i; | |
235 | + | |
236 | + for(i = 0; i < nb_sectors; i++) { | |
237 | + ivec.ll[0] = cpu_to_le64(sector_num); | |
238 | + ivec.ll[1] = 0; | |
239 | + AES_cbc_encrypt(in_buf, out_buf, 512, key, | |
240 | + ivec.b, enc); | |
241 | + sector_num++; | |
242 | + in_buf += 512; | |
243 | + out_buf += 512; | |
244 | + } | |
245 | +} | |
246 | + | |
247 | +/* 'allocate' is: | |
248 | + * | |
249 | + * 0 to not allocate. | |
250 | + * | |
251 | + * 1 to allocate a normal cluster (for sector indexes 'n_start' to | |
252 | + * 'n_end') | |
253 | + * | |
254 | + * 2 to allocate a compressed cluster of size | |
255 | + * 'compressed_size'. 'compressed_size' must be > 0 and < | |
256 | + * cluster_size | |
257 | + * | |
258 | + * return 0 if not allocated. | |
259 | + */ | |
260 | +static uint64_t get_cluster_offset(BlockDriverState *bs, | |
261 | + uint64_t offset, int allocate, | |
262 | + int compressed_size, | |
263 | + int n_start, int n_end) | |
264 | +{ | |
265 | + BDRVQcowState *s = bs->opaque; | |
266 | + int min_index, i, j, l1_index, l2_index; | |
267 | + uint64_t l2_offset, *l2_table, cluster_offset, tmp; | |
268 | + uint32_t min_count; | |
269 | + int new_l2_table; | |
270 | + | |
271 | + l1_index = offset >> (s->l2_bits + s->cluster_bits); | |
272 | + l2_offset = s->l1_table[l1_index]; | |
273 | + new_l2_table = 0; | |
274 | + if (!l2_offset) { | |
275 | + if (!allocate) | |
276 | + return 0; | |
277 | + /* allocate a new l2 entry */ | |
278 | + l2_offset = lseek64(s->fd, 0, SEEK_END); | |
279 | + /* round to cluster size */ | |
280 | + l2_offset = (l2_offset + s->cluster_size - 1) & ~(s->cluster_size - 1); | |
281 | + /* update the L1 entry */ | |
282 | + s->l1_table[l1_index] = l2_offset; | |
283 | + tmp = cpu_to_be64(l2_offset); | |
284 | + lseek64(s->fd, s->l1_table_offset + l1_index * sizeof(tmp), SEEK_SET); | |
285 | + if (write(s->fd, &tmp, sizeof(tmp)) != sizeof(tmp)) | |
286 | + return 0; | |
287 | + new_l2_table = 1; | |
288 | + } | |
289 | + for(i = 0; i < L2_CACHE_SIZE; i++) { | |
290 | + if (l2_offset == s->l2_cache_offsets[i]) { | |
291 | + /* increment the hit count */ | |
292 | + if (++s->l2_cache_counts[i] == 0xffffffff) { | |
293 | + for(j = 0; j < L2_CACHE_SIZE; j++) { | |
294 | + s->l2_cache_counts[j] >>= 1; | |
295 | + } | |
296 | + } | |
297 | + l2_table = s->l2_cache + (i << s->l2_bits); | |
298 | + goto found; | |
299 | + } | |
300 | + } | |
301 | + /* not found: load a new entry in the least used one */ | |
302 | + min_index = 0; | |
303 | + min_count = 0xffffffff; | |
304 | + for(i = 0; i < L2_CACHE_SIZE; i++) { | |
305 | + if (s->l2_cache_counts[i] < min_count) { | |
306 | + min_count = s->l2_cache_counts[i]; | |
307 | + min_index = i; | |
308 | + } | |
309 | + } | |
310 | + l2_table = s->l2_cache + (min_index << s->l2_bits); | |
311 | + lseek(s->fd, l2_offset, SEEK_SET); | |
312 | + if (new_l2_table) { | |
313 | + memset(l2_table, 0, s->l2_size * sizeof(uint64_t)); | |
314 | + if (write(s->fd, l2_table, s->l2_size * sizeof(uint64_t)) != | |
315 | + s->l2_size * sizeof(uint64_t)) | |
316 | + return 0; | |
317 | + } else { | |
318 | + if (read(s->fd, l2_table, s->l2_size * sizeof(uint64_t)) != | |
319 | + s->l2_size * sizeof(uint64_t)) | |
320 | + return 0; | |
321 | + } | |
322 | + s->l2_cache_offsets[min_index] = l2_offset; | |
323 | + s->l2_cache_counts[min_index] = 1; | |
324 | + found: | |
325 | + l2_index = (offset >> s->cluster_bits) & (s->l2_size - 1); | |
326 | + cluster_offset = be64_to_cpu(l2_table[l2_index]); | |
327 | + if (!cluster_offset || | |
328 | + ((cluster_offset & QCOW_OFLAG_COMPRESSED) && allocate == 1)) { | |
329 | + if (!allocate) | |
330 | + return 0; | |
331 | + /* allocate a new cluster */ | |
332 | + if ((cluster_offset & QCOW_OFLAG_COMPRESSED) && | |
333 | + (n_end - n_start) < s->cluster_sectors) { | |
334 | + /* if the cluster is already compressed, we must | |
335 | + decompress it in the case it is not completely | |
336 | + overwritten */ | |
337 | + if (decompress_cluster(s, cluster_offset) < 0) | |
338 | + return 0; | |
339 | + cluster_offset = lseek64(s->fd, 0, SEEK_END); | |
340 | + cluster_offset = (cluster_offset + s->cluster_size - 1) & | |
341 | + ~(s->cluster_size - 1); | |
342 | + /* write the cluster content */ | |
343 | + lseek64(s->fd, cluster_offset, SEEK_SET); | |
344 | + if (write(s->fd, s->cluster_cache, s->cluster_size) != | |
345 | + s->cluster_size) | |
346 | + return -1; | |
347 | + } else { | |
348 | + cluster_offset = lseek64(s->fd, 0, SEEK_END); | |
349 | + if (allocate == 1) { | |
350 | + /* round to cluster size */ | |
351 | + cluster_offset = (cluster_offset + s->cluster_size - 1) & | |
352 | + ~(s->cluster_size - 1); | |
353 | + ftruncate(s->fd, cluster_offset + s->cluster_size); | |
354 | + /* if encrypted, we must initialize the cluster | |
355 | + content which won't be written */ | |
356 | + if (s->crypt_method && | |
357 | + (n_end - n_start) < s->cluster_sectors) { | |
358 | + uint64_t start_sect; | |
359 | + start_sect = (offset & ~(s->cluster_size - 1)) >> 9; | |
360 | + memset(s->cluster_data + 512, 0xaa, 512); | |
361 | + for(i = 0; i < s->cluster_sectors; i++) { | |
362 | + if (i < n_start || i >= n_end) { | |
363 | + encrypt_sectors(s, start_sect + i, | |
364 | + s->cluster_data, | |
365 | + s->cluster_data + 512, 1, 1, | |
366 | + &s->aes_encrypt_key); | |
367 | + lseek64(s->fd, cluster_offset + i * 512, SEEK_SET); | |
368 | + if (write(s->fd, s->cluster_data, 512) != 512) | |
369 | + return -1; | |
370 | + } | |
371 | + } | |
372 | + } | |
373 | + } else { | |
374 | + cluster_offset |= QCOW_OFLAG_COMPRESSED | | |
375 | + (uint64_t)compressed_size << (63 - s->cluster_bits); | |
376 | + } | |
377 | + } | |
378 | + /* update L2 table */ | |
379 | + tmp = cpu_to_be64(cluster_offset); | |
380 | + l2_table[l2_index] = tmp; | |
381 | + lseek64(s->fd, l2_offset + l2_index * sizeof(tmp), SEEK_SET); | |
382 | + if (write(s->fd, &tmp, sizeof(tmp)) != sizeof(tmp)) | |
383 | + return 0; | |
384 | + } | |
385 | + return cluster_offset; | |
386 | +} | |
387 | + | |
388 | +static int qcow_is_allocated(BlockDriverState *bs, int64_t sector_num, | |
389 | + int nb_sectors, int *pnum) | |
390 | +{ | |
391 | + BDRVQcowState *s = bs->opaque; | |
392 | + int index_in_cluster, n; | |
393 | + uint64_t cluster_offset; | |
394 | + | |
395 | + cluster_offset = get_cluster_offset(bs, sector_num << 9, 0, 0, 0, 0); | |
396 | + index_in_cluster = sector_num & (s->cluster_sectors - 1); | |
397 | + n = s->cluster_sectors - index_in_cluster; | |
398 | + if (n > nb_sectors) | |
399 | + n = nb_sectors; | |
400 | + *pnum = n; | |
401 | + return (cluster_offset != 0); | |
402 | +} | |
403 | + | |
404 | +static int decompress_buffer(uint8_t *out_buf, int out_buf_size, | |
405 | + const uint8_t *buf, int buf_size) | |
406 | +{ | |
407 | + z_stream strm1, *strm = &strm1; | |
408 | + int ret, out_len; | |
409 | + | |
410 | + memset(strm, 0, sizeof(*strm)); | |
411 | + | |
412 | + strm->next_in = (uint8_t *)buf; | |
413 | + strm->avail_in = buf_size; | |
414 | + strm->next_out = out_buf; | |
415 | + strm->avail_out = out_buf_size; | |
416 | + | |
417 | + ret = inflateInit2(strm, -12); | |
418 | + if (ret != Z_OK) | |
419 | + return -1; | |
420 | + ret = inflate(strm, Z_FINISH); | |
421 | + out_len = strm->next_out - out_buf; | |
422 | + if ((ret != Z_STREAM_END && ret != Z_BUF_ERROR) || | |
423 | + out_len != out_buf_size) { | |
424 | + inflateEnd(strm); | |
425 | + return -1; | |
426 | + } | |
427 | + inflateEnd(strm); | |
428 | + return 0; | |
429 | +} | |
430 | + | |
431 | +static int decompress_cluster(BDRVQcowState *s, uint64_t cluster_offset) | |
432 | +{ | |
433 | + int ret, csize; | |
434 | + uint64_t coffset; | |
435 | + | |
436 | + coffset = cluster_offset & s->cluster_offset_mask; | |
437 | + if (s->cluster_cache_offset != coffset) { | |
438 | + csize = cluster_offset >> (63 - s->cluster_bits); | |
439 | + csize &= (s->cluster_size - 1); | |
440 | + lseek64(s->fd, coffset, SEEK_SET); | |
441 | + ret = read(s->fd, s->cluster_data, csize); | |
442 | + if (ret != csize) | |
443 | + return -1; | |
444 | + if (decompress_buffer(s->cluster_cache, s->cluster_size, | |
445 | + s->cluster_data, csize) < 0) { | |
446 | + return -1; | |
447 | + } | |
448 | + s->cluster_cache_offset = coffset; | |
449 | + } | |
450 | + return 0; | |
451 | +} | |
452 | + | |
453 | +static int qcow_read(BlockDriverState *bs, int64_t sector_num, | |
454 | + uint8_t *buf, int nb_sectors) | |
455 | +{ | |
456 | + BDRVQcowState *s = bs->opaque; | |
457 | + int ret, index_in_cluster, n; | |
458 | + uint64_t cluster_offset; | |
459 | + | |
460 | + while (nb_sectors > 0) { | |
461 | + cluster_offset = get_cluster_offset(bs, sector_num << 9, 0, 0, 0, 0); | |
462 | + index_in_cluster = sector_num & (s->cluster_sectors - 1); | |
463 | + n = s->cluster_sectors - index_in_cluster; | |
464 | + if (n > nb_sectors) | |
465 | + n = nb_sectors; | |
466 | + if (!cluster_offset) { | |
467 | + memset(buf, 0, 512 * n); | |
468 | + } else if (cluster_offset & QCOW_OFLAG_COMPRESSED) { | |
469 | + if (decompress_cluster(s, cluster_offset) < 0) | |
470 | + return -1; | |
471 | + memcpy(buf, s->cluster_cache + index_in_cluster * 512, 512 * n); | |
472 | + } else { | |
473 | + lseek64(s->fd, cluster_offset + index_in_cluster * 512, SEEK_SET); | |
474 | + ret = read(s->fd, buf, n * 512); | |
475 | + if (ret != n * 512) | |
476 | + return -1; | |
477 | + if (s->crypt_method) { | |
478 | + encrypt_sectors(s, sector_num, buf, buf, n, 0, | |
479 | + &s->aes_decrypt_key); | |
480 | + } | |
481 | + } | |
482 | + nb_sectors -= n; | |
483 | + sector_num += n; | |
484 | + buf += n * 512; | |
485 | + } | |
486 | + return 0; | |
487 | +} | |
488 | + | |
489 | +static int qcow_write(BlockDriverState *bs, int64_t sector_num, | |
490 | + const uint8_t *buf, int nb_sectors) | |
491 | +{ | |
492 | + BDRVQcowState *s = bs->opaque; | |
493 | + int ret, index_in_cluster, n; | |
494 | + uint64_t cluster_offset; | |
495 | + | |
496 | + while (nb_sectors > 0) { | |
497 | + index_in_cluster = sector_num & (s->cluster_sectors - 1); | |
498 | + n = s->cluster_sectors - index_in_cluster; | |
499 | + if (n > nb_sectors) | |
500 | + n = nb_sectors; | |
501 | + cluster_offset = get_cluster_offset(bs, sector_num << 9, 1, 0, | |
502 | + index_in_cluster, | |
503 | + index_in_cluster + n); | |
504 | + if (!cluster_offset) | |
505 | + return -1; | |
506 | + lseek64(s->fd, cluster_offset + index_in_cluster * 512, SEEK_SET); | |
507 | + if (s->crypt_method) { | |
508 | + encrypt_sectors(s, sector_num, s->cluster_data, buf, n, 1, | |
509 | + &s->aes_encrypt_key); | |
510 | + ret = write(s->fd, s->cluster_data, n * 512); | |
511 | + } else { | |
512 | + ret = write(s->fd, buf, n * 512); | |
513 | + } | |
514 | + if (ret != n * 512) | |
515 | + return -1; | |
516 | + nb_sectors -= n; | |
517 | + sector_num += n; | |
518 | + buf += n * 512; | |
519 | + } | |
520 | + s->cluster_cache_offset = -1; /* disable compressed cache */ | |
521 | + return 0; | |
522 | +} | |
523 | + | |
524 | +static int qcow_close(BlockDriverState *bs) | |
525 | +{ | |
526 | + BDRVQcowState *s = bs->opaque; | |
527 | + qemu_free(s->l1_table); | |
528 | + qemu_free(s->l2_cache); | |
529 | + qemu_free(s->cluster_cache); | |
530 | + qemu_free(s->cluster_data); | |
531 | + close(s->fd); | |
532 | +} | |
533 | + | |
534 | +static int qcow_create(const char *filename, int64_t total_size, | |
535 | + const char *backing_file, int flags) | |
536 | +{ | |
537 | + int fd, header_size, backing_filename_len, l1_size, i, shift; | |
538 | + QCowHeader header; | |
539 | + char backing_filename[1024]; | |
540 | + uint64_t tmp; | |
541 | + struct stat st; | |
542 | + | |
543 | + fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE, | |
544 | + 0644); | |
545 | + if (fd < 0) | |
546 | + return -1; | |
547 | + memset(&header, 0, sizeof(header)); | |
548 | + header.magic = cpu_to_be32(QCOW_MAGIC); | |
549 | + header.version = cpu_to_be32(QCOW_VERSION); | |
550 | + header.size = cpu_to_be64(total_size * 512); | |
551 | + header_size = sizeof(header); | |
552 | + backing_filename_len = 0; | |
553 | + if (backing_file) { | |
554 | + realpath(backing_file, backing_filename); | |
555 | + if (stat(backing_filename, &st) != 0) { | |
556 | + return -1; | |
557 | + } | |
558 | + header.mtime = cpu_to_be32(st.st_mtime); | |
559 | + header.backing_file_offset = cpu_to_be64(header_size); | |
560 | + backing_filename_len = strlen(backing_filename); | |
561 | + header.backing_file_size = cpu_to_be32(backing_filename_len); | |
562 | + header_size += backing_filename_len; | |
563 | + header.cluster_bits = 9; /* 512 byte cluster to avoid copying | |
564 | + unmodifyed sectors */ | |
565 | + header.l2_bits = 12; /* 32 KB L2 tables */ | |
566 | + } else { | |
567 | + header.cluster_bits = 12; /* 4 KB clusters */ | |
568 | + header.l2_bits = 9; /* 4 KB L2 tables */ | |
569 | + } | |
570 | + header_size = (header_size + 7) & ~7; | |
571 | + shift = header.cluster_bits + header.l2_bits; | |
572 | + l1_size = ((total_size * 512) + (1LL << shift) - 1) >> shift; | |
573 | + | |
574 | + header.l1_table_offset = cpu_to_be64(header_size); | |
575 | + if (flags) { | |
576 | + header.crypt_method = cpu_to_be32(QCOW_CRYPT_AES); | |
577 | + } else { | |
578 | + header.crypt_method = cpu_to_be32(QCOW_CRYPT_NONE); | |
579 | + } | |
580 | + | |
581 | + /* write all the data */ | |
582 | + write(fd, &header, sizeof(header)); | |
583 | + if (backing_file) { | |
584 | + write(fd, backing_filename, backing_filename_len); | |
585 | + } | |
586 | + lseek(fd, header_size, SEEK_SET); | |
587 | + tmp = 0; | |
588 | + for(i = 0;i < l1_size; i++) { | |
589 | + write(fd, &tmp, sizeof(tmp)); | |
590 | + } | |
591 | + close(fd); | |
592 | + return 0; | |
593 | +} | |
594 | + | |
595 | +int qcow_get_cluster_size(BlockDriverState *bs) | |
596 | +{ | |
597 | + BDRVQcowState *s = bs->opaque; | |
598 | + if (bs->drv != &bdrv_qcow) | |
599 | + return -1; | |
600 | + return s->cluster_size; | |
601 | +} | |
602 | + | |
603 | +/* XXX: put compressed sectors first, then all the cluster aligned | |
604 | + tables to avoid losing bytes in alignment */ | |
605 | +int qcow_compress_cluster(BlockDriverState *bs, int64_t sector_num, | |
606 | + const uint8_t *buf) | |
607 | +{ | |
608 | + BDRVQcowState *s = bs->opaque; | |
609 | + z_stream strm; | |
610 | + int ret, out_len; | |
611 | + uint8_t *out_buf; | |
612 | + uint64_t cluster_offset; | |
613 | + | |
614 | + if (bs->drv != &bdrv_qcow) | |
615 | + return -1; | |
616 | + | |
617 | + out_buf = qemu_malloc(s->cluster_size + (s->cluster_size / 1000) + 128); | |
618 | + if (!out_buf) | |
619 | + return -1; | |
620 | + | |
621 | + /* best compression, small window, no zlib header */ | |
622 | + memset(&strm, 0, sizeof(strm)); | |
623 | + ret = deflateInit2(&strm, Z_DEFAULT_COMPRESSION, | |
624 | + Z_DEFLATED, -12, | |
625 | + 9, Z_DEFAULT_STRATEGY); | |
626 | + if (ret != 0) { | |
627 | + qemu_free(out_buf); | |
628 | + return -1; | |
629 | + } | |
630 | + | |
631 | + strm.avail_in = s->cluster_size; | |
632 | + strm.next_in = (uint8_t *)buf; | |
633 | + strm.avail_out = s->cluster_size; | |
634 | + strm.next_out = out_buf; | |
635 | + | |
636 | + ret = deflate(&strm, Z_FINISH); | |
637 | + if (ret != Z_STREAM_END && ret != Z_OK) { | |
638 | + qemu_free(out_buf); | |
639 | + deflateEnd(&strm); | |
640 | + return -1; | |
641 | + } | |
642 | + out_len = strm.next_out - out_buf; | |
643 | + | |
644 | + deflateEnd(&strm); | |
645 | + | |
646 | + if (ret != Z_STREAM_END || out_len >= s->cluster_size) { | |
647 | + /* could not compress: write normal cluster */ | |
648 | + qcow_write(bs, sector_num, buf, s->cluster_sectors); | |
649 | + } else { | |
650 | + cluster_offset = get_cluster_offset(bs, sector_num << 9, 2, | |
651 | + out_len, 0, 0); | |
652 | + cluster_offset &= s->cluster_offset_mask; | |
653 | + lseek64(s->fd, cluster_offset, SEEK_SET); | |
654 | + if (write(s->fd, out_buf, out_len) != out_len) { | |
655 | + qemu_free(out_buf); | |
656 | + return -1; | |
657 | + } | |
658 | + } | |
659 | + | |
660 | + qemu_free(out_buf); | |
661 | + return 0; | |
662 | +} | |
663 | + | |
664 | +BlockDriver bdrv_qcow = { | |
665 | + "qcow", | |
666 | + sizeof(BDRVQcowState), | |
667 | + qcow_probe, | |
668 | + qcow_open, | |
669 | + qcow_read, | |
670 | + qcow_write, | |
671 | + qcow_close, | |
672 | + qcow_create, | |
673 | + qcow_is_allocated, | |
674 | + qcow_set_key, | |
675 | +}; | |
676 | + | |
677 | + | ... | ... |
block-vmdk.c
0 → 100644
1 | +/* | |
2 | + * Block driver for the VMDK 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 | +#include "vl.h" | |
25 | +#include "block_int.h" | |
26 | + | |
27 | +/* XXX: this code is untested */ | |
28 | +/* XXX: add write support */ | |
29 | + | |
30 | +#define VMDK3_MAGIC (('C' << 24) | ('O' << 16) | ('W' << 8) | 'D') | |
31 | +#define VMDK4_MAGIC (('K' << 24) | ('D' << 16) | ('M' << 8) | 'V') | |
32 | + | |
33 | +typedef struct { | |
34 | + uint32_t version; | |
35 | + uint32_t flags; | |
36 | + uint32_t disk_sectors; | |
37 | + uint32_t granularity; | |
38 | + uint32_t l1dir_offset; | |
39 | + uint32_t l1dir_size; | |
40 | + uint32_t file_sectors; | |
41 | + uint32_t cylinders; | |
42 | + uint32_t heads; | |
43 | + uint32_t sectors_per_track; | |
44 | +} VMDK3Header; | |
45 | + | |
46 | +typedef struct { | |
47 | + uint32_t version; | |
48 | + uint32_t flags; | |
49 | + int64_t capacity; | |
50 | + int64_t granularity; | |
51 | + int64_t desc_offset; | |
52 | + int64_t desc_size; | |
53 | + int32_t num_gtes_per_gte; | |
54 | + int64_t rgd_offset; | |
55 | + int64_t gd_offset; | |
56 | + int64_t grain_offset; | |
57 | + char filler[1]; | |
58 | + char check_bytes[4]; | |
59 | +} VMDK4Header; | |
60 | + | |
61 | +#define L2_CACHE_SIZE 16 | |
62 | + | |
63 | +typedef struct BDRVVmdkState { | |
64 | + int fd; | |
65 | + int64_t l1_table_offset; | |
66 | + uint32_t *l1_table; | |
67 | + unsigned int l1_size; | |
68 | + uint32_t l1_entry_sectors; | |
69 | + | |
70 | + unsigned int l2_size; | |
71 | + uint32_t *l2_cache; | |
72 | + uint32_t l2_cache_offsets[L2_CACHE_SIZE]; | |
73 | + uint32_t l2_cache_counts[L2_CACHE_SIZE]; | |
74 | + | |
75 | + unsigned int cluster_sectors; | |
76 | +} BDRVVmdkState; | |
77 | + | |
78 | +static int vmdk_probe(const uint8_t *buf, int buf_size, const char *filename) | |
79 | +{ | |
80 | + uint32_t magic; | |
81 | + | |
82 | + if (buf_size < 4) | |
83 | + return 0; | |
84 | + magic = be32_to_cpu(*(uint32_t *)buf); | |
85 | + if (magic == VMDK3_MAGIC || | |
86 | + magic == VMDK4_MAGIC) | |
87 | + return 100; | |
88 | + else | |
89 | + return 0; | |
90 | +} | |
91 | + | |
92 | +static int vmdk_open(BlockDriverState *bs, const char *filename) | |
93 | +{ | |
94 | + BDRVVmdkState *s = bs->opaque; | |
95 | + int fd, i; | |
96 | + uint32_t magic; | |
97 | + int l1_size; | |
98 | + | |
99 | + fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE); | |
100 | + if (fd < 0) | |
101 | + return -1; | |
102 | + if (read(fd, &magic, sizeof(magic)) != sizeof(magic)) | |
103 | + goto fail; | |
104 | + magic = le32_to_cpu(magic); | |
105 | + | |
106 | + if (magic == VMDK3_MAGIC) { | |
107 | + VMDK3Header header; | |
108 | + if (read(fd, &header, sizeof(header)) != | |
109 | + sizeof(header)) | |
110 | + goto fail; | |
111 | + s->cluster_sectors = le32_to_cpu(header.granularity); | |
112 | + s->l2_size = 1 << 9; | |
113 | + s->l1_size = 1 << 6; | |
114 | + bs->total_sectors = le32_to_cpu(header.disk_sectors); | |
115 | + s->l1_table_offset = le32_to_cpu(header.l1dir_offset) * 512; | |
116 | + s->l1_entry_sectors = s->l2_size * s->cluster_sectors; | |
117 | + } else if (magic == VMDK4_MAGIC) { | |
118 | + VMDK4Header header; | |
119 | + | |
120 | + if (read(fd, &header, sizeof(header)) != sizeof(header)) | |
121 | + goto fail; | |
122 | + bs->total_sectors = le32_to_cpu(header.capacity); | |
123 | + s->cluster_sectors = le32_to_cpu(header.granularity); | |
124 | + s->l2_size = le32_to_cpu(header.num_gtes_per_gte); | |
125 | + s->l1_entry_sectors = s->l2_size * s->cluster_sectors; | |
126 | + if (s->l1_entry_sectors <= 0) | |
127 | + goto fail; | |
128 | + s->l1_size = (bs->total_sectors + s->l1_entry_sectors - 1) | |
129 | + / s->l1_entry_sectors; | |
130 | + s->l1_table_offset = le64_to_cpu(header.rgd_offset) * 512; | |
131 | + } else { | |
132 | + goto fail; | |
133 | + } | |
134 | + /* read the L1 table */ | |
135 | + l1_size = s->l1_size * sizeof(uint32_t); | |
136 | + s->l1_table = qemu_malloc(l1_size); | |
137 | + if (!s->l1_table) | |
138 | + goto fail; | |
139 | + if (read(s->fd, s->l1_table, l1_size) != l1_size) | |
140 | + goto fail; | |
141 | + for(i = 0; i < s->l1_size; i++) { | |
142 | + le32_to_cpus(&s->l1_table[i]); | |
143 | + } | |
144 | + | |
145 | + s->l2_cache = qemu_malloc(s->l2_size * L2_CACHE_SIZE * sizeof(uint32_t)); | |
146 | + if (!s->l2_cache) | |
147 | + goto fail; | |
148 | + s->fd = fd; | |
149 | + /* XXX: currently only read only */ | |
150 | + bs->read_only = 1; | |
151 | + return 0; | |
152 | + fail: | |
153 | + qemu_free(s->l1_table); | |
154 | + qemu_free(s->l2_cache); | |
155 | + close(fd); | |
156 | + return -1; | |
157 | +} | |
158 | + | |
159 | +static uint64_t get_cluster_offset(BlockDriverState *bs, | |
160 | + uint64_t offset) | |
161 | +{ | |
162 | + BDRVVmdkState *s = bs->opaque; | |
163 | + unsigned int l1_index, l2_offset, l2_index; | |
164 | + int min_index, i, j; | |
165 | + uint32_t min_count, *l2_table; | |
166 | + uint64_t cluster_offset; | |
167 | + | |
168 | + l1_index = (offset >> 9) / s->l1_entry_sectors; | |
169 | + if (l1_index >= s->l1_size) | |
170 | + return 0; | |
171 | + l2_offset = s->l1_table[l1_index]; | |
172 | + if (!l2_offset) | |
173 | + return 0; | |
174 | + | |
175 | + for(i = 0; i < L2_CACHE_SIZE; i++) { | |
176 | + if (l2_offset == s->l2_cache_offsets[i]) { | |
177 | + /* increment the hit count */ | |
178 | + if (++s->l2_cache_counts[i] == 0xffffffff) { | |
179 | + for(j = 0; j < L2_CACHE_SIZE; j++) { | |
180 | + s->l2_cache_counts[j] >>= 1; | |
181 | + } | |
182 | + } | |
183 | + l2_table = s->l2_cache + (i * s->l2_size); | |
184 | + goto found; | |
185 | + } | |
186 | + } | |
187 | + /* not found: load a new entry in the least used one */ | |
188 | + min_index = 0; | |
189 | + min_count = 0xffffffff; | |
190 | + for(i = 0; i < L2_CACHE_SIZE; i++) { | |
191 | + if (s->l2_cache_counts[i] < min_count) { | |
192 | + min_count = s->l2_cache_counts[i]; | |
193 | + min_index = i; | |
194 | + } | |
195 | + } | |
196 | + l2_table = s->l2_cache + (min_index * s->l2_size); | |
197 | + lseek(s->fd, (int64_t)l2_offset * 512, SEEK_SET); | |
198 | + if (read(s->fd, l2_table, s->l2_size * sizeof(uint32_t)) != | |
199 | + s->l2_size * sizeof(uint32_t)) | |
200 | + return 0; | |
201 | + s->l2_cache_offsets[min_index] = l2_offset; | |
202 | + s->l2_cache_counts[min_index] = 1; | |
203 | + found: | |
204 | + l2_index = ((offset >> 9) / s->cluster_sectors) % s->l2_size; | |
205 | + cluster_offset = le32_to_cpu(l2_table[l2_index]); | |
206 | + cluster_offset <<= 9; | |
207 | + return cluster_offset; | |
208 | +} | |
209 | + | |
210 | +static int vmdk_is_allocated(BlockDriverState *bs, int64_t sector_num, | |
211 | + int nb_sectors, int *pnum) | |
212 | +{ | |
213 | + BDRVVmdkState *s = bs->opaque; | |
214 | + int index_in_cluster, n; | |
215 | + uint64_t cluster_offset; | |
216 | + | |
217 | + cluster_offset = get_cluster_offset(bs, sector_num << 9); | |
218 | + index_in_cluster = sector_num % s->cluster_sectors; | |
219 | + n = s->cluster_sectors - index_in_cluster; | |
220 | + if (n > nb_sectors) | |
221 | + n = nb_sectors; | |
222 | + *pnum = n; | |
223 | + return (cluster_offset != 0); | |
224 | +} | |
225 | + | |
226 | +static int vmdk_read(BlockDriverState *bs, int64_t sector_num, | |
227 | + uint8_t *buf, int nb_sectors) | |
228 | +{ | |
229 | + BDRVVmdkState *s = bs->opaque; | |
230 | + int ret, index_in_cluster, n; | |
231 | + uint64_t cluster_offset; | |
232 | + | |
233 | + while (nb_sectors > 0) { | |
234 | + cluster_offset = get_cluster_offset(bs, sector_num << 9); | |
235 | + index_in_cluster = sector_num % s->cluster_sectors; | |
236 | + n = s->cluster_sectors - index_in_cluster; | |
237 | + if (n > nb_sectors) | |
238 | + n = nb_sectors; | |
239 | + if (!cluster_offset) { | |
240 | + memset(buf, 0, 512 * n); | |
241 | + } else { | |
242 | + lseek64(s->fd, cluster_offset + index_in_cluster * 512, SEEK_SET); | |
243 | + ret = read(s->fd, buf, n * 512); | |
244 | + if (ret != n * 512) | |
245 | + return -1; | |
246 | + } | |
247 | + nb_sectors -= n; | |
248 | + sector_num += n; | |
249 | + buf += n * 512; | |
250 | + } | |
251 | + return 0; | |
252 | +} | |
253 | + | |
254 | +static int vmdk_write(BlockDriverState *bs, int64_t sector_num, | |
255 | + const uint8_t *buf, int nb_sectors) | |
256 | +{ | |
257 | + return -1; | |
258 | +} | |
259 | + | |
260 | +static int vmdk_close(BlockDriverState *bs) | |
261 | +{ | |
262 | + BDRVVmdkState *s = bs->opaque; | |
263 | + qemu_free(s->l1_table); | |
264 | + qemu_free(s->l2_cache); | |
265 | + close(s->fd); | |
266 | +} | |
267 | + | |
268 | +BlockDriver bdrv_vmdk = { | |
269 | + "vmdk", | |
270 | + sizeof(BDRVVmdkState), | |
271 | + vmdk_probe, | |
272 | + vmdk_open, | |
273 | + vmdk_read, | |
274 | + vmdk_write, | |
275 | + vmdk_close, | |
276 | + NULL, /* no create yet */ | |
277 | + vmdk_is_allocated, | |
278 | +}; | ... | ... |
block.c
... | ... | @@ -22,43 +22,16 @@ |
22 | 22 | * THE SOFTWARE. |
23 | 23 | */ |
24 | 24 | #include "vl.h" |
25 | - | |
26 | -#ifndef _WIN32 | |
27 | -#include <sys/mman.h> | |
28 | -#endif | |
29 | - | |
30 | -#include "cow.h" | |
31 | - | |
32 | -struct BlockDriverState { | |
33 | - int fd; /* if -1, only COW mappings */ | |
34 | - int64_t total_sectors; | |
35 | - int read_only; /* if true, the media is read only */ | |
36 | - int inserted; /* if true, the media is present */ | |
37 | - int removable; /* if true, the media can be removed */ | |
38 | - int locked; /* if true, the media cannot temporarily be ejected */ | |
39 | - /* event callback when inserting/removing */ | |
40 | - void (*change_cb)(void *opaque); | |
41 | - void *change_opaque; | |
42 | - | |
43 | - uint8_t *cow_bitmap; /* if non NULL, COW mappings are used first */ | |
44 | - uint8_t *cow_bitmap_addr; /* mmap address of cow_bitmap */ | |
45 | - int cow_bitmap_size; | |
46 | - int cow_fd; | |
47 | - int64_t cow_sectors_offset; | |
48 | - int boot_sector_enabled; | |
49 | - uint8_t boot_sector_data[512]; | |
50 | - | |
51 | - char filename[1024]; | |
52 | - | |
53 | - /* NOTE: the following infos are only hints for real hardware | |
54 | - drivers. They are not used by the block driver */ | |
55 | - int cyls, heads, secs; | |
56 | - int type; | |
57 | - char device_name[32]; | |
58 | - BlockDriverState *next; | |
59 | -}; | |
25 | +#include "block_int.h" | |
60 | 26 | |
61 | 27 | static BlockDriverState *bdrv_first; |
28 | +static BlockDriver *first_drv; | |
29 | + | |
30 | +void bdrv_register(BlockDriver *bdrv) | |
31 | +{ | |
32 | + bdrv->next = first_drv; | |
33 | + first_drv = bdrv; | |
34 | +} | |
62 | 35 | |
63 | 36 | /* create a new block device (by default it is empty) */ |
64 | 37 | BlockDriverState *bdrv_new(const char *device_name) |
... | ... | @@ -69,126 +42,149 @@ BlockDriverState *bdrv_new(const char *device_name) |
69 | 42 | if(!bs) |
70 | 43 | return NULL; |
71 | 44 | pstrcpy(bs->device_name, sizeof(bs->device_name), device_name); |
72 | - /* insert at the end */ | |
73 | - pbs = &bdrv_first; | |
74 | - while (*pbs != NULL) | |
75 | - pbs = &(*pbs)->next; | |
76 | - *pbs = bs; | |
45 | + if (device_name[0] != '\0') { | |
46 | + /* insert at the end */ | |
47 | + pbs = &bdrv_first; | |
48 | + while (*pbs != NULL) | |
49 | + pbs = &(*pbs)->next; | |
50 | + *pbs = bs; | |
51 | + } | |
77 | 52 | return bs; |
78 | 53 | } |
79 | 54 | |
80 | -int bdrv_open(BlockDriverState *bs, const char *filename, int snapshot) | |
55 | +BlockDriver *bdrv_find_format(const char *format_name) | |
56 | +{ | |
57 | + BlockDriver *drv1; | |
58 | + for(drv1 = first_drv; drv1 != NULL; drv1 = drv1->next) { | |
59 | + if (!strcmp(drv1->format_name, format_name)) | |
60 | + return drv1; | |
61 | + } | |
62 | + return NULL; | |
63 | +} | |
64 | + | |
65 | +int bdrv_create(BlockDriver *drv, | |
66 | + const char *filename, int64_t size_in_sectors, | |
67 | + const char *backing_file, int flags) | |
68 | +{ | |
69 | + if (!drv->bdrv_create) | |
70 | + return -ENOTSUP; | |
71 | + return drv->bdrv_create(filename, size_in_sectors, backing_file, flags); | |
72 | +} | |
73 | + | |
74 | +/* XXX: race condition possible */ | |
75 | +static void get_tmp_filename(char *filename, int size) | |
81 | 76 | { |
82 | 77 | int fd; |
83 | - int64_t size; | |
84 | - struct cow_header_v2 cow_header; | |
85 | -#ifndef _WIN32 | |
86 | - char template[] = "/tmp/vl.XXXXXX"; | |
87 | - int cow_fd; | |
88 | - struct stat st; | |
89 | -#endif | |
78 | + pstrcpy(filename, size, "/tmp/vl.XXXXXX"); | |
79 | + fd = mkstemp(filename); | |
80 | + close(fd); | |
81 | +} | |
90 | 82 | |
91 | - bs->read_only = 0; | |
92 | - bs->fd = -1; | |
93 | - bs->cow_fd = -1; | |
94 | - bs->cow_bitmap = NULL; | |
95 | - pstrcpy(bs->filename, sizeof(bs->filename), filename); | |
83 | +static BlockDriver *find_image_format(const char *filename) | |
84 | +{ | |
85 | + int fd, ret, score, score_max; | |
86 | + BlockDriver *drv1, *drv; | |
87 | + uint8_t buf[1024]; | |
96 | 88 | |
97 | - /* open standard HD image */ | |
98 | -#ifdef _WIN32 | |
99 | - fd = open(filename, O_RDWR | O_BINARY); | |
100 | -#else | |
101 | - fd = open(filename, O_RDWR | O_LARGEFILE); | |
102 | -#endif | |
103 | - if (fd < 0) { | |
104 | - /* read only image on disk */ | |
105 | -#ifdef _WIN32 | |
106 | - fd = open(filename, O_RDONLY | O_BINARY); | |
107 | -#else | |
108 | - fd = open(filename, O_RDONLY | O_LARGEFILE); | |
109 | -#endif | |
110 | - if (fd < 0) { | |
111 | - perror(filename); | |
112 | - goto fail; | |
89 | + fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE); | |
90 | + if (fd < 0) | |
91 | + return NULL; | |
92 | + ret = read(fd, buf, sizeof(buf)); | |
93 | + if (ret < 0) { | |
94 | + close(fd); | |
95 | + return NULL; | |
96 | + } | |
97 | + close(fd); | |
98 | + | |
99 | + drv = NULL; | |
100 | + score_max = 0; | |
101 | + for(drv1 = first_drv; drv1 != NULL; drv1 = drv1->next) { | |
102 | + score = drv1->bdrv_probe(buf, ret, filename); | |
103 | + if (score > score_max) { | |
104 | + score_max = score; | |
105 | + drv = drv1; | |
113 | 106 | } |
114 | - if (!snapshot) | |
115 | - bs->read_only = 1; | |
116 | 107 | } |
117 | - bs->fd = fd; | |
108 | + return drv; | |
109 | +} | |
110 | + | |
111 | +int bdrv_open(BlockDriverState *bs, const char *filename, int snapshot) | |
112 | +{ | |
113 | + return bdrv_open2(bs, filename, snapshot, NULL); | |
114 | +} | |
115 | + | |
116 | +int bdrv_open2(BlockDriverState *bs, const char *filename, int snapshot, | |
117 | + BlockDriver *drv) | |
118 | +{ | |
119 | + int ret; | |
120 | + char tmp_filename[1024]; | |
121 | + | |
122 | + bs->read_only = 0; | |
123 | + bs->is_temporary = 0; | |
124 | + bs->encrypted = 0; | |
125 | + | |
126 | + if (snapshot) { | |
127 | + BlockDriverState *bs1; | |
128 | + int64_t total_size; | |
129 | + | |
130 | + /* if snapshot, we create a temporary backing file and open it | |
131 | + instead of opening 'filename' directly */ | |
118 | 132 | |
119 | - /* see if it is a cow image */ | |
120 | - if (read(fd, &cow_header, sizeof(cow_header)) != sizeof(cow_header)) { | |
121 | - fprintf(stderr, "%s: could not read header\n", filename); | |
122 | - goto fail; | |
133 | + /* if there is a backing file, use it */ | |
134 | + bs1 = bdrv_new(""); | |
135 | + if (!bs1) { | |
136 | + return -1; | |
137 | + } | |
138 | + if (bdrv_open(bs1, filename, 0) < 0) { | |
139 | + bdrv_delete(bs1); | |
140 | + return -1; | |
141 | + } | |
142 | + total_size = bs1->total_sectors; | |
143 | + bdrv_delete(bs1); | |
144 | + | |
145 | + get_tmp_filename(tmp_filename, sizeof(tmp_filename)); | |
146 | + /* XXX: use cow for linux as it is more efficient ? */ | |
147 | + if (bdrv_create(&bdrv_qcow, tmp_filename, | |
148 | + total_size, filename, 0) < 0) { | |
149 | + return -1; | |
150 | + } | |
151 | + filename = tmp_filename; | |
152 | + bs->is_temporary = 1; | |
153 | + } | |
154 | + | |
155 | + pstrcpy(bs->filename, sizeof(bs->filename), filename); | |
156 | + if (!drv) { | |
157 | + drv = find_image_format(filename); | |
158 | + if (!drv) | |
159 | + return -1; | |
160 | + } | |
161 | + bs->drv = drv; | |
162 | + bs->opaque = qemu_mallocz(drv->instance_size); | |
163 | + if (bs->opaque == NULL && drv->instance_size > 0) | |
164 | + return -1; | |
165 | + | |
166 | + ret = drv->bdrv_open(bs, filename); | |
167 | + if (ret < 0) { | |
168 | + qemu_free(bs->opaque); | |
169 | + return -1; | |
123 | 170 | } |
124 | 171 | #ifndef _WIN32 |
125 | - if (be32_to_cpu(cow_header.magic) == COW_MAGIC && | |
126 | - be32_to_cpu(cow_header.version) == COW_VERSION) { | |
127 | - /* cow image found */ | |
128 | - size = cow_header.size; | |
129 | -#ifndef WORDS_BIGENDIAN | |
130 | - size = bswap64(size); | |
131 | -#endif | |
132 | - bs->total_sectors = size / 512; | |
133 | - | |
134 | - bs->cow_fd = fd; | |
135 | - bs->fd = -1; | |
136 | - if (cow_header.backing_file[0] != '\0') { | |
137 | - if (stat(cow_header.backing_file, &st) != 0) { | |
138 | - fprintf(stderr, "%s: could not find original disk image '%s'\n", filename, cow_header.backing_file); | |
139 | - goto fail; | |
140 | - } | |
141 | - if (st.st_mtime != be32_to_cpu(cow_header.mtime)) { | |
142 | - fprintf(stderr, "%s: original raw disk image '%s' does not match saved timestamp\n", filename, cow_header.backing_file); | |
143 | - goto fail; | |
144 | - } | |
145 | - fd = open(cow_header.backing_file, O_RDONLY | O_LARGEFILE); | |
146 | - if (fd < 0) | |
147 | - goto fail; | |
148 | - bs->fd = fd; | |
172 | + if (bs->is_temporary) { | |
173 | + unlink(filename); | |
174 | + } | |
175 | +#endif | |
176 | + if (bs->backing_file[0] != '\0' && drv->bdrv_is_allocated) { | |
177 | + /* if there is a backing file, use it */ | |
178 | + bs->backing_hd = bdrv_new(""); | |
179 | + if (!bs->backing_hd) { | |
180 | + fail: | |
181 | + bdrv_close(bs); | |
182 | + return -1; | |
149 | 183 | } |
150 | - /* mmap the bitmap */ | |
151 | - bs->cow_bitmap_size = ((bs->total_sectors + 7) >> 3) + sizeof(cow_header); | |
152 | - bs->cow_bitmap_addr = mmap(get_mmap_addr(bs->cow_bitmap_size), | |
153 | - bs->cow_bitmap_size, | |
154 | - PROT_READ | PROT_WRITE, | |
155 | - MAP_SHARED, bs->cow_fd, 0); | |
156 | - if (bs->cow_bitmap_addr == MAP_FAILED) | |
184 | + if (bdrv_open(bs->backing_hd, bs->backing_file, 0) < 0) | |
157 | 185 | goto fail; |
158 | - bs->cow_bitmap = bs->cow_bitmap_addr + sizeof(cow_header); | |
159 | - bs->cow_sectors_offset = (bs->cow_bitmap_size + 511) & ~511; | |
160 | - snapshot = 0; | |
161 | - } else | |
162 | -#endif | |
163 | - { | |
164 | - /* standard raw image */ | |
165 | - size = lseek64(fd, 0, SEEK_END); | |
166 | - bs->total_sectors = size / 512; | |
167 | - bs->fd = fd; | |
168 | 186 | } |
169 | 187 | |
170 | -#ifndef _WIN32 | |
171 | - if (snapshot) { | |
172 | - /* create a temporary COW file */ | |
173 | - cow_fd = mkstemp64(template); | |
174 | - if (cow_fd < 0) | |
175 | - goto fail; | |
176 | - bs->cow_fd = cow_fd; | |
177 | - unlink(template); | |
178 | - | |
179 | - /* just need to allocate bitmap */ | |
180 | - bs->cow_bitmap_size = (bs->total_sectors + 7) >> 3; | |
181 | - bs->cow_bitmap_addr = mmap(get_mmap_addr(bs->cow_bitmap_size), | |
182 | - bs->cow_bitmap_size, | |
183 | - PROT_READ | PROT_WRITE, | |
184 | - MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); | |
185 | - if (bs->cow_bitmap_addr == MAP_FAILED) | |
186 | - goto fail; | |
187 | - bs->cow_bitmap = bs->cow_bitmap_addr; | |
188 | - bs->cow_sectors_offset = 0; | |
189 | - } | |
190 | -#endif | |
191 | - | |
192 | 188 | bs->inserted = 1; |
193 | 189 | |
194 | 190 | /* call the change callback */ |
... | ... | @@ -196,23 +192,22 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int snapshot) |
196 | 192 | bs->change_cb(bs->change_opaque); |
197 | 193 | |
198 | 194 | return 0; |
199 | - fail: | |
200 | - bdrv_close(bs); | |
201 | - return -1; | |
202 | 195 | } |
203 | 196 | |
204 | 197 | void bdrv_close(BlockDriverState *bs) |
205 | 198 | { |
206 | 199 | if (bs->inserted) { |
207 | -#ifndef _WIN32 | |
208 | - /* we unmap the mapping so that it is written to the COW file */ | |
209 | - if (bs->cow_bitmap_addr) | |
210 | - munmap(bs->cow_bitmap_addr, bs->cow_bitmap_size); | |
200 | + if (bs->backing_hd) | |
201 | + bdrv_delete(bs->backing_hd); | |
202 | + bs->drv->bdrv_close(bs); | |
203 | + qemu_free(bs->opaque); | |
204 | +#ifdef _WIN32 | |
205 | + if (bs->is_temporary) { | |
206 | + unlink(bs->filename); | |
207 | + } | |
211 | 208 | #endif |
212 | - if (bs->cow_fd >= 0) | |
213 | - close(bs->cow_fd); | |
214 | - if (bs->fd >= 0) | |
215 | - close(bs->fd); | |
209 | + bs->opaque = NULL; | |
210 | + bs->drv = NULL; | |
216 | 211 | bs->inserted = 0; |
217 | 212 | |
218 | 213 | /* call the change callback */ |
... | ... | @@ -223,85 +218,45 @@ void bdrv_close(BlockDriverState *bs) |
223 | 218 | |
224 | 219 | void bdrv_delete(BlockDriverState *bs) |
225 | 220 | { |
221 | + /* XXX: remove the driver list */ | |
226 | 222 | bdrv_close(bs); |
227 | 223 | qemu_free(bs); |
228 | 224 | } |
229 | 225 | |
230 | -static inline void set_bit(uint8_t *bitmap, int64_t bitnum) | |
231 | -{ | |
232 | - bitmap[bitnum / 8] |= (1 << (bitnum%8)); | |
233 | -} | |
234 | - | |
235 | -static inline int is_bit_set(const uint8_t *bitmap, int64_t bitnum) | |
236 | -{ | |
237 | - return !!(bitmap[bitnum / 8] & (1 << (bitnum%8))); | |
238 | -} | |
239 | - | |
240 | - | |
241 | -/* Return true if first block has been changed (ie. current version is | |
242 | - * in COW file). Set the number of continuous blocks for which that | |
243 | - * is true. */ | |
244 | -static int is_changed(uint8_t *bitmap, | |
245 | - int64_t sector_num, int nb_sectors, | |
246 | - int *num_same) | |
247 | -{ | |
248 | - int changed; | |
249 | - | |
250 | - if (!bitmap || nb_sectors == 0) { | |
251 | - *num_same = nb_sectors; | |
252 | - return 0; | |
253 | - } | |
254 | - | |
255 | - changed = is_bit_set(bitmap, sector_num); | |
256 | - for (*num_same = 1; *num_same < nb_sectors; (*num_same)++) { | |
257 | - if (is_bit_set(bitmap, sector_num + *num_same) != changed) | |
258 | - break; | |
259 | - } | |
260 | - | |
261 | - return changed; | |
262 | -} | |
263 | - | |
264 | 226 | /* commit COW file into the raw image */ |
265 | 227 | int bdrv_commit(BlockDriverState *bs) |
266 | 228 | { |
267 | 229 | int64_t i; |
268 | - uint8_t *cow_bitmap; | |
230 | + int n, j; | |
231 | + unsigned char sector[512]; | |
269 | 232 | |
270 | 233 | if (!bs->inserted) |
271 | - return -1; | |
272 | - | |
273 | - if (!bs->cow_bitmap) { | |
274 | - fprintf(stderr, "Already committed to %s\n", bs->filename); | |
275 | - return 0; | |
276 | - } | |
234 | + return -ENOENT; | |
277 | 235 | |
278 | 236 | if (bs->read_only) { |
279 | - fprintf(stderr, "Can't commit to %s: read-only\n", bs->filename); | |
280 | - return -1; | |
237 | + return -EACCES; | |
281 | 238 | } |
282 | 239 | |
283 | - cow_bitmap = bs->cow_bitmap; | |
284 | - for (i = 0; i < bs->total_sectors; i++) { | |
285 | - if (is_bit_set(cow_bitmap, i)) { | |
286 | - unsigned char sector[512]; | |
287 | - if (bdrv_read(bs, i, sector, 1) != 0) { | |
288 | - fprintf(stderr, "Error reading sector %lli: aborting commit\n", | |
289 | - (long long)i); | |
290 | - return -1; | |
291 | - } | |
240 | + if (!bs->backing_hd) { | |
241 | + return -ENOTSUP; | |
242 | + } | |
292 | 243 | |
293 | - /* Make bdrv_write write to real file for a moment. */ | |
294 | - bs->cow_bitmap = NULL; | |
295 | - if (bdrv_write(bs, i, sector, 1) != 0) { | |
296 | - fprintf(stderr, "Error writing sector %lli: aborting commit\n", | |
297 | - (long long)i); | |
298 | - bs->cow_bitmap = cow_bitmap; | |
299 | - return -1; | |
244 | + for (i = 0; i < bs->total_sectors;) { | |
245 | + if (bs->drv->bdrv_is_allocated(bs, i, 65536, &n)) { | |
246 | + for(j = 0; j < n; j++) { | |
247 | + if (bdrv_read(bs, i, sector, 1) != 0) { | |
248 | + return -EIO; | |
249 | + } | |
250 | + | |
251 | + if (bdrv_write(bs->backing_hd, i, sector, 1) != 0) { | |
252 | + return -EIO; | |
253 | + } | |
254 | + i++; | |
300 | 255 | } |
301 | - bs->cow_bitmap = cow_bitmap; | |
302 | - } | |
256 | + } else { | |
257 | + i += n; | |
258 | + } | |
303 | 259 | } |
304 | - fprintf(stderr, "Committed snapshot to %s\n", bs->filename); | |
305 | 260 | return 0; |
306 | 261 | } |
307 | 262 | |
... | ... | @@ -309,37 +264,34 @@ int bdrv_commit(BlockDriverState *bs) |
309 | 264 | int bdrv_read(BlockDriverState *bs, int64_t sector_num, |
310 | 265 | uint8_t *buf, int nb_sectors) |
311 | 266 | { |
312 | - int ret, n, fd; | |
313 | - int64_t offset; | |
314 | - | |
267 | + int ret, n; | |
268 | + BlockDriver *drv = bs->drv; | |
269 | + | |
315 | 270 | if (!bs->inserted) |
316 | 271 | return -1; |
317 | 272 | |
318 | 273 | while (nb_sectors > 0) { |
319 | - if (is_changed(bs->cow_bitmap, sector_num, nb_sectors, &n)) { | |
320 | - fd = bs->cow_fd; | |
321 | - offset = bs->cow_sectors_offset; | |
322 | - } else if (sector_num == 0 && bs->boot_sector_enabled) { | |
274 | + if (sector_num == 0 && bs->boot_sector_enabled) { | |
323 | 275 | memcpy(buf, bs->boot_sector_data, 512); |
324 | 276 | n = 1; |
325 | - goto next; | |
326 | - } else { | |
327 | - fd = bs->fd; | |
328 | - offset = 0; | |
329 | - } | |
330 | - | |
331 | - if (fd < 0) { | |
332 | - /* no file, just return empty sectors */ | |
333 | - memset(buf, 0, n * 512); | |
277 | + } else if (bs->backing_hd) { | |
278 | + if (drv->bdrv_is_allocated(bs, sector_num, nb_sectors, &n)) { | |
279 | + ret = drv->bdrv_read(bs, sector_num, buf, n); | |
280 | + if (ret < 0) | |
281 | + return -1; | |
282 | + } else { | |
283 | + /* read from the base image */ | |
284 | + ret = bdrv_read(bs->backing_hd, sector_num, buf, n); | |
285 | + if (ret < 0) | |
286 | + return -1; | |
287 | + } | |
334 | 288 | } else { |
335 | - offset += sector_num * 512; | |
336 | - lseek64(fd, offset, SEEK_SET); | |
337 | - ret = read(fd, buf, n * 512); | |
338 | - if (ret != n * 512) { | |
289 | + ret = drv->bdrv_read(bs, sector_num, buf, nb_sectors); | |
290 | + if (ret < 0) | |
339 | 291 | return -1; |
340 | - } | |
292 | + /* no need to loop */ | |
293 | + break; | |
341 | 294 | } |
342 | - next: | |
343 | 295 | nb_sectors -= n; |
344 | 296 | sector_num += n; |
345 | 297 | buf += n * 512; |
... | ... | @@ -351,37 +303,11 @@ int bdrv_read(BlockDriverState *bs, int64_t sector_num, |
351 | 303 | int bdrv_write(BlockDriverState *bs, int64_t sector_num, |
352 | 304 | const uint8_t *buf, int nb_sectors) |
353 | 305 | { |
354 | - int ret, fd, i; | |
355 | - int64_t offset, retl; | |
356 | - | |
357 | 306 | if (!bs->inserted) |
358 | 307 | return -1; |
359 | 308 | if (bs->read_only) |
360 | 309 | return -1; |
361 | - | |
362 | - if (bs->cow_bitmap) { | |
363 | - fd = bs->cow_fd; | |
364 | - offset = bs->cow_sectors_offset; | |
365 | - } else { | |
366 | - fd = bs->fd; | |
367 | - offset = 0; | |
368 | - } | |
369 | - | |
370 | - offset += sector_num * 512; | |
371 | - retl = lseek64(fd, offset, SEEK_SET); | |
372 | - if (retl == -1) { | |
373 | - return -1; | |
374 | - } | |
375 | - ret = write(fd, buf, nb_sectors * 512); | |
376 | - if (ret != nb_sectors * 512) { | |
377 | - return -1; | |
378 | - } | |
379 | - | |
380 | - if (bs->cow_bitmap) { | |
381 | - for (i = 0; i < nb_sectors; i++) | |
382 | - set_bit(bs->cow_bitmap, sector_num + i); | |
383 | - } | |
384 | - return 0; | |
310 | + return bs->drv->bdrv_write(bs, sector_num, buf, nb_sectors); | |
385 | 311 | } |
386 | 312 | |
387 | 313 | void bdrv_get_geometry(BlockDriverState *bs, int64_t *nb_sectors_ptr) |
... | ... | @@ -459,6 +385,47 @@ void bdrv_set_change_cb(BlockDriverState *bs, |
459 | 385 | bs->change_opaque = opaque; |
460 | 386 | } |
461 | 387 | |
388 | +int bdrv_is_encrypted(BlockDriverState *bs) | |
389 | +{ | |
390 | + if (bs->backing_hd && bs->backing_hd->encrypted) | |
391 | + return 1; | |
392 | + return bs->encrypted; | |
393 | +} | |
394 | + | |
395 | +int bdrv_set_key(BlockDriverState *bs, const char *key) | |
396 | +{ | |
397 | + int ret; | |
398 | + if (bs->backing_hd && bs->backing_hd->encrypted) { | |
399 | + ret = bdrv_set_key(bs->backing_hd, key); | |
400 | + if (ret < 0) | |
401 | + return ret; | |
402 | + if (!bs->encrypted) | |
403 | + return 0; | |
404 | + } | |
405 | + if (!bs->encrypted || !bs->drv || !bs->drv->bdrv_set_key) | |
406 | + return -1; | |
407 | + return bs->drv->bdrv_set_key(bs, key); | |
408 | +} | |
409 | + | |
410 | +void bdrv_get_format(BlockDriverState *bs, char *buf, int buf_size) | |
411 | +{ | |
412 | + if (!bs->inserted || !bs->drv) { | |
413 | + buf[0] = '\0'; | |
414 | + } else { | |
415 | + pstrcpy(buf, buf_size, bs->drv->format_name); | |
416 | + } | |
417 | +} | |
418 | + | |
419 | +void bdrv_iterate_format(void (*it)(void *opaque, const char *name), | |
420 | + void *opaque) | |
421 | +{ | |
422 | + BlockDriver *drv; | |
423 | + | |
424 | + for (drv = first_drv; drv != NULL; drv = drv->next) { | |
425 | + it(opaque, drv->format_name); | |
426 | + } | |
427 | +} | |
428 | + | |
462 | 429 | BlockDriverState *bdrv_find(const char *name) |
463 | 430 | { |
464 | 431 | BlockDriverState *bs; |
... | ... | @@ -479,6 +446,11 @@ void bdrv_iterate(void (*it)(void *opaque, const char *name), void *opaque) |
479 | 446 | } |
480 | 447 | } |
481 | 448 | |
449 | +const char *bdrv_get_device_name(BlockDriverState *bs) | |
450 | +{ | |
451 | + return bs->device_name; | |
452 | +} | |
453 | + | |
482 | 454 | void bdrv_info(void) |
483 | 455 | { |
484 | 456 | BlockDriverState *bs; |
... | ... | @@ -503,10 +475,117 @@ void bdrv_info(void) |
503 | 475 | } |
504 | 476 | if (bs->inserted) { |
505 | 477 | term_printf(" file=%s", bs->filename); |
478 | + if (bs->backing_file[0] != '\0') | |
479 | + term_printf(" backing_file=%s", bs->backing_file); | |
506 | 480 | term_printf(" ro=%d", bs->read_only); |
481 | + term_printf(" drv=%s", bs->drv->format_name); | |
482 | + if (bs->encrypted) | |
483 | + term_printf(" encrypted"); | |
507 | 484 | } else { |
508 | 485 | term_printf(" [not inserted]"); |
509 | 486 | } |
510 | 487 | term_printf("\n"); |
511 | 488 | } |
512 | 489 | } |
490 | + | |
491 | + | |
492 | +/**************************************************************/ | |
493 | +/* RAW block driver */ | |
494 | + | |
495 | +typedef struct BDRVRawState { | |
496 | + int fd; | |
497 | +} BDRVRawState; | |
498 | + | |
499 | +static int raw_probe(const uint8_t *buf, int buf_size, const char *filename) | |
500 | +{ | |
501 | + return 1; /* maybe */ | |
502 | +} | |
503 | + | |
504 | +static int raw_open(BlockDriverState *bs, const char *filename) | |
505 | +{ | |
506 | + BDRVRawState *s = bs->opaque; | |
507 | + int fd; | |
508 | + int64_t size; | |
509 | + | |
510 | + fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE); | |
511 | + if (fd < 0) { | |
512 | + fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE); | |
513 | + if (fd < 0) | |
514 | + return -1; | |
515 | + bs->read_only = 1; | |
516 | + } | |
517 | + size = lseek64(fd, 0, SEEK_END); | |
518 | + bs->total_sectors = size / 512; | |
519 | + s->fd = fd; | |
520 | + return 0; | |
521 | +} | |
522 | + | |
523 | +static int raw_read(BlockDriverState *bs, int64_t sector_num, | |
524 | + uint8_t *buf, int nb_sectors) | |
525 | +{ | |
526 | + BDRVRawState *s = bs->opaque; | |
527 | + int ret; | |
528 | + | |
529 | + lseek64(s->fd, sector_num * 512, SEEK_SET); | |
530 | + ret = read(s->fd, buf, nb_sectors * 512); | |
531 | + if (ret != nb_sectors * 512) | |
532 | + return -1; | |
533 | + return 0; | |
534 | +} | |
535 | + | |
536 | +static int raw_write(BlockDriverState *bs, int64_t sector_num, | |
537 | + const uint8_t *buf, int nb_sectors) | |
538 | +{ | |
539 | + BDRVRawState *s = bs->opaque; | |
540 | + int ret; | |
541 | + | |
542 | + lseek64(s->fd, sector_num * 512, SEEK_SET); | |
543 | + ret = write(s->fd, buf, nb_sectors * 512); | |
544 | + if (ret != nb_sectors * 512) | |
545 | + return -1; | |
546 | + return 0; | |
547 | +} | |
548 | + | |
549 | +static int raw_close(BlockDriverState *bs) | |
550 | +{ | |
551 | + BDRVRawState *s = bs->opaque; | |
552 | + close(s->fd); | |
553 | +} | |
554 | + | |
555 | +static int raw_create(const char *filename, int64_t total_size, | |
556 | + const char *backing_file, int flags) | |
557 | +{ | |
558 | + int fd; | |
559 | + | |
560 | + if (flags || backing_file) | |
561 | + return -ENOTSUP; | |
562 | + | |
563 | + fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE, | |
564 | + 0644); | |
565 | + if (fd < 0) | |
566 | + return -EIO; | |
567 | + ftruncate64(fd, total_size * 512); | |
568 | + close(fd); | |
569 | + return 0; | |
570 | +} | |
571 | + | |
572 | +BlockDriver bdrv_raw = { | |
573 | + "raw", | |
574 | + sizeof(BDRVRawState), | |
575 | + raw_probe, | |
576 | + raw_open, | |
577 | + raw_read, | |
578 | + raw_write, | |
579 | + raw_close, | |
580 | + raw_create, | |
581 | +}; | |
582 | + | |
583 | +void bdrv_init(void) | |
584 | +{ | |
585 | + bdrv_register(&bdrv_raw); | |
586 | +#ifndef _WIN32 | |
587 | + bdrv_register(&bdrv_cow); | |
588 | +#endif | |
589 | + bdrv_register(&bdrv_qcow); | |
590 | + bdrv_register(&bdrv_vmdk); | |
591 | +} | ... | ... |
block_int.h
0 → 100644
1 | +/* | |
2 | + * QEMU System Emulator block driver | |
3 | + * | |
4 | + * Copyright (c) 2003 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 BLOCK_INT_H | |
25 | +#define BLOCK_INT_H | |
26 | + | |
27 | +struct BlockDriver { | |
28 | + const char *format_name; | |
29 | + int instance_size; | |
30 | + int (*bdrv_probe)(const uint8_t *buf, int buf_size, const char *filename); | |
31 | + int (*bdrv_open)(BlockDriverState *bs, const char *filename); | |
32 | + int (*bdrv_read)(BlockDriverState *bs, int64_t sector_num, | |
33 | + uint8_t *buf, int nb_sectors); | |
34 | + int (*bdrv_write)(BlockDriverState *bs, int64_t sector_num, | |
35 | + const uint8_t *buf, int nb_sectors); | |
36 | + int (*bdrv_close)(BlockDriverState *bs); | |
37 | + int (*bdrv_create)(const char *filename, int64_t total_sectors, | |
38 | + const char *backing_file, int flags); | |
39 | + int (*bdrv_is_allocated)(BlockDriverState *bs, int64_t sector_num, | |
40 | + int nb_sectors, int *pnum); | |
41 | + int (*bdrv_set_key)(BlockDriverState *bs, const char *key); | |
42 | + struct BlockDriver *next; | |
43 | +}; | |
44 | + | |
45 | +struct BlockDriverState { | |
46 | + int64_t total_sectors; | |
47 | + int read_only; /* if true, the media is read only */ | |
48 | + int inserted; /* if true, the media is present */ | |
49 | + int removable; /* if true, the media can be removed */ | |
50 | + int locked; /* if true, the media cannot temporarily be ejected */ | |
51 | + int encrypted; /* if true, the media is encrypted */ | |
52 | + /* event callback when inserting/removing */ | |
53 | + void (*change_cb)(void *opaque); | |
54 | + void *change_opaque; | |
55 | + | |
56 | + BlockDriver *drv; | |
57 | + void *opaque; | |
58 | + | |
59 | + int boot_sector_enabled; | |
60 | + uint8_t boot_sector_data[512]; | |
61 | + | |
62 | + char filename[1024]; | |
63 | + char backing_file[1024]; /* if non zero, the image is a diff of | |
64 | + this file image */ | |
65 | + int is_temporary; | |
66 | + | |
67 | + BlockDriverState *backing_hd; | |
68 | + | |
69 | + /* NOTE: the following infos are only hints for real hardware | |
70 | + drivers. They are not used by the block driver */ | |
71 | + int cyls, heads, secs; | |
72 | + int type; | |
73 | + char device_name[32]; | |
74 | + BlockDriverState *next; | |
75 | +}; | |
76 | + | |
77 | +#endif /* BLOCK_INT_H */ | ... | ... |
qemu-img.c
0 → 100644
1 | +/* | |
2 | + * create a COW disk image | |
3 | + * | |
4 | + * Copyright (c) 2003 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 "vl.h" | |
25 | + | |
26 | +void *get_mmap_addr(unsigned long size) | |
27 | +{ | |
28 | + return NULL; | |
29 | +} | |
30 | + | |
31 | +void qemu_free(void *ptr) | |
32 | +{ | |
33 | + free(ptr); | |
34 | +} | |
35 | + | |
36 | +void *qemu_malloc(size_t size) | |
37 | +{ | |
38 | + return malloc(size); | |
39 | +} | |
40 | + | |
41 | +void *qemu_mallocz(size_t size) | |
42 | +{ | |
43 | + void *ptr; | |
44 | + ptr = qemu_malloc(size); | |
45 | + if (!ptr) | |
46 | + return NULL; | |
47 | + memset(ptr, 0, size); | |
48 | + return ptr; | |
49 | +} | |
50 | + | |
51 | +char *qemu_strdup(const char *str) | |
52 | +{ | |
53 | + char *ptr; | |
54 | + ptr = qemu_malloc(strlen(str) + 1); | |
55 | + if (!ptr) | |
56 | + return NULL; | |
57 | + strcpy(ptr, str); | |
58 | + return ptr; | |
59 | +} | |
60 | + | |
61 | +void pstrcpy(char *buf, int buf_size, const char *str) | |
62 | +{ | |
63 | + int c; | |
64 | + char *q = buf; | |
65 | + | |
66 | + if (buf_size <= 0) | |
67 | + return; | |
68 | + | |
69 | + for(;;) { | |
70 | + c = *str++; | |
71 | + if (c == 0 || q >= buf + buf_size - 1) | |
72 | + break; | |
73 | + *q++ = c; | |
74 | + } | |
75 | + *q = '\0'; | |
76 | +} | |
77 | + | |
78 | +/* strcat and truncate. */ | |
79 | +char *pstrcat(char *buf, int buf_size, const char *s) | |
80 | +{ | |
81 | + int len; | |
82 | + len = strlen(buf); | |
83 | + if (len < buf_size) | |
84 | + pstrcpy(buf + len, buf_size - len, s); | |
85 | + return buf; | |
86 | +} | |
87 | + | |
88 | +int strstart(const char *str, const char *val, const char **ptr) | |
89 | +{ | |
90 | + const char *p, *q; | |
91 | + p = str; | |
92 | + q = val; | |
93 | + while (*q != '\0') { | |
94 | + if (*p != *q) | |
95 | + return 0; | |
96 | + p++; | |
97 | + q++; | |
98 | + } | |
99 | + if (ptr) | |
100 | + *ptr = p; | |
101 | + return 1; | |
102 | +} | |
103 | + | |
104 | +void term_printf(const char *fmt, ...) | |
105 | +{ | |
106 | + va_list ap; | |
107 | + va_start(ap, fmt); | |
108 | + vprintf(fmt, ap); | |
109 | + va_end(ap); | |
110 | +} | |
111 | + | |
112 | +void __attribute__((noreturn)) error(const char *fmt, ...) | |
113 | +{ | |
114 | + va_list ap; | |
115 | + va_start(ap, fmt); | |
116 | + fprintf(stderr, "qemuimg: "); | |
117 | + vfprintf(stderr, fmt, ap); | |
118 | + fprintf(stderr, "\n"); | |
119 | + exit(1); | |
120 | + va_end(ap); | |
121 | +} | |
122 | + | |
123 | +static void format_print(void *opaque, const char *name) | |
124 | +{ | |
125 | + printf(" %s", name); | |
126 | +} | |
127 | + | |
128 | +void help(void) | |
129 | +{ | |
130 | + printf("qemuimg version " QEMU_VERSION ", Copyright (c) 2004 Fabrice Bellard\n" | |
131 | + "usage: qemuimg command [command options]\n" | |
132 | + "QEMU disk image utility\n" | |
133 | + "\n" | |
134 | + "Command syntax:\n" | |
135 | + " create [-e] [-b base_image] [-f fmt] filename [size]\n" | |
136 | + " commit [-f fmt] filename\n" | |
137 | + " convert [-c] [-e] [-f fmt] filename [-O output_fmt] output_filename\n" | |
138 | + " info [-f fmt] filename\n" | |
139 | + "\n" | |
140 | + "Command parameters:\n" | |
141 | + " 'filename' is a disk image filename\n" | |
142 | + " 'base_image' is the read-only disk image which is used as base for a copy on\n" | |
143 | + " write image; the copy on write image only stores the modified data\n" | |
144 | + " 'fmt' is the disk image format. It is guessed automatically in most cases\n" | |
145 | + " 'size' is the disk image size in kilobytes. Optional suffixes 'M' (megabyte)\n" | |
146 | + " and 'G' (gigabyte) are supported\n" | |
147 | + " 'output_filename' is the destination disk image filename\n" | |
148 | + " 'output_fmt' is the destination format\n" | |
149 | + " '-c' indicates that target image must be compressed (qcow format only)\n" | |
150 | + " '-e' indicates that the target image must be encrypted (qcow format only)\n" | |
151 | + ); | |
152 | + printf("\nSupported format:"); | |
153 | + bdrv_iterate_format(format_print, NULL); | |
154 | + printf("\n"); | |
155 | + exit(1); | |
156 | +} | |
157 | + | |
158 | + | |
159 | +#define NB_SUFFIXES 4 | |
160 | + | |
161 | +static void get_human_readable_size(char *buf, int buf_size, int64_t size) | |
162 | +{ | |
163 | + char suffixes[NB_SUFFIXES] = "KMGT"; | |
164 | + int64_t base; | |
165 | + int i; | |
166 | + | |
167 | + if (size <= 999) { | |
168 | + snprintf(buf, buf_size, "%lld", size); | |
169 | + } else { | |
170 | + base = 1024; | |
171 | + for(i = 0; i < NB_SUFFIXES; i++) { | |
172 | + if (size < (10 * base)) { | |
173 | + snprintf(buf, buf_size, "%0.1f%c", | |
174 | + (double)size / base, | |
175 | + suffixes[i]); | |
176 | + break; | |
177 | + } else if (size < (1000 * base) || i == (NB_SUFFIXES - 1)) { | |
178 | + snprintf(buf, buf_size, "%lld%c", | |
179 | + (size + (base >> 1)) / base, | |
180 | + suffixes[i]); | |
181 | + break; | |
182 | + } | |
183 | + base = base * 1024; | |
184 | + } | |
185 | + } | |
186 | +} | |
187 | + | |
188 | +#if defined(WIN32) | |
189 | +/* XXX: put correct support for win32 */ | |
190 | +static int read_password(char *buf, int buf_size) | |
191 | +{ | |
192 | + int c, i; | |
193 | + printf("Password: "); | |
194 | + fflush(stdout); | |
195 | + i = 0; | |
196 | + for(;;) { | |
197 | + c = getchar(); | |
198 | + if (c == '\n') | |
199 | + break; | |
200 | + if (i < (buf_size - 1)) | |
201 | + buf[i++] = c; | |
202 | + } | |
203 | + buf[i] = '\0'; | |
204 | + return 0; | |
205 | +} | |
206 | + | |
207 | +#else | |
208 | + | |
209 | +#include <termios.h> | |
210 | + | |
211 | +static struct termios oldtty; | |
212 | + | |
213 | +static void term_exit(void) | |
214 | +{ | |
215 | + tcsetattr (0, TCSANOW, &oldtty); | |
216 | +} | |
217 | + | |
218 | +static void term_init(void) | |
219 | +{ | |
220 | + struct termios tty; | |
221 | + | |
222 | + tcgetattr (0, &tty); | |
223 | + oldtty = tty; | |
224 | + | |
225 | + tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP | |
226 | + |INLCR|IGNCR|ICRNL|IXON); | |
227 | + tty.c_oflag |= OPOST; | |
228 | + tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN); | |
229 | + tty.c_cflag &= ~(CSIZE|PARENB); | |
230 | + tty.c_cflag |= CS8; | |
231 | + tty.c_cc[VMIN] = 1; | |
232 | + tty.c_cc[VTIME] = 0; | |
233 | + | |
234 | + tcsetattr (0, TCSANOW, &tty); | |
235 | + | |
236 | + atexit(term_exit); | |
237 | +} | |
238 | + | |
239 | +int read_password(char *buf, int buf_size) | |
240 | +{ | |
241 | + uint8_t ch; | |
242 | + int i, ret; | |
243 | + | |
244 | + printf("password: "); | |
245 | + fflush(stdout); | |
246 | + term_init(); | |
247 | + i = 0; | |
248 | + for(;;) { | |
249 | + ret = read(0, &ch, 1); | |
250 | + if (ret == -1) { | |
251 | + if (errno == EAGAIN || errno == EINTR) { | |
252 | + continue; | |
253 | + } else { | |
254 | + ret = -1; | |
255 | + break; | |
256 | + } | |
257 | + } else if (ret == 0) { | |
258 | + ret = -1; | |
259 | + break; | |
260 | + } else { | |
261 | + if (ch == '\r') { | |
262 | + ret = 0; | |
263 | + break; | |
264 | + } | |
265 | + if (i < (buf_size - 1)) | |
266 | + buf[i++] = ch; | |
267 | + } | |
268 | + } | |
269 | + term_exit(); | |
270 | + buf[i] = '\0'; | |
271 | + printf("\n"); | |
272 | + return ret; | |
273 | +} | |
274 | +#endif | |
275 | + | |
276 | +static int img_create(int argc, char **argv) | |
277 | +{ | |
278 | + int c, ret, encrypted; | |
279 | + const char *fmt = "raw"; | |
280 | + const char *filename; | |
281 | + const char *base_filename = NULL; | |
282 | + int64_t size; | |
283 | + const char *p; | |
284 | + BlockDriver *drv; | |
285 | + | |
286 | + encrypted = 0; | |
287 | + for(;;) { | |
288 | + c = getopt(argc, argv, "b:f:he"); | |
289 | + if (c == -1) | |
290 | + break; | |
291 | + switch(c) { | |
292 | + case 'h': | |
293 | + help(); | |
294 | + break; | |
295 | + case 'b': | |
296 | + base_filename = optarg; | |
297 | + break; | |
298 | + case 'f': | |
299 | + fmt = optarg; | |
300 | + break; | |
301 | + case 'e': | |
302 | + encrypted = 1; | |
303 | + break; | |
304 | + } | |
305 | + } | |
306 | + optind++; | |
307 | + if (optind >= argc) | |
308 | + help(); | |
309 | + filename = argv[optind++]; | |
310 | + size = 0; | |
311 | + if (!base_filename) { | |
312 | + if (optind >= argc) | |
313 | + help(); | |
314 | + p = argv[optind]; | |
315 | + size = strtoul(p, (char **)&p, 0); | |
316 | + if (*p == 'M') { | |
317 | + size *= 1024 * 1024; | |
318 | + } else if (*p == 'G') { | |
319 | + size *= 1024 * 1024 * 1024; | |
320 | + } else if (*p == 'k' || *p == 'K' || *p == '\0') { | |
321 | + size *= 1024; | |
322 | + } else { | |
323 | + help(); | |
324 | + } | |
325 | + } | |
326 | + drv = bdrv_find_format(fmt); | |
327 | + if (!drv) | |
328 | + error("Unknown file format '%s'", fmt); | |
329 | + printf("Formating '%s', fmt=%s", | |
330 | + filename, fmt); | |
331 | + if (encrypted) | |
332 | + printf(", encrypted"); | |
333 | + if (base_filename) | |
334 | + printf(", backing_file=%s\n", | |
335 | + base_filename); | |
336 | + else | |
337 | + printf(", size=%lld kB\n", size / 1024); | |
338 | + ret = bdrv_create(drv, filename, size / 512, base_filename, encrypted); | |
339 | + if (ret < 0) { | |
340 | + if (ret == -ENOTSUP) { | |
341 | + error("Formatting or formatting option not suppored for file format '%s'", fmt); | |
342 | + } else { | |
343 | + error("Error while formatting"); | |
344 | + } | |
345 | + } | |
346 | + return 0; | |
347 | +} | |
348 | + | |
349 | +static int img_commit(int argc, char **argv) | |
350 | +{ | |
351 | + int c, ret; | |
352 | + const char *filename, *fmt; | |
353 | + BlockDriver *drv; | |
354 | + BlockDriverState *bs; | |
355 | + | |
356 | + fmt = NULL; | |
357 | + for(;;) { | |
358 | + c = getopt(argc, argv, "f:h"); | |
359 | + if (c == -1) | |
360 | + break; | |
361 | + switch(c) { | |
362 | + case 'h': | |
363 | + help(); | |
364 | + break; | |
365 | + case 'f': | |
366 | + fmt = optarg; | |
367 | + break; | |
368 | + } | |
369 | + } | |
370 | + optind++; | |
371 | + if (optind >= argc) | |
372 | + help(); | |
373 | + filename = argv[optind++]; | |
374 | + | |
375 | + bs = bdrv_new(""); | |
376 | + if (!bs) | |
377 | + error("Not enough memory"); | |
378 | + if (fmt) { | |
379 | + drv = bdrv_find_format(fmt); | |
380 | + if (!drv) | |
381 | + error("Unknown file format '%s'", fmt); | |
382 | + } else { | |
383 | + drv = NULL; | |
384 | + } | |
385 | + if (bdrv_open2(bs, filename, 0, drv) < 0) { | |
386 | + error("Could not open '%s'", filename); | |
387 | + } | |
388 | + ret = bdrv_commit(bs); | |
389 | + switch(ret) { | |
390 | + case 0: | |
391 | + printf("Image committed.\n"); | |
392 | + break; | |
393 | + case -ENOENT: | |
394 | + error("No disk inserted"); | |
395 | + break; | |
396 | + case -EACCES: | |
397 | + error("Image is read-only"); | |
398 | + break; | |
399 | + case -ENOTSUP: | |
400 | + error("Image is already committed"); | |
401 | + break; | |
402 | + default: | |
403 | + error("Error while committing image"); | |
404 | + break; | |
405 | + } | |
406 | + | |
407 | + bdrv_delete(bs); | |
408 | + return 0; | |
409 | +} | |
410 | + | |
411 | +static int is_not_zero(const uint8_t *sector, int len) | |
412 | +{ | |
413 | + int i; | |
414 | + len >>= 2; | |
415 | + for(i = 0;i < len; i++) { | |
416 | + if (((uint32_t *)sector)[i] != 0) | |
417 | + return 1; | |
418 | + } | |
419 | + return 0; | |
420 | +} | |
421 | + | |
422 | +static int is_allocated_sectors(const uint8_t *buf, int n, int *pnum) | |
423 | +{ | |
424 | + int v, i; | |
425 | + | |
426 | + if (n <= 0) { | |
427 | + *pnum = 0; | |
428 | + return 0; | |
429 | + } | |
430 | + v = is_not_zero(buf, 512); | |
431 | + for(i = 1; i < n; i++) { | |
432 | + buf += 512; | |
433 | + if (v != is_not_zero(buf, 512)) | |
434 | + break; | |
435 | + } | |
436 | + *pnum = i; | |
437 | + return v; | |
438 | +} | |
439 | + | |
440 | +static BlockDriverState *bdrv_new_open(const char *filename, | |
441 | + const char *fmt) | |
442 | +{ | |
443 | + BlockDriverState *bs; | |
444 | + BlockDriver *drv; | |
445 | + char password[256]; | |
446 | + | |
447 | + bs = bdrv_new(""); | |
448 | + if (!bs) | |
449 | + error("Not enough memory"); | |
450 | + if (fmt) { | |
451 | + drv = bdrv_find_format(fmt); | |
452 | + if (!drv) | |
453 | + error("Unknown file format '%s'", fmt); | |
454 | + } else { | |
455 | + drv = NULL; | |
456 | + } | |
457 | + if (bdrv_open2(bs, filename, 0, drv) < 0) { | |
458 | + error("Could not open '%s'", filename); | |
459 | + } | |
460 | + if (bdrv_is_encrypted(bs)) { | |
461 | + printf("Disk image '%s' is encrypted.\n", filename); | |
462 | + if (read_password(password, sizeof(password)) < 0) | |
463 | + error("No password given"); | |
464 | + if (bdrv_set_key(bs, password) < 0) | |
465 | + error("invalid password"); | |
466 | + } | |
467 | + return bs; | |
468 | +} | |
469 | + | |
470 | +#define IO_BUF_SIZE 65536 | |
471 | + | |
472 | +static int img_convert(int argc, char **argv) | |
473 | +{ | |
474 | + int c, ret, n, n1, compress, cluster_size, cluster_sectors, encrypt; | |
475 | + const char *filename, *fmt, *out_fmt, *out_filename; | |
476 | + BlockDriver *drv; | |
477 | + BlockDriverState *bs, *out_bs; | |
478 | + int64_t total_sectors, nb_sectors, sector_num; | |
479 | + uint8_t buf[IO_BUF_SIZE]; | |
480 | + const uint8_t *buf1; | |
481 | + | |
482 | + fmt = NULL; | |
483 | + out_fmt = "raw"; | |
484 | + compress = 0; | |
485 | + encrypt = 0; | |
486 | + for(;;) { | |
487 | + c = getopt(argc, argv, "f:O:hce"); | |
488 | + if (c == -1) | |
489 | + break; | |
490 | + switch(c) { | |
491 | + case 'h': | |
492 | + help(); | |
493 | + break; | |
494 | + case 'f': | |
495 | + fmt = optarg; | |
496 | + break; | |
497 | + case 'O': | |
498 | + out_fmt = optarg; | |
499 | + break; | |
500 | + case 'c': | |
501 | + compress = 1; | |
502 | + break; | |
503 | + case 'e': | |
504 | + encrypt = 1; | |
505 | + break; | |
506 | + } | |
507 | + } | |
508 | + optind++; | |
509 | + if (optind >= argc) | |
510 | + help(); | |
511 | + filename = argv[optind++]; | |
512 | + if (optind >= argc) | |
513 | + help(); | |
514 | + out_filename = argv[optind++]; | |
515 | + | |
516 | + bs = bdrv_new_open(filename, fmt); | |
517 | + | |
518 | + drv = bdrv_find_format(out_fmt); | |
519 | + if (!drv) | |
520 | + error("Unknown file format '%s'", fmt); | |
521 | + if (compress && drv != &bdrv_qcow) | |
522 | + error("Compression not supported for this file format"); | |
523 | + if (encrypt && drv != &bdrv_qcow) | |
524 | + error("Encryption not supported for this file format"); | |
525 | + if (compress && encrypt) | |
526 | + error("Compression and encryption not supported at the same time"); | |
527 | + bdrv_get_geometry(bs, &total_sectors); | |
528 | + ret = bdrv_create(drv, out_filename, total_sectors, NULL, encrypt); | |
529 | + if (ret < 0) { | |
530 | + if (ret == -ENOTSUP) { | |
531 | + error("Formatting not suppored for file format '%s'", fmt); | |
532 | + } else { | |
533 | + error("Error while formatting '%s'", out_filename); | |
534 | + } | |
535 | + } | |
536 | + | |
537 | + out_bs = bdrv_new_open(out_filename, out_fmt); | |
538 | + | |
539 | + if (compress) { | |
540 | + cluster_size = qcow_get_cluster_size(out_bs); | |
541 | + if (cluster_size <= 0 || cluster_size > IO_BUF_SIZE) | |
542 | + error("invalid cluster size"); | |
543 | + cluster_sectors = cluster_size >> 9; | |
544 | + sector_num = 0; | |
545 | + for(;;) { | |
546 | + nb_sectors = total_sectors - sector_num; | |
547 | + if (nb_sectors <= 0) | |
548 | + break; | |
549 | + if (nb_sectors >= cluster_sectors) | |
550 | + n = cluster_sectors; | |
551 | + else | |
552 | + n = nb_sectors; | |
553 | + if (bdrv_read(bs, sector_num, buf, n) < 0) | |
554 | + error("error while reading"); | |
555 | + if (n < cluster_sectors) | |
556 | + memset(buf + n * 512, 0, cluster_size - n * 512); | |
557 | + if (is_not_zero(buf, cluster_size)) { | |
558 | + if (qcow_compress_cluster(out_bs, sector_num, buf) != 0) | |
559 | + error("error while compressing sector %lld", sector_num); | |
560 | + } | |
561 | + sector_num += n; | |
562 | + } | |
563 | + } else { | |
564 | + sector_num = 0; | |
565 | + for(;;) { | |
566 | + nb_sectors = total_sectors - sector_num; | |
567 | + if (nb_sectors <= 0) | |
568 | + break; | |
569 | + if (nb_sectors >= (IO_BUF_SIZE / 512)) | |
570 | + n = (IO_BUF_SIZE / 512); | |
571 | + else | |
572 | + n = nb_sectors; | |
573 | + if (bdrv_read(bs, sector_num, buf, n) < 0) | |
574 | + error("error while reading"); | |
575 | + /* NOTE: at the same time we convert, we do not write zero | |
576 | + sectors to have a chance to compress the image. Ideally, we | |
577 | + should add a specific call to have the info to go faster */ | |
578 | + buf1 = buf; | |
579 | + while (n > 0) { | |
580 | + if (is_allocated_sectors(buf1, n, &n1)) { | |
581 | + if (bdrv_write(out_bs, sector_num, buf1, n1) < 0) | |
582 | + error("error while writing"); | |
583 | + } | |
584 | + sector_num += n1; | |
585 | + n -= n1; | |
586 | + buf1 += n1 * 512; | |
587 | + } | |
588 | + } | |
589 | + } | |
590 | + bdrv_delete(out_bs); | |
591 | + bdrv_delete(bs); | |
592 | + return 0; | |
593 | +} | |
594 | + | |
595 | +static int img_info(int argc, char **argv) | |
596 | +{ | |
597 | + int c; | |
598 | + const char *filename, *fmt; | |
599 | + BlockDriver *drv; | |
600 | + BlockDriverState *bs; | |
601 | + char fmt_name[128], size_buf[128], dsize_buf[128]; | |
602 | + int64_t total_sectors; | |
603 | + struct stat st; | |
604 | + | |
605 | + fmt = NULL; | |
606 | + for(;;) { | |
607 | + c = getopt(argc, argv, "f:h"); | |
608 | + if (c == -1) | |
609 | + break; | |
610 | + switch(c) { | |
611 | + case 'h': | |
612 | + help(); | |
613 | + break; | |
614 | + case 'f': | |
615 | + fmt = optarg; | |
616 | + break; | |
617 | + } | |
618 | + } | |
619 | + optind++; | |
620 | + if (optind >= argc) | |
621 | + help(); | |
622 | + filename = argv[optind++]; | |
623 | + | |
624 | + bs = bdrv_new(""); | |
625 | + if (!bs) | |
626 | + error("Not enough memory"); | |
627 | + if (fmt) { | |
628 | + drv = bdrv_find_format(fmt); | |
629 | + if (!drv) | |
630 | + error("Unknown file format '%s'", fmt); | |
631 | + } else { | |
632 | + drv = NULL; | |
633 | + } | |
634 | + if (bdrv_open2(bs, filename, 0, drv) < 0) { | |
635 | + error("Could not open '%s'", filename); | |
636 | + } | |
637 | + bdrv_get_format(bs, fmt_name, sizeof(fmt_name)); | |
638 | + bdrv_get_geometry(bs, &total_sectors); | |
639 | + get_human_readable_size(size_buf, sizeof(size_buf), total_sectors * 512); | |
640 | + if (stat(filename, &st) < 0) | |
641 | + error("Could not stat '%s'", filename); | |
642 | + get_human_readable_size(dsize_buf, sizeof(dsize_buf), | |
643 | + (int64_t)st.st_blocks * 512); | |
644 | + printf("image: %s\n" | |
645 | + "file format: %s\n" | |
646 | + "virtual size: %s (%lld bytes)\n" | |
647 | + "disk size: %s\n", | |
648 | + filename, fmt_name, size_buf, | |
649 | + total_sectors * 512, | |
650 | + dsize_buf); | |
651 | + if (bdrv_is_encrypted(bs)) | |
652 | + printf("encrypted: yes\n"); | |
653 | + bdrv_delete(bs); | |
654 | + return 0; | |
655 | +} | |
656 | + | |
657 | +int main(int argc, char **argv) | |
658 | +{ | |
659 | + const char *cmd; | |
660 | + | |
661 | + bdrv_init(); | |
662 | + if (argc < 2) | |
663 | + help(); | |
664 | + cmd = argv[1]; | |
665 | + if (!strcmp(cmd, "create")) { | |
666 | + img_create(argc, argv); | |
667 | + } else if (!strcmp(cmd, "commit")) { | |
668 | + img_commit(argc, argv); | |
669 | + } else if (!strcmp(cmd, "convert")) { | |
670 | + img_convert(argc, argv); | |
671 | + } else if (!strcmp(cmd, "info")) { | |
672 | + img_info(argc, argv); | |
673 | + } else { | |
674 | + help(); | |
675 | + } | |
676 | + return 0; | |
677 | +} | ... | ... |
vl.h
... | ... | @@ -48,8 +48,21 @@ |
48 | 48 | #define lseek64 _lseeki64 |
49 | 49 | #endif |
50 | 50 | |
51 | +#ifdef QEMU_TOOL | |
52 | + | |
53 | +/* we use QEMU_TOOL in the command line tools which do not depend on | |
54 | + the target CPU type */ | |
55 | +#include "config-host.h" | |
56 | +#include <setjmp.h> | |
57 | +#include "osdep.h" | |
58 | +#include "bswap.h" | |
59 | + | |
60 | +#else | |
61 | + | |
51 | 62 | #include "cpu.h" |
52 | 63 | |
64 | +#endif /* !defined(QEMU_TOOL) */ | |
65 | + | |
53 | 66 | #ifndef glue |
54 | 67 | #define xglue(x, y) x ## y |
55 | 68 | #define glue(x, y) xglue(x, y) |
... | ... | @@ -57,153 +70,6 @@ |
57 | 70 | #define tostring(s) #s |
58 | 71 | #endif |
59 | 72 | |
60 | -#if defined(WORDS_BIGENDIAN) | |
61 | -static inline uint32_t be32_to_cpu(uint32_t v) | |
62 | -{ | |
63 | - return v; | |
64 | -} | |
65 | - | |
66 | -static inline uint16_t be16_to_cpu(uint16_t v) | |
67 | -{ | |
68 | - return v; | |
69 | -} | |
70 | - | |
71 | -static inline uint32_t cpu_to_be32(uint32_t v) | |
72 | -{ | |
73 | - return v; | |
74 | -} | |
75 | - | |
76 | -static inline uint16_t cpu_to_be16(uint16_t v) | |
77 | -{ | |
78 | - return v; | |
79 | -} | |
80 | - | |
81 | -static inline uint32_t le32_to_cpu(uint32_t v) | |
82 | -{ | |
83 | - return bswap32(v); | |
84 | -} | |
85 | - | |
86 | -static inline uint16_t le16_to_cpu(uint16_t v) | |
87 | -{ | |
88 | - return bswap16(v); | |
89 | -} | |
90 | - | |
91 | -static inline uint32_t cpu_to_le32(uint32_t v) | |
92 | -{ | |
93 | - return bswap32(v); | |
94 | -} | |
95 | - | |
96 | -static inline uint16_t cpu_to_le16(uint16_t v) | |
97 | -{ | |
98 | - return bswap16(v); | |
99 | -} | |
100 | - | |
101 | -#else | |
102 | - | |
103 | -static inline uint32_t be32_to_cpu(uint32_t v) | |
104 | -{ | |
105 | - return bswap32(v); | |
106 | -} | |
107 | - | |
108 | -static inline uint16_t be16_to_cpu(uint16_t v) | |
109 | -{ | |
110 | - return bswap16(v); | |
111 | -} | |
112 | - | |
113 | -static inline uint32_t cpu_to_be32(uint32_t v) | |
114 | -{ | |
115 | - return bswap32(v); | |
116 | -} | |
117 | - | |
118 | -static inline uint16_t cpu_to_be16(uint16_t v) | |
119 | -{ | |
120 | - return bswap16(v); | |
121 | -} | |
122 | - | |
123 | -static inline uint32_t le32_to_cpu(uint32_t v) | |
124 | -{ | |
125 | - return v; | |
126 | -} | |
127 | - | |
128 | -static inline uint16_t le16_to_cpu(uint16_t v) | |
129 | -{ | |
130 | - return v; | |
131 | -} | |
132 | - | |
133 | -static inline uint32_t cpu_to_le32(uint32_t v) | |
134 | -{ | |
135 | - return v; | |
136 | -} | |
137 | - | |
138 | -static inline uint16_t cpu_to_le16(uint16_t v) | |
139 | -{ | |
140 | - return v; | |
141 | -} | |
142 | -#endif | |
143 | - | |
144 | -static inline void cpu_to_le16w(uint16_t *p, uint16_t v) | |
145 | -{ | |
146 | - *p = cpu_to_le16(v); | |
147 | -} | |
148 | - | |
149 | -static inline void cpu_to_le32w(uint32_t *p, uint32_t v) | |
150 | -{ | |
151 | - *p = cpu_to_le32(v); | |
152 | -} | |
153 | - | |
154 | -static inline uint16_t le16_to_cpup(const uint16_t *p) | |
155 | -{ | |
156 | - return le16_to_cpu(*p); | |
157 | -} | |
158 | - | |
159 | -static inline uint32_t le32_to_cpup(const uint32_t *p) | |
160 | -{ | |
161 | - return le32_to_cpu(*p); | |
162 | -} | |
163 | - | |
164 | -/* unaligned versions (optimized for frequent unaligned accesses)*/ | |
165 | - | |
166 | -#if defined(__i386__) || defined(__powerpc__) | |
167 | - | |
168 | -#define cpu_to_le16wu(p, v) cpu_to_le16w(p, v) | |
169 | -#define cpu_to_le32wu(p, v) cpu_to_le32w(p, v) | |
170 | -#define le16_to_cpupu(p) le16_to_cpup(p) | |
171 | -#define le32_to_cpupu(p) le32_to_cpup(p) | |
172 | - | |
173 | -#else | |
174 | - | |
175 | -static inline void cpu_to_le16wu(uint16_t *p, uint16_t v) | |
176 | -{ | |
177 | - uint8_t *p1 = (uint8_t *)p; | |
178 | - | |
179 | - p1[0] = v; | |
180 | - p1[1] = v >> 8; | |
181 | -} | |
182 | - | |
183 | -static inline void cpu_to_le32wu(uint32_t *p, uint32_t v) | |
184 | -{ | |
185 | - uint8_t *p1 = (uint8_t *)p; | |
186 | - | |
187 | - p1[0] = v; | |
188 | - p1[1] = v >> 8; | |
189 | - p1[2] = v >> 16; | |
190 | - p1[3] = v >> 24; | |
191 | -} | |
192 | - | |
193 | -static inline uint16_t le16_to_cpupu(const uint16_t *p) | |
194 | -{ | |
195 | - const uint8_t *p1 = (const uint8_t *)p; | |
196 | - return p1[0] | (p1[1] << 8); | |
197 | -} | |
198 | - | |
199 | -static inline uint32_t le32_to_cpupu(const uint32_t *p) | |
200 | -{ | |
201 | - const uint8_t *p1 = (const uint8_t *)p; | |
202 | - return p1[0] | (p1[1] << 8) | (p1[2] << 16) | (p1[3] << 24); | |
203 | -} | |
204 | - | |
205 | -#endif | |
206 | - | |
207 | 73 | /* vl.c */ |
208 | 74 | uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c); |
209 | 75 | |
... | ... | @@ -233,6 +99,8 @@ void qemu_register_reset(QEMUResetHandler *func, void *opaque); |
233 | 99 | void qemu_system_reset_request(void); |
234 | 100 | void qemu_system_shutdown_request(void); |
235 | 101 | |
102 | +void main_loop_wait(int timeout); | |
103 | + | |
236 | 104 | extern int audio_enabled; |
237 | 105 | extern int ram_size; |
238 | 106 | extern int bios_size; |
... | ... | @@ -301,6 +169,7 @@ void qemu_del_fd_read_handler(int fd); |
301 | 169 | /* character device */ |
302 | 170 | |
303 | 171 | #define CHR_EVENT_BREAK 0 /* serial break char */ |
172 | +#define CHR_EVENT_FOCUS 1 /* focus to this terminal (modal input needed) */ | |
304 | 173 | |
305 | 174 | typedef void IOEventHandler(void *opaque, int event); |
306 | 175 | |
... | ... | @@ -310,11 +179,13 @@ typedef struct CharDriverState { |
310 | 179 | IOCanRWHandler *fd_can_read, |
311 | 180 | IOReadHandler *fd_read, void *opaque); |
312 | 181 | IOEventHandler *chr_event; |
182 | + IOEventHandler *chr_send_event; | |
313 | 183 | void *opaque; |
314 | 184 | } CharDriverState; |
315 | 185 | |
316 | 186 | void qemu_chr_printf(CharDriverState *s, const char *fmt, ...); |
317 | 187 | int qemu_chr_write(CharDriverState *s, const uint8_t *buf, int len); |
188 | +void qemu_chr_send_event(CharDriverState *s, int event); | |
318 | 189 | void qemu_chr_add_read_handler(CharDriverState *s, |
319 | 190 | IOCanRWHandler *fd_can_read, |
320 | 191 | IOReadHandler *fd_read, void *opaque); |
... | ... | @@ -464,10 +335,23 @@ void qemu_put_timer(QEMUFile *f, QEMUTimer *ts); |
464 | 335 | |
465 | 336 | /* block.c */ |
466 | 337 | typedef struct BlockDriverState BlockDriverState; |
467 | - | |
338 | +typedef struct BlockDriver BlockDriver; | |
339 | + | |
340 | +extern BlockDriver bdrv_raw; | |
341 | +extern BlockDriver bdrv_cow; | |
342 | +extern BlockDriver bdrv_qcow; | |
343 | +extern BlockDriver bdrv_vmdk; | |
344 | + | |
345 | +void bdrv_init(void); | |
346 | +BlockDriver *bdrv_find_format(const char *format_name); | |
347 | +int bdrv_create(BlockDriver *drv, | |
348 | + const char *filename, int64_t size_in_sectors, | |
349 | + const char *backing_file, int flags); | |
468 | 350 | BlockDriverState *bdrv_new(const char *device_name); |
469 | 351 | void bdrv_delete(BlockDriverState *bs); |
470 | 352 | int bdrv_open(BlockDriverState *bs, const char *filename, int snapshot); |
353 | +int bdrv_open2(BlockDriverState *bs, const char *filename, int snapshot, | |
354 | + BlockDriver *drv); | |
471 | 355 | void bdrv_close(BlockDriverState *bs); |
472 | 356 | int bdrv_read(BlockDriverState *bs, int64_t sector_num, |
473 | 357 | uint8_t *buf, int nb_sectors); |
... | ... | @@ -494,11 +378,21 @@ int bdrv_is_locked(BlockDriverState *bs); |
494 | 378 | void bdrv_set_locked(BlockDriverState *bs, int locked); |
495 | 379 | void bdrv_set_change_cb(BlockDriverState *bs, |
496 | 380 | void (*change_cb)(void *opaque), void *opaque); |
497 | - | |
381 | +void bdrv_get_format(BlockDriverState *bs, char *buf, int buf_size); | |
498 | 382 | void bdrv_info(void); |
499 | 383 | BlockDriverState *bdrv_find(const char *name); |
500 | 384 | void bdrv_iterate(void (*it)(void *opaque, const char *name), void *opaque); |
385 | +int bdrv_is_encrypted(BlockDriverState *bs); | |
386 | +int bdrv_set_key(BlockDriverState *bs, const char *key); | |
387 | +void bdrv_iterate_format(void (*it)(void *opaque, const char *name), | |
388 | + void *opaque); | |
389 | +const char *bdrv_get_device_name(BlockDriverState *bs); | |
501 | 390 | |
391 | +int qcow_get_cluster_size(BlockDriverState *bs); | |
392 | +int qcow_compress_cluster(BlockDriverState *bs, int64_t sector_num, | |
393 | + const uint8_t *buf); | |
394 | + | |
395 | +#ifndef QEMU_TOOL | |
502 | 396 | /* ISA bus */ |
503 | 397 | |
504 | 398 | extern target_phys_addr_t isa_mem_base; |
... | ... | @@ -823,11 +717,28 @@ void adb_mouse_init(ADBBusState *bus); |
823 | 717 | extern ADBBusState adb_bus; |
824 | 718 | int cuda_init(openpic_t *openpic, int irq); |
825 | 719 | |
720 | +#endif /* defined(QEMU_TOOL) */ | |
721 | + | |
826 | 722 | /* monitor.c */ |
827 | 723 | void monitor_init(CharDriverState *hd, int show_banner); |
724 | +void term_puts(const char *str); | |
725 | +void term_vprintf(const char *fmt, va_list ap); | |
828 | 726 | void term_printf(const char *fmt, ...) __attribute__ ((__format__ (__printf__, 1, 2))); |
829 | 727 | void term_flush(void); |
830 | 728 | void term_print_help(void); |
729 | +void monitor_readline(const char *prompt, int is_password, | |
730 | + char *buf, int buf_size); | |
731 | + | |
732 | +/* readline.c */ | |
733 | +typedef void ReadLineFunc(void *opaque, const char *str); | |
734 | + | |
735 | +extern int completion_index; | |
736 | +void add_completion(const char *str); | |
737 | +void readline_handle_byte(int ch); | |
738 | +void readline_find_completion(const char *cmdline); | |
739 | +const char *readline_get_history(unsigned int index); | |
740 | +void readline_start(const char *prompt, int is_password, | |
741 | + ReadLineFunc *readline_func, void *opaque); | |
831 | 742 | |
832 | 743 | /* gdbstub.c */ |
833 | 744 | ... | ... |