Windows support for libvhd and vhd-util

Added windows support for libvhd and vhd-util.

Includes bug fixes as well.

See the README for details.
This commit is contained in:
Timothe Litt
2016-03-25 12:37:44 -04:00
parent 3f193e6f99
commit b00e213506
42 changed files with 15218 additions and 0 deletions

View File

@@ -0,0 +1,200 @@
/* Copyright (c) 2008, XenSource 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.
*/
/* Modified March 2016 Timothe Litt to work under windows.
* Copyright (C) 2016 Timothe Litt
* Modifications subject to the same license terms as above,
* substituting "Timothe Litt" for "XenSource Inc."
*/
#ifndef __BLKTAP2_UUID_H__
#define __BLKTAP2_UUID_H__
#if defined(__linux__)
#include <uuid/uuid.h>
typedef struct {
uuid_t uuid;
} blk_uuid_t;
static inline int blk_uuid_is_nil(blk_uuid_t *uuid)
{
return uuid_is_null(uuid->uuid);
}
static inline void blk_uuid_generate(blk_uuid_t *uuid)
{
uuid_generate(uuid->uuid);
}
static inline void blk_uuid_to_string(blk_uuid_t *uuid, char *out, size_t size)
{
(void) size;
uuid_unparse(uuid->uuid, out);
}
static inline void blk_uuid_from_string(blk_uuid_t *uuid, const char *in)
{
uuid_parse(in, uuid->uuid);
}
static inline void blk_uuid_copy(blk_uuid_t *dst, blk_uuid_t *src)
{
uuid_copy(dst->uuid, src->uuid);
}
static inline void blk_uuid_clear(blk_uuid_t *uuid)
{
uuid_clear(uuid->uuid);
}
static inline int blk_uuid_compare(blk_uuid_t *uuid1, blk_uuid_t *uuid2)
{
return uuid_compare(uuid1->uuid, uuid2->uuid);
}
#elif defined(__NetBSD__)
#include <uuid.h>
#include <string.h>
#include <stdlib.h>
typedef uuid_t blk_uuid_t;
static inline int blk_uuid_is_nil(blk_uuid_t *uuid)
{
uint32_t status;
return uuid_is_nil((uuid_t *)uuid, &status);
}
static inline void blk_uuid_generate(blk_uuid_t *uuid)
{
uint32_t status;
uuid_create((uuid_t *)uuid, &status);
}
static inline void blk_uuid_to_string(blk_uuid_t *uuid, char *out, size_t size)
{
uint32_t status;
char *_out = NULL;
uuid_to_string((uuid_t *)uuid, &_out, &status);
strlcpy(out, _out, size);
free(_out);
}
static inline void blk_uuid_from_string(blk_uuid_t *uuid, const char *in)
{
uint32_t status;
uuid_from_string(in, (uuid_t *)uuid, &status);
}
static inline void blk_uuid_copy(blk_uuid_t *dst, blk_uuid_t *src)
{
memcpy((uuid_t *)dst, (uuid_t *)src, sizeof(uuid_t));
}
static inline void blk_uuid_clear(blk_uuid_t *uuid)
{
memset((uuid_t *)uuid, 0, sizeof(uuid_t));
}
static inline int blk_uuid_compare(blk_uuid_t *uuid1, blk_uuid_t *uuid2)
{
uint32_t status;
return uuid_compare((uuid_t *)uuid1, (uuid_t *)uuid2, &status);
}
#elif defined(_WIN32)
#include <Rpc.h>
typedef UUID blk_uuid_t;
static size_t strlcpy( char *dst, const char *src, size_t size ) {
size_t srclen;
size--;
srclen = strlen( src );
if( srclen > size )
srclen = size;
memcpy( dst, src, srclen );
dst[srclen] = '\0';
return (srclen);
}
static inline int blk_uuid_is_nil( blk_uuid_t *uuid )
{
RPC_STATUS status;
return UuidIsNil( (uuid_t *)uuid, &status );
}
static inline void blk_uuid_generate( blk_uuid_t *uuid )
{
RPC_STATUS status;
status = UuidCreate( (uuid_t *)uuid );
if( status == RPC_S_OK || status == RPC_S_UUID_LOCAL_ONLY )
return;
abort();
}
static inline void blk_uuid_to_string( blk_uuid_t *uuid, char *out, size_t size )
{
RPC_CSTR _out = NULL;
if( UuidToString( (uuid_t *)uuid, &_out ) != RPC_S_OK )
return;
strlcpy( out, (const char *)_out, size );
RpcStringFree( &_out );
return;
}
static inline void blk_uuid_from_string( blk_uuid_t *uuid, const char *in )
{
UuidFromString( (RPC_CSTR)in, (uuid_t *)uuid );
}
static inline void blk_uuid_copy( blk_uuid_t *dst, blk_uuid_t *src )
{
memcpy( (uuid_t *)dst, (uuid_t *)src, sizeof( uuid_t ) );
}
static inline void blk_uuid_clear( blk_uuid_t *uuid )
{
memset( (uuid_t *)uuid, 0, sizeof( uuid_t ) );
}
static inline int blk_uuid_compare( blk_uuid_t *uuid1, blk_uuid_t *uuid2 )
{
RPC_STATUS status;
return UuidCompare( (uuid_t *)uuid1, (uuid_t *)uuid2, &status );
}
#else
#error "Please update blk_uuid.h for your OS"
#endif
#endif /* __BLKTAP2_UUID_H__ */

View File

@@ -0,0 +1,363 @@
/* Copyright (c) 2008, XenSource 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.
*/
/* Modified March 2016 Timothe Litt to work under windows.
* Copyright (C) 2016 Timothe Litt
* Modifications subject to the same license terms as above,
* substituting "Timothe Litt" for "XenSource Inc."
*/
#ifndef _VHD_LIB_H_
#define _VHD_LIB_H_
#define _CRT_SECURE_NO_WARNINGS 1
#include <string.h>
#if defined(__linux__)
#include <endian.h>
#include <byteswap.h>
#elif defined(__NetBSD__)
#include <sys/endian.h>
#include <sys/bswap.h>
#elif defined(_WIN32)
#undef BYTE_ORDER
#undef LITTLE_ENDIAN
#define BYTE_ORDER 1234
#define LITTLE_ENDIAN 1234
#define bswap_16(val) _byteswap_ushort(val)
#define bswap_32(val) _byteswap_ulong(val)
#define bswap_64(val) _byteswap_uint64(val)
#endif
#include "blk_uuid.h"
#include "vhd.h"
#ifndef O_LARGEFILE
#define O_LARGEFILE 0
#endif
#if defined(_WIN32) && defined(LIBVHD_DLL)
#ifdef LIBVHD_EXPORTS
#define LIBVHD_API __declspec(dllexport)
#else
#define LIBVHD_API __declspec(dllimport)
#endif
#else
#define LIBVHD_API
#endif
#if BYTE_ORDER == LITTLE_ENDIAN
#if defined(__linux__) || defined(_WIN32)
#define BE16_IN(foo) (*(foo)) = bswap_16(*(foo))
#define BE32_IN(foo) (*(foo)) = bswap_32(*(foo))
#define BE64_IN(foo) (*(foo)) = bswap_64(*(foo))
#define BE16_OUT(foo) (*(foo)) = bswap_16(*(foo))
#define BE32_OUT(foo) (*(foo)) = bswap_32(*(foo))
#define BE64_OUT(foo) (*(foo)) = bswap_64(*(foo))
#elif defined(__NetBSD__)
#define BE16_IN(foo) (*(foo)) = bswap16(*(foo))
#define BE32_IN(foo) (*(foo)) = bswap32(*(foo))
#define BE64_IN(foo) (*(foo)) = bswap64(*(foo))
#define BE16_OUT(foo) (*(foo)) = bswap16(*(foo))
#define BE32_OUT(foo) (*(foo)) = bswap32(*(foo))
#define BE64_OUT(foo) (*(foo)) = bswap64(*(foo))
#endif
#else
#define BE16_IN(foo)
#define BE32_IN(foo)
#define BE64_IN(foo)
#define BE32_OUT(foo)
#define BE32_OUT(foo)
#define BE64_OUT(foo)
#endif
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
#define VHD_MAX_NAME_LEN 1024
#define VHD_BLOCK_SHIFT 21
#define VHD_BLOCK_SIZE (1ULL << VHD_BLOCK_SHIFT)
#define UTF_16 "UTF-16"
#define UTF_16LE "UTF-16LE"
#define UTF_16BE "UTF-16BE"
#define VHD_OPEN_RDONLY 0x00001
#define VHD_OPEN_RDWR 0x00002
#define VHD_OPEN_FAST 0x00004
#define VHD_OPEN_STRICT 0x00008
#define VHD_OPEN_IGNORE_DISABLED 0x00010
#define VHD_FLAG_CREAT_PARENT_RAW 0x00001
#define vhd_flag_set(word, flag) ((word) |= (flag))
#define vhd_flag_clear(word, flag) ((word) &= ~(flag))
#define vhd_flag_test(word, flag) ((word) & (flag))
#ifndef _WIN32x
#define ENABLE_FAILURE_TESTING 1
#endif
#define FAIL_REPARENT_BEGIN 0
#define FAIL_REPARENT_LOCATOR 1
#define FAIL_REPARENT_END 2
#define FAIL_RESIZE_BEGIN 3
#define FAIL_RESIZE_DATA_MOVED 4
#define FAIL_RESIZE_METADATA_MOVED 5
#define FAIL_RESIZE_END 6
#define NUM_FAIL_TESTS 7
#ifdef ENABLE_FAILURE_TESTING
#define TEST_FAIL_AT(point) \
if (TEST_FAIL[point]) { \
printf("Failing at %s\n", ENV_VAR_FAIL[point]); exit(EINVAL); }
#ifdef _WIN32
#define TEST_FAIL_EXTERN_VARS \
LIBVHD_API extern const char* ENV_VAR_FAIL[]; \
LIBVHD_API extern int TEST_FAIL[];
#else
#define TEST_FAIL_EXTERN_VARS \
extern const char* ENV_VAR_FAIL[]; \
extern int TEST_FAIL[];
#endif
#else
#define TEST_FAIL_AT(point)
#define TEST_FAIL_EXTERN_VARS
#endif /* ENABLE_FAILURE_TESTING */
static const char VHD_POISON_COOKIE[] = "v_poison";
typedef struct hd_ftr vhd_footer_t;
typedef struct dd_hdr vhd_header_t;
typedef struct vhd_bat vhd_bat_t;
typedef struct vhd_batmap vhd_batmap_t;
typedef struct dd_batmap_hdr vhd_batmap_header_t;
typedef struct prt_loc vhd_parent_locator_t;
typedef struct vhd_context vhd_context_t;
typedef uint32_t vhd_flag_creat_t;
struct vhd_bat {
uint32_t spb;
uint32_t entries;
uint32_t *bat;
};
struct vhd_batmap {
vhd_batmap_header_t header;
char *map;
};
struct vhd_context {
int fd;
char *file;
int oflags;
int is_block;
uint32_t spb;
uint32_t bm_secs;
vhd_header_t header;
vhd_footer_t footer;
vhd_bat_t bat;
vhd_batmap_t batmap;
};
static inline uint32_t
secs_round_up(uint64_t bytes)
{
return (uint32_t)((bytes + (VHD_SECTOR_SIZE - 1)) >> VHD_SECTOR_SHIFT);
}
static inline uint32_t
secs_round_up_no_zero(uint64_t bytes)
{
uint32_t result;
result = secs_round_up(bytes);
return ( result? result : 1);
}
static inline uint64_t
vhd_sectors_to_bytes(uint64_t sectors)
{
return sectors << VHD_SECTOR_SHIFT;
}
static inline uint64_t
vhd_bytes_padded(uint64_t bytes)
{
return vhd_sectors_to_bytes(secs_round_up_no_zero(bytes));
}
static inline int
vhd_type_dynamic(vhd_context_t *ctx)
{
return (ctx->footer.type == HD_TYPE_DYNAMIC ||
ctx->footer.type == HD_TYPE_DIFF);
}
static inline int
vhd_creator_tapdisk(vhd_context_t *ctx)
{
return !strncmp(ctx->footer.crtr_app, "tap", 3);
}
static inline int
vhd_disabled(vhd_context_t *ctx)
{
return (!memcmp(ctx->footer.cookie,
VHD_POISON_COOKIE, sizeof(ctx->footer.cookie)));
}
static inline size_t
vhd_parent_locator_size(vhd_parent_locator_t *loc)
{
/*
* MICROSOFT_COMPAT
* data_space *should* be in sectors,
* but sometimes we find it in bytes
*/
if (loc->data_space < 512)
return (size_t)vhd_sectors_to_bytes(loc->data_space);
else if (loc->data_space % 512 == 0)
return loc->data_space;
else
return 0;
}
static inline int
vhd_parent_raw(vhd_context_t *ctx)
{
return blk_uuid_is_nil(&ctx->header.prt_uuid);
}
LIBVHD_API void libvhd_set_log_level(int);
LIBVHD_API int vhd_test_file_fixed(const char *, int *);
LIBVHD_API uint32_t vhd_time(time_t time);
LIBVHD_API size_t vhd_time_to_string(uint32_t timestamp, char *target);
LIBVHD_API uint32_t vhd_chs(uint64_t size);
LIBVHD_API uint32_t vhd_checksum_footer(vhd_footer_t *);
LIBVHD_API uint32_t vhd_checksum_header(vhd_header_t *);
LIBVHD_API uint32_t vhd_checksum_batmap(vhd_batmap_t *);
LIBVHD_API void vhd_footer_in(vhd_footer_t *);
LIBVHD_API void vhd_footer_out(vhd_footer_t *);
LIBVHD_API void vhd_header_in(vhd_header_t *);
LIBVHD_API void vhd_header_out(vhd_header_t *);
LIBVHD_API void vhd_bat_in(vhd_bat_t *);
LIBVHD_API void vhd_bat_out(vhd_bat_t *);
LIBVHD_API void vhd_batmap_header_in(vhd_batmap_t *);
LIBVHD_API void vhd_batmap_header_out(vhd_batmap_t *);
LIBVHD_API int vhd_validate_footer(vhd_footer_t *footer);
LIBVHD_API int vhd_validate_header(vhd_header_t *header);
LIBVHD_API int vhd_validate_batmap_header(vhd_batmap_t *batmap);
LIBVHD_API int vhd_validate_batmap(vhd_batmap_t *batmap);
LIBVHD_API int vhd_validate_platform_code(uint32_t code);
LIBVHD_API int vhd_open(vhd_context_t *, const char *file, int flags);
LIBVHD_API void vhd_close(vhd_context_t *);
LIBVHD_API int vhd_create(const char *name, uint64_t bytes, int type, vhd_flag_creat_t);
/* vhd_snapshot: the bytes parameter is optional and can be 0 if the snapshot
* is to have the same size as the (first non-empty) parent */
LIBVHD_API int vhd_snapshot(const char *snapshot, uint64_t bytes, const char *parent,
vhd_flag_creat_t);
LIBVHD_API int vhd_hidden(vhd_context_t *, int *);
LIBVHD_API int vhd_chain_depth(vhd_context_t *, int *);
LIBVHD_API off_t vhd_position(vhd_context_t *);
LIBVHD_API int vhd_seek(vhd_context_t *, off_t, int);
LIBVHD_API int vhd_read(vhd_context_t *, void *, size_t);
LIBVHD_API int vhd_write(vhd_context_t *, void *, size_t);
LIBVHD_API int vhd_offset(vhd_context_t *, uint32_t, uint32_t *);
LIBVHD_API int vhd_end_of_headers(vhd_context_t *ctx, off_t *off);
LIBVHD_API int vhd_end_of_data(vhd_context_t *ctx, off_t *off);
LIBVHD_API int vhd_batmap_header_offset(vhd_context_t *ctx, off_t *off);
LIBVHD_API int vhd_get_header(vhd_context_t *);
LIBVHD_API int vhd_get_footer(vhd_context_t *);
LIBVHD_API int vhd_get_bat(vhd_context_t *);
LIBVHD_API int vhd_get_batmap(vhd_context_t *);
LIBVHD_API void vhd_put_header(vhd_context_t *);
LIBVHD_API void vhd_put_footer(vhd_context_t *);
LIBVHD_API void vhd_put_bat(vhd_context_t *);
LIBVHD_API void vhd_put_batmap(vhd_context_t *);
LIBVHD_API int vhd_has_batmap(vhd_context_t *);
LIBVHD_API int vhd_batmap_test(vhd_context_t *, vhd_batmap_t *, uint32_t);
LIBVHD_API void vhd_batmap_set(vhd_context_t *, vhd_batmap_t *, uint32_t);
LIBVHD_API void vhd_batmap_clear(vhd_context_t *, vhd_batmap_t *, uint32_t);
LIBVHD_API int vhd_get_phys_size(vhd_context_t *, off_t *);
LIBVHD_API int vhd_set_phys_size(vhd_context_t *, off_t);
LIBVHD_API int vhd_bitmap_test(vhd_context_t *, char *, uint32_t);
LIBVHD_API void vhd_bitmap_set(vhd_context_t *, char *, uint32_t);
LIBVHD_API void vhd_bitmap_clear(vhd_context_t *, char *, uint32_t);
LIBVHD_API int vhd_parent_locator_count(vhd_context_t *);
LIBVHD_API int vhd_parent_locator_get(vhd_context_t *, char **);
LIBVHD_API int vhd_parent_locator_read(vhd_context_t *, vhd_parent_locator_t *, char **);
LIBVHD_API int vhd_find_parent(vhd_context_t *, const char *, char **);
LIBVHD_API int vhd_parent_locator_write_at(vhd_context_t *, const char *,
off_t, uint32_t, size_t,
vhd_parent_locator_t *);
LIBVHD_API int vhd_header_decode_parent(vhd_context_t *, vhd_header_t *, char **);
LIBVHD_API int vhd_change_parent(vhd_context_t *, char *parent_path, int raw);
LIBVHD_API int vhd_read_footer(vhd_context_t *, vhd_footer_t *);
LIBVHD_API int vhd_read_footer_at(vhd_context_t *, vhd_footer_t *, off_t);
LIBVHD_API int vhd_read_footer_strict(vhd_context_t *, vhd_footer_t *);
LIBVHD_API int vhd_read_header(vhd_context_t *, vhd_header_t *);
LIBVHD_API int vhd_read_header_at(vhd_context_t *, vhd_header_t *, off_t);
LIBVHD_API int vhd_read_bat(vhd_context_t *, vhd_bat_t *);
LIBVHD_API int vhd_read_batmap(vhd_context_t *, vhd_batmap_t *);
LIBVHD_API int vhd_read_bitmap(vhd_context_t *, uint32_t block, char **bufp);
LIBVHD_API int vhd_read_block(vhd_context_t *, uint32_t block, char **bufp);
LIBVHD_API int vhd_write_footer(vhd_context_t *, vhd_footer_t *);
LIBVHD_API int vhd_write_footer_at(vhd_context_t *, vhd_footer_t *, off_t);
LIBVHD_API int vhd_write_header(vhd_context_t *, vhd_header_t *);
LIBVHD_API int vhd_write_header_at(vhd_context_t *, vhd_header_t *, off_t);
LIBVHD_API int vhd_write_bat(vhd_context_t *, vhd_bat_t *);
LIBVHD_API int vhd_write_batmap(vhd_context_t *, vhd_batmap_t *);
LIBVHD_API int vhd_write_bitmap(vhd_context_t *, uint32_t block, char *bitmap);
LIBVHD_API int vhd_write_block(vhd_context_t *, uint32_t block, char *data);
LIBVHD_API int vhd_io_read(vhd_context_t *, char *, uint64_t, uint32_t);
LIBVHD_API int vhd_io_write(vhd_context_t *, char *, uint64_t, uint32_t);
#endif

