Revision ea2384d3 block.c
b/block.c | ||
---|---|---|
22 | 22 |
* THE SOFTWARE. |
23 | 23 |
*/ |
24 | 24 |
#include "vl.h" |
25 |
|
|
26 |
#ifndef _WIN32 |
|
27 |
#include <sys/mman.h> |
|
28 |
#endif |
|
29 |
|
|
30 |
#include "cow.h" |
|
31 |
|
|
32 |
struct BlockDriverState { |
|
33 |
int fd; /* if -1, only COW mappings */ |
|
34 |
int64_t total_sectors; |
|
35 |
int read_only; /* if true, the media is read only */ |
|
36 |
int inserted; /* if true, the media is present */ |
|
37 |
int removable; /* if true, the media can be removed */ |
|
38 |
int locked; /* if true, the media cannot temporarily be ejected */ |
|
39 |
/* event callback when inserting/removing */ |
|
40 |
void (*change_cb)(void *opaque); |
|
41 |
void *change_opaque; |
|
42 |
|
|
43 |
uint8_t *cow_bitmap; /* if non NULL, COW mappings are used first */ |
|
44 |
uint8_t *cow_bitmap_addr; /* mmap address of cow_bitmap */ |
|
45 |
int cow_bitmap_size; |
|
46 |
int cow_fd; |
|
47 |
int64_t cow_sectors_offset; |
|
48 |
int boot_sector_enabled; |
|
49 |
uint8_t boot_sector_data[512]; |
|
50 |
|
|
51 |
char filename[1024]; |
|
52 |
|
|
53 |
/* NOTE: the following infos are only hints for real hardware |
|
54 |
drivers. They are not used by the block driver */ |
|
55 |
int cyls, heads, secs; |
|
56 |
int type; |
|
57 |
char device_name[32]; |
|
58 |
BlockDriverState *next; |
|
59 |
}; |
|
25 |
#include "block_int.h" |
|
60 | 26 |
|
61 | 27 |
static BlockDriverState *bdrv_first; |
28 |
static BlockDriver *first_drv; |
|
29 |
|
|
30 |
void bdrv_register(BlockDriver *bdrv) |
|
31 |
{ |
|
32 |
bdrv->next = first_drv; |
|
33 |
first_drv = bdrv; |
|
34 |
} |
|
62 | 35 |
|
63 | 36 |
/* create a new block device (by default it is empty) */ |
64 | 37 |
BlockDriverState *bdrv_new(const char *device_name) |
... | ... | |
69 | 42 |
if(!bs) |
70 | 43 |
return NULL; |
71 | 44 |
pstrcpy(bs->device_name, sizeof(bs->device_name), device_name); |
72 |
/* insert at the end */ |
|
73 |
pbs = &bdrv_first; |
|
74 |
while (*pbs != NULL) |
|
75 |
pbs = &(*pbs)->next; |
|
76 |
*pbs = bs; |
|
45 |
if (device_name[0] != '\0') { |
|
46 |
/* insert at the end */ |
|
47 |
pbs = &bdrv_first; |
|
48 |
while (*pbs != NULL) |
|
49 |
pbs = &(*pbs)->next; |
|
50 |
*pbs = bs; |
|
51 |
} |
|
77 | 52 |
return bs; |
78 | 53 |
} |
79 | 54 |
|
80 |
int bdrv_open(BlockDriverState *bs, const char *filename, int snapshot) |
|
55 |
BlockDriver *bdrv_find_format(const char *format_name) |
|
56 |
{ |
|
57 |
BlockDriver *drv1; |
|
58 |
for(drv1 = first_drv; drv1 != NULL; drv1 = drv1->next) { |
|
59 |
if (!strcmp(drv1->format_name, format_name)) |
|
60 |
return drv1; |
|
61 |
} |
|
62 |
return NULL; |
|
63 |
} |
|
64 |
|
|
65 |
int bdrv_create(BlockDriver *drv, |
|
66 |
const char *filename, int64_t size_in_sectors, |
|
67 |
const char *backing_file, int flags) |
|
68 |
{ |
|
69 |
if (!drv->bdrv_create) |
|
70 |
return -ENOTSUP; |
|
71 |
return drv->bdrv_create(filename, size_in_sectors, backing_file, flags); |
|
72 |
} |
|
73 |
|
|
74 |
/* XXX: race condition possible */ |
|
75 |
static void get_tmp_filename(char *filename, int size) |
|
81 | 76 |
{ |
82 | 77 |
int fd; |
83 |
int64_t size; |
|
84 |
struct cow_header_v2 cow_header; |
|
85 |
#ifndef _WIN32 |
|
86 |
char template[] = "/tmp/vl.XXXXXX"; |
|
87 |
int cow_fd; |
|
88 |
struct stat st; |
|
89 |
#endif |
|
78 |
pstrcpy(filename, size, "/tmp/vl.XXXXXX"); |
|
79 |
fd = mkstemp(filename); |
|
80 |
close(fd); |
|
81 |
} |
|
90 | 82 |
|
91 |
bs->read_only = 0;
|
|
92 |
bs->fd = -1;
|
|
93 |
bs->cow_fd = -1;
|
|
94 |
bs->cow_bitmap = NULL;
|
|
95 |
pstrcpy(bs->filename, sizeof(bs->filename), filename);
|
|
83 |
static BlockDriver *find_image_format(const char *filename)
|
|
84 |
{
|
|
85 |
int fd, ret, score, score_max;
|
|
86 |
BlockDriver *drv1, *drv;
|
|
87 |
uint8_t buf[1024];
|
|
96 | 88 |
|
97 |
/* open standard HD image */ |
|
98 |
#ifdef _WIN32 |
|
99 |
fd = open(filename, O_RDWR | O_BINARY); |
|
100 |
#else |
|
101 |
fd = open(filename, O_RDWR | O_LARGEFILE); |
|
102 |
#endif |
|
103 |
if (fd < 0) { |
|
104 |
/* read only image on disk */ |
|
105 |
#ifdef _WIN32 |
|
106 |
fd = open(filename, O_RDONLY | O_BINARY); |
|
107 |
#else |
|
108 |
fd = open(filename, O_RDONLY | O_LARGEFILE); |
|
109 |
#endif |
|
110 |
if (fd < 0) { |
|
111 |
perror(filename); |
|
112 |
goto fail; |
|
89 |
fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE); |
|
90 |
if (fd < 0) |
|
91 |
return NULL; |
|
92 |
ret = read(fd, buf, sizeof(buf)); |
|
93 |
if (ret < 0) { |
|
94 |
close(fd); |
|
95 |
return NULL; |
|
96 |
} |
|
97 |
close(fd); |
|
98 |
|
|
99 |
drv = NULL; |
|
100 |
score_max = 0; |
|
101 |
for(drv1 = first_drv; drv1 != NULL; drv1 = drv1->next) { |
|
102 |
score = drv1->bdrv_probe(buf, ret, filename); |
|
103 |
if (score > score_max) { |
|
104 |
score_max = score; |
|
105 |
drv = drv1; |
|
113 | 106 |
} |
114 |
if (!snapshot) |
|
115 |
bs->read_only = 1; |
|
116 | 107 |
} |
117 |
bs->fd = fd; |
|
108 |
return drv; |
|
109 |
} |
|
110 |
|
|
111 |
int bdrv_open(BlockDriverState *bs, const char *filename, int snapshot) |
|
112 |
{ |
|
113 |
return bdrv_open2(bs, filename, snapshot, NULL); |
|
114 |
} |
|
115 |
|
|
116 |
int bdrv_open2(BlockDriverState *bs, const char *filename, int snapshot, |
|
117 |
BlockDriver *drv) |
|
118 |
{ |
|
119 |
int ret; |
|
120 |
char tmp_filename[1024]; |
|
121 |
|
|
122 |
bs->read_only = 0; |
|
123 |
bs->is_temporary = 0; |
|
124 |
bs->encrypted = 0; |
|
125 |
|
|
126 |
if (snapshot) { |
|
127 |
BlockDriverState *bs1; |
|
128 |
int64_t total_size; |
|
129 |
|
|
130 |
/* if snapshot, we create a temporary backing file and open it |
|
131 |
instead of opening 'filename' directly */ |
|
118 | 132 |
|
119 |
/* see if it is a cow image */ |
|
120 |
if (read(fd, &cow_header, sizeof(cow_header)) != sizeof(cow_header)) { |
|
121 |
fprintf(stderr, "%s: could not read header\n", filename); |
|
122 |
goto fail; |
|
133 |
/* if there is a backing file, use it */ |
|
134 |
bs1 = bdrv_new(""); |
|
135 |
if (!bs1) { |
|
136 |
return -1; |
|
137 |
} |
|
138 |
if (bdrv_open(bs1, filename, 0) < 0) { |
|
139 |
bdrv_delete(bs1); |
|
140 |
return -1; |
|
141 |
} |
|
142 |
total_size = bs1->total_sectors; |
|
143 |
bdrv_delete(bs1); |
|
144 |
|
|
145 |
get_tmp_filename(tmp_filename, sizeof(tmp_filename)); |
|
146 |
/* XXX: use cow for linux as it is more efficient ? */ |
|
147 |
if (bdrv_create(&bdrv_qcow, tmp_filename, |
|
148 |
total_size, filename, 0) < 0) { |
|
149 |
return -1; |
|
150 |
} |
|
151 |
filename = tmp_filename; |
|
152 |
bs->is_temporary = 1; |
|
153 |
} |
|
154 |
|
|
155 |
pstrcpy(bs->filename, sizeof(bs->filename), filename); |
|
156 |
if (!drv) { |
|
157 |
drv = find_image_format(filename); |
|
158 |
if (!drv) |
|
159 |
return -1; |
|
160 |
} |
|
161 |
bs->drv = drv; |
|
162 |
bs->opaque = qemu_mallocz(drv->instance_size); |
|
163 |
if (bs->opaque == NULL && drv->instance_size > 0) |
|
164 |
return -1; |
|
165 |
|
|
166 |
ret = drv->bdrv_open(bs, filename); |
|
167 |
if (ret < 0) { |
|
168 |
qemu_free(bs->opaque); |
|
169 |
return -1; |
|
123 | 170 |
} |
124 | 171 |
#ifndef _WIN32 |
125 |
if (be32_to_cpu(cow_header.magic) == COW_MAGIC && |
|
126 |
be32_to_cpu(cow_header.version) == COW_VERSION) { |
|
127 |
/* cow image found */ |
|
128 |
size = cow_header.size; |
|
129 |
#ifndef WORDS_BIGENDIAN |
|
130 |
size = bswap64(size); |
|
131 |
#endif |
|
132 |
bs->total_sectors = size / 512; |
|
133 |
|
|
134 |
bs->cow_fd = fd; |
|
135 |
bs->fd = -1; |
|
136 |
if (cow_header.backing_file[0] != '\0') { |
|
137 |
if (stat(cow_header.backing_file, &st) != 0) { |
|
138 |
fprintf(stderr, "%s: could not find original disk image '%s'\n", filename, cow_header.backing_file); |
|
139 |
goto fail; |
|
140 |
} |
|
141 |
if (st.st_mtime != be32_to_cpu(cow_header.mtime)) { |
|
142 |
fprintf(stderr, "%s: original raw disk image '%s' does not match saved timestamp\n", filename, cow_header.backing_file); |
|
143 |
goto fail; |
|
144 |
} |
|
145 |
fd = open(cow_header.backing_file, O_RDONLY | O_LARGEFILE); |
|
146 |
if (fd < 0) |
|
147 |
goto fail; |
|
148 |
bs->fd = fd; |
|
172 |
if (bs->is_temporary) { |
|
173 |
unlink(filename); |
|
174 |
} |
|
175 |
#endif |
|
176 |
if (bs->backing_file[0] != '\0' && drv->bdrv_is_allocated) { |
|
177 |
/* if there is a backing file, use it */ |
|
178 |
bs->backing_hd = bdrv_new(""); |
|
179 |
if (!bs->backing_hd) { |
|
180 |
fail: |
|
181 |
bdrv_close(bs); |
|
182 |
return -1; |
|
149 | 183 |
} |
150 |
/* mmap the bitmap */ |
|
151 |
bs->cow_bitmap_size = ((bs->total_sectors + 7) >> 3) + sizeof(cow_header); |
|
152 |
bs->cow_bitmap_addr = mmap(get_mmap_addr(bs->cow_bitmap_size), |
|
153 |
bs->cow_bitmap_size, |
|
154 |
PROT_READ | PROT_WRITE, |
|
155 |
MAP_SHARED, bs->cow_fd, 0); |
|
156 |
if (bs->cow_bitmap_addr == MAP_FAILED) |
|
184 |
if (bdrv_open(bs->backing_hd, bs->backing_file, 0) < 0) |
|
157 | 185 |
goto fail; |
158 |
bs->cow_bitmap = bs->cow_bitmap_addr + sizeof(cow_header); |
|
159 |
bs->cow_sectors_offset = (bs->cow_bitmap_size + 511) & ~511; |
|
160 |
snapshot = 0; |
|
161 |
} else |
|
162 |
#endif |
|
163 |
{ |
|
164 |
/* standard raw image */ |
|
165 |
size = lseek64(fd, 0, SEEK_END); |
|
166 |
bs->total_sectors = size / 512; |
|
167 |
bs->fd = fd; |
|
168 | 186 |
} |
169 | 187 |
|
170 |
#ifndef _WIN32 |
|
171 |
if (snapshot) { |
|
172 |
/* create a temporary COW file */ |
|
173 |
cow_fd = mkstemp64(template); |
|
174 |
if (cow_fd < 0) |
|
175 |
goto fail; |
|
176 |
bs->cow_fd = cow_fd; |
|
177 |
unlink(template); |
|
178 |
|
|
179 |
/* just need to allocate bitmap */ |
|
180 |
bs->cow_bitmap_size = (bs->total_sectors + 7) >> 3; |
|
181 |
bs->cow_bitmap_addr = mmap(get_mmap_addr(bs->cow_bitmap_size), |
|
182 |
bs->cow_bitmap_size, |
|
183 |
PROT_READ | PROT_WRITE, |
|
184 |
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); |
|
185 |
if (bs->cow_bitmap_addr == MAP_FAILED) |
|
186 |
goto fail; |
|
187 |
bs->cow_bitmap = bs->cow_bitmap_addr; |
|
188 |
bs->cow_sectors_offset = 0; |
|
189 |
} |
|
190 |
#endif |
|
191 |
|
|
192 | 188 |
bs->inserted = 1; |
193 | 189 |
|
194 | 190 |
/* call the change callback */ |
... | ... | |
196 | 192 |
bs->change_cb(bs->change_opaque); |
197 | 193 |
|
198 | 194 |
return 0; |
199 |
fail: |
|
200 |
bdrv_close(bs); |
|
201 |
return -1; |
|
202 | 195 |
} |
203 | 196 |
|
204 | 197 |
void bdrv_close(BlockDriverState *bs) |
205 | 198 |
{ |
206 | 199 |
if (bs->inserted) { |
207 |
#ifndef _WIN32 |
|
208 |
/* we unmap the mapping so that it is written to the COW file */ |
|
209 |
if (bs->cow_bitmap_addr) |
|
210 |
munmap(bs->cow_bitmap_addr, bs->cow_bitmap_size); |
|
200 |
if (bs->backing_hd) |
|
201 |
bdrv_delete(bs->backing_hd); |
|
202 |
bs->drv->bdrv_close(bs); |
|
203 |
qemu_free(bs->opaque); |
|
204 |
#ifdef _WIN32 |
|
205 |
if (bs->is_temporary) { |
|
206 |
unlink(bs->filename); |
|
207 |
} |
|
211 | 208 |
#endif |
212 |
if (bs->cow_fd >= 0) |
|
213 |
close(bs->cow_fd); |
|
214 |
if (bs->fd >= 0) |
|
215 |
close(bs->fd); |
|
209 |
bs->opaque = NULL; |
|
210 |
bs->drv = NULL; |
|
216 | 211 |
bs->inserted = 0; |
217 | 212 |
|
218 | 213 |
/* call the change callback */ |
... | ... | |
223 | 218 |
|
224 | 219 |
void bdrv_delete(BlockDriverState *bs) |
225 | 220 |
{ |
221 |
/* XXX: remove the driver list */ |
|
226 | 222 |
bdrv_close(bs); |
227 | 223 |
qemu_free(bs); |
228 | 224 |
} |
229 | 225 |
|
230 |
static inline void set_bit(uint8_t *bitmap, int64_t bitnum) |
|
231 |
{ |
|
232 |
bitmap[bitnum / 8] |= (1 << (bitnum%8)); |
|
233 |
} |
|
234 |
|
|
235 |
static inline int is_bit_set(const uint8_t *bitmap, int64_t bitnum) |
|
236 |
{ |
|
237 |
return !!(bitmap[bitnum / 8] & (1 << (bitnum%8))); |
|
238 |
} |
|
239 |
|
|
240 |
|
|
241 |
/* Return true if first block has been changed (ie. current version is |
|
242 |
* in COW file). Set the number of continuous blocks for which that |
|
243 |
* is true. */ |
|
244 |
static int is_changed(uint8_t *bitmap, |
|
245 |
int64_t sector_num, int nb_sectors, |
|
246 |
int *num_same) |
|
247 |
{ |
|
248 |
int changed; |
|
249 |
|
|
250 |
if (!bitmap || nb_sectors == 0) { |
|
251 |
*num_same = nb_sectors; |
|
252 |
return 0; |
|
253 |
} |
|
254 |
|
|
255 |
changed = is_bit_set(bitmap, sector_num); |
|
256 |
for (*num_same = 1; *num_same < nb_sectors; (*num_same)++) { |
|
257 |
if (is_bit_set(bitmap, sector_num + *num_same) != changed) |
|
258 |
break; |
|
259 |
} |
|
260 |
|
|
261 |
return changed; |
|
262 |
} |
|
263 |
|
|
264 | 226 |
/* commit COW file into the raw image */ |
265 | 227 |
int bdrv_commit(BlockDriverState *bs) |
266 | 228 |
{ |
267 | 229 |
int64_t i; |
268 |
uint8_t *cow_bitmap; |
|
230 |
int n, j; |
|
231 |
unsigned char sector[512]; |
|
269 | 232 |
|
270 | 233 |
if (!bs->inserted) |
271 |
return -1; |
|
272 |
|
|
273 |
if (!bs->cow_bitmap) { |
|
274 |
fprintf(stderr, "Already committed to %s\n", bs->filename); |
|
275 |
return 0; |
|
276 |
} |
|
234 |
return -ENOENT; |
|
277 | 235 |
|
278 | 236 |
if (bs->read_only) { |
279 |
fprintf(stderr, "Can't commit to %s: read-only\n", bs->filename); |
|
280 |
return -1; |
|
237 |
return -EACCES; |
|
281 | 238 |
} |
282 | 239 |
|
283 |
cow_bitmap = bs->cow_bitmap; |
|
284 |
for (i = 0; i < bs->total_sectors; i++) { |
|
285 |
if (is_bit_set(cow_bitmap, i)) { |
|
286 |
unsigned char sector[512]; |
|
287 |
if (bdrv_read(bs, i, sector, 1) != 0) { |
|
288 |
fprintf(stderr, "Error reading sector %lli: aborting commit\n", |
|
289 |
(long long)i); |
|
290 |
return -1; |
|
291 |
} |
|
240 |
if (!bs->backing_hd) { |
|
241 |
return -ENOTSUP; |
|
242 |
} |
|
292 | 243 |
|
293 |
/* Make bdrv_write write to real file for a moment. */ |
|
294 |
bs->cow_bitmap = NULL; |
|
295 |
if (bdrv_write(bs, i, sector, 1) != 0) { |
|
296 |
fprintf(stderr, "Error writing sector %lli: aborting commit\n", |
|
297 |
(long long)i); |
|
298 |
bs->cow_bitmap = cow_bitmap; |
|
299 |
return -1; |
|
244 |
for (i = 0; i < bs->total_sectors;) { |
|
245 |
if (bs->drv->bdrv_is_allocated(bs, i, 65536, &n)) { |
|
246 |
for(j = 0; j < n; j++) { |
|
247 |
if (bdrv_read(bs, i, sector, 1) != 0) { |
|
248 |
return -EIO; |
|
249 |
} |
|
250 |
|
|
251 |
if (bdrv_write(bs->backing_hd, i, sector, 1) != 0) { |
|
252 |
return -EIO; |
|
253 |
} |
|
254 |
i++; |
|
300 | 255 |
} |
301 |
bs->cow_bitmap = cow_bitmap; |
|
302 |
} |
|
256 |
} else { |
|
257 |
i += n; |
|
258 |
} |
|
303 | 259 |
} |
304 |
fprintf(stderr, "Committed snapshot to %s\n", bs->filename); |
|
305 | 260 |
return 0; |
306 | 261 |
} |
307 | 262 |
|
... | ... | |
309 | 264 |
int bdrv_read(BlockDriverState *bs, int64_t sector_num, |
310 | 265 |
uint8_t *buf, int nb_sectors) |
311 | 266 |
{ |
312 |
int ret, n, fd;
|
|
313 |
int64_t offset;
|
|
314 |
|
|
267 |
int ret, n; |
|
268 |
BlockDriver *drv = bs->drv;
|
|
269 |
|
|
315 | 270 |
if (!bs->inserted) |
316 | 271 |
return -1; |
317 | 272 |
|
318 | 273 |
while (nb_sectors > 0) { |
319 |
if (is_changed(bs->cow_bitmap, sector_num, nb_sectors, &n)) { |
|
320 |
fd = bs->cow_fd; |
|
321 |
offset = bs->cow_sectors_offset; |
|
322 |
} else if (sector_num == 0 && bs->boot_sector_enabled) { |
|
274 |
if (sector_num == 0 && bs->boot_sector_enabled) { |
|
323 | 275 |
memcpy(buf, bs->boot_sector_data, 512); |
324 | 276 |
n = 1; |
325 |
goto next; |
|
326 |
} else { |
|
327 |
fd = bs->fd; |
|
328 |
offset = 0; |
|
329 |
} |
|
330 |
|
|
331 |
if (fd < 0) { |
|
332 |
/* no file, just return empty sectors */ |
|
333 |
memset(buf, 0, n * 512); |
|
277 |
} else if (bs->backing_hd) { |
|
278 |
if (drv->bdrv_is_allocated(bs, sector_num, nb_sectors, &n)) { |
|
279 |
ret = drv->bdrv_read(bs, sector_num, buf, n); |
|
280 |
if (ret < 0) |
|
281 |
return -1; |
|
282 |
} else { |
|
283 |
/* read from the base image */ |
|
284 |
ret = bdrv_read(bs->backing_hd, sector_num, buf, n); |
|
285 |
if (ret < 0) |
|
286 |
return -1; |
|
287 |
} |
|
334 | 288 |
} else { |
335 |
offset += sector_num * 512; |
|
336 |
lseek64(fd, offset, SEEK_SET); |
|
337 |
ret = read(fd, buf, n * 512); |
|
338 |
if (ret != n * 512) { |
|
289 |
ret = drv->bdrv_read(bs, sector_num, buf, nb_sectors); |
|
290 |
if (ret < 0) |
|
339 | 291 |
return -1; |
340 |
} |
|
292 |
/* no need to loop */ |
|
293 |
break; |
|
341 | 294 |
} |
342 |
next: |
|
343 | 295 |
nb_sectors -= n; |
344 | 296 |
sector_num += n; |
345 | 297 |
buf += n * 512; |
... | ... | |
351 | 303 |
int bdrv_write(BlockDriverState *bs, int64_t sector_num, |
352 | 304 |
const uint8_t *buf, int nb_sectors) |
353 | 305 |
{ |
354 |
int ret, fd, i; |
|
355 |
int64_t offset, retl; |
|
356 |
|
|
357 | 306 |
if (!bs->inserted) |
358 | 307 |
return -1; |
359 | 308 |
if (bs->read_only) |
360 | 309 |
return -1; |
361 |
|
|
362 |
if (bs->cow_bitmap) { |
|
363 |
fd = bs->cow_fd; |
|
364 |
offset = bs->cow_sectors_offset; |
|
365 |
} else { |
|
366 |
fd = bs->fd; |
|
367 |
offset = 0; |
|
368 |
} |
|
369 |
|
|
370 |
offset += sector_num * 512; |
|
371 |
retl = lseek64(fd, offset, SEEK_SET); |
|
372 |
if (retl == -1) { |
|
373 |
return -1; |
|
374 |
} |
|
375 |
ret = write(fd, buf, nb_sectors * 512); |
|
376 |
if (ret != nb_sectors * 512) { |
|
377 |
return -1; |
|
378 |
} |
|
379 |
|
|
380 |
if (bs->cow_bitmap) { |
|
381 |
for (i = 0; i < nb_sectors; i++) |
|
382 |
set_bit(bs->cow_bitmap, sector_num + i); |
|
383 |
} |
|
384 |
return 0; |
|
310 |
return bs->drv->bdrv_write(bs, sector_num, buf, nb_sectors); |
|
385 | 311 |
} |
386 | 312 |
|
387 | 313 |
void bdrv_get_geometry(BlockDriverState *bs, int64_t *nb_sectors_ptr) |
... | ... | |
459 | 385 |
bs->change_opaque = opaque; |
460 | 386 |
} |
461 | 387 |
|
388 |
int bdrv_is_encrypted(BlockDriverState *bs) |
|
389 |
{ |
|
390 |
if (bs->backing_hd && bs->backing_hd->encrypted) |
|
391 |
return 1; |
|
392 |
return bs->encrypted; |
|
393 |
} |
|
394 |
|
|
395 |
int bdrv_set_key(BlockDriverState *bs, const char *key) |
|
396 |
{ |
|
397 |
int ret; |
|
398 |
if (bs->backing_hd && bs->backing_hd->encrypted) { |
|
399 |
ret = bdrv_set_key(bs->backing_hd, key); |
|
400 |
if (ret < 0) |
|
401 |
return ret; |
|
402 |
if (!bs->encrypted) |
|
403 |
return 0; |
|
404 |
} |
|
405 |
if (!bs->encrypted || !bs->drv || !bs->drv->bdrv_set_key) |
|
406 |
return -1; |
|
407 |
return bs->drv->bdrv_set_key(bs, key); |
|
408 |
} |
|
409 |
|
|
410 |
void bdrv_get_format(BlockDriverState *bs, char *buf, int buf_size) |
|
411 |
{ |
|
412 |
if (!bs->inserted || !bs->drv) { |
|
413 |
buf[0] = '\0'; |
|
414 |
} else { |
|
415 |
pstrcpy(buf, buf_size, bs->drv->format_name); |
|
416 |
} |
|
417 |
} |
|
418 |
|
|
419 |
void bdrv_iterate_format(void (*it)(void *opaque, const char *name), |
|
420 |
void *opaque) |
|
421 |
{ |
|
422 |
BlockDriver *drv; |
|
423 |
|
|
424 |
for (drv = first_drv; drv != NULL; drv = drv->next) { |
|
425 |
it(opaque, drv->format_name); |
|
426 |
} |
|
427 |
} |
|
428 |
|
|
462 | 429 |
BlockDriverState *bdrv_find(const char *name) |
463 | 430 |
{ |
464 | 431 |
BlockDriverState *bs; |
... | ... | |
479 | 446 |
} |
480 | 447 |
} |
481 | 448 |
|
449 |
const char *bdrv_get_device_name(BlockDriverState *bs) |
|
450 |
{ |
|
451 |
return bs->device_name; |
|
452 |
} |
|
453 |
|
|
482 | 454 |
void bdrv_info(void) |
483 | 455 |
{ |
484 | 456 |
BlockDriverState *bs; |
... | ... | |
503 | 475 |
} |
504 | 476 |
if (bs->inserted) { |
505 | 477 |
term_printf(" file=%s", bs->filename); |
478 |
if (bs->backing_file[0] != '\0') |
|
479 |
term_printf(" backing_file=%s", bs->backing_file); |
|
506 | 480 |
term_printf(" ro=%d", bs->read_only); |
481 |
term_printf(" drv=%s", bs->drv->format_name); |
|
482 |
if (bs->encrypted) |
|
483 |
term_printf(" encrypted"); |
|
507 | 484 |
} else { |
508 | 485 |
term_printf(" [not inserted]"); |
509 | 486 |
} |
510 | 487 |
term_printf("\n"); |
511 | 488 |
} |
512 | 489 |
} |
490 |
|
|
491 |
|
|
492 |
/**************************************************************/ |
|
493 |
/* RAW block driver */ |
|
494 |
|
|
495 |
typedef struct BDRVRawState { |
|
496 |
int fd; |
|
497 |
} BDRVRawState; |
|
498 |
|
|
499 |
static int raw_probe(const uint8_t *buf, int buf_size, const char *filename) |
|
500 |
{ |
|
501 |
return 1; /* maybe */ |
|
502 |
} |
|
503 |
|
|
504 |
static int raw_open(BlockDriverState *bs, const char *filename) |
|
505 |
{ |
|
506 |
BDRVRawState *s = bs->opaque; |
|
507 |
int fd; |
|
508 |
int64_t size; |
|
509 |
|
|
510 |
fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE); |
|
511 |
if (fd < 0) { |
|
512 |
fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE); |
|
513 |
if (fd < 0) |
|
514 |
return -1; |
|
515 |
bs->read_only = 1; |
|
516 |
} |
|
517 |
size = lseek64(fd, 0, SEEK_END); |
|
518 |
bs->total_sectors = size / 512; |
|
519 |
s->fd = fd; |
|
520 |
return 0; |
|
521 |
} |
|
522 |
|
|
523 |
static int raw_read(BlockDriverState *bs, int64_t sector_num, |
|
524 |
uint8_t *buf, int nb_sectors) |
|
525 |
{ |
|
526 |
BDRVRawState *s = bs->opaque; |
|
527 |
int ret; |
|
528 |
|
|
529 |
lseek64(s->fd, sector_num * 512, SEEK_SET); |
|
530 |
ret = read(s->fd, buf, nb_sectors * 512); |
|
531 |
if (ret != nb_sectors * 512) |
|
532 |
return -1; |
|
533 |
return 0; |
|
534 |
} |
|
535 |
|
|
536 |
static int raw_write(BlockDriverState *bs, int64_t sector_num, |
|
537 |
const uint8_t *buf, int nb_sectors) |
|
538 |
{ |
|
539 |
BDRVRawState *s = bs->opaque; |
|
540 |
int ret; |
|
541 |
|
|
542 |
lseek64(s->fd, sector_num * 512, SEEK_SET); |
|
543 |
ret = write(s->fd, buf, nb_sectors * 512); |
|
544 |
if (ret != nb_sectors * 512) |
|
545 |
return -1; |
|
546 |
return 0; |
|
547 |
} |
|
548 |
|
|
549 |
static int raw_close(BlockDriverState *bs) |
|
550 |
{ |
|
551 |
BDRVRawState *s = bs->opaque; |
|
552 |
close(s->fd); |
|
553 |
} |
|
554 |
|
|
555 |
static int raw_create(const char *filename, int64_t total_size, |
|
556 |
const char *backing_file, int flags) |
|
557 |
{ |
|
558 |
int fd; |
|
559 |
|
|
560 |
if (flags || backing_file) |
|
561 |
return -ENOTSUP; |
|
562 |
|
|
563 |
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE, |
|
564 |
0644); |
|
565 |
if (fd < 0) |
|
566 |
return -EIO; |
|
567 |
ftruncate64(fd, total_size * 512); |
|
568 |
close(fd); |
|
569 |
return 0; |
|
570 |
} |
|
571 |
|
|
572 |
BlockDriver bdrv_raw = { |
|
573 |
"raw", |
|
574 |
sizeof(BDRVRawState), |
|
575 |
raw_probe, |
|
576 |
raw_open, |
|
577 |
raw_read, |
|
578 |
raw_write, |
|
579 |
raw_close, |
|
580 |
raw_create, |
|
581 |
}; |
|
582 |
|
|
583 |
void bdrv_init(void) |
|
584 |
{ |
|
585 |
bdrv_register(&bdrv_raw); |
|
586 |
#ifndef _WIN32 |
|
587 |
bdrv_register(&bdrv_cow); |
|
588 |
#endif |
|
589 |
bdrv_register(&bdrv_qcow); |
|
590 |
bdrv_register(&bdrv_vmdk); |
|
591 |
} |
Also available in: Unified diff