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,43 +22,16 @@ | ||
22 | * THE SOFTWARE. | 22 | * THE SOFTWARE. |
23 | */ | 23 | */ |
24 | #include "vl.h" | 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 | static BlockDriverState *bdrv_first; | 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 | /* create a new block device (by default it is empty) */ | 36 | /* create a new block device (by default it is empty) */ |
64 | BlockDriverState *bdrv_new(const char *device_name) | 37 | BlockDriverState *bdrv_new(const char *device_name) |
@@ -69,126 +42,149 @@ BlockDriverState *bdrv_new(const char *device_name) | @@ -69,126 +42,149 @@ BlockDriverState *bdrv_new(const char *device_name) | ||
69 | if(!bs) | 42 | if(!bs) |
70 | return NULL; | 43 | return NULL; |
71 | pstrcpy(bs->device_name, sizeof(bs->device_name), device_name); | 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 | return bs; | 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 | int fd; | 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 | #ifndef _WIN32 | 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 | goto fail; | 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 | bs->inserted = 1; | 188 | bs->inserted = 1; |
193 | 189 | ||
194 | /* call the change callback */ | 190 | /* call the change callback */ |
@@ -196,23 +192,22 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int snapshot) | @@ -196,23 +192,22 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int snapshot) | ||
196 | bs->change_cb(bs->change_opaque); | 192 | bs->change_cb(bs->change_opaque); |
197 | 193 | ||
198 | return 0; | 194 | return 0; |
199 | - fail: | ||
200 | - bdrv_close(bs); | ||
201 | - return -1; | ||
202 | } | 195 | } |
203 | 196 | ||
204 | void bdrv_close(BlockDriverState *bs) | 197 | void bdrv_close(BlockDriverState *bs) |
205 | { | 198 | { |
206 | if (bs->inserted) { | 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 | #endif | 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 | bs->inserted = 0; | 211 | bs->inserted = 0; |
217 | 212 | ||
218 | /* call the change callback */ | 213 | /* call the change callback */ |
@@ -223,85 +218,45 @@ void bdrv_close(BlockDriverState *bs) | @@ -223,85 +218,45 @@ void bdrv_close(BlockDriverState *bs) | ||
223 | 218 | ||
224 | void bdrv_delete(BlockDriverState *bs) | 219 | void bdrv_delete(BlockDriverState *bs) |
225 | { | 220 | { |
221 | + /* XXX: remove the driver list */ | ||
226 | bdrv_close(bs); | 222 | bdrv_close(bs); |
227 | qemu_free(bs); | 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 | /* commit COW file into the raw image */ | 226 | /* commit COW file into the raw image */ |
265 | int bdrv_commit(BlockDriverState *bs) | 227 | int bdrv_commit(BlockDriverState *bs) |
266 | { | 228 | { |
267 | int64_t i; | 229 | int64_t i; |
268 | - uint8_t *cow_bitmap; | 230 | + int n, j; |
231 | + unsigned char sector[512]; | ||
269 | 232 | ||
270 | if (!bs->inserted) | 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 | if (bs->read_only) { | 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 | return 0; | 260 | return 0; |
306 | } | 261 | } |
307 | 262 | ||
@@ -309,37 +264,34 @@ int bdrv_commit(BlockDriverState *bs) | @@ -309,37 +264,34 @@ int bdrv_commit(BlockDriverState *bs) | ||
309 | int bdrv_read(BlockDriverState *bs, int64_t sector_num, | 264 | int bdrv_read(BlockDriverState *bs, int64_t sector_num, |
310 | uint8_t *buf, int nb_sectors) | 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 | if (!bs->inserted) | 270 | if (!bs->inserted) |
316 | return -1; | 271 | return -1; |
317 | 272 | ||
318 | while (nb_sectors > 0) { | 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 | memcpy(buf, bs->boot_sector_data, 512); | 275 | memcpy(buf, bs->boot_sector_data, 512); |
324 | n = 1; | 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 | } else { | 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 | return -1; | 291 | return -1; |
340 | - } | 292 | + /* no need to loop */ |
293 | + break; | ||
341 | } | 294 | } |
342 | - next: | ||
343 | nb_sectors -= n; | 295 | nb_sectors -= n; |
344 | sector_num += n; | 296 | sector_num += n; |
345 | buf += n * 512; | 297 | buf += n * 512; |
@@ -351,37 +303,11 @@ int bdrv_read(BlockDriverState *bs, int64_t sector_num, | @@ -351,37 +303,11 @@ int bdrv_read(BlockDriverState *bs, int64_t sector_num, | ||
351 | int bdrv_write(BlockDriverState *bs, int64_t sector_num, | 303 | int bdrv_write(BlockDriverState *bs, int64_t sector_num, |
352 | const uint8_t *buf, int nb_sectors) | 304 | const uint8_t *buf, int nb_sectors) |
353 | { | 305 | { |
354 | - int ret, fd, i; | ||
355 | - int64_t offset, retl; | ||
356 | - | ||
357 | if (!bs->inserted) | 306 | if (!bs->inserted) |
358 | return -1; | 307 | return -1; |
359 | if (bs->read_only) | 308 | if (bs->read_only) |
360 | return -1; | 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 | void bdrv_get_geometry(BlockDriverState *bs, int64_t *nb_sectors_ptr) | 313 | void bdrv_get_geometry(BlockDriverState *bs, int64_t *nb_sectors_ptr) |
@@ -459,6 +385,47 @@ void bdrv_set_change_cb(BlockDriverState *bs, | @@ -459,6 +385,47 @@ void bdrv_set_change_cb(BlockDriverState *bs, | ||
459 | bs->change_opaque = opaque; | 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 | BlockDriverState *bdrv_find(const char *name) | 429 | BlockDriverState *bdrv_find(const char *name) |
463 | { | 430 | { |
464 | BlockDriverState *bs; | 431 | BlockDriverState *bs; |
@@ -479,6 +446,11 @@ void bdrv_iterate(void (*it)(void *opaque, const char *name), void *opaque) | @@ -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 | void bdrv_info(void) | 454 | void bdrv_info(void) |
483 | { | 455 | { |
484 | BlockDriverState *bs; | 456 | BlockDriverState *bs; |
@@ -503,10 +475,117 @@ void bdrv_info(void) | @@ -503,10 +475,117 @@ void bdrv_info(void) | ||
503 | } | 475 | } |
504 | if (bs->inserted) { | 476 | if (bs->inserted) { |
505 | term_printf(" file=%s", bs->filename); | 477 | term_printf(" file=%s", bs->filename); |
478 | + if (bs->backing_file[0] != '\0') | ||
479 | + term_printf(" backing_file=%s", bs->backing_file); | ||
506 | term_printf(" ro=%d", bs->read_only); | 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 | } else { | 484 | } else { |
508 | term_printf(" [not inserted]"); | 485 | term_printf(" [not inserted]"); |
509 | } | 486 | } |
510 | term_printf("\n"); | 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,8 +48,21 @@ | ||
48 | #define lseek64 _lseeki64 | 48 | #define lseek64 _lseeki64 |
49 | #endif | 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 | #include "cpu.h" | 62 | #include "cpu.h" |
52 | 63 | ||
64 | +#endif /* !defined(QEMU_TOOL) */ | ||
65 | + | ||
53 | #ifndef glue | 66 | #ifndef glue |
54 | #define xglue(x, y) x ## y | 67 | #define xglue(x, y) x ## y |
55 | #define glue(x, y) xglue(x, y) | 68 | #define glue(x, y) xglue(x, y) |
@@ -57,153 +70,6 @@ | @@ -57,153 +70,6 @@ | ||
57 | #define tostring(s) #s | 70 | #define tostring(s) #s |
58 | #endif | 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 | /* vl.c */ | 73 | /* vl.c */ |
208 | uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c); | 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,6 +99,8 @@ void qemu_register_reset(QEMUResetHandler *func, void *opaque); | ||
233 | void qemu_system_reset_request(void); | 99 | void qemu_system_reset_request(void); |
234 | void qemu_system_shutdown_request(void); | 100 | void qemu_system_shutdown_request(void); |
235 | 101 | ||
102 | +void main_loop_wait(int timeout); | ||
103 | + | ||
236 | extern int audio_enabled; | 104 | extern int audio_enabled; |
237 | extern int ram_size; | 105 | extern int ram_size; |
238 | extern int bios_size; | 106 | extern int bios_size; |
@@ -301,6 +169,7 @@ void qemu_del_fd_read_handler(int fd); | @@ -301,6 +169,7 @@ void qemu_del_fd_read_handler(int fd); | ||
301 | /* character device */ | 169 | /* character device */ |
302 | 170 | ||
303 | #define CHR_EVENT_BREAK 0 /* serial break char */ | 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 | typedef void IOEventHandler(void *opaque, int event); | 174 | typedef void IOEventHandler(void *opaque, int event); |
306 | 175 | ||
@@ -310,11 +179,13 @@ typedef struct CharDriverState { | @@ -310,11 +179,13 @@ typedef struct CharDriverState { | ||
310 | IOCanRWHandler *fd_can_read, | 179 | IOCanRWHandler *fd_can_read, |
311 | IOReadHandler *fd_read, void *opaque); | 180 | IOReadHandler *fd_read, void *opaque); |
312 | IOEventHandler *chr_event; | 181 | IOEventHandler *chr_event; |
182 | + IOEventHandler *chr_send_event; | ||
313 | void *opaque; | 183 | void *opaque; |
314 | } CharDriverState; | 184 | } CharDriverState; |
315 | 185 | ||
316 | void qemu_chr_printf(CharDriverState *s, const char *fmt, ...); | 186 | void qemu_chr_printf(CharDriverState *s, const char *fmt, ...); |
317 | int qemu_chr_write(CharDriverState *s, const uint8_t *buf, int len); | 187 | int qemu_chr_write(CharDriverState *s, const uint8_t *buf, int len); |
188 | +void qemu_chr_send_event(CharDriverState *s, int event); | ||
318 | void qemu_chr_add_read_handler(CharDriverState *s, | 189 | void qemu_chr_add_read_handler(CharDriverState *s, |
319 | IOCanRWHandler *fd_can_read, | 190 | IOCanRWHandler *fd_can_read, |
320 | IOReadHandler *fd_read, void *opaque); | 191 | IOReadHandler *fd_read, void *opaque); |
@@ -464,10 +335,23 @@ void qemu_put_timer(QEMUFile *f, QEMUTimer *ts); | @@ -464,10 +335,23 @@ void qemu_put_timer(QEMUFile *f, QEMUTimer *ts); | ||
464 | 335 | ||
465 | /* block.c */ | 336 | /* block.c */ |
466 | typedef struct BlockDriverState BlockDriverState; | 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 | BlockDriverState *bdrv_new(const char *device_name); | 350 | BlockDriverState *bdrv_new(const char *device_name); |
469 | void bdrv_delete(BlockDriverState *bs); | 351 | void bdrv_delete(BlockDriverState *bs); |
470 | int bdrv_open(BlockDriverState *bs, const char *filename, int snapshot); | 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 | void bdrv_close(BlockDriverState *bs); | 355 | void bdrv_close(BlockDriverState *bs); |
472 | int bdrv_read(BlockDriverState *bs, int64_t sector_num, | 356 | int bdrv_read(BlockDriverState *bs, int64_t sector_num, |
473 | uint8_t *buf, int nb_sectors); | 357 | uint8_t *buf, int nb_sectors); |
@@ -494,11 +378,21 @@ int bdrv_is_locked(BlockDriverState *bs); | @@ -494,11 +378,21 @@ int bdrv_is_locked(BlockDriverState *bs); | ||
494 | void bdrv_set_locked(BlockDriverState *bs, int locked); | 378 | void bdrv_set_locked(BlockDriverState *bs, int locked); |
495 | void bdrv_set_change_cb(BlockDriverState *bs, | 379 | void bdrv_set_change_cb(BlockDriverState *bs, |
496 | void (*change_cb)(void *opaque), void *opaque); | 380 | void (*change_cb)(void *opaque), void *opaque); |
497 | - | 381 | +void bdrv_get_format(BlockDriverState *bs, char *buf, int buf_size); |
498 | void bdrv_info(void); | 382 | void bdrv_info(void); |
499 | BlockDriverState *bdrv_find(const char *name); | 383 | BlockDriverState *bdrv_find(const char *name); |
500 | void bdrv_iterate(void (*it)(void *opaque, const char *name), void *opaque); | 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 | /* ISA bus */ | 396 | /* ISA bus */ |
503 | 397 | ||
504 | extern target_phys_addr_t isa_mem_base; | 398 | extern target_phys_addr_t isa_mem_base; |
@@ -823,11 +717,28 @@ void adb_mouse_init(ADBBusState *bus); | @@ -823,11 +717,28 @@ void adb_mouse_init(ADBBusState *bus); | ||
823 | extern ADBBusState adb_bus; | 717 | extern ADBBusState adb_bus; |
824 | int cuda_init(openpic_t *openpic, int irq); | 718 | int cuda_init(openpic_t *openpic, int irq); |
825 | 719 | ||
720 | +#endif /* defined(QEMU_TOOL) */ | ||
721 | + | ||
826 | /* monitor.c */ | 722 | /* monitor.c */ |
827 | void monitor_init(CharDriverState *hd, int show_banner); | 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 | void term_printf(const char *fmt, ...) __attribute__ ((__format__ (__printf__, 1, 2))); | 726 | void term_printf(const char *fmt, ...) __attribute__ ((__format__ (__printf__, 1, 2))); |
829 | void term_flush(void); | 727 | void term_flush(void); |
830 | void term_print_help(void); | 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 | /* gdbstub.c */ | 743 | /* gdbstub.c */ |
833 | 744 |