View File

@@ -0,0 +1,59 @@
/* Copyright (c) 2008, XenSource 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.
*/
/* Modified March 2016 Timothe Litt to work under windows.
* Copyright (C) 2016 Timothe Litt
* Modifications subject to the same license terms as above,
* substituting "Timothe Litt" for "XenSource Inc."
*/
#ifndef _RELATIVE_PATH_H_
#define _RELATIVE_PATH_H_
#define MAX_NAME_LEN 1000
#if defined(_WIN32) && defined(LIBVHD_DLL)
#ifdef LIBVHD_EXPORTS
#define LIBVHD_API __declspec(dllexport)
#else
#define LIBVHD_API __declspec(dllimport)
#endif
#else
#define LIBVHD_API
#endif
/*
* returns a relative path from @src to @dest
* result should be freed
*/
LIBVHD_API char *relative_path_to(char *src, char *dest, int *err);
#ifdef _WIN32
LIBVHD_API char *realpath( const char *path, char *resolved );
LIBVHD_API int asprintf( char **result, const char *fmt, ... );
#endif
#endif

View File

@@ -0,0 +1,228 @@
/* Copyright (c) 2008, XenSource 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.
*/
/* Modified March 2016 Timothe Litt to work under windows.
* Copyright (C) 2016 Timothe Litt
* Modifications subject to the same license terms as above,
* substituting "Timothe Litt" for "XenSource Inc."
*/
#ifndef __VHD_H__
#define __VHD_H__
#include <inttypes.h>
typedef uint32_t u32;
typedef uint64_t u64;
/* #define DEBUG 1 */
/* ---------------------------------------------------------------------- */
/* General definitions. */
/* ---------------------------------------------------------------------- */
#define VHD_SECTOR_SIZE 512
#define VHD_SECTOR_SHIFT 9
/* ---------------------------------------------------------------------- */
/* This is the generic disk footer, used by all disks. */
/* ---------------------------------------------------------------------- */
struct hd_ftr {
char cookie[8]; /* Identifies original creator of the disk */
u32 features; /* Feature Support -- see below */
u32 ff_version; /* (major,minor) version of disk file */
u64 data_offset; /* Abs. offset from SOF to next structure */
u32 timestamp; /* Creation time. secs since 1/1/2000GMT */
char crtr_app[4]; /* Creator application */
u32 crtr_ver; /* Creator version (major,minor) */
u32 crtr_os; /* Creator host OS */
u64 orig_size; /* Size at creation (bytes) */
u64 curr_size; /* Current size of disk (bytes) */
u32 geometry; /* Disk geometry */
u32 type; /* Disk type */
u32 checksum; /* 1's comp sum of this struct. */
blk_uuid_t uuid; /* Unique disk ID, used for naming parents */
char saved; /* one-bit -- is this disk/VM in a saved state? */
char hidden; /* tapdisk-specific field: is this vdi hidden? */
char reserved[426]; /* padding */
};
/* VHD cookie string. */
static const char HD_COOKIE[9] = "conectix";
/* Feature fields in hd_ftr */
#define HD_NO_FEATURES 0x00000000
#define HD_TEMPORARY 0x00000001 /* disk can be deleted on shutdown */
#define HD_RESERVED 0x00000002 /* NOTE: must always be set */
/* Version field in hd_ftr */
#define HD_FF_VERSION 0x00010000
/* Known creator OS type fields in hd_ftr.crtr_os */
#define HD_CR_OS_WINDOWS 0x5769326B /* (Wi2k) */
#define HD_CR_OS_MACINTOSH 0x4D616320 /* (Mac ) */
#define HD_CR_OS_UNIX 0x556E6978 /* (Unix) */
#define HD_CR_OS_VMS 0x4F564D53 /* (OVMS) */
/*
* version 0.1: little endian bitmaps
* version 1.1: big endian bitmaps; batmap
* version 1.2: libvhd
* version 1.3: batmap version bump to 1.2
*/
#define VHD_VERSION(major, minor) (((major) << 16) | ((minor) & 0x0000FFFF))
#define VHD_CURRENT_VERSION VHD_VERSION(1, 3)
/* Disk geometry accessor macros. */
/* Geometry is a triple of (cylinders (2 bytes), tracks (1 byte), and
* secotrs-per-track (1 byte))
*/
#define GEOM_GET_CYLS(_g) (((_g) >> 16) & 0xffff)
#define GEOM_GET_HEADS(_g) (((_g) >> 8) & 0xff)
#define GEOM_GET_SPT(_g) ((_g) & 0xff)
#define GEOM_ENCODE(_c, _h, _s) (((_c) << 16) | ((_h) << 8) | (_s))
/* type field in hd_ftr */
#define HD_TYPE_NONE 0
#define HD_TYPE_FIXED 2 /* fixed-allocation disk */
#define HD_TYPE_DYNAMIC 3 /* dynamic disk */
#define HD_TYPE_DIFF 4 /* differencing disk */
/* String table for hd.type */
#ifdef __GNUC__
__attribute__((unused))
#endif
static const char *HD_TYPE_STR[7] = {
"None", /* 0 */
"Reserved (deprecated)", /* 1 */
"Fixed hard disk", /* 2 */
"Dynamic hard disk", /* 3 */
"Differencing hard disk", /* 4 */
"Reserved (deprecated)", /* 5 */
"Reserved (deprecated)" /* 6 */
};
#define HD_TYPE_MAX 6
struct prt_loc {
u32 code; /* Platform code -- see defines below. */
u32 data_space; /* Number of 512-byte sectors to store locator */
u32 data_len; /* Actual length of parent locator in bytes */
u32 res; /* Must be zero */
u64 data_offset; /* Absolute offset of locator data (bytes) */
};
/* Platform Codes */
#define PLAT_CODE_NONE 0x0
#define PLAT_CODE_WI2R 0x57693272 /* deprecated */
#define PLAT_CODE_WI2K 0x5769326B /* deprecated */
#define PLAT_CODE_W2RU 0x57327275 /* Windows relative path (UTF-16) */
#define PLAT_CODE_W2KU 0x57326B75 /* Windows absolute path (UTF-16) */
#define PLAT_CODE_MAC 0x4D616320 /* MacOS alias stored as a blob. */
#define PLAT_CODE_MACX 0x4D616358 /* File URL (UTF-8), see RFC 2396. */
/* ---------------------------------------------------------------------- */
/* This is the dynamic disk header. */
/* ---------------------------------------------------------------------- */
struct dd_hdr {
char cookie[8]; /* Should contain "cxsparse" */
u64 data_offset; /* Byte offset of next record. (Unused) 0xffs */
u64 table_offset; /* Absolute offset to the BAT. */
u32 hdr_ver; /* Version of the dd_hdr (major,minor) */
u32 max_bat_size; /* Maximum number of entries in the BAT */
u32 block_size; /* Block size in bytes. Must be power of 2. */
u32 checksum; /* Header checksum. 1's comp of all fields. */
blk_uuid_t prt_uuid; /* ID of the parent disk. */
u32 prt_ts; /* Modification time of the parent disk */
u32 res1; /* Reserved. */
char prt_name[512]; /* Parent unicode name. */
struct prt_loc loc[8]; /* Parent locator entries. */
char res2[256]; /* Reserved. */
};
/* VHD cookie string. */
static const char DD_COOKIE[9] = "cxsparse";
/* Version field in hd_ftr */
#define DD_VERSION 0x00010000
/* Default blocksize is 2 meg. */
#define DD_BLOCKSIZE_DEFAULT 0x00200000
#define DD_BLK_UNUSED 0xFFFFFFFF
struct dd_batmap_hdr {
char cookie[8]; /* should contain "tdbatmap" */
u64 batmap_offset; /* byte offset to batmap */
u32 batmap_size; /* batmap size in sectors */
u32 batmap_version; /* version of batmap */
u32 checksum; /* batmap checksum -- 1's complement of batmap */
};
static const char VHD_BATMAP_COOKIE[9] = "tdbatmap";
/*
* version 1.1: signed char checksum
*/
#define VHD_BATMAP_VERSION(major, minor) (((major) << 16) | ((minor) & 0x0000FFFF))
#define VHD_BATMAP_CURRENT_VERSION VHD_BATMAP_VERSION(1, 2)
/* Layout of a dynamic disk:
*
* +-------------------------------------------------+
* | Mirror image of HD footer (hd_ftr) (512 bytes) |
* +-------------------------------------------------+
* | Sparse drive header (dd_hdr) (1024 bytes) |
* +-------------------------------------------------+
* | BAT (Block allocation table) |
* | - Array of absolute sector offsets into the |
* | file (u32). |
* | - Rounded up to a sector boundary. |
* | - Unused entries are marked as 0xFFFFFFFF |
* | - max entries in dd_hdr->max_bat_size |
* +-------------------------------------------------+
* | Data Block 0 |
* | Bitmap (padded to 512 byte sector boundary) |
* | - each bit indicates whether the associated |
* | sector within this block is used. |
* | Data |
* | - power-of-two multiple of sectors. |
* | - default 2MB (4096 * 512) |
* | - Any entries with zero in bitmap should be |
* | zero on disk |
* +-------------------------------------------------+
* | Data Block 1 |
* +-------------------------------------------------+
* | ... |
* +-------------------------------------------------+
* | Data Block n |
* +-------------------------------------------------+
* | HD Footer (511 bytes) |
* +-------------------------------------------------+
*/
#endif

4190
extracters/libvhd/libvhd.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,41 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.24720.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libvhd", "libvhd.vcxproj", "{695E504C-32F4-43AF-8AD6-761DE66D0EAB}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vhd-util", "..\vhd-util\vhd-util.vcxproj", "{CC5FB437-0C01-4ECF-A75F-10C37B607AC6}"
ProjectSection(ProjectDependencies) = postProject
{695E504C-32F4-43AF-8AD6-761DE66D0EAB} = {695E504C-32F4-43AF-8AD6-761DE66D0EAB}
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{695E504C-32F4-43AF-8AD6-761DE66D0EAB}.Debug|x64.ActiveCfg = Debug|x64
{695E504C-32F4-43AF-8AD6-761DE66D0EAB}.Debug|x64.Build.0 = Debug|x64
{695E504C-32F4-43AF-8AD6-761DE66D0EAB}.Debug|x86.ActiveCfg = Debug|Win32
{695E504C-32F4-43AF-8AD6-761DE66D0EAB}.Debug|x86.Build.0 = Debug|Win32
{695E504C-32F4-43AF-8AD6-761DE66D0EAB}.Release|x64.ActiveCfg = Release|x64
{695E504C-32F4-43AF-8AD6-761DE66D0EAB}.Release|x64.Build.0 = Release|x64
{695E504C-32F4-43AF-8AD6-761DE66D0EAB}.Release|x86.ActiveCfg = Release|Win32
{695E504C-32F4-43AF-8AD6-761DE66D0EAB}.Release|x86.Build.0 = Release|Win32
{CC5FB437-0C01-4ECF-A75F-10C37B607AC6}.Debug|x64.ActiveCfg = Debug|x64
{CC5FB437-0C01-4ECF-A75F-10C37B607AC6}.Debug|x64.Build.0 = Debug|x64
{CC5FB437-0C01-4ECF-A75F-10C37B607AC6}.Debug|x86.ActiveCfg = Debug|Win32
{CC5FB437-0C01-4ECF-A75F-10C37B607AC6}.Debug|x86.Build.0 = Debug|Win32
{CC5FB437-0C01-4ECF-A75F-10C37B607AC6}.Release|x64.ActiveCfg = Release|x64
{CC5FB437-0C01-4ECF-A75F-10C37B607AC6}.Release|x64.Build.0 = Release|x64
{CC5FB437-0C01-4ECF-A75F-10C37B607AC6}.Release|x86.ActiveCfg = Release|Win32
{CC5FB437-0C01-4ECF-A75F-10C37B607AC6}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View File

@@ -0,0 +1,125 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{695E504C-32F4-43AF-8AD6-761DE66D0EAB}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<TargetMachine>MachineX86</TargetMachine>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
<AdditionalDependencies>Rpcrt4.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<GenerateMapFile>false</GenerateMapFile>
<MapExports>true</MapExports>
</Link>
<Lib>
<AdditionalLibraryDirectories />
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<AdditionalIncludeDirectories>include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<TargetMachine>MachineX86</TargetMachine>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>Rpcrt4.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<Lib>
<AdditionalLibraryDirectories />
</Lib>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="libvhd.c" />
<ClCompile Include="relative-path.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="include\blk_uuid.h" />
<ClInclude Include="include\libvhd.h" />
<ClInclude Include="include\relative-path.h" />
<ClInclude Include="include\vhd.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@@ -0,0 +1,39 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="libvhd.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="relative-path.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="include\blk_uuid.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\libvhd.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\relative-path.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\vhd.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>

View File

