#include "kvm/disk-image.h"
+#include "kvm/read-write.h"
#include "kvm/util.h"
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
-static const char QCOW_MAGIC[] = { 'Q', 'F', 'I', 0xfb };
-
-struct qcow_header {
- uint8_t magic[5];
-};
-
-static bool disk_image__is_qcow(struct disk_image *self)
-{
- struct qcow_header *header = self->mmap;
-
- return !memcmp(header->magic, QCOW_MAGIC, ARRAY_SIZE(QCOW_MAGIC));
-}
-
struct disk_image *disk_image__open(const char *filename)
{
struct disk_image *self;
if (!self)
return NULL;
- self->fd = open(filename, O_RDONLY);
+ self->fd = open(filename, O_RDWR);
if (self->fd < 0)
goto failed_free;
self->size = st.st_size;
- self->mmap = mmap(NULL, self->size, PROT_READ|PROT_WRITE, MAP_PRIVATE, self->fd, 0);
- if (self->mmap == MAP_FAILED)
- goto failed_close_fd;
-
- if (disk_image__is_qcow(self))
- die("QCOW disk image format is not supported.");
-
return self;
failed_close_fd:
void disk_image__close(struct disk_image *self)
{
- if (munmap(self->mmap, self->size) < 0)
- warning("munmap() failed");
-
if (close(self->fd) < 0)
warning("close() failed");
if (offset + dst_len > self->size)
return -1;
- memcpy(dst, self->mmap + offset, dst_len);
+ if (lseek(self->fd, offset, SEEK_SET) < 0)
+ return -1;
+
+ if (read_in_full(self->fd, dst, dst_len) < 0)
+ return -1;
return 0;
}
if (offset + src_len > self->size)
return -1;
- memcpy(self->mmap + offset, src, src_len);
+ if (lseek(self->fd, offset, SEEK_SET) < 0)
+ return -1;
+
+ if (write_in_full(self->fd, src, src_len) < 0)
+ return -1;
return 0;
}
--- /dev/null
+#ifndef KVM_READ_WRITE_H
+#define KVM_READ_WRITE_H
+
+#include <sys/types.h>
+#include <unistd.h>
+
+ssize_t xread(int fd, void *buf, size_t count);
+ssize_t xwrite(int fd, const void *buf, size_t count);
+
+ssize_t read_in_full(int fd, void *buf, size_t count);
+ssize_t write_in_full(int fd, const void *buf, size_t count);
+
+#endif /* KVM_READ_WRITE_H */
--- /dev/null
+#include "kvm/read-write.h"
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+
+/* Same as read(2) except that this function never returns EAGAIN or EINTR. */
+ssize_t xread(int fd, void *buf, size_t count)
+{
+ ssize_t nr;
+
+restart:
+ nr = read(fd, buf, count);
+ if ((nr < 0) && ((errno == EAGAIN) || (errno == EINTR)))
+ goto restart;
+
+ return nr;
+}
+
+/* Same as write(2) except that this function never returns EAGAIN or EINTR. */
+ssize_t xwrite(int fd, const void *buf, size_t count)
+{
+ ssize_t nr;
+
+restart:
+ nr = write(fd, buf, count);
+ if ((nr < 0) && ((errno == EAGAIN) || (errno == EINTR)))
+ goto restart;
+
+ return nr;
+}
+
+ssize_t read_in_full(int fd, void *buf, size_t count)
+{
+ ssize_t total = 0;
+ char *p = buf;
+
+ while (count > 0) {
+ ssize_t nr;
+
+ nr = xread(fd, p, count);
+ if (nr <= 0) {
+ if (total > 0)
+ return total;
+
+ return -1;
+ }
+
+ count -= nr;
+ total += nr;
+ p += nr;
+ }
+
+ return total;
+}
+
+ssize_t write_in_full(int fd, const void *buf, size_t count)
+{
+ const char *p = buf;
+ ssize_t total = 0;
+
+ while (count > 0) {
+ ssize_t nr;
+
+ nr = xwrite(fd, p, count);
+ if (nr < 0)
+ return -1;
+ if (nr == 0) {
+ errno = ENOSPC;
+ return -1;
+ }
+ count -= nr;
+ total += nr;
+ p += nr;
+ }
+
+ return total;
+}