[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [PATCH 3 of 8] 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


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.