@@ -0,0 +1,442 @@
/* Copyright (c) 2008, XenSource 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.
*/
/* Modified March 2016 Timothe Litt to work under windows.
* Copyright (C) 2016 Timothe Litt
* Modifications subject to the same license terms as above,
* substituting "Timothe Litt" for "XenSource Inc."
*/
#ifdef _WIN32
#define _CRT_SECURE_NO_WARNINGS 1
#endif
#include <stdarg.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include "relative-path.h"
#ifdef _WIN32
#include <stdio.h>
#include <windows.h>
#include <Shlwapi.h>
#define strdup _strdup
#else
#include <syslog.h>
#endif
#define DELIMITER '/'
#define FN __func__
#define EPRINTF(a) rpath_log_error a
static void rpath_log_error( const char *func, const char *fmt, ... )
#ifdef __GNUC__
__attribute__((format(printf,2,3)));
#else
;
#endif
#ifndef LIBVHD_HAS_SYSLOG
#ifdef _WIN32
#define LIBVHD_HAS_SYSLOG 0
#else
#define LIBVHD_HAS_SYSLOG 1
#endif
#endif
#define sfree(ptr) \
do { \
free(ptr); \
ptr = NULL; \
} while (0)
#ifdef _WIN32
LIBVHD_API char *realpath( const char *path, char *resolved ) {
char *p;
DWORD len;
p = resolved;
if( resolved == NULL ) {
resolved = malloc( 1+ MAX_PATH + 1 );
if( resolved == NULL ) {
return NULL;
}
}
if( (len = GetFullPathName( path[0] == '/'? path+1:path, MAX_PATH + 1, resolved, NULL )) == 0 ) {
if( p == NULL )
free( resolved );
return NULL;
}
if( len > MAX_PATH ) {
if( p != NULL )
return NULL;
if( (p = realloc( resolved, len )) == NULL ) {
free( resolved );
return NULL;
}
resolved = p;
len = GetFullPathName( path, MAX_PATH + 1, resolved, NULL );
if( len > MAX_PATH || len == 0 ) {
free( resolved );
return NULL;
}
}
for( p = resolved; *p; p++ ) {
if( *p == '\\')
*p = '/';
}
for( p = resolved; isalpha( *p ); p++ )
;
if( *p == ':' ) { /* Hide drive under '/' for callers. */
memmove( resolved + 1, resolved, strlen( resolved ) +1 );
resolved[0] = '/'; /* Callers must skip '/' when touching filesystem. */
}
return resolved;
}
LIBVHD_API int asprintf( char **result, const char *fmt, ... ) {
int len;
va_list ap;
char *np;
/* It would be better to va_copy() the list and do a prescan,
* but va_copy apparently has issues with versions of MS C
* still in the field. This approach is ugly and wasteful, but
* should work. (A KB just isn't what it used to be...)
*/
if( (*result = malloc( 1 * 100 * 1000 + 1 )) == NULL )
return -1;
va_start( ap, fmt );
len = vsprintf( *result, fmt, ap );
np = realloc( *result, len + 1 );
if( np != NULL )
*result = np;
return len;
}
#endif
/*
* count number of tokens between DELIMITER characters
*/
int count_nodes(char *path)
{
int i;
char *tmp;
if (!path)
return 0;
for (i = 0, tmp = path; *tmp != '\0'; tmp++)
if (*tmp == DELIMITER)
i++;
return i;
}
/*
* return copy of next node in @path, or NULL
* @path is moved to the end of the next node
* @err is set to -errno on failure
* copy should be freed
*/
static char *
next_node(char **path, int *err)
{
int ret;
char *tmp, *start;
if (!path || !*path) {
*err = -EINVAL;
return NULL;
}
*err = 0;
start = *path;
for (tmp = *path; *tmp != '\0'; tmp++)
if (*tmp == DELIMITER) {
int size;
char *node;
size = tmp - start + 1;
node = malloc(size);
if (!node) {
*err = -ENOMEM;
return NULL;
}
ret = snprintf(node, size, "%s", start);
if (ret < 0) {
free(node);
*err = -EINVAL;
return NULL;
}
*path = tmp;
return node;
}
return NULL;
}
/*
* count number of nodes in common betwee @to and @from
* returns number of common nodes, or -errno on failure
*/
static int
count_common_nodes(char *to, char *from)
{
int err, common;
char *to_node, *from_node;
if (!to || !from)
return -EINVAL;
err = 0;
common = 0;
to_node = NULL;
from_node = NULL;
do {
to_node = next_node(&to, &err);
if (err || !to_node)
break;
from_node = next_node(&from, &err);
if (err || !from_node)
break;
if (strncmp(to_node, from_node, MAX_NAME_LEN))
break;
++to;
++from;
++common;
sfree(to_node);
sfree(from_node);
} while (1);
sfree(to_node);
sfree(from_node);
if (err)
return err;
return common;
}
/*
* construct path of @count '../', './' if @count is zero, or NULL on error
* result should be freed
*/
static char *
up_nodes(int count)
{
char *path, *tmp;
int i, ret, len, size;
if (!count)
return strdup("./");
len = strlen("../");
size = len * count;
if (size >= MAX_NAME_LEN)
return NULL;
path = malloc(size + 1);
if (!path)
return NULL;
tmp = path;
for (i = 0; i < count; i++) {
ret = sprintf(tmp, "../");
if (ret < 0 || ret != len) {
free(path);
return NULL;
}
tmp += ret;
}
return path;
}
/*
* return pointer to @offset'th node of path or NULL on error
*/
static char *
node_offset(char *from, int offset)
{
char *path;
if (!from || !offset)
return NULL;
for (path = from; *path != '\0'; path++) {
if (*path == DELIMITER)
if (--offset == 0)
return path + 1;
}
return NULL;
}
/*
* return a relative path from @from to @to
* result should be freed
*/
LIBVHD_API
char *
relative_path_to(char *from, char *to, int *err)
{
int from_nodes, common;
char *to_absolute, *from_absolute;
char *up, *common_target_path, *relative_path;
*err = 0;
up = NULL;
to_absolute = NULL;
from_absolute = NULL;
relative_path = NULL;
if (strnlen(to, MAX_NAME_LEN) == MAX_NAME_LEN ||
strnlen(from, MAX_NAME_LEN) == MAX_NAME_LEN) {
EPRINTF((FN,"invalid input; max path length is %d\n",
MAX_NAME_LEN));
*err = -ENAMETOOLONG;
return NULL;
}
to_absolute = realpath(to, NULL);
if (!to_absolute) {
EPRINTF((FN,"failed to get absolute path of %s\n", to));
*err = -errno;
goto out;
}
from_absolute = realpath(from, NULL);
if (!from_absolute) {
EPRINTF((FN,"failed to get absolute path of %s\n", from));
*err = -errno;
goto out;
}
if (strnlen(to_absolute, MAX_NAME_LEN) == MAX_NAME_LEN ||
strnlen(from_absolute, MAX_NAME_LEN) == MAX_NAME_LEN) {
EPRINTF((FN,"invalid input; max path length is %d\n",
MAX_NAME_LEN));
*err = -ENAMETOOLONG;
goto out;
}
/* count nodes in source path */
from_nodes = count_nodes(from_absolute);
/* count nodes in common */
common = count_common_nodes(to_absolute + 1, from_absolute + 1);
if (common < 0) {
EPRINTF((FN,"failed to count common nodes of %s and %s: %d\n",
to_absolute, from_absolute, common));
*err = common;
goto out;
}
/* move up to common node */
up = up_nodes(from_nodes - common - 1);
if (!up) {
EPRINTF((FN,"failed to allocate relative path for %s: %d\n",
from_absolute, -ENOMEM));
*err = -ENOMEM;
goto out;
}
/* get path from common node to target */
common_target_path = node_offset(to_absolute, common + 1);
if (!common_target_path) {
EPRINTF((FN,"failed to find common target path to %s: %d\n",
to_absolute, -EINVAL));
*err = -EINVAL;
goto out;
}
/* get relative path */
if (asprintf(&relative_path, "%s%s", up, common_target_path) == -1) {
EPRINTF((FN,"failed to construct final path %s%s: %d\n",
up, common_target_path, -ENOMEM));
relative_path = NULL;
*err = -ENOMEM;
goto out;
}
out:
sfree(up);
sfree(to_absolute);
sfree(from_absolute);
return relative_path;
}
static void rpath_log_error( const char *func, const char *fmt, ... )
{
char *buf, nilbuf;
size_t ilen, len;
va_list ap;
ilen = sizeof( "tap-err:%s: " ) + strlen( func ) -2;
va_start(ap, fmt );
len = vsnprintf( &nilbuf, 1, fmt, ap );
va_end( ap );
if( (buf = malloc( ilen + len + 1 )) == NULL ) {
#if LIBVHD_HAS_SYSLOG
syslog( LOG_INFO, "tap-err:%s: Out of memory", func );
#else
fprintf( stderr, "tap-err%s: Out of memory for %s\n", func, fmt );
#endif
return;
}
va_start(ap, fmt);
(void) snprintf( buf, ilen, "tap-err:%s: ", func );
(void) vsnprintf( buf + ilen -1, len+1, fmt, ap );
va_end( ap );
len += ilen -1;
if( buf[ len -1 ] != '\n' )
buf[len++] = '\n';
buf[len] = '\0';
#if LIBVHD_HAS_SYSLOG
syslog(LOG_INFO, buf);
#else
fputs( buf, stderr );
#endif
free( buf );
return;
}

View File

