|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH 3 of 8 RESEND] blktap3/vhd: Introduce libvhd-index.c
This patch introduces libvhd-index.c, imported from blktap2.5. It seems to
contain definitions for the VHD on-file header as well as functionality for
accessing/manipulating it.
Signed-off-by: Thanos Makatos <thanos.makatos@xxxxxxxxxx>
diff --git a/tools/blktap3/vhd/lib/libvhd-index.c
b/tools/blktap3/vhd/lib/libvhd-index.c
new file mode 100644
--- /dev/null
+++ b/tools/blktap3/vhd/lib/libvhd-index.c
@@ -0,0 +1,1198 @@
+/*
+ * Copyright (c) 2008, XenSource Inc.
+ * Copyright (c) 2010, Citrix Systems, Inc.
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of XenSource Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <libgen.h>
+#include <limits.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include "libvhd.h"
+#include "libvhd-index.h"
+#include "relative-path.h"
+
+typedef struct vhdi_path vhdi_path_t;
+typedef struct vhdi_header vhdi_header_t;
+typedef struct vhdi_bat_header vhdi_bat_header_t;
+typedef struct vhdi_file_table_header vhdi_file_table_header_t;
+typedef struct vhdi_file_table_entry vhdi_file_table_entry_t;
+
+static const char VHDI_HEADER_COOKIE[] = "vhdindex";
+static const char VHDI_BAT_HEADER_COOKIE[] = "vhdi-bat";
+static const char VHDI_FILE_TABLE_HEADER_COOKIE[] = "vhdifile";
+
+struct vhdi_path {
+ char path[VHD_MAX_NAME_LEN];
+ uint16_t bytes;
+};
+
+struct vhdi_header {
+ char cookie[8];
+ uint32_t vhd_block_size;
+ uint64_t table_offset;
+};
+
+struct vhdi_bat_header {
+ char cookie[8];
+ uint64_t vhd_blocks;
+ uint32_t vhd_block_size;
+ vhdi_path_t vhd_path;
+ vhdi_path_t index_path;
+ vhdi_path_t file_table_path;
+ uint64_t table_offset;
+};
+
+struct vhdi_file_table_header {
+ char cookie[8];
+ uint32_t files;
+ uint64_t table_offset;
+};
+
+struct vhdi_file_table_entry {
+ vhdi_path_t p;
+ vhdi_file_id_t file_id;
+ uuid_t vhd_uuid;
+ uint32_t vhd_timestamp;
+};
+
+static inline int vhdi_seek(vhdi_context_t * ctx, off64_t off, int whence)
+{
+ int err;
+
+ err = lseek64(ctx->fd, off, whence);
+ if (err == (off64_t) - 1)
+ return -errno;
+
+ return 0;
+}
+
+static inline off64_t vhdi_position(vhdi_context_t * ctx)
+{
+ return lseek64(ctx->fd, 0, SEEK_CUR);
+}
+
+static inline int vhdi_read(vhdi_context_t * ctx, void *buf, size_t size)
+{
+ int err;
+
+ err = read(ctx->fd, buf, size);
+ if (err != size)
+ return (errno ? -errno : -EIO);
+
+ return 0;
+}
+
+static inline int vhdi_write(vhdi_context_t * ctx, void *buf, size_t size)
+{
+ int err;
+
+ err = write(ctx->fd, buf, size);
+ if (err != size)
+ return (errno ? -errno : -EIO);
+
+ return 0;
+}
+
+static inline int vhdi_check_block_size(uint32_t block_size)
+{
+ int i, cnt;
+
+ cnt = 0;
+ for (i = 0; i < 32; i++)
+ if ((block_size >> i) & 0x0001)
+ cnt++;
+
+ if (cnt == 1)
+ return 0;
+
+ return -EINVAL;
+}
+
+static inline void vhdi_header_in(vhdi_header_t * header)
+{
+ BE32_IN(&header->vhd_block_size);
+ BE64_IN(&header->table_offset);
+}
+
+static inline void vhdi_header_out(vhdi_header_t * header)
+{
+ BE32_OUT(&header->vhd_block_size);
+ BE64_OUT(&header->table_offset);
+}
+
+static inline int vhdi_header_validate(vhdi_header_t * header)
+{
+ if (memcmp(header->cookie, VHDI_HEADER_COOKIE, sizeof(header->cookie)))
+ return -EINVAL;
+
+ return vhdi_check_block_size(header->vhd_block_size);
+}
+
+void vhdi_entry_in(vhdi_entry_t * entry)
+{
+ BE32_IN(&entry->file_id);
+ BE32_IN(&entry->offset);
+}
+
+static inline vhdi_entry_t vhdi_entry_out(vhdi_entry_t * entry)
+{
+ vhdi_entry_t e;
+
+ e = *entry;
+ BE32_OUT(&e.file_id);
+ BE32_OUT(&e.offset);
+
+ return e;
+}
+
+static inline void vhdi_path_in(vhdi_path_t * path)
+{
+ BE16_IN(&path->bytes);
+}
+
+static inline void vhdi_path_out(vhdi_path_t * path)
+{
+ BE16_OUT(&path->bytes);
+}
+
+static inline void vhdi_bat_header_in(vhdi_bat_header_t * header)
+{
+ BE64_IN(&header->vhd_blocks);
+ BE32_IN(&header->vhd_block_size);
+ vhdi_path_in(&header->vhd_path);
+ vhdi_path_in(&header->index_path);
+ vhdi_path_in(&header->file_table_path);
+ BE64_IN(&header->table_offset);
+}
+
+static inline void vhdi_bat_header_out(vhdi_bat_header_t * header)
+{
+ BE64_OUT(&header->vhd_blocks);
+ BE32_OUT(&header->vhd_block_size);
+ vhdi_path_out(&header->vhd_path);
+ vhdi_path_out(&header->index_path);
+ vhdi_path_out(&header->file_table_path);
+ BE64_OUT(&header->table_offset);
+}
+
+static inline int vhdi_path_validate(vhdi_path_t * path)
+{
+ int i;
+
+ if (path->bytes >= VHD_MAX_NAME_LEN - 1)
+ return -ENAMETOOLONG;
+
+ for (i = 0; i < path->bytes; i++)
+ if (path->path[i] == '\0')
+ return 0;
+
+ return -EINVAL;
+}
+
+static inline char *vhdi_path_expand(const char *src, vhdi_path_t * dest,
+ int *err)
+{
+ int len;
+ char *path, *base, copy[VHD_MAX_NAME_LEN];
+ char *absolute_path, __absolute_path[PATH_MAX];
+
+ strcpy(copy, src);
+ base = dirname(copy);
+
+ *err = asprintf(&path, "%s/%s", base, dest->path);
+ if (*err == -1) {
+ *err = -ENOMEM;
+ return NULL;
+ }
+
+ absolute_path = realpath(path, __absolute_path);
+ free(path);
+ if (absolute_path)
+ absolute_path = strdup(absolute_path);
+ if (!absolute_path) {
+ *err = -errno;
+ return NULL;
+ }
+
+ len = strnlen(absolute_path, VHD_MAX_NAME_LEN - 1);
+ if (len == VHD_MAX_NAME_LEN - 1) {
+ free(absolute_path);
+ *err = -ENAMETOOLONG;
+ return NULL;
+ }
+
+ *err = 0;
+ return absolute_path;
+}
+
+static inline int vhdi_bat_header_validate(vhdi_bat_header_t * header)
+{
+ int err;
+
+ if (memcmp(header->cookie,
+ VHDI_BAT_HEADER_COOKIE, sizeof(header->cookie)))
+ return -EINVAL;
+
+ err = vhdi_check_block_size(header->vhd_block_size);
+ if (err)
+ return err;
+
+ err = vhdi_path_validate(&header->vhd_path);
+ if (err)
+ return err;
+
+ err = vhdi_path_validate(&header->index_path);
+ if (err)
+ return err;
+
+ err = vhdi_path_validate(&header->file_table_path);
+ if (err)
+ return err;
+
+ return 0;
+}
+
+static inline int vhdi_bat_load_header(int fd, vhdi_bat_header_t * header)
+{
+ int err;
+
+ err = lseek64(fd, 0, SEEK_SET);
+ if (err == (off64_t) - 1)
+ return -errno;
+
+ err = read(fd, header, sizeof(vhdi_bat_header_t));
+ if (err != sizeof(vhdi_bat_header_t))
+ return (errno ? -errno : -EIO);
+
+ vhdi_bat_header_in(header);
+ return vhdi_bat_header_validate(header);
+}
+
+static inline void
+vhdi_file_table_header_in(vhdi_file_table_header_t * header)
+{
+ BE32_OUT(&header->files);
+ BE64_OUT(&header->table_offset);
+}
+
+static inline void
+vhdi_file_table_header_out(vhdi_file_table_header_t * header)
+{
+ BE32_OUT(&header->files);
+ BE64_OUT(&header->table_offset);
+}
+
+static inline int
+vhdi_file_table_header_validate(vhdi_file_table_header_t * header)
+{
+ if (memcmp(header->cookie,
+ VHDI_FILE_TABLE_HEADER_COOKIE, sizeof(header->cookie)))
+ return -EINVAL;
+
+ return 0;
+}
+
+static inline int
+vhdi_file_table_load_header(int fd, vhdi_file_table_header_t * header)
+{
+ int err;
+
+ err = lseek64(fd, 0, SEEK_SET);
+ if (err == (off64_t) - 1)
+ return -errno;
+
+ err = read(fd, header, sizeof(vhdi_file_table_header_t));
+ if (err != sizeof(vhdi_file_table_header_t))
+ return (errno ? -errno : -EIO);
+
+ vhdi_file_table_header_in(header);
+ return vhdi_file_table_header_validate(header);
+}
+
+static inline int
+vhdi_file_table_write_header(int fd, vhdi_file_table_header_t * header)
+{
+ int err;
+
+ err = lseek64(fd, 0, SEEK_SET);
+ if (err == (off64_t) - 1)
+ return -errno;
+
+ err = vhdi_file_table_header_validate(header);
+ if (err)
+ return err;
+
+ vhdi_file_table_header_out(header);
+
+ err = write(fd, header, sizeof(vhdi_file_table_header_t));
+ if (err != sizeof(vhdi_file_table_header_t))
+ return (errno ? -errno : -EIO);
+
+ return 0;
+}
+
+static inline void
+vhdi_file_table_entry_in(vhdi_file_table_entry_t * entry)
+{
+ vhdi_path_in(&entry->p);
+ BE32_IN(&entry->file_id);
+ BE32_IN(&entry->vhd_timestamp);
+}
+
+static inline void
+vhdi_file_table_entry_out(vhdi_file_table_entry_t * entry)
+{
+ vhdi_path_out(&entry->p);
+ BE32_OUT(&entry->file_id);
+ BE32_OUT(&entry->vhd_timestamp);
+}
+
+static inline int
+vhdi_file_table_entry_validate(vhdi_file_table_entry_t * entry)
+{
+ return vhdi_path_validate(&entry->p);
+}
+
+static inline int
+vhdi_file_table_entry_validate_vhd(vhdi_file_table_entry_t * entry,
+ const char *path)
+{
+ int err;
+ vhd_context_t vhd;
+ struct stat stats;
+
+ err = stat(path, &stats);
+ if (err == -1)
+ return -errno;
+
+ if (entry->vhd_timestamp != vhd_time(stats.st_mtime))
+ return -EINVAL;
+
+ err = vhd_open(&vhd, path, VHD_OPEN_RDONLY);
+ if (err)
+ return err;
+
+ err = vhd_get_footer(&vhd);
+ if (err)
+ goto out;
+
+ if (uuid_compare(entry->vhd_uuid, vhd.footer.uuid)) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ out:
+ vhd_close(&vhd);
+ return err;
+}
+
+int vhdi_create(const char *name, uint32_t vhd_block_size)
+{
+ void *buf;
+ int err, fd;
+ size_t size;
+ vhdi_header_t header;
+
+ memset(&header, 0, sizeof(vhdi_header_t));
+
+ err = vhdi_check_block_size(vhd_block_size);
+ if (err)
+ return err;
+
+ err = access(name, F_OK);
+ if (!err || errno != ENOENT)
+ return (err ? err : -EEXIST);
+
+ memcpy(header.cookie, VHDI_HEADER_COOKIE, sizeof(header.cookie));
+ header.vhd_block_size = vhd_block_size;
+ header.table_offset = vhd_bytes_padded(sizeof(vhdi_header_t));
+
+ err = vhdi_header_validate(&header);
+ if (err)
+ return err;
+
+ vhdi_header_out(&header);
+
+ size = vhd_bytes_padded(sizeof(vhdi_header_t));
+ err = posix_memalign(&buf, VHD_SECTOR_SIZE, size);
+ if (err)
+ return -err;
+
+ memset(buf, 0, size);
+ memcpy(buf, &header, sizeof(vhdi_header_t));
+
+ fd = open(name, O_CREAT | O_TRUNC | O_RDWR, 0600);
+ if (fd == -1)
+ return -errno;
+
+ err = write(fd, buf, size);
+ if (err != size) {
+ err = (errno ? -errno : -EIO);
+ goto fail;
+ }
+
+ close(fd);
+ free(buf);
+
+ return 0;
+
+ fail:
+ close(fd);
+ free(buf);
+ unlink(name);
+ return err;
+}
+
+int vhdi_open(vhdi_context_t * ctx, const char *file, int flags)
+{
+ int err, fd;
+ size_t size;
+ char *name;
+ void *buf;
+ vhdi_header_t header;
+
+ buf = NULL;
+ memset(ctx, 0, sizeof(vhdi_context_t));
+
+ name = strdup(file);
+ if (!name)
+ return -ENOMEM;
+
+ fd = open(file, flags | O_LARGEFILE);
+ if (fd == -1) {
+ free(name);
+ return -errno;
+ }
+
+ size = vhd_bytes_padded(sizeof(vhdi_header_t));
+ err = posix_memalign(&buf, VHD_SECTOR_SIZE, size);
+ if (err) {
+ err = -err;
+ goto fail;
+ }
+
+ err = read(fd, buf, size);
+ if (err != size) {
+ err = (errno ? -errno : -EIO);
+ goto fail;
+ }
+
+ memcpy(&header, buf, sizeof(vhdi_header_t));
+ free(buf);
+ buf = NULL;
+
+ vhdi_header_in(&header);
+ err = vhdi_header_validate(&header);
+ if (err)
+ goto fail;
+
+ ctx->fd = fd;
+ ctx->name = name;
+ ctx->spb = header.vhd_block_size >> VHD_SECTOR_SHIFT;
+ ctx->vhd_block_size = header.vhd_block_size;
+
+ return 0;
+
+ fail:
+ close(fd);
+ free(buf);
+ free(name);
+ return err;
+}
+
+void vhdi_close(vhdi_context_t * ctx)
+{
+ close(ctx->fd);
+ free(ctx->name);
+}
+
+int
+vhdi_read_block(vhdi_context_t * ctx, vhdi_block_t * block,
+ uint32_t sector)
+{
+ int i, err;
+ size_t size;
+ void *tab;
+
+ err = vhdi_seek(ctx, vhd_sectors_to_bytes(sector), SEEK_SET);
+ if (err)
+ return err;
+
+ size = vhd_bytes_padded(ctx->spb * sizeof(vhdi_entry_t));
+
+ block->entries = ctx->spb;
+ err = posix_memalign(&tab, VHD_SECTOR_SIZE, size);
+ if (err)
+ return -err;
+
+ block->table = tab;
+
+ err = vhdi_read(ctx, block->table, size);
+ if (err)
+ goto fail;
+
+ for (i = 0; i < block->entries; i++)
+ vhdi_entry_in(&block->table[i]);
+
+ return 0;
+
+ fail:
+ free(block->table);
+ return err;
+}
+
+int
+vhdi_write_block(vhdi_context_t * ctx, vhdi_block_t * block,
+ uint32_t sector)
+{
+ void *buf;
+ int i, err;
+ size_t size;
+ vhdi_entry_t *entries;
+
+ err = vhdi_seek(ctx, vhd_sectors_to_bytes(sector), SEEK_SET);
+ if (err)
+ return err;
+
+ size = vhd_bytes_padded(ctx->spb * sizeof(vhdi_entry_t));
+ err = posix_memalign(&buf, VHD_SECTOR_SIZE, size);
+ if (err)
+ return -err;
+
+ memset(buf, 0, size);
+ entries = (vhdi_entry_t *) buf;
+
+ for (i = 0; i < block->entries; i++)
+ entries[i] = vhdi_entry_out(&block->table[i]);
+
+ err = vhdi_write(ctx, entries, size);
+ if (err)
+ goto out;
+
+ err = 0;
+
+ out:
+ free(entries);
+ return err;
+}
+
+int
+vhdi_append_block(vhdi_context_t * ctx, vhdi_block_t * block,
+ uint32_t * sector)
+{
+ void *buf;
+ int i, err;
+ off64_t off;
+ size_t size;
+ vhdi_entry_t *entries;
+
+ err = vhdi_seek(ctx, 0, SEEK_END);
+ if (err)
+ return err;
+
+ off = vhd_bytes_padded(vhdi_position(ctx));
+
+ err = vhdi_seek(ctx, off, SEEK_SET);
+ if (err)
+ return err;
+
+ size = vhd_bytes_padded(block->entries * sizeof(vhdi_entry_t));
+ err = posix_memalign(&buf, VHD_SECTOR_SIZE, size);
+ if (err)
+ return -err;
+
+ memset(buf, 0, size);
+ entries = buf;
+
+ for (i = 0; i < block->entries; i++)
+ entries[i] = vhdi_entry_out(&block->table[i]);
+
+ err = vhdi_write(ctx, entries, block->entries * sizeof(vhdi_entry_t));
+ if (err)
+ goto out;
+
+ err = 0;
+ *sector = off >> VHD_SECTOR_SHIFT;
+ out:
+ if (err) {
+ int gcc = ftruncate(ctx->fd, off);
+ if (gcc) {
+ }
+ }
+ free(entries);
+ return err;
+}
+
+static int
+vhdi_copy_path_to(vhdi_path_t * path, const char *src, const char *dest)
+{
+ int len, err;
+ char *file, *relative_path, copy[VHD_MAX_NAME_LEN];
+ char *absolute_path, __absolute_path[PATH_MAX];
+
+ strcpy(copy, dest);
+
+ file = basename(copy);
+ absolute_path = realpath(copy, __absolute_path);
+ relative_path = NULL;
+
+ if (!absolute_path) {
+ err = -errno;
+ goto out;
+ }
+
+ if (!strcmp(file, "")) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ relative_path = relative_path_to((char *) src, absolute_path, &err);
+ if (!relative_path || err) {
+ err = (err ? err : -EINVAL);
+ goto out;
+ }
+
+ len = strnlen(relative_path, VHD_MAX_NAME_LEN - 1);
+ if (len == VHD_MAX_NAME_LEN - 1) {
+ err = -ENAMETOOLONG;
+ goto out;
+ }
+
+ strcpy(path->path, relative_path);
+ path->bytes = len + 1;
+
+ err = 0;
+
+ out:
+ free(relative_path);
+ return err;
+}
+
+int
+vhdi_bat_create(const char *name, const char *vhd,
+ const char *index, const char *file_table)
+{
+ int err, fd;
+ off64_t off;
+ vhd_context_t ctx;
+ vhdi_bat_header_t header;
+
+ memset(&header, 0, sizeof(vhdi_bat_header_t));
+
+ err = access(name, F_OK);
+ if (!err || errno != ENOENT)
+ return (err ? -err : -EEXIST);
+
+ err = vhd_open(&ctx, vhd, VHD_OPEN_RDONLY);
+ if (err)
+ return err;
+
+ err = vhd_get_header(&ctx);
+ if (err) {
+ vhd_close(&ctx);
+ return err;
+ }
+
+ header.vhd_blocks = ctx.header.max_bat_size;
+ header.vhd_block_size = ctx.header.block_size;
+
+ vhd_close(&ctx);
+
+ fd = open(name, O_CREAT | O_TRUNC | O_RDWR, 0600);
+ if (fd == -1)
+ return -errno;
+
+ err = vhdi_copy_path_to(&header.vhd_path, name, vhd);
+ if (err)
+ goto fail;
+
+ err = vhdi_copy_path_to(&header.index_path, name, index);
+ if (err)
+ goto fail;
+
+ err = vhdi_copy_path_to(&header.file_table_path, name, file_table);
+ if (err)
+ goto fail;
+
+ off = vhd_bytes_padded(sizeof(vhdi_bat_header_t));
+
+ header.table_offset = off;
+ memcpy(header.cookie, VHDI_BAT_HEADER_COOKIE, sizeof(header.cookie));
+
+ err = vhdi_bat_header_validate(&header);
+ if (err)
+ goto fail;
+
+ vhdi_bat_header_out(&header);
+
+ err = write(fd, &header, sizeof(vhdi_bat_header_t));
+ if (err != sizeof(vhdi_bat_header_t)) {
+ err = (errno ? -errno : -EIO);
+ goto fail;
+ }
+
+ close(fd);
+ return 0;
+
+ fail:
+ close(fd);
+ unlink(name);
+ return err;
+}
+
+int vhdi_bat_load(const char *name, vhdi_bat_t * bat)
+{
+ char *path;
+ int err, fd;
+ size_t size;
+ uint32_t *table;
+ vhdi_bat_header_t header;
+
+ table = NULL;
+
+ fd = open(name, O_RDONLY | O_LARGEFILE);
+ if (fd == -1)
+ return -errno;
+
+ err = vhdi_bat_load_header(fd, &header);
+ if (err)
+ goto out;
+
+ size = header.vhd_blocks * sizeof(uint32_t);
+ table = malloc(size);
+ if (!table) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ err = lseek64(fd, header.table_offset, SEEK_SET);
+ if (err == (off64_t) - 1) {
+ err = -errno;
+ goto out;
+ }
+
+ err = read(fd, table, size);
+ if (err != size) {
+ err = (errno ? -errno : -EIO);
+ goto out;
+ }
+
+ path = vhdi_path_expand(name, &header.vhd_path, &err);
+ if (err)
+ goto out;
+ strcpy(bat->vhd_path, path);
+ free(path);
+
+ err = access(bat->vhd_path, F_OK);
+ if (err == -1) {
+ err = -errno;
+ goto out;
+ }
+
+ path = vhdi_path_expand(name, &header.index_path, &err);
+ if (err)
+ goto out;
+ strcpy(bat->index_path, path);
+ free(path);
+
+ err = access(bat->index_path, F_OK);
+ if (err == -1) {
+ err = -errno;
+ goto out;
+ }
+
+ path = vhdi_path_expand(name, &header.file_table_path, &err);
+ if (err)
+ goto out;
+ strcpy(bat->file_table_path, path);
+ free(path);
+
+ err = access(bat->file_table_path, F_OK);
+ if (err == -1) {
+ err = -errno;
+ goto out;
+ }
+
+ bat->vhd_blocks = header.vhd_blocks;
+ bat->vhd_block_size = header.vhd_block_size;
+ bat->table = table;
+
+ err = 0;
+
+ out:
+ close(fd);
+ if (err) {
+ free(table);
+ memset(bat, 0, sizeof(vhdi_bat_t));
+ }
+
+ return err;
+}
+
+int vhdi_bat_write(const char *name, vhdi_bat_t * bat)
+{
+ int err, fd;
+ size_t size;
+ vhdi_bat_header_t header;
+
+ fd = open(name, O_RDWR | O_LARGEFILE);
+ if (fd == -1)
+ return -errno;
+
+ err = vhdi_bat_load_header(fd, &header);
+ if (err)
+ goto out;
+
+ if (header.vhd_blocks != bat->vhd_blocks ||
+ header.vhd_block_size != bat->vhd_block_size) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ err = lseek64(fd, header.table_offset, SEEK_SET);
+ if (err == (off64_t) - 1) {
+ err = -errno;
+ goto out;
+ }
+
+ size = bat->vhd_blocks * sizeof(uint32_t);
+ err = write(fd, bat->table, size);
+ if (err != size) {
+ err = (errno ? -errno : -EIO);
+ goto out;
+ }
+
+ err = 0;
+
+ out:
+ close(fd);
+ return err;
+}
+
+int vhdi_file_table_create(const char *file)
+{
+ int err, fd;
+ off64_t off;
+ vhdi_file_table_header_t header;
+
+ memset(&header, 0, sizeof(vhdi_file_table_header_t));
+
+ err = access(file, F_OK);
+ if (!err || errno != ENOENT)
+ return (err ? err : -EEXIST);
+
+ off = vhd_bytes_padded(sizeof(vhdi_file_table_header_t));
+
+ header.files = 0;
+ header.table_offset = off;
+ memcpy(header.cookie,
+ VHDI_FILE_TABLE_HEADER_COOKIE, sizeof(header.cookie));
+
+ vhdi_file_table_header_out(&header);
+
+ fd = open(file, O_CREAT | O_TRUNC | O_RDWR, 0600);
+ if (fd == -1)
+ return -errno;
+
+ err = write(fd, &header, sizeof(vhdi_file_table_header_t));
+ if (err != sizeof(vhdi_file_table_header_t)) {
+ err = (errno ? -errno : -EIO);
+ goto out;
+ }
+
+ err = 0;
+
+ out:
+ close(fd);
+ return err;
+}
+
+int vhdi_file_table_load(const char *name, vhdi_file_table_t * table)
+{
+ off64_t off;
+ size_t size;
+ int err, i, fd;
+ vhdi_file_table_header_t header;
+ vhdi_file_table_entry_t *entries;
+
+ entries = NULL;
+
+ fd = open(name, O_RDONLY | O_LARGEFILE);
+ if (fd == -1)
+ return -errno;
+
+ err = vhdi_file_table_load_header(fd, &header);
+ if (err)
+ goto out;
+
+ if (!header.files)
+ goto out;
+
+ table->table = calloc(header.files, sizeof(vhdi_file_ref_t));
+ if (!table->table) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ off = header.table_offset;
+ err = lseek64(fd, off, SEEK_SET);
+ if (err == (off64_t) - 1) {
+ err = -errno;
+ goto out;
+ }
+
+ size = header.files * sizeof(vhdi_file_table_entry_t);
+ entries = calloc(header.files, sizeof(vhdi_file_table_entry_t));
+ if (!entries) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ err = read(fd, entries, size);
+ if (err != size) {
+ err = (errno ? -errno : -EIO);
+ goto out;
+ }
+
+ for (i = 0; i < header.files; i++) {
+ vhdi_file_table_entry_t *entry;
+
+ entry = entries + i;
+ vhdi_file_table_entry_in(entry);
+
+ err = vhdi_file_table_entry_validate(entry);
+ if (err)
+ goto out;
+
+ table->table[i].path = vhdi_path_expand(name, &entry->p, &err);
+ if (err)
+ goto out;
+
+ err = vhdi_file_table_entry_validate_vhd(entry,
+ table->table[i].path);
+ if (err)
+ goto out;
+
+ table->table[i].file_id = entry->file_id;
+ table->table[i].vhd_timestamp = entry->vhd_timestamp;
+ uuid_copy(table->table[i].vhd_uuid, entry->vhd_uuid);
+ }
+
+ err = 0;
+ table->entries = header.files;
+
+ out:
+ close(fd);
+ free(entries);
+ if (err) {
+ if (table->table) {
+ for (i = 0; i < header.files; i++)
+ free(table->table[i].path);
+ free(table->table);
+ }
+ memset(table, 0, sizeof(vhdi_file_table_t));
+ }
+
+ return err;
+}
+
+static int
+vhdi_file_table_next_fid(const char *name,
+ const char *file, vhdi_file_id_t * fid)
+{
+ int i, err;
+ char *path, __path[PATH_MAX];
+ vhdi_file_id_t max;
+ vhdi_file_table_t files;
+
+ max = 0;
+ path = NULL;
+
+ err = vhdi_file_table_load(name, &files);
+ if (err)
+ return err;
+
+ path = realpath(file, __path);
+ if (!path) {
+ err = -errno;
+ goto out;
+ }
+
+ for (i = 0; i < files.entries; i++) {
+ if (!strcmp(path, files.table[i].path)) {
+ err = -EEXIST;
+ goto out;
+ }
+
+ max = MAX(max, files.table[i].file_id);
+ }
+
+ *fid = max + 1;
+ err = 0;
+
+ out:
+ vhdi_file_table_free(&files);
+
+ return err;
+}
+
+static inline int
+vhdi_file_table_entry_initialize(vhdi_file_table_entry_t * entry,
+ const char *file_table, const char *file,
+ vhdi_file_id_t fid)
+{
+ int err;
+ struct stat stats;
+ vhd_context_t vhd;
+
+ memset(entry, 0, sizeof(vhdi_file_table_entry_t));
+
+ err = stat(file, &stats);
+ if (err == -1)
+ return -errno;
+
+ entry->file_id = fid;
+ entry->vhd_timestamp = vhd_time(stats.st_mtime);
+
+ err = vhd_open(&vhd, file, VHD_OPEN_RDONLY);
+ if (err)
+ goto out;
+
+ err = vhd_get_footer(&vhd);
+ if (err) {
+ vhd_close(&vhd);
+ goto out;
+ }
+
+ uuid_copy(entry->vhd_uuid, vhd.footer.uuid);
+
+ vhd_close(&vhd);
+
+ err = vhdi_copy_path_to(&entry->p, file_table, file);
+ if (err)
+ goto out;
+
+ err = 0;
+
+ out:
+ if (err)
+ memset(entry, 0, sizeof(vhdi_file_table_entry_t));
+
+ return err;
+}
+
+int
+vhdi_file_table_add(const char *name, const char *file,
+ vhdi_file_id_t * _fid)
+{
+ off64_t off;
+ size_t size;
+ vhdi_file_id_t fid;
+ int err, fd, len;
+ vhdi_file_table_entry_t entry;
+ vhdi_file_table_header_t header;
+
+ off = 0;
+ fid = 0;
+ *_fid = 0;
+
+ len = strnlen(file, VHD_MAX_NAME_LEN - 1);
+ if (len == VHD_MAX_NAME_LEN - 1)
+ return -ENAMETOOLONG;
+
+ err = vhdi_file_table_next_fid(name, file, &fid);
+ if (err)
+ return err;
+
+ fd = open(name, O_RDWR | O_LARGEFILE);
+ if (fd == -1)
+ return -errno;
+
+ err = vhdi_file_table_load_header(fd, &header);
+ if (err)
+ goto out;
+
+ size = sizeof(vhdi_file_table_entry_t);
+ off = header.table_offset + size * header.files;
+
+ err = lseek64(fd, off, SEEK_SET);
+ if (err == (off64_t) - 1) {
+ err = -errno;
+ goto out;
+ }
+
+ err = vhdi_file_table_entry_initialize(&entry, name, file, fid);
+ if (err)
+ goto out;
+
+ vhdi_file_table_entry_out(&entry);
+
+ err = write(fd, &entry, size);
+ if (err != size) {
+ err = (errno ? -errno : -EIO);
+ goto out;
+ }
+
+ header.files++;
+ err = vhdi_file_table_write_header(fd, &header);
+ if (err)
+ goto out;
+
+ err = 0;
+ *_fid = fid;
+
+ out:
+ if (err && off) {
+ int gcc = ftruncate(fd, off);
+ if (gcc) {
+ };
+ }
+ close(fd);
+
+ return err;
+}
+
+void vhdi_file_table_free(vhdi_file_table_t * table)
+{
+ int i;
+
+ if (table->table) {
+ for (i = 0; i < table->entries; i++)
+ free(table->table[i].path);
+ free(table->table);
+ }
+
+ memset(table, 0, sizeof(vhdi_file_table_t));
+}
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |