Revision 5dafc53f vl.c
b/vl.c | ||
---|---|---|
6198 | 6198 |
#define IO_BUF_SIZE 32768 |
6199 | 6199 |
|
6200 | 6200 |
struct QEMUFile { |
6201 |
FILE *outfile; |
|
6202 |
BlockDriverState *bs; |
|
6203 |
int is_file; |
|
6204 |
int is_writable; |
|
6205 |
int64_t base_offset; |
|
6201 |
QEMUFilePutBufferFunc *put_buffer; |
|
6202 |
QEMUFileGetBufferFunc *get_buffer; |
|
6203 |
QEMUFileCloseFunc *close; |
|
6204 |
QEMUFileRateLimit *rate_limit; |
|
6205 |
void *opaque; |
|
6206 |
|
|
6206 | 6207 |
int64_t buf_offset; /* start of buffer when writing, end of buffer |
6207 | 6208 |
when reading */ |
6208 | 6209 |
int buf_index; |
... | ... | |
6210 | 6211 |
uint8_t buf[IO_BUF_SIZE]; |
6211 | 6212 |
}; |
6212 | 6213 |
|
6214 |
typedef struct QEMUFileFD |
|
6215 |
{ |
|
6216 |
int fd; |
|
6217 |
QEMUFile *file; |
|
6218 |
} QEMUFileFD; |
|
6219 |
|
|
6220 |
static void fd_put_notify(void *opaque) |
|
6221 |
{ |
|
6222 |
QEMUFileFD *s = opaque; |
|
6223 |
|
|
6224 |
/* Remove writable callback and do a put notify */ |
|
6225 |
qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL); |
|
6226 |
qemu_file_put_notify(s->file); |
|
6227 |
} |
|
6228 |
|
|
6229 |
static int fd_put_buffer(void *opaque, const uint8_t *buf, |
|
6230 |
int64_t pos, int size) |
|
6231 |
{ |
|
6232 |
QEMUFileFD *s = opaque; |
|
6233 |
ssize_t len; |
|
6234 |
|
|
6235 |
do { |
|
6236 |
len = write(s->fd, buf, size); |
|
6237 |
} while (len == -1 && errno == EINTR); |
|
6238 |
|
|
6239 |
if (len == -1) |
|
6240 |
len = -errno; |
|
6241 |
|
|
6242 |
/* When the fd becomes writable again, register a callback to do |
|
6243 |
* a put notify */ |
|
6244 |
if (len == -EAGAIN) |
|
6245 |
qemu_set_fd_handler2(s->fd, NULL, NULL, fd_put_notify, s); |
|
6246 |
|
|
6247 |
return len; |
|
6248 |
} |
|
6249 |
|
|
6250 |
static int fd_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size) |
|
6251 |
{ |
|
6252 |
QEMUFileFD *s = opaque; |
|
6253 |
ssize_t len; |
|
6254 |
|
|
6255 |
do { |
|
6256 |
len = read(s->fd, buf, size); |
|
6257 |
} while (len == -1 && errno == EINTR); |
|
6258 |
|
|
6259 |
if (len == -1) |
|
6260 |
len = -errno; |
|
6261 |
|
|
6262 |
return len; |
|
6263 |
} |
|
6264 |
|
|
6265 |
static int fd_close(void *opaque) |
|
6266 |
{ |
|
6267 |
QEMUFileFD *s = opaque; |
|
6268 |
qemu_free(s); |
|
6269 |
return 0; |
|
6270 |
} |
|
6271 |
|
|
6272 |
QEMUFile *qemu_fopen_fd(int fd) |
|
6273 |
{ |
|
6274 |
QEMUFileFD *s = qemu_mallocz(sizeof(QEMUFileFD)); |
|
6275 |
|
|
6276 |
if (s == NULL) |
|
6277 |
return NULL; |
|
6278 |
|
|
6279 |
s->fd = fd; |
|
6280 |
s->file = qemu_fopen_ops(s, fd_put_buffer, fd_get_buffer, fd_close, NULL); |
|
6281 |
return s->file; |
|
6282 |
} |
|
6283 |
|
|
6284 |
typedef struct QEMUFileStdio |
|
6285 |
{ |
|
6286 |
FILE *outfile; |
|
6287 |
} QEMUFileStdio; |
|
6288 |
|
|
6289 |
static void file_put_buffer(void *opaque, const uint8_t *buf, |
|
6290 |
int64_t pos, int size) |
|
6291 |
{ |
|
6292 |
QEMUFileStdio *s = opaque; |
|
6293 |
fseek(s->outfile, pos, SEEK_SET); |
|
6294 |
fwrite(buf, 1, size, s->outfile); |
|
6295 |
} |
|
6296 |
|
|
6297 |
static int file_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size) |
|
6298 |
{ |
|
6299 |
QEMUFileStdio *s = opaque; |
|
6300 |
fseek(s->outfile, pos, SEEK_SET); |
|
6301 |
return fread(buf, 1, size, s->outfile); |
|
6302 |
} |
|
6303 |
|
|
6304 |
static int file_close(void *opaque) |
|
6305 |
{ |
|
6306 |
QEMUFileStdio *s = opaque; |
|
6307 |
fclose(s->outfile); |
|
6308 |
qemu_free(s); |
|
6309 |
return 0; |
|
6310 |
} |
|
6311 |
|
|
6213 | 6312 |
QEMUFile *qemu_fopen(const char *filename, const char *mode) |
6214 | 6313 |
{ |
6215 |
QEMUFile *f;
|
|
6314 |
QEMUFileStdio *s;
|
|
6216 | 6315 |
|
6217 |
f = qemu_mallocz(sizeof(QEMUFile));
|
|
6218 |
if (!f)
|
|
6316 |
s = qemu_mallocz(sizeof(QEMUFileStdio));
|
|
6317 |
if (!s)
|
|
6219 | 6318 |
return NULL; |
6220 |
if (!strcmp(mode, "wb")) { |
|
6221 |
f->is_writable = 1; |
|
6222 |
} else if (!strcmp(mode, "rb")) { |
|
6223 |
f->is_writable = 0; |
|
6224 |
} else { |
|
6225 |
goto fail; |
|
6226 |
} |
|
6227 |
f->outfile = fopen(filename, mode); |
|
6228 |
if (!f->outfile) |
|
6319 |
|
|
6320 |
s->outfile = fopen(filename, mode); |
|
6321 |
if (!s->outfile) |
|
6229 | 6322 |
goto fail; |
6230 |
f->is_file = 1; |
|
6231 |
return f; |
|
6232 |
fail: |
|
6233 |
if (f->outfile) |
|
6234 |
fclose(f->outfile); |
|
6235 |
qemu_free(f); |
|
6323 |
|
|
6324 |
if (!strcmp(mode, "wb")) |
|
6325 |
return qemu_fopen_ops(s, file_put_buffer, NULL, file_close, NULL); |
|
6326 |
else if (!strcmp(mode, "rb")) |
|
6327 |
return qemu_fopen_ops(s, NULL, file_get_buffer, file_close, NULL); |
|
6328 |
|
|
6329 |
fail: |
|
6330 |
if (s->outfile) |
|
6331 |
fclose(s->outfile); |
|
6332 |
qemu_free(s); |
|
6236 | 6333 |
return NULL; |
6237 | 6334 |
} |
6238 | 6335 |
|
6239 |
static QEMUFile *qemu_fopen_bdrv(BlockDriverState *bs, int64_t offset, int is_writable) |
|
6336 |
typedef struct QEMUFileBdrv |
|
6337 |
{ |
|
6338 |
BlockDriverState *bs; |
|
6339 |
int64_t base_offset; |
|
6340 |
} QEMUFileBdrv; |
|
6341 |
|
|
6342 |
static void bdrv_put_buffer(void *opaque, const uint8_t *buf, |
|
6343 |
int64_t pos, int size) |
|
6344 |
{ |
|
6345 |
QEMUFileBdrv *s = opaque; |
|
6346 |
bdrv_pwrite(s->bs, s->base_offset + pos, buf, size); |
|
6347 |
} |
|
6348 |
|
|
6349 |
static int bdrv_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size) |
|
6350 |
{ |
|
6351 |
QEMUFileBdrv *s = opaque; |
|
6352 |
return bdrv_pread(s->bs, s->base_offset + pos, buf, size); |
|
6353 |
} |
|
6354 |
|
|
6355 |
static int bdrv_fclose(void *opaque) |
|
6356 |
{ |
|
6357 |
QEMUFileBdrv *s = opaque; |
|
6358 |
qemu_free(s); |
|
6359 |
return 0; |
|
6360 |
} |
|
6361 |
|
|
6362 |
QEMUFile *qemu_fopen_bdrv(BlockDriverState *bs, int64_t offset, int is_writable) |
|
6363 |
{ |
|
6364 |
QEMUFileBdrv *s; |
|
6365 |
|
|
6366 |
s = qemu_mallocz(sizeof(QEMUFileBdrv)); |
|
6367 |
if (!s) |
|
6368 |
return NULL; |
|
6369 |
|
|
6370 |
s->bs = bs; |
|
6371 |
s->base_offset = offset; |
|
6372 |
|
|
6373 |
if (is_writable) |
|
6374 |
return qemu_fopen_ops(s, bdrv_put_buffer, NULL, bdrv_fclose, NULL); |
|
6375 |
|
|
6376 |
return qemu_fopen_ops(s, NULL, bdrv_get_buffer, bdrv_fclose, NULL); |
|
6377 |
} |
|
6378 |
|
|
6379 |
QEMUFile *qemu_fopen_ops(void *opaque, QEMUFilePutBufferFunc *put_buffer, |
|
6380 |
QEMUFileGetBufferFunc *get_buffer, |
|
6381 |
QEMUFileCloseFunc *close, |
|
6382 |
QEMUFileRateLimit *rate_limit) |
|
6240 | 6383 |
{ |
6241 | 6384 |
QEMUFile *f; |
6242 | 6385 |
|
6243 | 6386 |
f = qemu_mallocz(sizeof(QEMUFile)); |
6244 | 6387 |
if (!f) |
6245 | 6388 |
return NULL; |
6246 |
f->is_file = 0; |
|
6247 |
f->bs = bs; |
|
6248 |
f->is_writable = is_writable; |
|
6249 |
f->base_offset = offset; |
|
6389 |
|
|
6390 |
f->opaque = opaque; |
|
6391 |
f->put_buffer = put_buffer; |
|
6392 |
f->get_buffer = get_buffer; |
|
6393 |
f->close = close; |
|
6394 |
f->rate_limit = rate_limit; |
|
6395 |
|
|
6250 | 6396 |
return f; |
6251 | 6397 |
} |
6252 | 6398 |
|
6253 | 6399 |
void qemu_fflush(QEMUFile *f) |
6254 | 6400 |
{ |
6255 |
if (!f->is_writable)
|
|
6401 |
if (!f->put_buffer)
|
|
6256 | 6402 |
return; |
6403 |
|
|
6257 | 6404 |
if (f->buf_index > 0) { |
6258 |
if (f->is_file) { |
|
6259 |
fseek(f->outfile, f->buf_offset, SEEK_SET); |
|
6260 |
fwrite(f->buf, 1, f->buf_index, f->outfile); |
|
6261 |
} else { |
|
6262 |
bdrv_pwrite(f->bs, f->base_offset + f->buf_offset, |
|
6263 |
f->buf, f->buf_index); |
|
6264 |
} |
|
6405 |
f->put_buffer(f->opaque, f->buf, f->buf_offset, f->buf_index); |
|
6265 | 6406 |
f->buf_offset += f->buf_index; |
6266 | 6407 |
f->buf_index = 0; |
6267 | 6408 |
} |
... | ... | |
6271 | 6412 |
{ |
6272 | 6413 |
int len; |
6273 | 6414 |
|
6274 |
if (f->is_writable)
|
|
6415 |
if (!f->get_buffer)
|
|
6275 | 6416 |
return; |
6276 |
if (f->is_file) { |
|
6277 |
fseek(f->outfile, f->buf_offset, SEEK_SET); |
|
6278 |
len = fread(f->buf, 1, IO_BUF_SIZE, f->outfile); |
|
6279 |
if (len < 0) |
|
6280 |
len = 0; |
|
6281 |
} else { |
|
6282 |
len = bdrv_pread(f->bs, f->base_offset + f->buf_offset, |
|
6283 |
f->buf, IO_BUF_SIZE); |
|
6284 |
if (len < 0) |
|
6285 |
len = 0; |
|
6286 |
} |
|
6417 |
|
|
6418 |
len = f->get_buffer(f->opaque, f->buf, f->buf_offset, IO_BUF_SIZE); |
|
6419 |
if (len < 0) |
|
6420 |
len = 0; |
|
6421 |
|
|
6287 | 6422 |
f->buf_index = 0; |
6288 | 6423 |
f->buf_size = len; |
6289 | 6424 |
f->buf_offset += len; |
6290 | 6425 |
} |
6291 | 6426 |
|
6292 |
void qemu_fclose(QEMUFile *f)
|
|
6427 |
int qemu_fclose(QEMUFile *f)
|
|
6293 | 6428 |
{ |
6294 |
if (f->is_writable) |
|
6295 |
qemu_fflush(f); |
|
6296 |
if (f->is_file) { |
|
6297 |
fclose(f->outfile); |
|
6298 |
} |
|
6429 |
int ret = 0; |
|
6430 |
qemu_fflush(f); |
|
6431 |
if (f->close) |
|
6432 |
ret = f->close(f->opaque); |
|
6299 | 6433 |
qemu_free(f); |
6434 |
return ret; |
|
6435 |
} |
|
6436 |
|
|
6437 |
void qemu_file_put_notify(QEMUFile *f) |
|
6438 |
{ |
|
6439 |
f->put_buffer(f->opaque, NULL, 0, 0); |
|
6300 | 6440 |
} |
6301 | 6441 |
|
6302 | 6442 |
void qemu_put_buffer(QEMUFile *f, const uint8_t *buf, int size) |
... | ... | |
6370 | 6510 |
/* SEEK_END not supported */ |
6371 | 6511 |
return -1; |
6372 | 6512 |
} |
6373 |
if (f->is_writable) {
|
|
6513 |
if (f->put_buffer) {
|
|
6374 | 6514 |
qemu_fflush(f); |
6375 | 6515 |
f->buf_offset = pos; |
6376 | 6516 |
} else { |
... | ... | |
6381 | 6521 |
return pos; |
6382 | 6522 |
} |
6383 | 6523 |
|
6524 |
int qemu_file_rate_limit(QEMUFile *f) |
|
6525 |
{ |
|
6526 |
if (f->rate_limit) |
|
6527 |
return f->rate_limit(f->opaque); |
|
6528 |
|
|
6529 |
return 0; |
|
6530 |
} |
|
6531 |
|
|
6384 | 6532 |
void qemu_put_be16(QEMUFile *f, unsigned int v) |
6385 | 6533 |
{ |
6386 | 6534 |
qemu_put_byte(f, v >> 8); |
Also available in: Unified diff