@@ -0,0 +1,33 @@
* Copyright (c) 2008, XenSource 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.
*/
The Windows version uses a stripped version of the GNU C library's getopt,
and hence is covered by the GPL.
The modifications made by Timothe Litt are Copyright (C) 2016 by Timothe Litt.
They may be used under the same terms as the XenSource license above (substituting "Timothe Litt" for "Xensource Inc" as appropriate.

View File

@@ -0,0 +1,31 @@
This is a port of the Xen vhd-util tool and the libvhd library to windows.
It still works (with minor enhancements) on Unix.
The distribution kit includes prebuilt executables for Linux and Windows.
There are two components:
libvhd - library for VHD file access
vhd-util - tool for managing VHD files.
Each has a directory, which should be at the same level.
On Unix:
cd vhd-util && make && make install
cd vhd-util && make PREFIX=/usr && make PREFIX=/usr
To place somewhere else.
This creates a sharable library (libvhd) and the vhd-util command.
On Windows:
Builds under microsoft Visual Studio (2015), free edition.
Open libvhd/libvhd.sln and build it.
On Windows, a DLL is NOT created as the API doesn't support it.
(The DLL allocates memory that the client must free, but doesn't
provide routines to do this. On windows, the pools are different.)
Licensing is described in COPYING.

View File

@@ -0,0 +1,115 @@
# -*- Makefile -*-
# Builds vhd-util and the libvhd shared library.
PREFIX = /usr/local
LIBDIR = $(PREFIX)/lib
BINDIR = $(PREFIX)/bin
CPPFLAGS = -D_GNU_SOURCE -I include -I $(LIBVHD)/include
CFLAGS = -O4
LDFLAGS = -L. -L $(LIBVHD)
LDLIBS = -lvhd-util -luuid -lvhd
LDCONFIG_D = /etc/ld.so.conf.d/vhd-util
LIBVHD = ../libvhd
SRCS = atomicio.c \
libvhd-journal.c \
vhd-util-check.c \
vhd-util-coalesce.c \
vhd-util-create.c \
vhd-util-fill.c \
lvm-util.c \
vhd-util-modify.c \
vhd-util-query.c \
vhd-util-read.c \
vhd-util-repair.c \
vhd-util-resize.c \
vhd-util-revert.c \
vhd-util-scan.c \
vhd-util-set-field.c \
vhd-util-snapshot.c
OBJS = $(SRCS:.c=.o)
LIBVHDSO = libvhd.so
LIBVHDSONAME = $(LIBVHDSO).2
LIBVHDSOFILE = $(LIBVHDSONAME).1.0
all: vhd-util $(LIBVHD)/$(LIBVHDSO)
# The utility
libvhd-util.a : $(OBJS)
$(AR) -rs libvhd-util.a $(OBJS)
vhd-util : vhd-util.o libvhd-util.a $(LIBVHD)/$(LIBVHDSO)
$(CC) $(LDFLAGS) -Wl,-rpath,$(LIBDIR) -o vhd-util vhd-util.o $(LDLIBS)
# The sharable library
$(LIBVHD)/$(LIBVHDSOFILE) : $(LIBVHD)/libvhd.c $(LIBVHD)/relative-path.c
$(CC) -shared -o $(LIBVHD)/$(LIBVHDSOFILE) -Wl,-soname,$(LIBVHDSONAME) $(CPPFLAGS) $(CFLAGS) -fPIC $(LIBVHD)/libvhd.c $(LIBVHD)/relative-path.c -luuid
# The symlinks in the local directory necessary for linking
$(LIBVHD)/$(LIBVHDSO) : $(LIBVHD)/$(LIBVHDSOFILE)
ldconfig -n $(LIBVHD)
ln -sf $(LIBVHD)/$(LIBVHDSOFILE) $(LIBVHD)/$(LIBVHDSO)
# Install (note that to run the utility before installation, you must set
# LD_LOAD_LIBRARY to $(VLDLIB)
install: all
cp -p $(LIBVHD)/$(LIBVHDSOFILE) $(LIBDIR)/
cp -p vhd-util $(BINDIR)/
echo "$(LIBDIR)" >$(LDCONFIG_D)
ldconfig
ln -sf $(LIBVHDSONAME) $(LIBDIR)/$(LIBVHDSO)
# Un-install
uninstall:
rm -f $(BINDIR)/vhd-util $(LIBDIR)/$(LIBVHDSOFILE) $(LIBDIR)/$(LIBVHDSONAME) $(LIBDIR)/$(LIBVHDSO)
ldconfig
rm -f $(LDCONFIG_D)
# Clean working area
clean: tidy
rm -f vhd-util vhd-util.exe $(LIBVHD)/$(LIBVHDSOFILE) $(LIBVHD)/$(LIBVHDSONAME) $(LIBVHD)/$(LIBVHDSO)
# Clean intermediate files only, leaving outputs
tidy:
rm -f $(OBJS) libvhd-util.a vhd-util.o
KITFILES = \
vhd-util/README \
vhd-util/INSTALL \
vhd-util/COPYING \
vhd-util/*.c \
vhd-util/include/*.h \
vhd-util/vhd-util \
vhd-util/vhd-util.exe \
vhd-util/Makefile \
vhd-util/vhd-util.vcxproj \
vhd-util/vhd-util.vcxproj.filters \
\
libvhd/*.c \
libvhd/libvhd.so* \
libvhd/libvhd.sln \
libvhd/libvhd.vcxproj \
libvhd/libvhd.vcxproj.filters \
libvhd/include/*.h \
KITEXES = \
vhd-util/vhd-util \
vhd-util/vhd-util.exe \
libvhd/libvhd.so*
kit: all
cd .. && chown -h $(USER).$(USER) $(KITFILES) && chmod -x $(KITFILES) && chmod +x $(KITEXES) && tar -czf vhd-tools.tgz $(KITFILES)

229
extracters/vhd-util/README Normal file
View File

@@ -0,0 +1,229 @@
vhd-util is originally an unsupported tool provided with the Xen emulator
family. It was not designed as a user tool, but it does have some
functions that can be used without internals knowledge.
It is a "sharp" tool - you can do irreversible damage with it.
Use at your own risk.
This version has been modified to:
o Work on Windows as well as Unix
o Resolve a number of compiler-detected issues
o Identify the creator OS
o Fix some bugs.
o The 'scan' command, which operates on LVM volumes, was
not ported to Windows. All other commands (should) work.
o An error message is generated when a command fails.
o Some safeguards have been added to the 'modify' command.
o read -P summarizes file and its parents.
The tool is undocumentd by Xen, except for a few cryptic comments
in the README that assume the Xen environment.
The following should be more useful as a stand-alone tool.
This document is the result of reverse-engineering the vhd-util code,
and may contain errors. As with the tool, use with caution and at
your own risk.
vhd-util is a command-line utility with the following general syntax:
vhd-util COMMAND OPTIONS
Most commands produce a cryptic usage with the -h option.
The target of a command is specified with the (required) -n "option".
Commands tend to fail when they don't make sense - e.g. asking about
difference disk data structures on a fixed-size disk.
Some terminology:
Sector - Address on virtual disk. Always 512 bytes.
Block - Allocation unit in sparse disks. Default 4096 sectors
(2 MB).
Fixed disk - Virtual disk of fixed size = maximum size + small header.
Dynamic disk - (Sparse disk) Virtual disk that grows as data is
written. Simulator sees it as fixed (max) size.
Diff disk - (Snapshot) Dynamic disk that contains (only) changes
to a parent Dynamic (or Diff) disk. Used for
backups, or to experiment with easy rollback.
BAT - "Block allocation table": map of virtual blocks to
physical sectors in a dynamic/diff disk.
Bitmap - Bits associated with each Block indicating which
sectors within the block have been written.
vhd-util create
Create a new disk image file.
-n filename File to create
-s size Specify file size (MB)
-r Create a fixed size image file (default is sparse)
vhd-util snapshot
Create a new snapshot (difference image) of a sparse file.
Any subsequent modification to the parent file invalidates
the snapshot. The parent filename is stored in the snapshot.
Snapshots can be chained to arbitrary depth, at perfomance cost.
-n filename File to create
-p filename Filename of parent disk
-l limit Maximum depth of snapshot chain
-m Parent disk is raw (physical). Not supported on windows.
vhd-util check
Check metadata of VHD file for consistency and reports any errors
detected.
-n filename File to check
-p Check parents as well
-i Ignore missing primary footer (repair can fix)
vhd-util read
Read and format the metadata of a sparse (dynamic) disk.
-n filename File to query
-p Print formatted header and footer.
-P Print formatted summary of file and its parents
The following options are used for debugging.
-t sector# Translate logical sector to VHD location
-b block# Print BAT directory for block
-m block# Print BINARY bitmap. (Pipe to a hex editor or file)
-i sec# Print block/sector address and written status
-a Print BINARY BAT map entries
-j block# Print allocation status of block
-d block# Print BINARY content of block data
-c # Repeat command # times for consecutivie blocks/sectors.
-r sector# Print BINARY content of sector(s)
-x Print (some) values in hex.
vhd-util query
Print key fields from the metadata. Mostly unlabeled, suitable for
consumption by a script.
-n filename File to query
-v Print virtual size (MB)
-p Print filename of parent
-s Print physical size (bytes) Includes metadata.
-f Print Xen's "hidden" state field. (Non-standard)
-d Print chain depth (# files from -n to ultimate parent)
vhd-util coalesce
Merges a snapshot (differencing) disk into its parent.
-n filename File to merge (parent is found automagically)
vhd-util repair
Attempt to repair a damaged volume.
Copies redundant copy of metadata to correct place at the
end of the file. N.B. OS level data may still be corrupt...
-n filename File to repair
vhd-util resize
Change the size of an image file. Can expand, or if
unwritten space at end, shrink. N.B. Does NOT tell the
OS filesystem, nor respect it. Restricted to files created
by Xen (including vhd-util).
Shrink currently aborts with "partially implemented" for
dynamic disks...
-n filename File to resize
-j filename Journal file (Must not exist,deleted at end.)
-s size (MB) New size
vhd-util fill
Reads and rewrites (with the same data) every block of the disk.
Effect is to allocate zero blocks for every page of a dynamic
(sparse) disk.
-n filename File to process
vhd-util modify
Modify file metadata
-n filename File to modify
-P filename (Extension) change parent only after verifying
that the UUID of the parent matches the old one.
Safer alternative for case where parent has been
renamed or moved.
The following **dangerous** options are used for debugging.
-p filename Change parent to this file. Actually changing
to a different file will corrupt data. Think
at least three times before using!
-s byteaddress Move the file footer. Can be used for changing
physical size of file, but it's tricky. Xen "
Change the size of the file containing the VHD
image. This does NOT affect the VHD disk capacity,
only the physical size of the file containing
the VHD. Naturally, it is not possible to set the
file size to be less than what the VHD utilizes.
The operation doesn't actually change the file
size, but it writes the footer in the right
location such that resizing the file (manually, as
a separate step) will produce the correct results.
If the new file size is greater than the current
file size, the file must first be expanded and
then altered with this operation.
If the new size is smaller than the current size,
the VHD must first be altered with this operation
and then the file must be shrunk.
Failing to resize the file will result in a
corrupted VHD."
-P is an extension to the Xen tool.
For protection against typos, -p must be specified twice.
vhd-util revert
Applies a journal file to recover from a failed operation.
Resize can fail with VHD in an inconsistent state; the journal file
records the changes made so that they can (hopefully) be reversed.
A VHD file in this state has a special 'poisoned' cookie to prevent
it from being accessed normally.
-n filename The file to be recovered
-j filename The journal file (specified with -j on the resize)
vhd-util set
Set the (Xen-specifix) hidden flag.
-n filename File to modify
-f hidden Only "hidden" supported.
-v value Decimal value for field.
vhd-util scan
Scan LVM volumes for VHD files and report capacity, size and parent.
Unix only.
-m filter Select files to consider (match name)
-f Do a 'fast' scan
-c Continue on errors
-l volume Scan LVM volume
-p Pretty-print results
-a Scan parents
-v Verbose
For example, to create a sparse image -
vhd-util create -n MyVHDFile -s 1024
This creates a sparse 1GB file named "MyVHDFile" that can be mounted
and populated with data.
One can also base the image on an existing file -
vhd-util snapshot -n MyVHDFile -p SomeFile
This creates a sparse VHD file named "MyVHDFile" using "SomeFile"
as a parent image. Copy-on-write semantics ensure that writes will be
stored in "MyVHDFile" while reads will be directed to the most
recently written version of the data, either in "MyVHDFile" or
"SomeFile" as is appropriate.
This document is Copyright (C) 2016 Timothe Litt.
See the COPYING file for license.

View File

@@ -0,0 +1,62 @@
/*
* Copyright (c) 2005 Anil Madhavapeddy. All rights reserved.
* Copyright (c) 1995,1999 Theo de Raadt. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include "atomicio.h"
/*
* ensure all of data on socket comes through. f==read || f==vwrite
*/
size_t
atomicio(f, fd, _s, n)
ssize_t (*f) (int, void *, size_t);
int fd;
void *_s;
size_t n;
{
char *s = _s;
size_t pos = 0;
ssize_t res;
while (n > pos) {
res = (f) (fd, s + pos, n - pos);
switch (res) {
case -1:
if (errno == EINTR || errno == EAGAIN)
continue;
return 0;
case 0:
errno = EPIPE;
return pos;
default:
pos += (size_t)res;
}
}
return (pos);
}

View File

@@ -0,0 +1,506 @@
/* This is GNU's getopt.c */
char *optarg;
int optind = 1;
int __getopt_initialized;
static char *nextchar;
int opterr = 1;
int optopt = '?';
static enum
{
REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
} ordering;
static char *posixly_correct = 0;
#include <string.h>
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#define _(x) x
static char *
my_index (str, chr)
const char *str;
int chr;
{
while (*str)
{
if (*str == chr)
return (char *) str;
str++;
}
return 0;
}
static int first_nonopt;
static int last_nonopt;
# define SWAP_FLAGS(ch1, ch2)
#if defined __STDC__ && __STDC__
static void exchange (char **);
#endif
static void
exchange (argv)
char **argv;
{
int bottom = first_nonopt;
int middle = last_nonopt;
int top = optind;
char *tem;
while (top > middle && middle > bottom)
{
if (top - middle > middle - bottom)
{
int len = middle - bottom;
register int i;
for (i = 0; i < len; i++)
{
tem = argv[bottom + i];
argv[bottom + i] = argv[top - (middle - bottom) + i];
argv[top - (middle - bottom) + i] = tem;
SWAP_FLAGS (bottom + i, top - (middle - bottom) + i);
}
top -= len;
}
else
{
int len = top - middle;
register int i;
for (i = 0; i < len; i++)
{
tem = argv[bottom + i];
argv[bottom + i] = argv[middle + i];
argv[middle + i] = tem;
SWAP_FLAGS (bottom + i, middle + i);
}
bottom += len;
}
}
first_nonopt += (optind - last_nonopt);
last_nonopt = optind;
}
#if defined __STDC__ && __STDC__
static const char *_getopt_initialize (int, char *const *, const char *);
#endif
static const char *
_getopt_initialize (argc, argv, optstring)
int argc;
char *const *argv;
const char *optstring;
{
first_nonopt = last_nonopt = optind;
nextchar = NULL;
if (optstring[0] == '-')
{
ordering = RETURN_IN_ORDER;
++optstring;
}
else if (optstring[0] == '+')
{
ordering = REQUIRE_ORDER;
++optstring;
}
else if (posixly_correct != NULL)
ordering = REQUIRE_ORDER;
else
ordering = PERMUTE;
return optstring;
}
int
_getopt_internal (argc, argv, optstring, longopts, longind, long_only)
int argc;
char *const *argv;
const char *optstring;
const struct option *longopts;
int *longind;
int long_only;
{
int print_errors = opterr;
if (optstring[0] == ':')
print_errors = 0;
optarg = NULL;
if (optind == 0 || !__getopt_initialized)
{
if (optind == 0)
optind = 1; /* Don't scan ARGV[0], the program name. */
optstring = _getopt_initialize (argc, argv, optstring);
__getopt_initialized = 1;
}
# define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0')
if (nextchar == NULL || *nextchar == '\0')
{
if (last_nonopt > optind)
last_nonopt = optind;
if (first_nonopt > optind)
first_nonopt = optind;
if (ordering == PERMUTE)
{
if (first_nonopt != last_nonopt && last_nonopt != optind)
exchange ((char **) argv);
else if (last_nonopt != optind)
first_nonopt = optind;
while (optind < argc && NONOPTION_P)
optind++;
last_nonopt = optind;
}
if (optind != argc && !strcmp (argv[optind], "--"))
{
optind++;
if (first_nonopt != last_nonopt && last_nonopt != optind)
exchange ((char **) argv);
else if (first_nonopt == last_nonopt)
first_nonopt = optind;
last_nonopt = argc;
optind = argc;
}
if (optind == argc)
{
if (first_nonopt != last_nonopt)
optind = first_nonopt;
return -1;
}
if (NONOPTION_P)
{
if (ordering == REQUIRE_ORDER)
return -1;
optarg = argv[optind++];
return 1;
}
nextchar = (argv[optind] + 1
+ (longopts != NULL && argv[optind][1] == '-'));
}
if (longopts != NULL
&& (argv[optind][1] == '-'
|| (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1])))))
{
char *nameend;
const struct option *p;
const struct option *pfound = NULL;
int exact = 0;
int ambig = 0;
int indfound = -1;
int option_index;
for (nameend = nextchar; *nameend && *nameend != '='; nameend++)
/* Do nothing. */ ;
for (p = longopts, option_index = 0; p->name; p++, option_index++)
if (!strncmp (p->name, nextchar, nameend - nextchar))
{
if ((unsigned int) (nameend - nextchar)
== (unsigned int) strlen (p->name))
{
pfound = p;
indfound = option_index;
exact = 1;
break;
}
else if (pfound == NULL)
{
pfound = p;
indfound = option_index;
}
else
ambig = 1;
}
if (ambig && !exact)
{
if (print_errors)
fprintf (stderr, _("%s: option `%s' is ambiguous\n"),
argv[0], argv[optind]);
nextchar += strlen (nextchar);
optind++;
optopt = 0;
return '?';
}
if (pfound != NULL)
{
option_index = indfound;
optind++;
if (*nameend)
{
if (pfound->has_arg)
optarg = nameend + 1;
else
{
if (print_errors)
{
if (argv[optind - 1][1] == '-')
fprintf (stderr,
_("%s: option `--%s' doesn't allow an argument\n"),
argv[0], pfound->name);
else
fprintf (stderr,
_("%s: option `%c%s' doesn't allow an argument\n"),
argv[0], argv[optind - 1][0], pfound->name);
}
nextchar += strlen (nextchar);
optopt = pfound->val;
return '?';
}
}
else if (pfound->has_arg == 1)
{
if (optind < argc)
optarg = argv[optind++];
else
{
if (print_errors)
fprintf (stderr,
_("%s: option `%s' requires an argument\n"),
argv[0], argv[optind - 1]);
nextchar += strlen (nextchar);
optopt = pfound->val;
return optstring[0] == ':' ? ':' : '?';
}
}
nextchar += strlen (nextchar);
if (longind != NULL)
*longind = option_index;
if (pfound->flag)
{
*(pfound->flag) = pfound->val;
return 0;
}
return pfound->val;
}
if (!long_only || argv[optind][1] == '-'
|| my_index (optstring, *nextchar) == NULL)
{
if (print_errors)
{
if (argv[optind][1] == '-')
fprintf (stderr, _("%s: unrecognized option `--%s'\n"),
argv[0], nextchar);
else
/* +option or -option */
fprintf (stderr, _("%s: unrecognized option `%c%s'\n"),
argv[0], argv[optind][0], nextchar);
}
nextchar = (char *) "";
optind++;
optopt = 0;
return '?';
}
}
{
char c = *nextchar++;
char *temp = my_index (optstring, c);
if (*nextchar == '\0')
++optind;
if (temp == NULL || c == ':')
{
if (print_errors)
{
if (posixly_correct)
fprintf (stderr, _("%s: illegal option -- %c\n"),
argv[0], c);
else
fprintf (stderr, _("%s: invalid option -- %c\n"),
argv[0], c);
}
optopt = c;
return '?';
}
if (temp[0] == 'W' && temp[1] == ';')
{
char *nameend;
const struct option *p;
const struct option *pfound = NULL;
int exact = 0;
int ambig = 0;
int indfound = 0;
int option_index;
if (*nextchar != '\0')
{
optarg = nextchar;
optind++;
}
else if (optind == argc)
{
if (print_errors)
{
fprintf (stderr, _("%s: option requires an argument -- %c\n"),
argv[0], c);
}
optopt = c;
if (optstring[0] == ':')
c = ':';
else
c = '?';
return c;
}
else
optarg = argv[optind++];
for (nextchar = nameend = optarg; *nameend && *nameend != '='; nameend++)
/* Do nothing. */ ;
for (p = longopts, option_index = 0; p->name; p++, option_index++)
if (!strncmp (p->name, nextchar, nameend - nextchar))
{
if ((unsigned int) (nameend - nextchar) == strlen (p->name))
{
pfound = p;
indfound = option_index;
exact = 1;
break;
}
else if (pfound == NULL)
{
pfound = p;
indfound = option_index;
}
else
ambig = 1;
}
if (ambig && !exact)
{
if (print_errors)
fprintf (stderr, _("%s: option `-W %s' is ambiguous\n"),
argv[0], argv[optind]);
nextchar += strlen (nextchar);
optind++;
return '?';
}
if (pfound != NULL)
{
option_index = indfound;
if (*nameend)
{
if (pfound->has_arg)
optarg = nameend + 1;
else
{
if (print_errors)
fprintf (stderr, _("\
%s: option `-W %s' doesn't allow an argument\n"),
argv[0], pfound->name);
nextchar += strlen (nextchar);
return '?';
}
}
else if (pfound->has_arg == 1)
{
if (optind < argc)
optarg = argv[optind++];
else
{
if (print_errors)
fprintf (stderr,
_("%s: option `%s' requires an argument\n"),
argv[0], argv[optind - 1]);
nextchar += strlen (nextchar);
return optstring[0] == ':' ? ':' : '?';
}
}
nextchar += strlen (nextchar);
if (longind != NULL)
*longind = option_index;
if (pfound->flag)
{
*(pfound->flag) = pfound->val;
return 0;
}
return pfound->val;
}
nextchar = NULL;
return 'W'; /* Let the application handle it. */
}
if (temp[1] == ':')
{
if (temp[2] == ':')
{
if (*nextchar != '\0')
{
optarg = nextchar;
optind++;
}
else
optarg = NULL;
nextchar = NULL;
}
else
{
if (*nextchar != '\0')
{
optarg = nextchar;
optind++;
}
else if (optind == argc)
{
if (print_errors)
{
fprintf (stderr,
_("%s: option requires an argument -- %c\n"),
argv[0], c);
}
optopt = c;
if (optstring[0] == ':')
c = ':';
else
c = '?';
}
else
optarg = argv[optind++];
nextchar = NULL;
}
}
return c;
}
}
int
getopt (argc, argv, optstring)
int argc;
char *const *argv;
const char *optstring;
{
return _getopt_internal (argc, argv, optstring,
(const struct option *) 0,
(int *) 0,
0);
}

View File

@@ -0,0 +1,33 @@
/* $OpenBSD: atomicio.h,v 1.6 2005/05/24 17:32:43 avsm Exp $ */
/*
* Copyright (c) 1995,1999 Theo de Raadt. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
*/
/*
* Ensure all of data on socket comes through. f==read || f==vwrite
*/
size_t atomicio(ssize_t (*)(int, void *, size_t), int, void *, size_t);
#define vwrite (ssize_t (*)(int, void *, size_t))write

View File

@@ -0,0 +1,68 @@
/* Copyright (c) 2008, XenSource 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.
*/
#ifndef _VHD_JOURNAL_H_
#define _VHD_JOURNAL_H_
#include <inttypes.h>
#include "libvhd.h"
#define VHD_JOURNAL_METADATA 0x01
#define VHD_JOURNAL_DATA 0x02
#define VHD_JOURNAL_HEADER_COOKIE "vjournal"
#define VHD_JOURNAL_ENTRY_COOKIE 0xaaaa12344321aaaa
typedef struct vhd_journal_header {
char cookie[8];
blk_uuid_t uuid;
uint64_t vhd_footer_offset;
uint32_t journal_data_entries;
uint32_t journal_metadata_entries;
uint64_t journal_data_offset;
uint64_t journal_metadata_offset;
uint64_t journal_eof;
char pad[448];
} vhd_journal_header_t;
typedef struct vhd_journal {
char *jname;
int jfd;
int is_block; /* is jfd a block device */
vhd_journal_header_t header;
vhd_context_t vhd;
} vhd_journal_t;
int vhd_journal_create(vhd_journal_t *, const char *file, const char *jfile);
int vhd_journal_open(vhd_journal_t *, const char *file, const char *jfile);
int vhd_journal_add_block(vhd_journal_t *, uint32_t block, char mode);
int vhd_journal_commit(vhd_journal_t *);
int vhd_journal_revert(vhd_journal_t *);
int vhd_journal_close(vhd_journal_t *);
int vhd_journal_remove(vhd_journal_t *);
#endif

View File

@@ -0,0 +1,124 @@
/*
* list.h
*
* This is a subset of linux's list.h intended to be used in user-space.
* XXX The namespace conflicts with NetBSD's <sys/queue.h>
*
*/
#ifndef __LIST_H__
#define __LIST_H__
#define LIST_POISON1 ((void *) 0x00100100)
#define LIST_POISON2 ((void *) 0x00200200)
struct list_head {
struct list_head *next, *prev;
};
/* XXX workaround for conflicts. The list API should use its own
* namespace prefix, i.e. BLK_
*/
#ifdef LIST_HEAD_INIT
#undef LIST_HEAD_INIT
#endif
#ifndef LIST_HEAD
#undef LIST_HEAD
#endif
#define LIST_HEAD_INIT(name) { &(name), &(name) }
#define LIST_HEAD(name) \
struct list_head name = LIST_HEAD_INIT(name)
static inline void INIT_LIST_HEAD(struct list_head *list)
{
list->next = list;
list->prev = list;
}
static inline void __list_add(struct list_head *new,
struct list_head *prev,
struct list_head *next)
{
next->prev = new;
new->next = next;
new->prev = prev;
prev->next = new;
}
static inline void list_add(struct list_head *new, struct list_head *head)
{
__list_add(new, head, head->next);
}
static inline void list_add_tail(struct list_head *new, struct list_head *head)
{
__list_add(new, head->prev, head);
}
static inline void __list_del(struct list_head * prev, struct list_head * next)
{
next->prev = prev;
prev->next = next;
}
static inline void list_del(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
entry->next = LIST_POISON1;
entry->prev = LIST_POISON2;
}
static inline void list_del_init(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
INIT_LIST_HEAD(entry);
}
static inline int list_empty(const struct list_head *head)
{
return head->next == head;
}
static inline int list_is_last(const struct list_head *list,
const struct list_head *head)
{
return list->next == head;
}
static inline void __list_splice(struct list_head *list,
struct list_head *head)
{
struct list_head *first = list->next;
struct list_head *last = list->prev;
struct list_head *at = head->next;
first->prev = head;
head->next = first;
last->next = at;
at->prev = last;
}
static inline void list_splice(struct list_head *list, struct list_head *head)
{
if (!list_empty(list))
__list_splice(list, head);
}
#define list_entry(ptr, type, member) \
((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
#define list_for_each_entry(pos, head, member) \
for (pos = list_entry((head)->next, typeof(*pos), member); \
&pos->member != (head); \
pos = list_entry(pos->member.next, typeof(*pos), member))
#define list_for_each_entry_safe(pos, n, head, member) \
for (pos = list_entry((head)->next, typeof(*pos), member), \
n = list_entry(pos->member.next, typeof(*pos), member); \
&pos->member != (head); \
pos = n, n = list_entry(n->member.next, typeof(*n), member))
#endif /* __LIST_H__ */

View File

@@ -0,0 +1,71 @@
/*
* Copyright (c) 2008, XenSource 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.
*/
#ifndef _LVM_UTIL_H_
#define _LVM_UTIL_H_
#include <inttypes.h>
#define MAX_NAME_SIZE 256
#define LVM_SEG_TYPE_LINEAR 1
#define LVM_SEG_TYPE_UNKNOWN 2
struct lv_segment {
uint8_t type;
char device[MAX_NAME_SIZE];
uint64_t pe_start;
uint64_t pe_size;
};
struct lv {
char name[MAX_NAME_SIZE];
uint64_t size;
uint32_t segments;
struct lv_segment first_segment;
};
struct pv {
char name[MAX_NAME_SIZE];
uint64_t start;
};
struct vg {
char name[MAX_NAME_SIZE];
uint64_t extent_size;
int pv_cnt;
struct pv *pvs;
int lv_cnt;
struct lv *lvs;
};
int lvm_scan_vg(const char *vg_name, struct vg *vg);
void lvm_free_vg(struct vg *vg);
#endif

View File

@@ -0,0 +1,73 @@
/*
* Compatibility file for Windows.
* Compiler-forced #include at line 1 of every source.
*/
#include <windows.h>
#include <errno.h>
#include <io.h>
#include <stdlib.h>
#include <stddef.h>
#include <sys/types.h>
#if defined(_MSC_VER)
#include <BaseTsd.h>
typedef SSIZE_T ssize_t;
#endif
#include <wingetopt.h>
#include "relative-path.h"
#define O_DIRECT 0
#define STDIN_FILENO 0
#define STDOUT_FILENO 1
#define STDERR_FILENO 2
#define open _open
#define close _close
static inline int ftruncate(int fd, __int64 length)
{
HANDLE fh = (HANDLE)_get_osfhandle(fd);
if (!fh || _lseeki64(fd, length, SEEK_SET))
return -1;
return SetEndOfFile(fh) ? 0 : -1;
}
#define fdatasync fsync
static inline int
fsync (int fd)
{
HANDLE h = (HANDLE) _get_osfhandle (fd);
DWORD err;
if (h == INVALID_HANDLE_VALUE)
{
errno = EBADF;
return -1;
}
if (!FlushFileBuffers (h))
{
err = GetLastError ();
switch (err)
{
case ERROR_ACCESS_DENIED:
return 0;
case ERROR_INVALID_HANDLE:
errno = EINVAL;
break;
default:
errno = EIO;
}
return -1;
}
return 0;
}
/* Emulated in libvhd */
char *basename( char *path );

View File

@@ -0,0 +1,44 @@
/* Copyright (c) 2008, XenSource 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.
*/
#ifndef _VHD_UTIL_H_
#define _VHD_UTIL_H_
int vhd_util_create(int argc, char **argv);
int vhd_util_snapshot(int argc, char **argv);
int vhd_util_query(int argc, char **argv);
int vhd_util_read(int argc, char **argv);
int vhd_util_set_field(int argc, char **argv);
int vhd_util_repair(int argc, char **argv);
int vhd_util_fill(int argc, char **argv);
int vhd_util_resize(int argc, char **argv);
int vhd_util_coalesce(int argc, char **argv);
int vhd_util_modify(int argc, char **argv);
int vhd_util_scan(int argc, char **argv);
int vhd_util_check(int argc, char **argv);
int vhd_util_revert(int argc, char **argv);
#endif

View File

@@ -0,0 +1,88 @@
/* Declarations for getopt.
Copyright (C) 1989,90,91,92,93,94,96,97,98 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with the GNU C Library; see the file COPYING.LIB. If not,
write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA. */
#ifndef _GETOPT_H
#ifndef __need_getopt
# define _GETOPT_H 1
#endif
#ifdef __cplusplus
extern "C" {
#endif
extern char *optarg;
extern int optind;
extern int opterr;
extern int optopt;
#ifndef __need_getopt
struct option
{
# if defined __STDC__ && __STDC__
const char *name;
# else
char *name;
# endif
int has_arg;
int *flag;
int val;
};
# define no_argument 0
# define required_argument 1
# define optional_argument 2
#endif /* need getopt */
#if defined __STDC__ && __STDC__
extern int getopt ();
# ifndef __need_getopt
extern int getopt_long (int __argc, char *const *__argv, const char *__shortopts,
const struct option *__longopts, int *__longind);
extern int getopt_long_only (int __argc, char *const *__argv,
const char *__shortopts,
const struct option *__longopts, int *__longind);
extern int _getopt_internal (int __argc, char *const *__argv,
const char *__shortopts,
const struct option *__longopts, int *__longind,
int __long_only);
# endif
#else /* not __STDC__ */
extern int getopt ();
# ifndef __need_getopt
extern int getopt_long ();
extern int getopt_long_only ();
extern int _getopt_internal ();
# endif
#endif /* __STDC__ */
#ifdef __cplusplus
}
#endif
#undef __need_getopt
#endif /* getopt.h */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,349 @@
/*
* Copyright (c) 2008, XenSource 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 <stdlib.h>
#include <string.h>
#include "lvm-util.h"
#define _NAME "%255s"
static char line[1024];
static inline int
lvm_read_line(FILE *scan)
{
memset(line, 0, sizeof(line));
return (fscanf(scan, "%1023[^\n]", line) != 1);
}
static inline int
lvm_next_line(FILE *scan)
{
return (fscanf(scan, "%1023[\n]", line) != 1);
}
static int
lvm_copy_name(char *dst, const char *src, size_t size)
{
if (strnlen(src, size) == size)
return -ENAMETOOLONG;
strcpy(dst, src);
return 0;
}
static int
lvm_parse_pv(struct vg *vg, const char *name, int pvs, uint64_t start)
{
int i, err;
struct pv *pv;
pv = NULL;
if (!vg->pvs) {
vg->pvs = calloc(pvs, sizeof(struct pv));
if (!vg->pvs)
return -ENOMEM;
}
for (i = 0; i < pvs; i++) {
pv = vg->pvs + i;
if (!pv->name[0])
break;
if (!strcmp(pv->name, name))
return -EEXIST;
}
if (!pv)
return -ENOENT;
if (i == pvs)
return -ENOMEM;
err = lvm_copy_name(pv->name, name, sizeof(pv->name) - 1);
if (err)
return err;
pv->start = start;
return 0;
}
static int
lvm_open_vg(const char *vgname, struct vg *vg)
{
FILE *scan;
int i, err, pvs, lvs;
char *cmd, pvname[256];
uint64_t size, pv_start;
memset(vg, 0, sizeof(*vg));
err = asprintf(&cmd, "/usr/sbin/vgs %s --noheadings --nosuffix --units=b "
"--options=vg_name,vg_extent_size,lv_count,pv_count,"
"pv_name,pe_start --unbuffered 2> /dev/null", vgname);
if (err == -1)
return -ENOMEM;
errno = 0;
scan = popen(cmd, "r");
if (!scan) {
err = (errno ? -errno : ENOMEM);
goto out;
}
for (;;) {
if (lvm_read_line(scan))
break;
err = -EINVAL;
if (sscanf(line, _NAME" %"SCNu64" %d %d "_NAME" %"SCNu64,
vg->name, &size, &lvs, &pvs, pvname, &pv_start) != 6)
goto out;
if (strcmp(vg->name, vgname))
goto out;
err = lvm_parse_pv(vg, pvname, pvs, pv_start);
if (err)
goto out;
if (lvm_next_line(scan))
break;
}
err = -EINVAL;
if (strcmp(vg->name, vgname))
goto out;
for (i = 0; i < pvs; i++)
if (!vg->pvs[i].name[0])
goto out;
err = -ENOMEM;
vg->lvs = calloc(lvs, sizeof(struct lv));
if (!vg->lvs)
goto out;
err = 0;
vg->lv_cnt = lvs;
vg->pv_cnt = pvs;
vg->extent_size = size;
out:
if (scan)
pclose(scan);
if (err)
lvm_free_vg(vg);
free(cmd);
return err;
}
static int
lvm_parse_lv_devices(struct vg *vg, struct lv_segment *seg, char *devices)
{
size_t i;
uint64_t start, pe_start;
for (i = 0; i < strlen(devices); i++)
if (strchr(",()", devices[i]))
devices[i] = ' ';
if (sscanf(devices, _NAME" %"SCNu64, seg->device, &start) != 2)
return -EINVAL;
pe_start = -1;
for (i = 0; i < (size_t)vg->pv_cnt; i++)
if (!strcmp(vg->pvs[i].name, seg->device)) {
pe_start = vg->pvs[i].start;
break;
}
if (pe_start == -1)
return -EINVAL;
seg->pe_start = (start * vg->extent_size) + pe_start;
return 0;
}
static int
lvm_scan_lvs(struct vg *vg)
{
char *cmd;
FILE *scan;
int i, err;
err = asprintf(&cmd, "/usr/sbin/lvs %s --noheadings --nosuffix --units=b "
"--options=lv_name,lv_size,segtype,seg_count,seg_start,"
"seg_size,devices --unbuffered 2> /dev/null", vg->name);
if (err == -1)
return -ENOMEM;
errno = 0;
scan = popen(cmd, "r");
if (!scan) {
err = (errno ? -errno : -ENOMEM);
goto out;
}
for (i = 0;;) {
int segs;
struct lv *lv;
struct lv_segment seg;
uint64_t size, seg_start;
char type[32], name[256], devices[1024];
if (i >= vg->lv_cnt)
break;
if (lvm_read_line(scan)) {
vg->lv_cnt = i;
break;
}
err = -EINVAL;
lv = vg->lvs + i;
if (sscanf(line, _NAME" %"SCNu64" %31s %u %"SCNu64" %"SCNu64" %1023s",
name, &size, type, &segs, &seg_start,
&seg.pe_size, devices) != 7)
goto out;
if (seg_start)
goto next;
if (!strcmp(type, "linear"))
seg.type = LVM_SEG_TYPE_LINEAR;
else
seg.type = LVM_SEG_TYPE_UNKNOWN;
if (lvm_parse_lv_devices(vg, &seg, devices))
goto out;
i++;
lv->size = size;
lv->segments = segs;
lv->first_segment = seg;
err = lvm_copy_name(lv->name, name, sizeof(lv->name) - 1);
if (err)
goto out;
err = -EINVAL;
next:
if (lvm_next_line(scan))
goto out;
}
err = 0;
out:
if (scan)
pclose(scan);
free(cmd);
return err;
}
void
lvm_free_vg(struct vg *vg)
{
free(vg->lvs);
free(vg->pvs);
memset(vg, 0, sizeof(*vg));
}
int
lvm_scan_vg(const char *vg_name, struct vg *vg)
{
int err;
memset(vg, 0, sizeof(*vg));
err = lvm_open_vg(vg_name, vg);
if (err)
return err;
err = lvm_scan_lvs(vg);
if (err) {
lvm_free_vg(vg);
return err;
}
return 0;
}
#ifdef LVM_UTIL
static int
usage(void)
{
printf("usage: lvm-util <vgname>\n");
exit(EINVAL);
}
int
main(int argc, char **argv)
{
int i, err;
struct vg vg;
struct pv *pv;
struct lv *lv;
struct lv_segment *seg;
if (argc != 2)
usage();
err = lvm_scan_vg(argv[1], &vg);
if (err) {
printf("scan failed: %d\n", err);
return (err >= 0 ? err : -err);
}
printf("vg %s: extent_size: %"PRIu64", pvs: %d, lvs: %d\n",
vg.name, vg.extent_size, vg.pv_cnt, vg.lv_cnt);
for (i = 0; i < vg.pv_cnt; i++) {
pv = vg.pvs + i;
printf("pv %s: start %"PRIu64"\n", pv->name, pv->start);
}
for (i = 0; i < vg.lv_cnt; i++) {
lv = vg.lvs + i;
seg = &lv->first_segment;
printf("lv %s: size: %"PRIu64", segments: %u, type: %u, "
"dev: %s, pe_start: %"PRIu64", pe_size: %"PRIu64"\n",
lv->name, lv->size, lv->segments, seg->type,
seg->device, seg->pe_start, seg->pe_size);
}
lvm_free_vg(&vg);
return 0;
}
#endif

BIN
extracters/vhd-util/vhd-util Executable file

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,232 @@
/* Copyright (c) 2008, XenSource 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 <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#ifndef _WIN32
#include <unistd.h>
#define O_BINARY 0
#endif
#include "libvhd.h"
static int
__raw_io_write(int fd, char* buf, uint64_t sec, uint32_t secs)
{
off_t off;
size_t ret;
errno = 0;
off = lseek(fd, (off_t)vhd_sectors_to_bytes(sec), SEEK_SET);
if (off == (off_t)-1) {
printf("raw parent: seek(0x%08"PRIx64") failed: %d\n",
vhd_sectors_to_bytes(sec), -errno);
return -errno;
}
ret = write(fd, buf, (size_t)vhd_sectors_to_bytes(secs));
if (ret == vhd_sectors_to_bytes(secs))
return 0;
printf("raw parent: write of 0x%"PRIx64" returned %zd, errno: %d\n",
vhd_sectors_to_bytes(secs), ret, -errno);
return (errno ? -errno : -EIO);
}
/*
* Use 'parent' if the parent is VHD, and 'parent_fd' if the parent is raw
*/
static int
vhd_util_coalesce_block(vhd_context_t *vhd, vhd_context_t *parent,
int parent_fd, uint64_t block)
{
size_t i;
int err;
char *buf, *map;
uint64_t sec, secs;
buf = NULL;
map = NULL;
sec = block * vhd->spb;
if (vhd->bat.bat[block] == DD_BLK_UNUSED)
return 0;
#ifdef _WIN32
buf = _aligned_malloc( vhd->header.block_size, 4096 );
if( buf == NULL )
return -errno;
#else
err = posix_memalign( (void **)&buf, 4096, vhd->header.block_size );
if( err )
return -err;
#endif
err = vhd_io_read(vhd, buf, sec, vhd->spb);
if (err)
goto done;
if (vhd_has_batmap(vhd) && vhd_batmap_test(vhd, &vhd->batmap, (uint32_t)block)) {
if (parent->file)
err = vhd_io_write(parent, buf, sec, vhd->spb);
else
err = __raw_io_write(parent_fd, buf, sec, vhd->spb);
goto done;
}
err = vhd_read_bitmap(vhd, (uint32_t)block, &map);
if (err)
goto done;
for (i = 0; i < vhd->spb; i++) {
if (!vhd_bitmap_test(vhd, map, i))
continue;
for (secs = 0; i + secs < vhd->spb; secs++)
if (!vhd_bitmap_test(vhd, map, i + (uint32_t)secs))
break;
if (parent->file)
err = vhd_io_write(parent,
buf + vhd_sectors_to_bytes(i),
sec + i, (uint32_t)secs);
else
err = __raw_io_write(parent_fd,
buf + vhd_sectors_to_bytes(i),
sec + i, (uint32_t)secs);
if (err)
goto done;
i += (uint32_t)secs;
}
err = 0;
done:
#ifdef _WIN32
_aligned_free( buf );
#else
free( buf );
#endif
free(map);
return err;
}
int
vhd_util_coalesce(int argc, char **argv)
{
int err, c;
uint64_t i;
char *name, *pname;
vhd_context_t vhd, parent;
int parent_fd = -1;
name = NULL;
pname = NULL;
parent.file = NULL;
if (!argc || !argv)
goto usage;
optind = 0;
while ((c = getopt(argc, argv, "n:h")) != -1) {
switch (c) {
case 'n':
name = optarg;
break;
case 'h':
default:
goto usage;
}
}
if (!name || optind != argc)
goto usage;
err = vhd_open(&vhd, name, VHD_OPEN_RDONLY);
if (err) {
printf("error opening %s: %d\n", name, err);
return err;
}
err = vhd_parent_locator_get(&vhd, &pname);
if (err) {
printf("error finding %s parent: %d\n", name, err);
vhd_close(&vhd);
return err;
}
if (vhd_parent_raw(&vhd)) {
parent_fd = open(pname, O_RDWR | O_DIRECT | O_LARGEFILE | O_BINARY, 0644);
if (parent_fd == -1) {
err = -errno;
printf("failed to open parent %s: %d\n", pname, err);
vhd_close(&vhd);
return err;
}
} else {
err = vhd_open(&parent, pname, VHD_OPEN_RDWR);
if (err) {
printf("error opening %s: %d\n", pname, err);
free(pname);
vhd_close(&vhd);
return err;
}
}
err = vhd_get_bat(&vhd);
if (err)
goto done;
if (vhd_has_batmap(&vhd)) {
err = vhd_get_batmap(&vhd);
if (err)
goto done;
}
for (i = 0; i < vhd.bat.entries; i++) {
err = vhd_util_coalesce_block(&vhd, &parent, parent_fd, i);
if (err)
goto done;
}
err = 0;
done:
free(pname);
vhd_close(&vhd);
if (parent.file)
vhd_close(&parent);
else
close(parent_fd);
return err;
usage:
printf("options: <-n name> [-h help]\n");
return -EINVAL;
}

View File

@@ -0,0 +1,82 @@
/* Copyright (c) 2008, XenSource 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 <stdlib.h>
#ifndef _WIN32
#include <unistd.h>
#endif
#include "libvhd.h"
int
vhd_util_create(int argc, char **argv)
{
char *name;
uint64_t size;
int c, sparse, err;
vhd_flag_creat_t flags;
err = -EINVAL;
size = 0;
sparse = 1;
name = NULL;
flags = 0;
if (!argc || !argv)
goto usage;
optind = 0;
while ((c = getopt(argc, argv, "n:s:rh")) != -1) {
switch (c) {
case 'n':
name = optarg;
break;
case 's':
err = 0;
size = strtoull(optarg, NULL, 10);
break;
case 'r':
sparse = 0;
break;
case 'h':
default:
goto usage;
}
}
if (err || !name || optind != argc)
goto usage;
return vhd_create(name, size << 20,
(sparse ? HD_TYPE_DYNAMIC : HD_TYPE_FIXED),
flags);
usage:
printf("options: <-n name> <-s size (MB)> [-r reserve] [-h help]\n");
return -EINVAL;
}

View File

@@ -0,0 +1,119 @@
/* Copyright (c) 2008, XenSource 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 <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#ifndef _WIN32
#include <unistd.h>
#endif
#include "libvhd.h"
int
vhd_util_fill( int argc, char **argv )
{
int err, c;
char *buf, *name;
vhd_context_t vhd;
uint64_t i, sec, secs;
buf = NULL;
name = NULL;
if( !argc || !argv )
goto usage;
optind = 0;
while( (c = getopt( argc, argv, "n:h" )) != -1 ) {
switch( c ) {
case 'n':
name = optarg;
break;
case 'h':
default:
goto usage;
}
}
if( !name || optind != argc )
goto usage;
err = vhd_open( &vhd, name, VHD_OPEN_RDWR );
if( err ) {
printf( "error opening %s: %d\n", name, err );
return err;
}
err = vhd_get_bat( &vhd );
if( err )
goto done;
#ifdef _WIN32
buf = _aligned_malloc( vhd.header.block_size, 4096 );
if( buf == NULL ) {
err = -errno;
goto done;
}
#else
err = posix_memalign((void **)&buf, 4096, vhd.header.block_size);
if (err) {
err = -err;
goto done;
}
#endif
sec = 0;
secs = vhd.header.block_size >> VHD_SECTOR_SHIFT;
for (i = 0; i < vhd.header.max_bat_size; i++) {
err = vhd_io_read(&vhd, buf, sec, (uint32_t)secs);
if (err)
goto done;
err = vhd_io_write(&vhd, buf, sec, (uint32_t)secs);
if (err)
goto done;
sec += secs;
}
err = 0;
done:
#ifdef _WIN32
_aligned_free( buf );
#else
free( buf );
#endif
vhd_close(&vhd);
return err;
usage:
printf("options: <-n name> [-h help]\n");
return -EINVAL;
}

View File

@@ -0,0 +1,144 @@
/* Copyright (c) 2008, XenSource 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.
*
* Altering operations:
*
* 1. Change the parent pointer to another file.
* 2. Change the size of the file containing the VHD image. This does NOT
* affect the VHD disk capacity, only the physical size of the file containing
* the VHD. Naturally, it is not possible to set the file size to be less than
* the what VHD utilizes.
* The operation doesn't actually change the file size, but it writes the
* footer in the right location such that resizing the file (manually, as a
* separate step) will produce the correct results. If the new file size is
* greater than the current file size, the file must first be expanded and then
* altered with this operation. If the new size is smaller than the current
* size, the VHD must first be altered with this operation and then the file
* must be shrunk. Failing to resize the file will result in a corrupted VHD.
*/
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#ifndef _WIN32
#include <unistd.h>
#endif
#include "libvhd.h"
TEST_FAIL_EXTERN_VARS;
int
vhd_util_modify(int argc, char **argv)
{
char *name;
vhd_context_t vhd;
int err, c, size, parent, parent_flags;
off_t newsize = 0;
char *newparent = NULL;
name = NULL;
size = 0;
parent = 0;
parent_flags = 0;
optind = 0;
while ((c = getopt(argc, argv, "n:s:p:P:mh")) != -1) {
switch (c) {
case 'n':
name = optarg;
break;
case 's':
size = 1;
errno = 0;
newsize = (off_t)strtoll(optarg, NULL, 10);
if (errno) {
fprintf(stderr, "Invalid size '%s'\n", optarg);
goto usage;
}
break;
case 'p':
if( parent && strcmp( newparent, optarg ) ) {
fprintf(stderr, "Parent name doesn't match\n");
goto usage;
}
++parent;
newparent = optarg;
break;
case 'P':
parent = 2;
parent_flags |= 2;
newparent = optarg;
break;
case 'm':
parent_flags |= 1;
break;
case 'h':
default:
goto usage;
}
}
if (!name || optind != argc || (parent && parent <2))
goto usage;
err = vhd_open(&vhd, name, VHD_OPEN_RDWR);
if (err) {
printf("error opening %s: %d\n", name, err);
return err;
}
if (size) {
err = vhd_set_phys_size(&vhd, newsize);
if (err)
printf("failed to set physical size to %"PRIu64":"
" %d\n", (uintmax_t)newsize, err);
}
if (parent) {
TEST_FAIL_AT(FAIL_REPARENT_BEGIN);
err = vhd_change_parent(&vhd, newparent, parent_flags);
if (err) {
printf("failed to set parent to '%s': %d\n",
newparent, err);
goto done;
}
TEST_FAIL_AT(FAIL_REPARENT_END);
}
done:
vhd_close(&vhd);
return err;
usage:
printf("*** Dangerous operations, use with care ***\n");
printf("options: <-n name> [-p NEW_PARENT set parent [-m raw]] "
"[-P change PARENT with uuid check] "
"[-s NEW_SIZE set size] [-h help]\n");
return -EINVAL;
}

View File

@@ -0,0 +1,161 @@
/* Copyright (c) 2008, XenSource 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 <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#ifndef _WIN32
#include <unistd.h>
#endif
#include "libvhd.h"
int
vhd_util_query(int argc, char **argv)
{
char *name;
vhd_context_t vhd;
off_t currsize;
int ret, err, c, size, physize, parent, fields, depth;
name = NULL;
size = 0;
physize = 0;
parent = 0;
fields = 0;
depth = 0;
if (!argc || !argv) {
err = -EINVAL;
goto usage;
}
optind = 0;
while ((c = getopt(argc, argv, "n:vspfdh")) != -1) {
switch (c) {
case 'n':
name = optarg;
break;
case 'v':
size = 1;
break;
case 's':
physize = 1;
break;
case 'p':
parent = 1;
break;
case 'f':
fields = 1;
break;
case 'd':
depth = 1;
break;
case 'h':
err = 0;
goto usage;
default:
err = -EINVAL;
goto usage;
}
}
if (!name || optind != argc) {
err = -EINVAL;
goto usage;
}
err = vhd_open(&vhd, name, VHD_OPEN_RDONLY | VHD_OPEN_IGNORE_DISABLED);
if (err) {
printf("error opening %s: %d\n", name, err);
return err;
}
if (size)
printf("%"PRIu64"\n", vhd.footer.curr_size >> 20);
if (physize) {
err = vhd_get_phys_size(&vhd, &currsize);
if (err)
printf("failed to get physical size: %d\n", err);
else
printf("%"PRIu64"\n", (uintmax_t)currsize);
}
if (parent) {
ret = 0;
if (vhd.footer.type != HD_TYPE_DIFF)
printf("%s has no parent\n", name);
else {
char *pname;
ret = vhd_parent_locator_get(&vhd, &pname);
if (ret)
printf("query failed\n");
else {
printf("%s\n", pname);
free(pname);
}
}
err = (err ? err : ret);
}
if (fields) {
int hidden;
ret = vhd_hidden(&vhd, &hidden);
if (ret)
printf("error checking 'hidden' field: %d\n", ret);
else
printf("hidden: %d\n", hidden);
err = (err ? err : ret);
}
if (depth) {
int length;
ret = vhd_chain_depth(&vhd, &length);
if (ret)
printf("error checking chain depth: %d\n", ret);
else
printf("chain depth: %d\n", length);
err = (err ? err : ret);
}
vhd_close(&vhd);
return err;
usage:
printf("options: <-n name> [-v print virtual size (in MB)] "
"[-s print physical utilization (bytes)] [-p print parent] "
"[-f print fields] [-d print chain depth] [-h help]\n");
return err;
}

View File

@@ -0,0 +1,876 @@
/* Copyright (c) 2008, XenSource 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 <stdlib.h>
#ifndef _WIN32
#include <unistd.h>
#define _O_BINARY 0
#endif
#include <inttypes.h>
#include "libvhd.h"
#include "vhd-util.h"
#define nsize 15
static char nbuf[nsize];
static inline char *
__xconv(uint64_t num)
{
snprintf(nbuf, nsize, "%#" PRIx64 , num);
return nbuf;
}
static inline char *
__dconv(uint64_t num)
{
snprintf(nbuf, nsize, "%" PRIu64, num);
return nbuf;
}
#define conv(hex, num) \
(hex ? __xconv((uint64_t)num) : __dconv((uint64_t)num))
static void
vhd_print_header(vhd_context_t *vhd, vhd_header_t *h, int hex)
{
int err;
uint32_t cksm;
char uuid[39], time_str[26], cookie[9], *name;
printf("VHD Header Summary:\n-------------------\n");
snprintf(cookie, sizeof(cookie), "%s", h->cookie);
printf("Cookie : %s\n", cookie);
printf("Data offset (unusd) : %s\n", conv(hex, h->data_offset));
printf("Table offset : %s\n", conv(hex, h->table_offset));
printf("Header version : 0x%08x\n", h->hdr_ver);
printf("Max BAT size : %s\n", conv(hex, h->max_bat_size));
printf("Block size : %s ", conv(hex, h->block_size));
printf("(%s MB)\n", conv(hex, h->block_size >> 20));
err = vhd_header_decode_parent(vhd, h, &name);
printf("Parent name : %s\n",
(err ? "failed to read name" : name));
free(name);
blk_uuid_to_string(&h->prt_uuid, uuid, sizeof(uuid));
printf("Parent UUID : %s\n", uuid);
vhd_time_to_string(h->prt_ts, time_str);
printf("Parent timestamp : %s\n", time_str);
cksm = vhd_checksum_header(h);
printf("Checksum : 0x%x|0x%x (%s)\n", h->checksum, cksm,
h->checksum == cksm ? "Good!" : "Bad!");
printf("\n");
}
static void
vhd_print_footer(vhd_footer_t *f, int hex)
{
uint64_t c, h, s;
uint32_t ff_maj, ff_min, cr_maj, cr_min, cksm;
char time_str[26], creator[5], uuid[39], cookie[9];
printf("VHD Footer Summary:\n-------------------\n");
snprintf(cookie, sizeof(cookie), "%s", f->cookie);
printf("Cookie : %s\n", cookie);
printf("Features : (0x%08x) %s%s\n", f->features,
(f->features & HD_TEMPORARY) ? "<TEMP>" : "",
(f->features & HD_RESERVED) ? "<RESV>" : "");
ff_maj = f->ff_version >> 16;
ff_min = f->ff_version & 0xffff;
printf("File format version : Major: %d, Minor: %d\n",
ff_maj, ff_min);
printf("Data offset : %s\n", conv(hex, f->data_offset));
vhd_time_to_string(f->timestamp, time_str);
printf("Timestamp : %s\n", time_str);
memcpy(creator, f->crtr_app, 4);
creator[4] = '\0';
printf("Creator Application : '%s'\n", creator);
cr_maj = f->crtr_ver >> 16;
cr_min = f->crtr_ver & 0xffff;
printf("Creator version : Major: %d, Minor: %d\n",
cr_maj, cr_min);
printf("Creator OS : %s\n",
((f->crtr_os == HD_CR_OS_WINDOWS) ? "Windows" :
((f->crtr_os == HD_CR_OS_MACINTOSH) ? "Macintosh" :
((f->crtr_os == HD_CR_OS_UNIX) ? "Unix" :
((f->crtr_os == HD_CR_OS_VMS) ? "VMS" :
"Unknown!")))));
printf("Original disk size : %s MB ", conv(hex, f->orig_size >> 20));
printf("(%s Bytes)\n", conv(hex, f->orig_size));
printf("Current disk size : %s MB ", conv(hex, f->curr_size >> 20));
printf("(%s Bytes)\n", conv(hex, f->curr_size));
c = f->geometry >> 16;
h = (f->geometry & 0x0000FF00) >> 8;
s = f->geometry & 0x000000FF;
printf("Geometry : Cyl: %s, ", conv(hex, c));
printf("Hds: %s, ", conv(hex, h));
printf("Sctrs: %s\n", conv(hex, s));
printf(" : = %s MB ", conv(hex, (c * h * s) >> 11));
printf("(%s Bytes)\n", conv(hex, c * h * s << 9));
printf("Disk type : %s\n",
f->type <= HD_TYPE_MAX ?
HD_TYPE_STR[f->type] : "Unknown");
cksm = vhd_checksum_footer(f);
printf("Checksum : 0x%x|0x%x (%s)\n", f->checksum, cksm,
f->checksum == cksm ? "Good!" : "Bad!");
blk_uuid_to_string(&f->uuid, uuid, sizeof(uuid));
printf("UUID : %s\n", uuid);
printf("Saved state : %s\n", f->saved == 0 ? "No" : "Yes");
printf("Hidden : %d\n", f->hidden);
printf("\n");
}
static inline char *
code_name(uint32_t code)
{
switch(code) {
case PLAT_CODE_NONE:
return "PLAT_CODE_NONE";
case PLAT_CODE_WI2R:
return "PLAT_CODE_WI2R";
case PLAT_CODE_WI2K:
return "PLAT_CODE_WI2K";
case PLAT_CODE_W2RU:
return "PLAT_CODE_W2RU";
case PLAT_CODE_W2KU:
return "PLAT_CODE_W2KU";
case PLAT_CODE_MAC:
return "PLAT_CODE_MAC";
case PLAT_CODE_MACX:
return "PLAT_CODE_MACX";
default:
return "UNKOWN";
}
}
static void
vhd_print_parent(vhd_context_t *vhd, vhd_parent_locator_t *loc)
{
int err;
char *buf;
err = vhd_parent_locator_read(vhd, loc, &buf);
if (err) {
printf("failed to read parent name\n");
return;
}
printf(" decoded name : %s\n", buf);
free( buf );
}
static void
vhd_print_parent_locators(vhd_context_t *vhd, int hex)
{
int i, n;
vhd_parent_locator_t *loc;
printf("VHD Parent Locators:\n--------------------\n");
n = sizeof(vhd->header.loc) / sizeof(struct prt_loc);
for (i = 0; i < n; i++) {
loc = &vhd->header.loc[i];
if (loc->code == PLAT_CODE_NONE)
continue;
printf("locator: : %d\n", i);
printf(" code : %s\n",
code_name(loc->code));
printf(" data_space : %s\n",
conv(hex, loc->data_space));
printf(" data_length : %s\n",
conv(hex, loc->data_len));
printf(" data_offset : %s\n",
conv(hex, loc->data_offset));
vhd_print_parent(vhd, loc);
printf("\n");
}
}
static void
vhd_print_batmap_header(vhd_batmap_t *batmap, int hex)
{
uint32_t cksm;
printf("VHD Batmap Summary:\n-------------------\n");
printf("Batmap offset : %s\n",
conv(hex, batmap->header.batmap_offset));
printf("Batmap size (secs) : %s\n",
conv(hex, batmap->header.batmap_size));
printf("Batmap version : 0x%08x\n",
batmap->header.batmap_version);
cksm = vhd_checksum_batmap(batmap);
printf("Checksum : 0x%x|0x%x (%s)\n",
batmap->header.checksum, cksm,
(batmap->header.checksum == cksm ? "Good!" : "Bad!"));
printf("\n");
}
static inline int
check_block_range(vhd_context_t *vhd, uint64_t block, int hex)
{
if (block > vhd->header.max_bat_size) {
fprintf(stderr, "block %s past end of file\n",
conv(hex, block));
return -ERANGE;
}
return 0;
}
static int
vhd_print_headers(vhd_context_t *vhd, int hex)
{
int err;
vhd_print_footer(&vhd->footer, hex);
if (vhd_type_dynamic(vhd)) {
vhd_print_header(vhd, &vhd->header, hex);
if (vhd->footer.type == HD_TYPE_DIFF)
vhd_print_parent_locators(vhd, hex);
if (vhd_has_batmap(vhd)) {
err = vhd_get_batmap(vhd);
if (err) {
printf("failed to get batmap header\n");
return err;
}
vhd_print_batmap_header(&vhd->batmap, hex);
}
}
return 0;
}
static int
vhd_dump_headers(const char *name, int hex)
{
vhd_context_t vhd;
libvhd_set_log_level(1);
memset(&vhd, 0, sizeof(vhd));
printf("\n%s appears invalid; dumping headers\n\n", name);
vhd.fd = open(name, O_DIRECT | O_LARGEFILE | O_RDONLY | _O_BINARY);
if (vhd.fd == -1)
return -errno;
vhd.file = strdup(name);
vhd_read_footer(&vhd, &vhd.footer);
vhd_read_header(&vhd, &vhd.header);
vhd_print_footer(&vhd.footer, hex);
vhd_print_header(&vhd, &vhd.header, hex);
close(vhd.fd);
free(vhd.file);
return 0;
}
static int
vhd_print_logical_to_physical(vhd_context_t *vhd,
uint64_t sector, int count, int hex)
{
int i;
uint32_t blk, lsec;
uint64_t cur, offset;
if (vhd_sectors_to_bytes(sector + count) > vhd->footer.curr_size) {
fprintf(stderr, "sector %s past end of file\n",
conv(hex, sector + count));
return -ERANGE;
}
for (i = 0; i < count; i++) {
cur = sector + i;
blk = (uint32_t)(cur / vhd->spb);
lsec = cur % vhd->spb;
offset = vhd->bat.bat[blk];
if (offset != DD_BLK_UNUSED) {
offset += lsec + 1;
offset = vhd_sectors_to_bytes(offset);
}
printf("logical sector %s: ", conv(hex, cur));
printf("block number: %s, ", conv(hex, blk));
printf("sector offset: %s, ", conv(hex, lsec));
printf("file offset: %s\n", (offset == DD_BLK_UNUSED ?
"not allocated" : conv(hex, offset)));
}
return 0;
}
static int
vhd_print_bat(vhd_context_t *vhd, uint64_t block, int count, int hex)
{
int i;
uint64_t cur, offset;
if (check_block_range(vhd, block + count, hex))
return -ERANGE;
for (i = 0; i < count; i++) {
cur = block + i;
offset = vhd->bat.bat[cur];
printf("block: %s: ", conv(hex, cur));
printf("offset: %s\n",
(offset == DD_BLK_UNUSED ? "not allocated" :
conv(hex, vhd_sectors_to_bytes(offset))));
}
return 0;
}
static inline void
write_full(int fd, void* buf, size_t count)
{
ssize_t num_written = 0;
if (!buf) return;
while(count > 0) {
num_written = write(fd, buf, count);
if (num_written == -1) {
if (errno == EINTR)
continue;
else
return;
}
count -= num_written;
buf = ((char *)buf) + num_written;
}
}
static int
vhd_print_bitmap(vhd_context_t *vhd, uint64_t block, int count, int hex)
{
char *buf;
int i, err;
uint64_t cur;
if (check_block_range(vhd, block + count, hex))
return -ERANGE;
for (i = 0; i < count; i++) {
cur = block + i;
if (vhd->bat.bat[cur] == DD_BLK_UNUSED) {
printf("block %s not allocated\n", conv(hex, cur));
continue;
}
err = vhd_read_bitmap(vhd, (uint32_t)cur, &buf);
if (err)
goto out;
write_full(STDOUT_FILENO, buf,
(size_t)vhd_sectors_to_bytes(vhd->bm_secs));
#ifdef _WIN32
_aligned_free(buf);
#else
free(buf);
#endif
}
err = 0;
out:
return err;
}
static int
vhd_test_bitmap(vhd_context_t *vhd, uint64_t sector, int count, int hex)
{
char *buf;
uint64_t cur;
int i, err, bit;
uint32_t blk, bm_blk, sec;
if (vhd_sectors_to_bytes(sector + count) > vhd->footer.curr_size) {
printf("sector %s past end of file\n", conv(hex, sector));
return -ERANGE;
}
bm_blk = -1;
buf = NULL;
for (i = 0; i < count; i++) {
cur = sector + i;
blk = (uint32_t)(cur / vhd->spb);
sec = cur % vhd->spb;
if (blk != bm_blk) {
bm_blk = blk;
free(buf);
buf = NULL;
if (vhd->bat.bat[blk] != DD_BLK_UNUSED) {
err = vhd_read_bitmap(vhd, blk, &buf);
if (err)
goto out;
}
}
if (vhd->bat.bat[blk] == DD_BLK_UNUSED)
bit = 0;
else
bit = vhd_bitmap_test(vhd, buf, blk);
printf("block %s: ", conv(hex, blk));
printf("sec: %s: %d\n", conv(hex, sec), bit);
}
err = 0;
out:
#ifdef _WIN32
_aligned_free( buf );
#else
free( buf );
#endif
return err;
}
static int
vhd_print_batmap(vhd_context_t *vhd)
{
int err;
size_t size;
err = vhd_get_batmap(vhd);
if (err) {
printf("failed to read batmap: %d\n", err);
return err;
}
size = (uint32_t)vhd_sectors_to_bytes(vhd->batmap.header.batmap_size);
write_full(STDOUT_FILENO, vhd->batmap.map, size);
return 0;
}
static int
vhd_test_batmap(vhd_context_t *vhd, uint64_t block, int count, int hex)
{
int i, err;
uint64_t cur;
if (check_block_range(vhd, block + count, hex))
return -ERANGE;
err = vhd_get_batmap(vhd);
if (err) {
fprintf(stderr, "failed to get batmap\n");
return err;
}
for (i = 0; i < count; i++) {
cur = block + i;
fprintf(stderr, "batmap for block %s: %d\n", conv(hex, cur),
vhd_batmap_test(vhd, &vhd->batmap, (uint32_t)cur));
}
return 0;
}
static int
vhd_print_data(vhd_context_t *vhd, uint64_t block, int count, int hex)
{
char *buf;
int i, err;
uint64_t cur;
err = 0;
if (check_block_range(vhd, block + count, hex))
return -ERANGE;
for (i = 0; i < count; i++) {
cur = block + i;
if (vhd->bat.bat[cur] == DD_BLK_UNUSED) {
printf("block %s not allocated\n", conv(hex, cur));
continue;
}
err = vhd_read_block(vhd, (uint32_t)cur, &buf);
if (err)
break;
write_full(STDOUT_FILENO, buf, vhd->header.block_size);
free(buf);
}
return err;
}
static int
vhd_read_data(vhd_context_t *vhd, uint64_t sec, int count, int hex)
{
char *buf;
uint64_t cur;
int err;
size_t max, secs;
if (vhd_sectors_to_bytes(sec + count) > vhd->footer.curr_size)
return -ERANGE;
max = MIN((size_t)vhd_sectors_to_bytes(count), VHD_BLOCK_SIZE);
#ifdef _WIN32
buf = _aligned_malloc( max, VHD_SECTOR_SIZE );
if( buf == NULL )
return -errno;
#else
err = posix_memalign((void **)&buf, VHD_SECTOR_SIZE, max);
if (err)
return -err;
#endif
cur = sec;
while (count) {
secs = MIN((max >> VHD_SECTOR_SHIFT), (size_t)count);
err = vhd_io_read(vhd, buf, cur, secs);
if (err)
break;
write_full(STDOUT_FILENO, buf, (size_t)vhd_sectors_to_bytes(secs));
cur += secs;
count -= secs;
}
#ifdef _WIN32
_aligned_free( buf );
#else
free( buf );
#endif
return err;
}
static void vhd_print_brief(vhd_context_t *cvhd, char *name) {
int err;
size_t i, n, level = 0;
vhd_parent_locator_t *loc;
vhd_context_t *vhd;
char uuid[39], time_str[26], *pname;
if( !vhd_type_dynamic(cvhd) ) {
printf( "%s has no parent\n",
cvhd->footer.type <= HD_TYPE_MAX?
HD_TYPE_STR[cvhd->footer.type] :
"Unknown disk type" );
return;
}
name = strdup( name );
if( name == NULL )
return;
vhd = malloc( sizeof( vhd_context_t ) );
if( vhd == NULL )
goto out;
memcpy( vhd, cvhd, sizeof( vhd_context_t ) );
pname = NULL;
level = 0;
while( 1 ) {
printf( "%s\n", name );
free( name );
name = NULL;
printf(" Disk type : %s\n",
vhd->footer.type <= HD_TYPE_MAX ?
HD_TYPE_STR[vhd->footer.type] : "Unknown");
if( vhd->footer.type != HD_TYPE_DIFF ) {
blk_uuid_to_string(&vhd->footer.uuid, uuid, sizeof(uuid));
printf(" UUID : %s\n", uuid);
vhd_time_to_string(vhd->footer.timestamp, time_str);
printf(" Timestamp : %s\n", time_str);
break;
}
err = vhd_header_decode_parent(vhd, &vhd->header, &name);
printf(" Parent name : %s\n",
(err ? "failed to read name" : name));
free(name);
name = NULL;
blk_uuid_to_string(&vhd->header.prt_uuid, uuid, sizeof(uuid));
printf(" Parent UUID : %s\n", uuid);
vhd_time_to_string(vhd->header.prt_ts, time_str);
printf(" Parent timestamp : %s\n", time_str);
n = sizeof(vhd->header.loc) / sizeof(struct prt_loc);
for (i = 0; i < n; i++) {
loc = &vhd->header.loc[i];
if (loc->code == PLAT_CODE_NONE)
continue;
err = vhd_parent_locator_read( vhd, loc, &name );
if( err ) {
printf( "Failed to read parent locator %u", i );
break;
}
printf(" Parent location %4d: %s\n", i, name );
if( pname == NULL ) {
err = vhd_find_parent( vhd, name, &pname );
}
free( name );
name = NULL;
}
if( pname == NULL )
break;
printf( "\nParent is " );
name = pname;
pname = NULL;
if( level != 0 )
vhd_close(vhd);
err = vhd_open(vhd, name, VHD_OPEN_RDONLY | VHD_OPEN_IGNORE_DISABLED);
if (err) {
printf("unable to open: %d\n", err);
break;
}
++level;
}
out:
if( level > 0 )
vhd_close( vhd );
free( vhd );
free( pname );
free( name );
return;
}
int
vhd_util_read(int argc, char **argv)
{
char *name;
vhd_context_t vhd;
int c, err, headers, brief, hex;
uint64_t bat, bitmap, tbitmap, batmap, tbatmap, data, lsec, count, read;
err = 0;
hex = 0;
headers = 0;
brief = 0;
count = 1;
bat = -1;
bitmap = -1;
tbitmap = -1;
batmap = -1;
tbatmap = -1;
data = -1;
lsec = -1;
read = -1;
name = NULL;
if (!argc || !argv)
goto usage;
optind = 0;
while ((c = getopt(argc, argv, "n:pPt:b:m:i:aj:d:c:r:xh")) != -1) {
switch(c) {
case 'n':
name = optarg;
break;
case 'p':
headers = 1;
break;
case 'P':
brief = 1;
break;
case 't':
lsec = strtoul(optarg, NULL, 10);
break;
case 'b':
bat = strtoull(optarg, NULL, 10);
break;
case 'm':
bitmap = strtoull(optarg, NULL, 10);
break;
case 'i':
tbitmap = strtoul(optarg, NULL, 10);
break;
case 'a':
batmap = 1;
break;
case 'j':
tbatmap = strtoull(optarg, NULL, 10);
break;
case 'd':
data = strtoull(optarg, NULL, 10);
break;
case 'r':
read = strtoull(optarg, NULL, 10);
break;
case 'c':
count = strtoul(optarg, NULL, 10);
break;
case 'x':
hex = 1;
break;
case 'h':
default:
goto usage;
}
}
if (!name || optind != argc)
goto usage;
err = vhd_open(&vhd, name, VHD_OPEN_RDONLY | VHD_OPEN_IGNORE_DISABLED);
if (err) {
printf("Failed to open %s: %d\n", name, err);
vhd_dump_headers(name, hex);
return err;
}
err = vhd_get_bat(&vhd);
if (err) {
printf("Failed to get bat for %s: %d\n", name, err);
goto out;
}
if (headers)
vhd_print_headers(&vhd, hex);
if (brief)
vhd_print_brief(&vhd, name);
if (lsec != -1) {
err = vhd_print_logical_to_physical(&vhd, lsec, (int)count, hex);
if (err)
goto out;
}
if (bat != -1) {
err = vhd_print_bat(&vhd, bat, (int)count, hex);
if (err)
goto out;
}
if (bitmap != -1) {
err = vhd_print_bitmap(&vhd, bitmap, (int)count, hex);
if (err)
goto out;
}
if (tbitmap != -1) {
err = vhd_test_bitmap(&vhd, tbitmap, (int)count, hex);
if (err)
goto out;
}
if (batmap != -1) {
err = vhd_print_batmap(&vhd);
if (err)
goto out;
}
if (tbatmap != -1) {
err = vhd_test_batmap(&vhd, tbatmap, (int)count, hex);
if (err)
goto out;
}
if (data != -1) {
err = vhd_print_data(&vhd, data, (int)count, hex);
if (err)
goto out;
}
if (read != -1) {
err = vhd_read_data(&vhd, read, (int)count, hex);
if (err)
goto out;
}
err = 0;
out:
vhd_close(&vhd);
return err;
usage:
printf("options:\n"
"-h help\n"
"-n name\n"
"-p print VHD headers\n"
"-P print parent summary\n"
"-t sec translate logical sector to VHD location\n"
"-b blk print bat entry\n"
"-m blk print bitmap\n"
"-i sec test bitmap for logical sector\n"
"-a print batmap\n"
"-j blk test batmap for block\n"
"-d blk print data\n"
"-c num num units\n"
"-r sec read num sectors at sec\n"
"-x print in hex\n");
return EINVAL;
}

View File

@@ -0,0 +1,86 @@
/* Copyright (c) 2008, XenSource 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 <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#ifndef _WIN32
#include <unistd.h>
#endif
#include "libvhd.h"
int
vhd_util_repair(int argc, char **argv)
{
char *name;
int err, c;
off_t eof;
vhd_context_t vhd;
name = NULL;
if (!argc || !argv)
goto usage;
optind = 0;
while ((c = getopt(argc, argv, "n:h")) != -1) {
switch (c) {
case 'n':
name = optarg;
break;
case 'h':
default:
goto usage;
}
}
if (!name || optind != argc)
goto usage;
err = vhd_open(&vhd, name, VHD_OPEN_RDWR);
if (err) {
printf("error opening %s: %d\n", name, err);
return err;
}
err = vhd_end_of_data(&vhd, &eof);
if (err) {
printf("error finding end of data: %d\n", err);
goto done;
}
err = vhd_write_footer_at(&vhd, &vhd.footer, eof);
done:
vhd_close(&vhd);
return err;
usage:
printf("options: <-n name> [-h help]\n");
return -EINVAL;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,108 @@
/* Copyright (c) 2008, XenSource 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.
*
* Altering operations:
*
* 1. Change the parent pointer to another file.
* 2. Change the size of the file containing the VHD image. This does NOT
* affect the VHD disk capacity, only the physical size of the file containing
* the VHD. Naturally, it is not possible to set the file size to be less than
* the what VHD utilizes.
* The operation doesn't actually change the file size, but it writes the
* footer in the right location such that resizing the file (manually, as a
* separate step) will produce the correct results. If the new file size is
* greater than the current file size, the file must first be expanded and then
* altered with this operation. If the new size is smaller than the current
* size, the VHD must first be altered with this operation and then the file
* must be shrunk. Failing to resize the file will result in a corrupted VHD.
*/
#include <errno.h>
/*#include <fcntl.h>*/
#include <stdio.h>
/*#include <stdlib.h> */
#ifndef _WIN32
#include <unistd.h>
#endif
#include "libvhd.h"
#include "libvhd-journal.h"
int
vhd_util_revert(int argc, char **argv)
{
char *name, *jname;
vhd_journal_t journal;
int c, err;
name = NULL;
jname = NULL;
optind = 0;
while ((c = getopt(argc, argv, "n:j:h")) != -1) {
switch (c) {
case 'n':
name = optarg;
break;
case 'j':
jname = optarg;
break;
case 'h':
default:
goto usage;
}
}
if (!name || !jname || argc != optind)
goto usage;
libvhd_set_log_level(1);
err = vhd_journal_open(&journal, name, jname);
if (err) {
printf("opening journal failed: %d\n", err);
return err;
}
err = vhd_journal_revert(&journal);
if (err) {
printf("reverting journal failed: %d\n", err);
vhd_journal_close(&journal);
return err;
}
err = vhd_journal_remove(&journal);
if (err) {
printf("removing journal failed: %d\n", err);
vhd_journal_close(&journal);
return err;
}
return 0;
usage:
printf("options: <-n name> <-j journal> [-h help]\n");
return -EINVAL;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,106 @@
/* Copyright (c) 2008, XenSource 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 <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#ifndef _WIN32
#include <unistd.h>
#endif
#include "libvhd.h"
int
vhd_util_set_field(int argc, char **argv)
{
long value;
int err, c;
vhd_context_t vhd;
char *name, *field;
err = -EINVAL;
value = 0;
name = NULL;
field = NULL;
if (!argc || !argv)
goto usage;
optind = 0;
while ((c = getopt(argc, argv, "n:f:v:h")) != -1) {
switch (c) {
case 'n':
name = optarg;
break;
case 'f':
field = optarg;
break;
case 'v':
err = 0;
value = strtol(optarg, NULL, 10);
break;
case 'h':
default:
goto usage;
}
}
if (!name || !field || optind != argc || err)
goto usage;
if (strnlen(field, 25) >= 25) {
printf("invalid field\n");
goto usage;
}
if (strcmp(field, "hidden")) {
printf("invalid field %s\n", field);
goto usage;
}
if (value < 0 || value > 255) {
printf("invalid value %ld\n", value);
goto usage;
}
err = vhd_open(&vhd, name, VHD_OPEN_RDWR);
if (err) {
printf("error opening %s: %d\n", name, err);
return err;
}
vhd.footer.hidden = (char)value;
err = vhd_write_footer(&vhd, &vhd.footer);
vhd_close(&vhd);
return err;
usage:
printf("options: <-n name> <-f field> <-v value> [-h help]\n");
return -EINVAL;
}

View File

@@ -0,0 +1,225 @@
/* Copyright (c) 2008, XenSource 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 <errno.h>
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#ifndef _WIN32
#include <unistd.h>
#endif
#include "libvhd.h"
static int
vhd_util_find_snapshot_target(const char *name, char **result, int *parent_raw)
{
size_t i;
int err;
char *target;
vhd_context_t vhd;
*parent_raw = 0;
*result = NULL;
target = strdup(name);
if (!target)
return -ENOMEM;
for (;;) {
err = vhd_open(&vhd, target, VHD_OPEN_RDONLY);
if (err)
return err;
if (vhd.footer.type != HD_TYPE_DIFF)
goto out;
err = vhd_get_bat(&vhd);
if (err)
goto out;
for (i = 0; i < vhd.bat.entries; i++)
if (vhd.bat.bat[i] != DD_BLK_UNUSED)
goto out;
free(target);
err = vhd_parent_locator_get(&vhd, &target);
if (err)
goto out;
if (vhd_parent_raw(&vhd)) {
*parent_raw = 1;
goto out;
}
vhd_close(&vhd);
}
out:
vhd_close(&vhd);
if (err)
free(target);
else
*result = target;
return err;
}
static int
vhd_util_check_depth(const char *name, int *depth)
{
int err;
vhd_context_t vhd;
err = vhd_open(&vhd, name, VHD_OPEN_RDONLY);
if (err)
return err;
err = vhd_chain_depth(&vhd, depth);
vhd_close(&vhd);
return err;
}
int
vhd_util_snapshot(int argc, char **argv)
{
vhd_flag_creat_t flags;
int c, err, prt_raw, limit;
char *name, *pname, *ppath, *backing;
uint64_t size;
vhd_context_t vhd;
name = NULL;
pname = NULL;
ppath = NULL;
backing = NULL;
size = 0;
flags = 0;
limit = 0;
if (!argc || !argv) {
err = -EINVAL;
goto usage;
}
optind = 0;
while ((c = getopt(argc, argv, "n:p:l:mh")) != -1) {
switch (c) {
case 'n':
name = optarg;
break;
case 'p':
pname = optarg;
break;
case 'l':
limit = strtol(optarg, NULL, 10);
break;
case 'm':
vhd_flag_set(flags, VHD_FLAG_CREAT_PARENT_RAW);
break;
case 'h':
err = 0;
goto usage;
default:
err = -EINVAL;
goto usage;
}
}
if (!name || !pname || optind != argc) {
err = -EINVAL;
goto usage;
}
ppath = realpath(pname, NULL);
if (!ppath)
return -errno;
#ifdef _WIN32
ppath++;
#endif
if (vhd_flag_test(flags, VHD_FLAG_CREAT_PARENT_RAW)) {
backing = strdup(ppath);
if (!backing) {
err = -ENOMEM;
goto out;
}
} else {
err = vhd_util_find_snapshot_target(ppath, &backing, &prt_raw);
if (err) {
backing = NULL;
goto out;
}
/*
* if the sizes of the parent chain are non-uniform, we need to
* pick the right size: that of the supplied parent
*/
if (strcmp(ppath, backing)) {
err = vhd_open(&vhd, ppath, VHD_OPEN_RDONLY);
if (err)
goto out;
size = vhd.footer.curr_size;
vhd_close(&vhd);
}
if (prt_raw)
vhd_flag_set(flags, VHD_FLAG_CREAT_PARENT_RAW);
}
if (limit && !vhd_flag_test(flags, VHD_FLAG_CREAT_PARENT_RAW)) {
int depth;
err = vhd_util_check_depth(backing, &depth);
if (err)
printf("error checking snapshot depth: %d\n", err);
else if (depth + 1 > limit) {
err = -ENOSPC;
printf("snapshot depth exceeded: "
"current depth: %d, limit: %d\n", depth, limit);
}
if (err)
goto out;
}
err = vhd_snapshot(name, size, pname, flags);
out:
#ifdef _WIN32
free( ppath - 1 );
#else
free(ppath);
#endif
free(backing);
return err;
usage:
printf("options: <-n name> <-p parent name> [-l snapshot depth limit]"
" [-m parent_is_raw] [-h help]\n");
return err;
}

View File

@@ -0,0 +1,168 @@
/* Copyright (c) 2008, XenSource 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 <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "libvhd.h"
#include "vhd-util.h"
#ifndef _WIN32
#if 1
#define DFPRINTF(_f, _a...) fprintf(stdout, _f , ##_a)
#else
#define DFPRINTF(_f, _a...) ((void)0)
#endif
#endif
typedef int (*vhd_util_func_t) (int, char **);
struct command {
char *name;
vhd_util_func_t func;
};
struct command commands[] = {
{ .name = "create", .func = vhd_util_create },
{ .name = "snapshot", .func = vhd_util_snapshot },
{ .name = "query", .func = vhd_util_query },
{ .name = "read", .func = vhd_util_read },
{ .name = "set", .func = vhd_util_set_field },
{ .name = "repair", .func = vhd_util_repair },
{ .name = "resize", .func = vhd_util_resize },
{ .name = "fill", .func = vhd_util_fill },
{ .name = "coalesce", .func = vhd_util_coalesce },
{ .name = "modify", .func = vhd_util_modify },
#ifndef _WIN32
{ .name = "scan", .func = vhd_util_scan },
#endif
{.name = "check", .func = vhd_util_check },
{ .name = "revert", .func = vhd_util_revert },
};
#define print_commands() \
do { \
int i, n; \
n = sizeof(commands) / sizeof(struct command); \
printf("COMMAND := { "); \
printf("%s", commands[0].name); \
for (i = 1; i < n; i++) \
printf(" | %s", commands[i].name); \
printf(" }\n"); \
} while (0)
TEST_FAIL_EXTERN_VARS;
void
help(void)
{
printf("usage: vhd-util COMMAND [OPTIONS]\n");
print_commands();
exit(0);
}
struct command *
get_command(char *command)
{
int i, n;
if (strnlen(command, 25) >= 25)
return NULL;
n = sizeof(commands) / sizeof (struct command);
for (i = 0; i < n; i++)
if (!strcmp(command, commands[i].name))
return &commands[i];
return NULL;
}
int
main(int argc, char *argv[])
{
char **cargv;
struct command *cmd;
int cargc, i, cnt, ret;
#ifdef CORE_DUMP
#include <sys/resource.h>
struct rlimit rlim;
rlim.rlim_cur = RLIM_INFINITY;
rlim.rlim_max = RLIM_INFINITY;
if (setrlimit(RLIMIT_CORE, &rlim) < 0)
fprintf(stderr, "setrlimit failed: %d\n", errno);
#endif
ret = 0;
libvhd_set_log_level(-1);
if (argc < 2)
help();
cargc = argc - 1;
cmd = get_command(argv[1]);
if (!cmd) {
fprintf(stderr, "invalid COMMAND %s\n", argv[1]);
help();
}
cargv = malloc(sizeof(char *) * cargc);
if (!cargv)
exit(ENOMEM);
cnt = 1;
cargv[0] = cmd->name;
for (i = 1; i < cargc; i++) {
char *arg = argv[i + (argc - cargc)];
if (!strcmp(arg, "--debug")) {
libvhd_set_log_level(1);
continue;
}
cargv[cnt++] = arg;
}
#ifdef ENABLE_FAILURE_TESTING
for (i = 0; i < NUM_FAIL_TESTS; i++) {
TEST_FAIL[i] = 0;
if (getenv(ENV_VAR_FAIL[i]))
TEST_FAIL[i] = 1;
}
#endif /* ENABLE_FAILURE_TESTING */
ret = cmd->func(cnt, cargv);
free(cargv);
if( ret )
printf( "Failed: (%d): %s\n", ret, strerror( (ret >0)? ret: -ret ) );
return (ret >= 0 ? ret : -ret);
}

BIN
extracters/vhd-util/vhd-util.exe Executable file

Binary file not shown.

View File

@@ -0,0 +1,145 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{CC5FB437-0C01-4ECF-A75F-10C37B607AC6}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<OutDir>$(ProjectDir)$(Configuration)\</OutDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(ProjectDir)$(Configuration)\</OutDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PreprocessorDefinitions>_CRT_NONSTDC_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>include;../libvhd/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<ForcedIncludeFiles>vhd-util-win32.h</ForcedIncludeFiles>
<SDLCheck>false</SDLCheck>
<PreprocessToFile>false</PreprocessToFile>
</ClCompile>
<Link>
<TargetMachine>MachineX86</TargetMachine>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
<AdditionalDependencies>../libvhd/Debug/libvhd.lib;Rpcrt4.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<PreprocessorDefinitions>_CRT_NONSTDC_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<AdditionalIncludeDirectories>include;../libvhd/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<SDLCheck>false</SDLCheck>
<ForcedIncludeFiles>vhd-util-win32.h</ForcedIncludeFiles>
</ClCompile>
<Link>
<TargetMachine>MachineX86</TargetMachine>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>../libvhd/Release/libvhd.lib;Rpcrt4.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<PostBuildEvent>
<Command>copy $(TargetPath) $(TargetDir)..\</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="atomicio.c" />
<ClCompile Include="gnugetopt.c" />
<ClCompile Include="libvhd-journal.c" />
<ClCompile Include="vhd-util-check.c" />
<ClCompile Include="vhd-util-coalesce.c" />
<ClCompile Include="vhd-util-create.c" />
<ClCompile Include="vhd-util-fill.c" />
<ClCompile Include="vhd-util-modify.c" />
<ClCompile Include="vhd-util-query.c" />
<ClCompile Include="vhd-util-read.c" />
<ClCompile Include="vhd-util-repair.c" />
<ClCompile Include="vhd-util-resize.c" />
<ClCompile Include="vhd-util-revert.c" />
<ClCompile Include="vhd-util-set-field.c" />
<ClCompile Include="vhd-util-snapshot.c" />
<ClCompile Include="vhd-util.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\libvhd\include\libvhd.h" />
<ClInclude Include="..\libvhd\include\relative-path.h" />
<ClInclude Include="..\libvhd\include\vhd.h" />
<ClInclude Include="include\atomicio.h" />
<ClInclude Include="include\wingetopt.h" />
<ClInclude Include="include\libvhd-journal.h" />
<ClInclude Include="include\list.h" />
<ClInclude Include="include\vhd-util.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@@ -0,0 +1,93 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="include\atomicio.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\libvhd-journal.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\list.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\vhd-util.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\libvhd\include\libvhd.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\libvhd\include\vhd.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\libvhd\include\relative-path.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="include\wingetopt.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="atomicio.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="libvhd-journal.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="vhd-util.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="vhd-util-check.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="vhd-util-coalesce.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="vhd-util-create.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="vhd-util-fill.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="vhd-util-modify.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="vhd-util-query.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="vhd-util-read.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="vhd-util-repair.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="vhd-util-resize.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="vhd-util-revert.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="vhd-util-set-field.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="vhd-util-snapshot.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="gnugetopt.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>