mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
import vhd-tools from xen-4.0.1
This commit is contained in:
parent
0ef191bed7
commit
fecd83d2b4
17
tools/vhd-tools/Makefile
Normal file
17
tools/vhd-tools/Makefile
Normal file
@ -0,0 +1,17 @@
|
||||
XEN_ROOT = ../..
|
||||
include $(XEN_ROOT)/tools/Rules.mk
|
||||
|
||||
CFLAGS += $(CFLAGS_libxenctrl)
|
||||
LDFLAGS += $(LDFLAGS_libxenctrl)
|
||||
|
||||
SUBDIRS-y :=
|
||||
SUBDIRS-y += include
|
||||
SUBDIRS-y += lvm
|
||||
SUBDIRS-y += vhd
|
||||
SUBDIRS-y += drivers
|
||||
|
||||
clean:
|
||||
rm -rf *.a *.so *.o *.rpm $(LIB) *~ $(DEPS) TAGS
|
||||
|
||||
.PHONY: all clean install
|
||||
all clean install: %: subdirs-%
|
||||
321
tools/vhd-tools/README
Normal file
321
tools/vhd-tools/README
Normal file
@ -0,0 +1,321 @@
|
||||
Blktap2 Userspace Tools + Library
|
||||
================================
|
||||
|
||||
Dutch Meyer
|
||||
4th June 2009
|
||||
|
||||
Andrew Warfield and Julian Chesterfield
|
||||
16th June 2006
|
||||
|
||||
|
||||
The blktap2 userspace toolkit provides a user-level disk I/O
|
||||
interface. The blktap2 mechanism involves a kernel driver that acts
|
||||
similarly to the existing Xen/Linux blkback driver, and a set of
|
||||
associated user-level libraries. Using these tools, blktap2 allows
|
||||
virtual block devices presented to VMs to be implemented in userspace
|
||||
and to be backed by raw partitions, files, network, etc.
|
||||
|
||||
The key benefit of blktap2 is that it makes it easy and fast to write
|
||||
arbitrary block backends, and that these user-level backends actually
|
||||
perform very well. Specifically:
|
||||
|
||||
- Metadata disk formats such as Copy-on-Write, encrypted disks, sparse
|
||||
formats and other compression features can be easily implemented.
|
||||
|
||||
- Accessing file-based images from userspace avoids problems related
|
||||
to flushing dirty pages which are present in the Linux loopback
|
||||
driver. (Specifically, doing a large number of writes to an
|
||||
NFS-backed image don't result in the OOM killer going berserk.)
|
||||
|
||||
- Per-disk handler processes enable easier userspace policing of block
|
||||
resources, and process-granularity QoS techniques (disk scheduling
|
||||
and related tools) may be trivially applied to block devices.
|
||||
|
||||
- It's very easy to take advantage of userspace facilities such as
|
||||
networking libraries, compression utilities, peer-to-peer
|
||||
file-sharing systems and so on to build more complex block backends.
|
||||
|
||||
- Crashes are contained -- incremental development/debugging is very
|
||||
fast.
|
||||
|
||||
How it works (in one paragraph):
|
||||
|
||||
Working in conjunction with the kernel blktap2 driver, all disk I/O
|
||||
requests from VMs are passed to the userspace deamon (using a shared
|
||||
memory interface) through a character device. Each active disk is
|
||||
mapped to an individual device node, allowing per-disk processes to
|
||||
implement individual block devices where desired. The userspace
|
||||
drivers are implemented using asynchronous (Linux libaio),
|
||||
O_DIRECT-based calls to preserve the unbuffered, batched and
|
||||
asynchronous request dispatch achieved with the existing blkback
|
||||
code. We provide a simple, asynchronous virtual disk interface that
|
||||
makes it quite easy to add new disk implementations.
|
||||
|
||||
As of June 2009 the current supported disk formats are:
|
||||
|
||||
- Raw Images (both on partitions and in image files)
|
||||
- Fast sharable RAM disk between VMs (requires some form of
|
||||
cluster-based filesystem support e.g. OCFS2 in the guest kernel)
|
||||
- VHD, including snapshots and sparse images
|
||||
- Qcow, including snapshots and sparse images
|
||||
|
||||
|
||||
Build and Installation Instructions
|
||||
===================================
|
||||
|
||||
Make to configure the blktap2 backend driver in your dom0 kernel. It
|
||||
will inter-operate with the existing backend and frontend drivers. It
|
||||
will also cohabitate with the original blktap driver. However, some
|
||||
formats (currently aio and qcow) will default to their blktap2
|
||||
versions when specified in a vm configuration file.
|
||||
|
||||
To build the tools separately, "make && make install" in
|
||||
tools/blktap2.
|
||||
|
||||
|
||||
Using the Tools
|
||||
===============
|
||||
|
||||
Preparing an image for boot:
|
||||
|
||||
The userspace disk agent is configured to start automatically via xend
|
||||
|
||||
Customize the VM config file to use the 'tap:tapdisk' handler,
|
||||
followed by the driver type. e.g. for a raw image such as a file or
|
||||
partition:
|
||||
|
||||
disk = ['tap:tapdisk:aio:<FILENAME>,sda1,w']
|
||||
|
||||
Alternatively, the vhd-util tool (installed with make install, or in
|
||||
/blktap2/vhd) can be used to build sparse copy-on-write vhd images.
|
||||
|
||||
For example, to build 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 a raw file -
|
||||
vhd-util snapshot -n MyVHDFile -p SomeRawFile -m
|
||||
|
||||
This creates a sparse VHD file named "MyVHDFile" using "SomeRawFile"
|
||||
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
|
||||
"SomeRawFile" as is appropriate. Other options exist as well, consult
|
||||
the vhd-util application for the complete set of VHD tools.
|
||||
|
||||
VHD files can be mounted automatically in a guest similarly to the
|
||||
above AIO example simply by specifying the vhd driver.
|
||||
|
||||
disk = ['tap:tapdisk:vhd:<VHD FILENAME>,sda1,w']
|
||||
|
||||
|
||||
Snapshots:
|
||||
|
||||
Pausing a guest will also plug the corresponding IO queue for blktap2
|
||||
devices and stop blktap2 drivers. This can be used to implement a
|
||||
safe live snapshot of qcow and vhd disks. An example script "xmsnap"
|
||||
is shown in the tools/blktap2/drivers directory. This script will
|
||||
perform a live snapshot of a qcow disk. VHD files can use the
|
||||
"vhd-util snapshot" tool discussed above. If this snapshot command is
|
||||
applied to a raw file mounted with tap:tapdisk:AIO, include the -m
|
||||
flag and the driver will be reloaded as VHD. If applied to an already
|
||||
mounted VHD file, omit the -m flag.
|
||||
|
||||
|
||||
Mounting images in Dom0 using the blktap2 driver
|
||||
===============================================
|
||||
Tap (and blkback) disks are also mountable in Dom0 without requiring an
|
||||
active VM to attach.
|
||||
|
||||
The syntax is -
|
||||
tapdisk2 -n <type>:<full path to file>
|
||||
|
||||
For example -
|
||||
tapdisk2 -n aio:/home/images/rawFile.img
|
||||
|
||||
When successful the location of the new device will be provided by
|
||||
tapdisk2 to stdout and tapdisk2 will terminate. From that point
|
||||
forward control of the device is provided through sysfs in the
|
||||
directory-
|
||||
|
||||
/sys/class/blktap2/blktap#/
|
||||
|
||||
Where # is a blktap2 device number present in the path that tapdisk2
|
||||
printed before terminating. The sysfs interface is largely intuitive,
|
||||
for example, to remove tap device 0 one would-
|
||||
|
||||
echo 1 > /sys/class/blktap2/blktap0/remove
|
||||
|
||||
Similarly, a pause control is available, which is can be used to plug
|
||||
the request queue of a live running guest.
|
||||
|
||||
Previous versions of blktap mounted devices in dom0 by using blkfront
|
||||
in dom0 and the xm block-attach command. This approach is still
|
||||
available, though slightly more cumbersome.
|
||||
|
||||
|
||||
Tapdisk Development
|
||||
===============================================
|
||||
|
||||
People regularly ask how to develop their own tapdisk drivers, and
|
||||
while it has not yet been well documented, the process is relatively
|
||||
easy. Here I will provide a brief overview. The best reference, of
|
||||
course, comes from the existing drivers. Specifically,
|
||||
blktap2/drivers/block-ram.c and blktap2/drivers/block-aio.c provide
|
||||
the clearest examples of simple drivers.
|
||||
|
||||
|
||||
Setup:
|
||||
|
||||
First you need to register your new driver with blktap. This is done
|
||||
in disktypes.h. There are five things that you must do. To
|
||||
demonstrate, I will create a disk called "mynewdisk", you can name
|
||||
yours freely.
|
||||
|
||||
1) Forward declare an instance of struct tap_disk.
|
||||
|
||||
e.g. -
|
||||
extern struct tap_disk tapdisk_mynewdisk;
|
||||
|
||||
2) Claim one of the unused disk type numbers, take care to observe the
|
||||
MAX_DISK_TYPES macro, increasing the number if necessary.
|
||||
|
||||
e.g. -
|
||||
#define DISK_TYPE_MYNEWDISK 10
|
||||
|
||||
3) Create an instance of disk_info_t. The bulk of this file contains examples of these.
|
||||
|
||||
e.g. -
|
||||
static disk_info_t mynewdisk_disk = {
|
||||
DISK_TYPE_MYNEWDISK,
|
||||
"My New Disk (mynewdisk)",
|
||||
"mynewdisk",
|
||||
0,
|
||||
#ifdef TAPDISK
|
||||
&tapdisk_mynewdisk,
|
||||
#endif
|
||||
};
|
||||
|
||||
A few words about what these mean. The first field must be the disk
|
||||
type number you claimed in step (2). The second field is a string
|
||||
describing your disk, and may contain any relevant info. The third
|
||||
field is the name of your disk as will be used by the tapdisk2 utility
|
||||
and xend (for example tapdisk2 -n mynewdisk:/path/to/disk.image, or in
|
||||
your xm create config file). The forth is binary and determines
|
||||
whether you will have one instance of your driver, or many. Here, a 1
|
||||
means that your driver is a singleton and will coordinate access to
|
||||
any number of tap devices. 0 is more common, meaning that you will
|
||||
have one driver for each device that is created. The final field
|
||||
should contain a reference to the struct tap_disk you created in step
|
||||
(1).
|
||||
|
||||
4) Add a reference to your disk info structure (from step (3)) to the
|
||||
dtypes array. Take care here - you need to place it in the position
|
||||
corresponding to the device type number you claimed in step (2). So
|
||||
we would place &mynewdisk_disk in dtypes[10]. Look at the other
|
||||
devices in this array and pad with "&null_disk," as necessary.
|
||||
|
||||
5) Modify the xend python scripts. You need to add your disk name to
|
||||
the list of disks that xend recognizes.
|
||||
|
||||
edit:
|
||||
tools/python/xen/xend/server/BlktapController.py
|
||||
|
||||
And add your disk to the "blktap_disk_types" array near the top of
|
||||
your file. Use the same name you specified in the third field of step
|
||||
(3). The order of this list is not important.
|
||||
|
||||
|
||||
Now your driver is ready to be written. Create a block-mynewdisk.c in
|
||||
tools/blktap2/drivers and add it to the Makefile.
|
||||
|
||||
|
||||
Development:
|
||||
|
||||
Copying block-aio.c and block-ram.c would be a good place to start.
|
||||
Read those files as you go through this, I will be assisting by
|
||||
commenting on a few useful functions and structures.
|
||||
|
||||
struct tap_disk:
|
||||
|
||||
Remember the forward declaration in step (1) of the setup phase above?
|
||||
Now is the time to make that structure a reality. This structure
|
||||
contains a list of function pointers for all the routines that will be
|
||||
asked of your driver. Currently the required functions are open,
|
||||
close, read, write, get_parent_id, validate_parent, and debug.
|
||||
|
||||
e.g. -
|
||||
struct tap_disk tapdisk_mynewdisk = {
|
||||
.disk_type = "tapdisk_mynewdisk",
|
||||
.flags = 0,
|
||||
.private_data_size = sizeof(struct tdmynewdisk_state),
|
||||
.td_open = tdmynewdisk_open,
|
||||
....
|
||||
|
||||
The private_data_size field is used to provide a structure to store
|
||||
the state of your device. It is very likely that you will want
|
||||
something here, but you are free to design whatever structure you
|
||||
want. Blktap will allocate this space for you, you just need to tell
|
||||
it how much space you want.
|
||||
|
||||
|
||||
tdmynewdisk_open:
|
||||
|
||||
This is the open routine. The first argument is a structure
|
||||
representing your driver. Two fields in this array are
|
||||
interesting.
|
||||
|
||||
driver->data will contain a block of memory of the size your requested
|
||||
in in the .private_data_size field of your struct tap_disk (above).
|
||||
|
||||
driver->info contains a structure that details information about your
|
||||
disk. You need to fill this out. By convention this is done with a
|
||||
_get_image_info() function. Assign a size (the total number of
|
||||
sectors), sector_size (the size of each sector in bytes, and set
|
||||
driver->info->info to 0.
|
||||
|
||||
The second parameter contains the name that was specified in the
|
||||
creation of your device, either through xend, or on the command line
|
||||
with tapdisk2. Usually this specifies a file that you will open in
|
||||
this routine. The final parameter, flags, contains one of a number of
|
||||
flags specified in tapdisk.h that may change the way you treat the
|
||||
disk.
|
||||
|
||||
|
||||
_queue_read/write:
|
||||
|
||||
These are your read and write operations. What you do here will
|
||||
depend on your disk, but you should do exactly one of-
|
||||
|
||||
1) call td_complete_request with either error or success code.
|
||||
|
||||
2) Call td_forward_request, which will forward the request to the next
|
||||
driver in the stack.
|
||||
|
||||
3) Queue the request for asynchronous processing with
|
||||
td_prep_read/write. In doing so, you will also register a callback
|
||||
for request completion. When the request completes you must do one of
|
||||
options (1) or (2) above. Finally, call td_queue_tiocb to submit the
|
||||
request to a wait queue.
|
||||
|
||||
The above functions are defined in tapdisk-interface.c. If you don't
|
||||
use them as specified you will run into problems as your driver will
|
||||
fail to inform blktap of the state of requests that have been
|
||||
submitted. Blktap keeps track of all requests and does not like losing track.
|
||||
|
||||
|
||||
_close, _get_parent_id, _validate_parent:
|
||||
|
||||
These last few tend to be very routine. _close is called when the
|
||||
device is closed, and also when it is paused (in this case, open will
|
||||
also be called later). The other functions are used in stacking
|
||||
drivers. Most often drivers will return TD_NO_PARENT and -EINVAL,
|
||||
respectively.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
14
tools/vhd-tools/include/Makefile
Normal file
14
tools/vhd-tools/include/Makefile
Normal file
@ -0,0 +1,14 @@
|
||||
XEN_ROOT := ../../..
|
||||
include $(XEN_ROOT)/tools/Rules.mk
|
||||
|
||||
.PHONY: all
|
||||
all:
|
||||
|
||||
.PHONY: install
|
||||
install:
|
||||
$(INSTALL_DIR) -p $(DESTDIR)$(INCLUDEDIR)
|
||||
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
@:
|
||||
33
tools/vhd-tools/include/atomicio.h
Normal file
33
tools/vhd-tools/include/atomicio.h
Normal 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
|
||||
130
tools/vhd-tools/include/blk_uuid.h
Normal file
130
tools/vhd-tools/include/blk_uuid.h
Normal file
@ -0,0 +1,130 @@
|
||||
/* 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 __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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#error "Please update blk_uuid.h for your OS"
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* __BLKTAP2_UUID_H__ */
|
||||
250
tools/vhd-tools/include/blktaplib.h
Normal file
250
tools/vhd-tools/include/blktaplib.h
Normal file
@ -0,0 +1,250 @@
|
||||
/* blktaplib.h
|
||||
*
|
||||
* Blktap library userspace code.
|
||||
*
|
||||
* Copyright (c) 2007, 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 __BLKTAPLIB_H__
|
||||
#define __BLKTAPLIB_H__
|
||||
|
||||
#include <syslog.h>
|
||||
#include <xenctrl.h>
|
||||
#include <xen/io/blkif.h>
|
||||
|
||||
#if 1
|
||||
#define DPRINTF(_f, _a...) syslog(LOG_INFO, _f, ##_a)
|
||||
#else
|
||||
#define DPRINTF(_f, _a...) ((void)0)
|
||||
#endif
|
||||
|
||||
#define EPRINTF(_f, _a...) syslog(LOG_ERR, "tap-err:%s: " _f, __func__, ##_a)
|
||||
#define PERROR(_f, _a...) EPRINTF(_f ": %s", ##_a, strerror(errno))
|
||||
|
||||
#define BLK_RING_SIZE __CONST_RING_SIZE(blkif, XC_PAGE_SIZE)
|
||||
|
||||
/* size of the extra VMA area to map in attached pages. */
|
||||
#define BLKTAP_VMA_PAGES BLK_RING_SIZE
|
||||
|
||||
/* blktap IOCTLs: These must correspond with the blktap driver ioctls */
|
||||
#define BLKTAP_IOCTL_KICK_FE 1
|
||||
#define BLKTAP_IOCTL_KICK_BE 2
|
||||
#define BLKTAP_IOCTL_SETMODE 3
|
||||
#define BLKTAP_IOCTL_SENDPID 4
|
||||
#define BLKTAP_IOCTL_NEWINTF 5
|
||||
#define BLKTAP_IOCTL_MINOR 6
|
||||
#define BLKTAP_IOCTL_MAJOR 7
|
||||
#define BLKTAP_QUERY_ALLOC_REQS 8
|
||||
#define BLKTAP_IOCTL_FREEINTF 9
|
||||
#define BLKTAP_IOCTL_PRINT_IDXS 100
|
||||
#define BLKTAP_IOCTL_BACKDEV_SETUP 200
|
||||
|
||||
#define PRIO_SPECIAL_IO -9999
|
||||
|
||||
/* blktap switching modes: (Set with BLKTAP_IOCTL_SETMODE) */
|
||||
#define BLKTAP_MODE_PASSTHROUGH 0x00000000 /* default */
|
||||
#define BLKTAP_MODE_INTERCEPT_FE 0x00000001
|
||||
#define BLKTAP_MODE_INTERCEPT_BE 0x00000002
|
||||
|
||||
#define BLKTAP_MODE_INTERPOSE \
|
||||
(BLKTAP_MODE_INTERCEPT_FE | BLKTAP_MODE_INTERCEPT_BE)
|
||||
|
||||
static inline int BLKTAP_MODE_VALID(unsigned long arg)
|
||||
{
|
||||
return (
|
||||
( arg == BLKTAP_MODE_PASSTHROUGH ) ||
|
||||
( arg == BLKTAP_MODE_INTERCEPT_FE ) ||
|
||||
( arg == BLKTAP_MODE_INTERPOSE ) );
|
||||
}
|
||||
|
||||
#define MAX_REQUESTS BLK_RING_SIZE
|
||||
|
||||
#define BLKTAP_IOCTL_KICK 1
|
||||
#define MAX_PENDING_REQS BLK_RING_SIZE
|
||||
#define BLKTAP_DEV_DIR "/dev/xen"
|
||||
#define BLKTAP_DEV_NAME "blktap"
|
||||
#define BACKDEV_NAME "backdev"
|
||||
#define BLKTAP_DEV_MINOR 0
|
||||
#define BLKTAP_CTRL_DIR "/var/run/tap"
|
||||
|
||||
extern int blktap_major;
|
||||
|
||||
#define BLKTAP_RING_PAGES 1 /* Front */
|
||||
#define BLKTAP_MMAP_REGION_SIZE (BLKTAP_RING_PAGES + MMAP_PAGES)
|
||||
|
||||
struct blkif;
|
||||
struct blkif_info;
|
||||
|
||||
typedef struct {
|
||||
blkif_request_t req;
|
||||
int submitting;
|
||||
int secs_pending;
|
||||
int16_t status;
|
||||
int num_retries;
|
||||
struct timeval last_try;
|
||||
} pending_req_t;
|
||||
|
||||
typedef struct blkif {
|
||||
domid_t domid;
|
||||
long int handle;
|
||||
|
||||
long int pdev;
|
||||
long int readonly;
|
||||
|
||||
enum { DISCONNECTED, DISCONNECTING, CONNECTED } state;
|
||||
|
||||
struct blkif_ops *ops;
|
||||
struct blkif *hash_next;
|
||||
|
||||
void *prv; /* device-specific data */
|
||||
struct blkif_info *info; /*Image parameter passing */
|
||||
pending_req_t pending_list[MAX_REQUESTS];
|
||||
int devnum;
|
||||
int fds[2];
|
||||
int be_id;
|
||||
char *backend_path;
|
||||
int major;
|
||||
int minor;
|
||||
pid_t tappid;
|
||||
int drivertype;
|
||||
uint16_t cookie;
|
||||
int err;
|
||||
} blkif_t;
|
||||
|
||||
typedef struct blkif_info {
|
||||
char *params;
|
||||
int readonly;
|
||||
int storage;
|
||||
} blkif_info_t;
|
||||
|
||||
typedef struct tapdev_info {
|
||||
int fd;
|
||||
char *mem;
|
||||
blkif_sring_t *sring;
|
||||
blkif_back_ring_t fe_ring;
|
||||
unsigned long vstart;
|
||||
blkif_t *blkif;
|
||||
} tapdev_info_t;
|
||||
|
||||
typedef struct domid_translate {
|
||||
unsigned short domid;
|
||||
unsigned short busid;
|
||||
} domid_translate_t ;
|
||||
|
||||
typedef struct image {
|
||||
unsigned long long size;
|
||||
unsigned long secsize;
|
||||
unsigned int info;
|
||||
} image_t;
|
||||
|
||||
typedef struct msg_hdr {
|
||||
uint16_t type;
|
||||
uint16_t len;
|
||||
uint16_t drivertype;
|
||||
uint16_t cookie;
|
||||
} msg_hdr_t;
|
||||
|
||||
typedef struct msg_params {
|
||||
uint8_t readonly;
|
||||
int path_off;
|
||||
int path_len;
|
||||
int storage;
|
||||
} msg_params_t;
|
||||
|
||||
typedef struct msg_newdev {
|
||||
uint8_t devnum;
|
||||
uint16_t domid;
|
||||
} msg_newdev_t;
|
||||
|
||||
typedef struct msg_pid {
|
||||
pid_t pid;
|
||||
} msg_pid_t;
|
||||
|
||||
typedef struct msg_cp {
|
||||
int cp_uuid_off;
|
||||
int cp_uuid_len;
|
||||
int cp_drivertype;
|
||||
} msg_cp_t;
|
||||
|
||||
typedef struct msg_lock {
|
||||
int ro;
|
||||
int enforce;
|
||||
int uuid_off;
|
||||
int uuid_len;
|
||||
} msg_lock_t;
|
||||
|
||||
#define READ 0
|
||||
#define WRITE 1
|
||||
|
||||
/*Control Messages between manager and tapdev*/
|
||||
#define CTLMSG_PARAMS 1
|
||||
#define CTLMSG_IMG 2
|
||||
#define CTLMSG_IMG_FAIL 3
|
||||
#define CTLMSG_NEWDEV 4
|
||||
#define CTLMSG_NEWDEV_RSP 5
|
||||
#define CTLMSG_NEWDEV_FAIL 6
|
||||
#define CTLMSG_CLOSE 7
|
||||
#define CTLMSG_CLOSE_RSP 8
|
||||
#define CTLMSG_PID 9
|
||||
#define CTLMSG_PID_RSP 10
|
||||
#define CTLMSG_CHECKPOINT 11
|
||||
#define CTLMSG_CHECKPOINT_RSP 12
|
||||
#define CTLMSG_LOCK 13
|
||||
#define CTLMSG_LOCK_RSP 14
|
||||
#define CTLMSG_PAUSE 15
|
||||
#define CTLMSG_PAUSE_RSP 16
|
||||
#define CTLMSG_RESUME 17
|
||||
#define CTLMSG_RESUME_RSP 18
|
||||
|
||||
#define TAPDISK_STORAGE_TYPE_NFS 1
|
||||
#define TAPDISK_STORAGE_TYPE_EXT 2
|
||||
#define TAPDISK_STORAGE_TYPE_LVM 3
|
||||
#define TAPDISK_STORAGE_TYPE_DEFAULT TAPDISK_STORAGE_TYPE_EXT
|
||||
|
||||
/* Abitrary values, must match the underlying driver... */
|
||||
#define MAX_TAP_DEV 256
|
||||
|
||||
/* Accessing attached data page mappings */
|
||||
#define MMAP_PAGES \
|
||||
(MAX_PENDING_REQS * BLKIF_MAX_SEGMENTS_PER_REQUEST)
|
||||
#define MMAP_VADDR(_vstart,_req,_seg) \
|
||||
((_vstart) + \
|
||||
((_req) * BLKIF_MAX_SEGMENTS_PER_REQUEST * getpagesize()) + \
|
||||
((_seg) * getpagesize()))
|
||||
|
||||
/* Defines that are only used by library clients */
|
||||
|
||||
#ifndef __COMPILING_BLKTAP_LIB
|
||||
|
||||
static char *blkif_op_name[] = {
|
||||
[BLKIF_OP_READ] = "READ",
|
||||
[BLKIF_OP_WRITE] = "WRITE",
|
||||
};
|
||||
|
||||
#endif /* __COMPILING_BLKTAP_LIB */
|
||||
|
||||
#endif /* __BLKTAPLIB_H__ */
|
||||
68
tools/vhd-tools/include/libvhd-journal.h
Normal file
68
tools/vhd-tools/include/libvhd-journal.h
Normal 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
|
||||
326
tools/vhd-tools/include/libvhd.h
Normal file
326
tools/vhd-tools/include/libvhd.h
Normal file
@ -0,0 +1,326 @@
|
||||
/* 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_LIB_H_
|
||||
#define _VHD_LIB_H_
|
||||
|
||||
#include <string.h>
|
||||
#if defined(__linux__)
|
||||
#include <endian.h>
|
||||
#include <byteswap.h>
|
||||
#elif defined(__NetBSD__)
|
||||
#include <sys/endian.h>
|
||||
#include <sys/bswap.h>
|
||||
#endif
|
||||
|
||||
#include "blk_uuid.h"
|
||||
#include "vhd.h"
|
||||
|
||||
#ifndef O_LARGEFILE
|
||||
#define O_LARGEFILE 0
|
||||
#endif
|
||||
|
||||
#if BYTE_ORDER == LITTLE_ENDIAN
|
||||
#if defined(__linux__)
|
||||
#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))
|
||||
|
||||
|
||||
#define ENABLE_FAILURE_TESTING
|
||||
#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); }
|
||||
#define TEST_FAIL_EXTERN_VARS \
|
||||
extern const char* ENV_VAR_FAIL[]; \
|
||||
extern int TEST_FAIL[];
|
||||
#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 ((bytes + (VHD_SECTOR_SIZE - 1)) >> VHD_SECTOR_SHIFT);
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
secs_round_up_no_zero(uint64_t bytes)
|
||||
{
|
||||
return (secs_round_up(bytes) ? : 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 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);
|
||||
}
|
||||
|
||||
void libvhd_set_log_level(int);
|
||||
|
||||
int vhd_test_file_fixed(const char *, int *);
|
||||
|
||||
uint32_t vhd_time(time_t time);
|
||||
size_t vhd_time_to_string(uint32_t timestamp, char *target);
|
||||
uint32_t vhd_chs(uint64_t size);
|
||||
|
||||
uint32_t vhd_checksum_footer(vhd_footer_t *);
|
||||
uint32_t vhd_checksum_header(vhd_header_t *);
|
||||
uint32_t vhd_checksum_batmap(vhd_batmap_t *);
|
||||
|
||||
void vhd_footer_in(vhd_footer_t *);
|
||||
void vhd_footer_out(vhd_footer_t *);
|
||||
void vhd_header_in(vhd_header_t *);
|
||||
void vhd_header_out(vhd_header_t *);
|
||||
void vhd_bat_in(vhd_bat_t *);
|
||||
void vhd_bat_out(vhd_bat_t *);
|
||||
void vhd_batmap_header_in(vhd_batmap_t *);
|
||||
void vhd_batmap_header_out(vhd_batmap_t *);
|
||||
|
||||
int vhd_validate_footer(vhd_footer_t *footer);
|
||||
int vhd_validate_header(vhd_header_t *header);
|
||||
int vhd_validate_batmap_header(vhd_batmap_t *batmap);
|
||||
int vhd_validate_batmap(vhd_batmap_t *batmap);
|
||||
int vhd_validate_platform_code(uint32_t code);
|
||||
|
||||
int vhd_open(vhd_context_t *, const char *file, int flags);
|
||||
void vhd_close(vhd_context_t *);
|
||||
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 */
|
||||
int vhd_snapshot(const char *snapshot, uint64_t bytes, const char *parent,
|
||||
vhd_flag_creat_t);
|
||||
|
||||
int vhd_hidden(vhd_context_t *, int *);
|
||||
int vhd_chain_depth(vhd_context_t *, int *);
|
||||
|
||||
off_t vhd_position(vhd_context_t *);
|
||||
int vhd_seek(vhd_context_t *, off_t, int);
|
||||
int vhd_read(vhd_context_t *, void *, size_t);
|
||||
int vhd_write(vhd_context_t *, void *, size_t);
|
||||
|
||||
int vhd_offset(vhd_context_t *, uint32_t, uint32_t *);
|
||||
|
||||
int vhd_end_of_headers(vhd_context_t *ctx, off_t *off);
|
||||
int vhd_end_of_data(vhd_context_t *ctx, off_t *off);
|
||||
int vhd_batmap_header_offset(vhd_context_t *ctx, off_t *off);
|
||||
|
||||
int vhd_get_header(vhd_context_t *);
|
||||
int vhd_get_footer(vhd_context_t *);
|
||||
int vhd_get_bat(vhd_context_t *);
|
||||
int vhd_get_batmap(vhd_context_t *);
|
||||
|
||||
void vhd_put_header(vhd_context_t *);
|
||||
void vhd_put_footer(vhd_context_t *);
|
||||
void vhd_put_bat(vhd_context_t *);
|
||||
void vhd_put_batmap(vhd_context_t *);
|
||||
|
||||
int vhd_has_batmap(vhd_context_t *);
|
||||
int vhd_batmap_test(vhd_context_t *, vhd_batmap_t *, uint32_t);
|
||||
void vhd_batmap_set(vhd_context_t *, vhd_batmap_t *, uint32_t);
|
||||
void vhd_batmap_clear(vhd_context_t *, vhd_batmap_t *, uint32_t);
|
||||
|
||||
int vhd_get_phys_size(vhd_context_t *, off_t *);
|
||||
int vhd_set_phys_size(vhd_context_t *, off_t);
|
||||
|
||||
int vhd_bitmap_test(vhd_context_t *, char *, uint32_t);
|
||||
void vhd_bitmap_set(vhd_context_t *, char *, uint32_t);
|
||||
void vhd_bitmap_clear(vhd_context_t *, char *, uint32_t);
|
||||
|
||||
int vhd_parent_locator_count(vhd_context_t *);
|
||||
int vhd_parent_locator_get(vhd_context_t *, char **);
|
||||
int vhd_parent_locator_read(vhd_context_t *, vhd_parent_locator_t *, char **);
|
||||
int vhd_find_parent(vhd_context_t *, const char *, char **);
|
||||
int vhd_parent_locator_write_at(vhd_context_t *, const char *,
|
||||
off_t, uint32_t, size_t,
|
||||
vhd_parent_locator_t *);
|
||||
|
||||
int vhd_header_decode_parent(vhd_context_t *, vhd_header_t *, char **);
|
||||
int vhd_change_parent(vhd_context_t *, char *parent_path, int raw);
|
||||
|
||||
int vhd_read_footer(vhd_context_t *, vhd_footer_t *);
|
||||
int vhd_read_footer_at(vhd_context_t *, vhd_footer_t *, off_t);
|
||||
int vhd_read_footer_strict(vhd_context_t *, vhd_footer_t *);
|
||||
int vhd_read_header(vhd_context_t *, vhd_header_t *);
|
||||
int vhd_read_header_at(vhd_context_t *, vhd_header_t *, off_t);
|
||||
int vhd_read_bat(vhd_context_t *, vhd_bat_t *);
|
||||
int vhd_read_batmap(vhd_context_t *, vhd_batmap_t *);
|
||||
int vhd_read_bitmap(vhd_context_t *, uint32_t block, char **bufp);
|
||||
int vhd_read_block(vhd_context_t *, uint32_t block, char **bufp);
|
||||
|
||||
int vhd_write_footer(vhd_context_t *, vhd_footer_t *);
|
||||
int vhd_write_footer_at(vhd_context_t *, vhd_footer_t *, off_t);
|
||||
int vhd_write_header(vhd_context_t *, vhd_header_t *);
|
||||
int vhd_write_header_at(vhd_context_t *, vhd_header_t *, off_t);
|
||||
int vhd_write_bat(vhd_context_t *, vhd_bat_t *);
|
||||
int vhd_write_batmap(vhd_context_t *, vhd_batmap_t *);
|
||||
int vhd_write_bitmap(vhd_context_t *, uint32_t block, char *bitmap);
|
||||
int vhd_write_block(vhd_context_t *, uint32_t block, char *data);
|
||||
|
||||
int vhd_io_read(vhd_context_t *, char *, uint64_t, uint32_t);
|
||||
int vhd_io_write(vhd_context_t *, char *, uint64_t, uint32_t);
|
||||
|
||||
#endif
|
||||
124
tools/vhd-tools/include/list.h
Normal file
124
tools/vhd-tools/include/list.h
Normal 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__ */
|
||||
71
tools/vhd-tools/include/lvm-util.h
Normal file
71
tools/vhd-tools/include/lvm-util.h
Normal 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
|
||||
43
tools/vhd-tools/include/relative-path.h
Normal file
43
tools/vhd-tools/include/relative-path.h
Normal file
@ -0,0 +1,43 @@
|
||||
/* 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 _RELATIVE_PATH_H_
|
||||
#define _RELATIVE_PATH_H_
|
||||
|
||||
#include <syslog.h>
|
||||
|
||||
#define DELIMITER '/'
|
||||
#define MAX_NAME_LEN 1000
|
||||
|
||||
#define EPRINTF(_f, _a...) syslog(LOG_ERR, "tap-err:%s: " _f, __func__, ##_a)
|
||||
|
||||
/*
|
||||
* returns a relative path from @src to @dest
|
||||
* result should be freed
|
||||
*/
|
||||
char *relative_path_to(char *src, char *dest, int *err);
|
||||
|
||||
#endif
|
||||
141
tools/vhd-tools/include/tapdisk-message.h
Normal file
141
tools/vhd-tools/include/tapdisk-message.h
Normal file
@ -0,0 +1,141 @@
|
||||
/* 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 _TAPDISK_MESSAGE_H_
|
||||
#define _TAPDISK_MESSAGE_H_
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#define TAPDISK_MESSAGE_MAX_PATH_LENGTH 256
|
||||
#define TAPDISK_MESSAGE_STRING_LENGTH 256
|
||||
|
||||
#define TAPDISK_MESSAGE_FLAG_SHARED 0x01
|
||||
#define TAPDISK_MESSAGE_FLAG_RDONLY 0x02
|
||||
#define TAPDISK_MESSAGE_FLAG_ADD_CACHE 0x04
|
||||
#define TAPDISK_MESSAGE_FLAG_VHD_INDEX 0x08
|
||||
#define TAPDISK_MESSAGE_FLAG_LOG_DIRTY 0x10
|
||||
|
||||
typedef struct tapdisk_message tapdisk_message_t;
|
||||
typedef uint8_t tapdisk_message_flag_t;
|
||||
typedef struct tapdisk_message_image tapdisk_message_image_t;
|
||||
typedef struct tapdisk_message_params tapdisk_message_params_t;
|
||||
typedef struct tapdisk_message_string tapdisk_message_string_t;
|
||||
|
||||
struct tapdisk_message_params {
|
||||
tapdisk_message_flag_t flags;
|
||||
|
||||
uint8_t storage;
|
||||
uint32_t devnum;
|
||||
uint32_t domid;
|
||||
uint16_t path_len;
|
||||
char path[TAPDISK_MESSAGE_MAX_PATH_LENGTH];
|
||||
};
|
||||
|
||||
struct tapdisk_message_image {
|
||||
uint64_t sectors;
|
||||
uint32_t sector_size;
|
||||
uint32_t info;
|
||||
};
|
||||
|
||||
struct tapdisk_message_string {
|
||||
char text[TAPDISK_MESSAGE_STRING_LENGTH];
|
||||
};
|
||||
|
||||
struct tapdisk_message {
|
||||
uint16_t type;
|
||||
uint16_t cookie;
|
||||
uint16_t drivertype;
|
||||
|
||||
union {
|
||||
pid_t tapdisk_pid;
|
||||
tapdisk_message_image_t image;
|
||||
tapdisk_message_params_t params;
|
||||
tapdisk_message_string_t string;
|
||||
} u;
|
||||
};
|
||||
|
||||
enum tapdisk_message_id {
|
||||
TAPDISK_MESSAGE_ERROR = 1,
|
||||
TAPDISK_MESSAGE_RUNTIME_ERROR,
|
||||
TAPDISK_MESSAGE_PID,
|
||||
TAPDISK_MESSAGE_PID_RSP,
|
||||
TAPDISK_MESSAGE_OPEN,
|
||||
TAPDISK_MESSAGE_OPEN_RSP,
|
||||
TAPDISK_MESSAGE_PAUSE,
|
||||
TAPDISK_MESSAGE_PAUSE_RSP,
|
||||
TAPDISK_MESSAGE_RESUME,
|
||||
TAPDISK_MESSAGE_RESUME_RSP,
|
||||
TAPDISK_MESSAGE_CLOSE,
|
||||
TAPDISK_MESSAGE_CLOSE_RSP,
|
||||
TAPDISK_MESSAGE_EXIT,
|
||||
};
|
||||
|
||||
static inline char *
|
||||
tapdisk_message_name(enum tapdisk_message_id id)
|
||||
{
|
||||
switch (id) {
|
||||
case TAPDISK_MESSAGE_ERROR:
|
||||
return "error";
|
||||
|
||||
case TAPDISK_MESSAGE_PID:
|
||||
return "pid";
|
||||
|
||||
case TAPDISK_MESSAGE_PID_RSP:
|
||||
return "pid response";
|
||||
|
||||
case TAPDISK_MESSAGE_OPEN:
|
||||
return "open";
|
||||
|
||||
case TAPDISK_MESSAGE_OPEN_RSP:
|
||||
return "open response";
|
||||
|
||||
case TAPDISK_MESSAGE_PAUSE:
|
||||
return "pause";
|
||||
|
||||
case TAPDISK_MESSAGE_PAUSE_RSP:
|
||||
return "pause response";
|
||||
|
||||
case TAPDISK_MESSAGE_RESUME:
|
||||
return "resume";
|
||||
|
||||
case TAPDISK_MESSAGE_RESUME_RSP:
|
||||
return "resume response";
|
||||
|
||||
case TAPDISK_MESSAGE_CLOSE:
|
||||
return "close";
|
||||
|
||||
case TAPDISK_MESSAGE_CLOSE_RSP:
|
||||
return "close response";
|
||||
|
||||
case TAPDISK_MESSAGE_EXIT:
|
||||
return "exit";
|
||||
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
44
tools/vhd-tools/include/vhd-util.h
Normal file
44
tools/vhd-tools/include/vhd-util.h
Normal 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
|
||||
219
tools/vhd-tools/include/vhd.h
Normal file
219
tools/vhd-tools/include/vhd.h
Normal file
@ -0,0 +1,219 @@
|
||||
/* 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_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 ) */
|
||||
|
||||
/*
|
||||
* 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 */
|
||||
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
|
||||
38
tools/vhd-tools/lvm/Makefile
Normal file
38
tools/vhd-tools/lvm/Makefile
Normal file
@ -0,0 +1,38 @@
|
||||
XEN_ROOT = ../../..
|
||||
BLKTAP_ROOT := ..
|
||||
include $(XEN_ROOT)/tools/Rules.mk
|
||||
|
||||
ifeq ($(LVM_UTIL_TEST),y)
|
||||
TEST := lvm-util
|
||||
endif
|
||||
|
||||
CFLAGS += -Werror
|
||||
CFLAGS += -Wno-unused
|
||||
CFLAGS += -I../include
|
||||
CFLAGS += -D_GNU_SOURCE
|
||||
|
||||
ifeq ($(CONFIG_X86_64),y)
|
||||
CFLAGS += -fPIC
|
||||
endif
|
||||
|
||||
# Get gcc to generate the dependencies for us.
|
||||
CFLAGS += -Wp,-MD,.$(@F).d
|
||||
DEPS = .*.d
|
||||
|
||||
LVM-OBJS := lvm-util.o
|
||||
|
||||
all: build
|
||||
|
||||
build: $(TEST) $(LVM-OBJS)
|
||||
|
||||
install: all
|
||||
|
||||
lvm-util: lvm-util.o
|
||||
$(CC) $(CFLAGS) -DLVM_UTIL $(LDFLAGS) -o lvm-util lvm-util.c
|
||||
|
||||
clean:
|
||||
rm -rf *.o *~ $(DEPS) $(IBIN)
|
||||
|
||||
.PHONY: all build clean install lvm-util
|
||||
|
||||
-include $(DEPS)
|
||||
349
tools/vhd-tools/lvm/lvm-util.c
Normal file
349
tools/vhd-tools/lvm/lvm-util.c
Normal 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)
|
||||
{
|
||||
int 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 < 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], dev[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
|
||||
56
tools/vhd-tools/vhd/Makefile
Normal file
56
tools/vhd-tools/vhd/Makefile
Normal file
@ -0,0 +1,56 @@
|
||||
XEN_ROOT=../../..
|
||||
BLKTAP_ROOT := ..
|
||||
include $(XEN_ROOT)/tools/Rules.mk
|
||||
|
||||
SUBDIRS-y :=
|
||||
SUBDIRS-y += lib
|
||||
|
||||
IBIN = vhd-util vhd-update
|
||||
INST_DIR = $(SBINDIR)
|
||||
|
||||
CFLAGS += -Werror
|
||||
CFLAGS += -Wno-unused
|
||||
CFLAGS += -I../include
|
||||
CFLAGS += -D_GNU_SOURCE
|
||||
|
||||
ifeq ($(CONFIG_X86_64),y)
|
||||
CFLAGS += -fPIC
|
||||
endif
|
||||
|
||||
ifeq ($(VHD_STATIC),y)
|
||||
CFLAGS += -static
|
||||
endif
|
||||
|
||||
LIBS := -Llib -lvhd
|
||||
ifeq ($(CONFIG_Linux),y)
|
||||
LIBS += -luuid
|
||||
endif
|
||||
|
||||
# Get gcc to generate the dependencies for us.
|
||||
CFLAGS += -Wp,-MD,.$(@F).d
|
||||
DEPS = .*.d
|
||||
|
||||
all: subdirs-all build
|
||||
|
||||
build: $(IBIN)
|
||||
|
||||
LIBS_DEPENDS := lib/libvhd.so lib/vhd.a
|
||||
$(LIBS_DEPENDS):subdirs-all
|
||||
|
||||
vhd-util: vhd-util.o $(LIBS_DEPENDS)
|
||||
$(CC) $(CFLAGS) -o vhd-util vhd-util.o $(LDFLAGS) $(LIBS)
|
||||
|
||||
vhd-update: vhd-update.o $(LIBS_DEPENDS)
|
||||
$(CC) $(CFLAGS) -o vhd-update vhd-update.o $(LDFLAGS) $(LIBS)
|
||||
|
||||
install: all
|
||||
$(MAKE) subdirs-install
|
||||
$(INSTALL_DIR) -p $(DESTDIR)$(INST_DIR)
|
||||
$(INSTALL_PROG) $(IBIN) $(DESTDIR)$(INST_DIR)
|
||||
|
||||
clean: subdirs-clean
|
||||
rm -rf *.o *~ $(DEPS) $(IBIN)
|
||||
|
||||
.PHONY: all build clean install vhd-util vhd-update
|
||||
|
||||
-include $(DEPS)
|
||||
75
tools/vhd-tools/vhd/lib/Makefile
Normal file
75
tools/vhd-tools/vhd/lib/Makefile
Normal file
@ -0,0 +1,75 @@
|
||||
XEN_ROOT=../../../..
|
||||
BLKTAP_ROOT := ../..
|
||||
include $(XEN_ROOT)/tools/Rules.mk
|
||||
|
||||
LIBVHD-MAJOR = 1.0
|
||||
LIBVHD-MINOR = 0
|
||||
LIBVHD-SONAME = libvhd.so.$(LIBVHD-MAJOR)
|
||||
|
||||
LVM-UTIL-OBJ := $(BLKTAP_ROOT)/lvm/lvm-util.o
|
||||
|
||||
LIBVHD-BUILD := libvhd.a
|
||||
|
||||
INST-DIR = $(LIBDIR)
|
||||
|
||||
CFLAGS += -Werror
|
||||
CFLAGS += -Wno-unused
|
||||
CFLAGS += -I../../include
|
||||
CFLAGS += -D_GNU_SOURCE
|
||||
CFLAGS += -fPIC
|
||||
CFLAGS += -g
|
||||
|
||||
ifeq ($(CONFIG_Linux),y)
|
||||
LIBS := -luuid
|
||||
endif
|
||||
|
||||
# Get gcc to generate the dependencies for us.
|
||||
CFLAGS += -Wp,-MD,.$(@F).d
|
||||
DEPS = .*.d
|
||||
|
||||
LIB-SRCS := libvhd.c
|
||||
LIB-SRCS += libvhd-journal.c
|
||||
LIB-SRCS += vhd-util-coalesce.c
|
||||
LIB-SRCS += vhd-util-create.c
|
||||
LIB-SRCS += vhd-util-fill.c
|
||||
LIB-SRCS += vhd-util-modify.c
|
||||
LIB-SRCS += vhd-util-query.c
|
||||
LIB-SRCS += vhd-util-read.c
|
||||
LIB-SRCS += vhd-util-repair.c
|
||||
LIB-SRCS += vhd-util-resize.c
|
||||
LIB-SRCS += vhd-util-revert.c
|
||||
LIB-SRCS += vhd-util-set-field.c
|
||||
LIB-SRCS += vhd-util-snapshot.c
|
||||
LIB-SRCS += vhd-util-scan.c
|
||||
LIB-SRCS += vhd-util-check.c
|
||||
LIB-SRCS += relative-path.c
|
||||
LIB-SRCS += atomicio.c
|
||||
|
||||
LIB-OBJS = $(patsubst %.c,%.o,$(LIB-SRCS))
|
||||
LIB-OBJS += $(LVM-UTIL-OBJ)
|
||||
|
||||
LIBVHD = libvhd.a libvhd.so.$(LIBVHD-MAJOR).$(LIBVHD-MINOR)
|
||||
|
||||
all: build
|
||||
|
||||
build: $(LIBVHD-BUILD)
|
||||
|
||||
libvhd.a: $(LIB-OBJS)
|
||||
$(CC) $(CFLAGS) -Wl,$(SONAME_LDFLAG),$(LIBVHD-SONAME) $(SHLIB_CFLAGS) \
|
||||
$(LDFLAGS) -o libvhd.so.$(LIBVHD-MAJOR).$(LIBVHD-MINOR) $(LIBS) $^
|
||||
ln -sf libvhd.so.$(LIBVHD-MAJOR).$(LIBVHD-MINOR) libvhd.so.$(LIBVHD-MAJOR)
|
||||
ln -sf libvhd.so.$(LIBVHD-MAJOR) libvhd.so
|
||||
$(AR) rc $@ $^
|
||||
|
||||
install: all
|
||||
$(INSTALL_DIR) -p $(DESTDIR)$(INST-DIR)
|
||||
$(INSTALL_DATA) $(LIBVHD) $(DESTDIR)$(INST-DIR)
|
||||
ln -sf libvhd.so.$(LIBVHD-MAJOR).$(LIBVHD-MINOR) $(DESTDIR)$(INST-DIR)/libvhd.so.$(LIBVHD-MAJOR)
|
||||
ln -sf libvhd.so.$(LIBVHD-MAJOR) $(DESTDIR)$(INST-DIR)/libvhd.so
|
||||
|
||||
clean:
|
||||
rm -rf *.a *.so* *.o *~ $(DEPS) $(LIBVHD)
|
||||
|
||||
.PHONY: all build clean install libvhd
|
||||
|
||||
-include $(DEPS)
|
||||
61
tools/vhd-tools/vhd/lib/atomicio.c
Normal file
61
tools/vhd-tools/vhd/lib/atomicio.c
Normal file
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* 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 "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);
|
||||
}
|
||||
|
||||
1534
tools/vhd-tools/vhd/lib/libvhd-journal.c
Normal file
1534
tools/vhd-tools/vhd/lib/libvhd-journal.c
Normal file
File diff suppressed because it is too large
Load Diff
3352
tools/vhd-tools/vhd/lib/libvhd.c
Normal file
3352
tools/vhd-tools/vhd/lib/libvhd.c
Normal file
File diff suppressed because it is too large
Load Diff
299
tools/vhd-tools/vhd/lib/relative-path.c
Normal file
299
tools/vhd-tools/vhd/lib/relative-path.c
Normal file
@ -0,0 +1,299 @@
|
||||
/* 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 "relative-path.h"
|
||||
|
||||
#define sfree(ptr) \
|
||||
do { \
|
||||
free(ptr); \
|
||||
ptr = NULL; \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* count number of tokens between DELIMETER characters
|
||||
*/
|
||||
static 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
|
||||
*/
|
||||
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("invalid input; max path length is %d\n",
|
||||
MAX_NAME_LEN);
|
||||
*err = -ENAMETOOLONG;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
to_absolute = realpath(to, NULL);
|
||||
if (!to_absolute) {
|
||||
EPRINTF("failed to get absolute path of %s\n", to);
|
||||
*err = -errno;
|
||||
goto out;
|
||||
}
|
||||
|
||||
from_absolute = realpath(from, NULL);
|
||||
if (!from_absolute) {
|
||||
EPRINTF("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("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("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("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("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("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;
|
||||
}
|
||||
980
tools/vhd-tools/vhd/lib/vhd-util-check.c
Normal file
980
tools/vhd-tools/vhd/lib/vhd-util-check.c
Normal file
@ -0,0 +1,980 @@
|
||||
/* 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 <time.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <libgen.h>
|
||||
#include <inttypes.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "libvhd.h"
|
||||
#include "vhd-util.h"
|
||||
|
||||
// allow the VHD timestamp to be at most this many seconds into the future to
|
||||
// account for time skew with NFS servers
|
||||
#define TIMESTAMP_MAX_SLACK 1800
|
||||
|
||||
static int
|
||||
vhd_util_check_zeros(void *buf, size_t size)
|
||||
{
|
||||
int i;
|
||||
char *p;
|
||||
|
||||
p = buf;
|
||||
for (i = 0; i < size; i++)
|
||||
if (p[i])
|
||||
return i;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
vhd_util_check_footer_opened(vhd_footer_t *footer)
|
||||
{
|
||||
int i, n;
|
||||
uint32_t *buf;
|
||||
|
||||
buf = (uint32_t *)footer;
|
||||
n = sizeof(*footer) / sizeof(uint32_t);
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
if (buf[i] != 0xc7c7c7c7)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static char *
|
||||
vhd_util_check_validate_footer(vhd_footer_t *footer)
|
||||
{
|
||||
int size;
|
||||
uint32_t checksum, now;
|
||||
|
||||
size = sizeof(footer->cookie);
|
||||
if (memcmp(footer->cookie, HD_COOKIE, size))
|
||||
return "invalid cookie";
|
||||
|
||||
checksum = vhd_checksum_footer(footer);
|
||||
if (checksum != footer->checksum) {
|
||||
if (footer->hidden &&
|
||||
!strncmp(footer->crtr_app, "tap", 3) &&
|
||||
(footer->crtr_ver == VHD_VERSION(0, 1) ||
|
||||
footer->crtr_ver == VHD_VERSION(1, 1))) {
|
||||
char tmp = footer->hidden;
|
||||
footer->hidden = 0;
|
||||
checksum = vhd_checksum_footer(footer);
|
||||
footer->hidden = tmp;
|
||||
|
||||
if (checksum == footer->checksum)
|
||||
goto ok;
|
||||
}
|
||||
|
||||
return "invalid checksum";
|
||||
}
|
||||
|
||||
ok:
|
||||
if (!(footer->features & HD_RESERVED))
|
||||
return "invalid 'reserved' feature";
|
||||
|
||||
if (footer->features & ~(HD_TEMPORARY | HD_RESERVED))
|
||||
return "invalid extra features";
|
||||
|
||||
if (footer->ff_version != HD_FF_VERSION)
|
||||
return "invalid file format version";
|
||||
|
||||
if (footer->type != HD_TYPE_DYNAMIC &&
|
||||
footer->type != HD_TYPE_DIFF &&
|
||||
footer->data_offset != ~(0ULL))
|
||||
return "invalid data offset";
|
||||
|
||||
now = vhd_time(time(NULL));
|
||||
if (footer->timestamp > now + TIMESTAMP_MAX_SLACK)
|
||||
return "creation time in future";
|
||||
|
||||
if (!strncmp(footer->crtr_app, "tap", 3) &&
|
||||
footer->crtr_ver > VHD_CURRENT_VERSION)
|
||||
return "unsupported tap creator version";
|
||||
|
||||
if (vhd_chs(footer->curr_size) < footer->geometry)
|
||||
return "geometry too large";
|
||||
|
||||
if (footer->type != HD_TYPE_FIXED &&
|
||||
footer->type != HD_TYPE_DYNAMIC &&
|
||||
footer->type != HD_TYPE_DIFF)
|
||||
return "invalid type";
|
||||
|
||||
if (footer->saved && footer->saved != 1)
|
||||
return "invalid 'saved' state";
|
||||
|
||||
if (footer->hidden && footer->hidden != 1)
|
||||
return "invalid 'hidden' state";
|
||||
|
||||
if (vhd_util_check_zeros(footer->reserved,
|
||||
sizeof(footer->reserved)))
|
||||
return "invalid 'reserved' bits";
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static char *
|
||||
vhd_util_check_validate_header(int fd, vhd_header_t *header)
|
||||
{
|
||||
off_t eof;
|
||||
int i, cnt, size;
|
||||
uint32_t checksum;
|
||||
|
||||
size = sizeof(header->cookie);
|
||||
if (memcmp(header->cookie, DD_COOKIE, size))
|
||||
return "invalid cookie";
|
||||
|
||||
checksum = vhd_checksum_header(header);
|
||||
if (checksum != header->checksum)
|
||||
return "invalid checksum";
|
||||
|
||||
if (header->hdr_ver != 0x00010000)
|
||||
return "invalid header version";
|
||||
|
||||
if (header->data_offset != ~(0ULL))
|
||||
return "invalid data offset";
|
||||
|
||||
eof = lseek(fd, 0, SEEK_END);
|
||||
if (eof == (off_t)-1)
|
||||
return "error finding eof";
|
||||
|
||||
if (header->table_offset <= 0 ||
|
||||
header->table_offset % 512 ||
|
||||
(header->table_offset +
|
||||
(header->max_bat_size * sizeof(uint32_t)) >
|
||||
eof - sizeof(vhd_footer_t)))
|
||||
return "invalid table offset";
|
||||
|
||||
for (cnt = 0, i = 0; i < sizeof(header->block_size) * 8; i++)
|
||||
if ((header->block_size >> i) & 1)
|
||||
cnt++;
|
||||
|
||||
if (cnt != 1)
|
||||
return "invalid block size";
|
||||
|
||||
if (header->res1)
|
||||
return "invalid reserved bits";
|
||||
|
||||
if (vhd_util_check_zeros(header->res2, sizeof(header->res2)))
|
||||
return "invalid reserved bits";
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static char *
|
||||
vhd_util_check_validate_differencing_header(vhd_context_t *vhd)
|
||||
{
|
||||
vhd_header_t *header;
|
||||
|
||||
header = &vhd->header;
|
||||
|
||||
if (vhd->footer.type == HD_TYPE_DIFF) {
|
||||
char *parent;
|
||||
uint32_t now;
|
||||
|
||||
now = vhd_time(time(NULL));
|
||||
if (header->prt_ts > now + TIMESTAMP_MAX_SLACK)
|
||||
return "parent creation time in future";
|
||||
|
||||
if (vhd_header_decode_parent(vhd, header, &parent))
|
||||
return "invalid parent name";
|
||||
|
||||
free(parent);
|
||||
} else {
|
||||
if (vhd_util_check_zeros(header->prt_name,
|
||||
sizeof(header->prt_name)))
|
||||
return "invalid non-null parent name";
|
||||
|
||||
if (vhd_util_check_zeros(header->loc, sizeof(header->loc)))
|
||||
return "invalid non-null parent locators";
|
||||
|
||||
if (!blk_uuid_is_nil(&header->prt_uuid))
|
||||
return "invalid non-null parent uuid";
|
||||
|
||||
if (header->prt_ts)
|
||||
return "invalid non-zero parent timestamp";
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static char *
|
||||
vhd_util_check_validate_batmap(vhd_context_t *vhd, vhd_batmap_t *batmap)
|
||||
{
|
||||
int size;
|
||||
off_t eof;
|
||||
uint32_t checksum;
|
||||
|
||||
size = sizeof(batmap->header.cookie);
|
||||
if (memcmp(batmap->header.cookie, VHD_BATMAP_COOKIE, size))
|
||||
return "invalid cookie";
|
||||
|
||||
if (batmap->header.batmap_version > VHD_BATMAP_CURRENT_VERSION)
|
||||
return "unsupported batmap version";
|
||||
|
||||
checksum = vhd_checksum_batmap(batmap);
|
||||
if (checksum != batmap->header.checksum)
|
||||
return "invalid checksum";
|
||||
|
||||
if (!batmap->header.batmap_size)
|
||||
return "invalid size zero";
|
||||
|
||||
eof = lseek(vhd->fd, 0, SEEK_END);
|
||||
if (eof == (off_t)-1)
|
||||
return "error finding eof";
|
||||
|
||||
if (!batmap->header.batmap_offset ||
|
||||
batmap->header.batmap_offset % 512)
|
||||
return "invalid batmap offset";
|
||||
|
||||
if ((batmap->header.batmap_offset +
|
||||
vhd_sectors_to_bytes(batmap->header.batmap_size)) >
|
||||
eof - sizeof(vhd_footer_t))
|
||||
return "invalid batmap size";
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static char *
|
||||
vhd_util_check_validate_parent_locator(vhd_context_t *vhd,
|
||||
vhd_parent_locator_t *loc)
|
||||
{
|
||||
off_t eof;
|
||||
|
||||
if (vhd_validate_platform_code(loc->code))
|
||||
return "invalid platform code";
|
||||
|
||||
if (loc->code == PLAT_CODE_NONE) {
|
||||
if (vhd_util_check_zeros(loc, sizeof(*loc)))
|
||||
return "non-zero locator";
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!loc->data_offset)
|
||||
return "invalid data offset";
|
||||
|
||||
if (!loc->data_space)
|
||||
return "invalid data space";
|
||||
|
||||
if (!loc->data_len)
|
||||
return "invalid data length";
|
||||
|
||||
eof = lseek(vhd->fd, 0, SEEK_END);
|
||||
if (eof == (off_t)-1)
|
||||
return "error finding eof";
|
||||
|
||||
if (loc->data_offset + vhd_parent_locator_size(loc) >
|
||||
eof - sizeof(vhd_footer_t))
|
||||
return "invalid size";
|
||||
|
||||
if (loc->res)
|
||||
return "invalid reserved bits";
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char *
|
||||
vhd_util_check_validate_parent(vhd_context_t *vhd, const char *ppath)
|
||||
{
|
||||
const char *msg;
|
||||
vhd_context_t parent;
|
||||
uint32_t status;
|
||||
|
||||
msg = NULL;
|
||||
|
||||
if (vhd_parent_raw(vhd))
|
||||
return msg;
|
||||
|
||||
if (vhd_open(&parent, ppath,
|
||||
VHD_OPEN_RDONLY | VHD_OPEN_IGNORE_DISABLED))
|
||||
return "error opening parent";
|
||||
|
||||
if (blk_uuid_compare(&vhd->header.prt_uuid, &parent.footer.uuid)) {
|
||||
msg = "invalid parent uuid";
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
vhd_close(&parent);
|
||||
return msg;
|
||||
}
|
||||
|
||||
static int
|
||||
vhd_util_check_footer(int fd, vhd_footer_t *footer, int ignore)
|
||||
{
|
||||
size_t size;
|
||||
int err, opened;
|
||||
char *msg, *buf;
|
||||
off_t eof, off;
|
||||
vhd_footer_t primary, backup;
|
||||
|
||||
memset(&primary, 0, sizeof(primary));
|
||||
memset(&backup, 0, sizeof(backup));
|
||||
|
||||
err = posix_memalign((void **)&buf, VHD_SECTOR_SIZE, sizeof(primary));
|
||||
if (err) {
|
||||
printf("error allocating buffer: %d\n", err);
|
||||
return -err;
|
||||
}
|
||||
|
||||
memset(buf, 0, sizeof(primary));
|
||||
|
||||
eof = lseek(fd, 0, SEEK_END);
|
||||
if (eof == (off_t)-1) {
|
||||
err = -errno;
|
||||
printf("error calculating end of file: %d\n", err);
|
||||
goto out;
|
||||
}
|
||||
|
||||
size = ((eof % 512) ? 511 : 512);
|
||||
eof = lseek(fd, eof - size, SEEK_SET);
|
||||
if (eof == (off_t)-1) {
|
||||
err = -errno;
|
||||
printf("error calculating end of file: %d\n", err);
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = read(fd, buf, 512);
|
||||
if (err != size) {
|
||||
err = (errno ? -errno : -EIO);
|
||||
printf("error reading primary footer: %d\n", err);
|
||||
goto out;
|
||||
}
|
||||
|
||||
memcpy(&primary, buf, sizeof(primary));
|
||||
opened = vhd_util_check_footer_opened(&primary);
|
||||
vhd_footer_in(&primary);
|
||||
|
||||
msg = vhd_util_check_validate_footer(&primary);
|
||||
if (msg) {
|
||||
if (opened && ignore)
|
||||
goto check_backup;
|
||||
|
||||
err = -EINVAL;
|
||||
printf("primary footer invalid: %s\n", msg);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (primary.type == HD_TYPE_FIXED) {
|
||||
err = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
check_backup:
|
||||
off = lseek(fd, 0, SEEK_SET);
|
||||
if (off == (off_t)-1) {
|
||||
err = -errno;
|
||||
printf("error seeking to backup footer: %d\n", err);
|
||||
goto out;
|
||||
}
|
||||
|
||||
size = 512;
|
||||
memset(buf, 0, sizeof(primary));
|
||||
|
||||
err = read(fd, buf, size);
|
||||
if (err != size) {
|
||||
err = (errno ? -errno : -EIO);
|
||||
printf("error reading backup footer: %d\n", err);
|
||||
goto out;
|
||||
}
|
||||
|
||||
memcpy(&backup, buf, sizeof(backup));
|
||||
vhd_footer_in(&backup);
|
||||
|
||||
msg = vhd_util_check_validate_footer(&backup);
|
||||
if (msg) {
|
||||
err = -EINVAL;
|
||||
printf("backup footer invalid: %s\n", msg);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (memcmp(&primary, &backup, sizeof(primary))) {
|
||||
if (opened && ignore) {
|
||||
memcpy(&primary, &backup, sizeof(primary));
|
||||
goto ok;
|
||||
}
|
||||
|
||||
if (backup.hidden &&
|
||||
!strncmp(backup.crtr_app, "tap", 3) &&
|
||||
(backup.crtr_ver == VHD_VERSION(0, 1) ||
|
||||
backup.crtr_ver == VHD_VERSION(1, 1))) {
|
||||
char cmp, tmp = backup.hidden;
|
||||
backup.hidden = 0;
|
||||
cmp = memcmp(&primary, &backup, sizeof(primary));
|
||||
backup.hidden = tmp;
|
||||
if (!cmp)
|
||||
goto ok;
|
||||
}
|
||||
|
||||
err = -EINVAL;
|
||||
printf("primary and backup footers do not match\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
ok:
|
||||
err = 0;
|
||||
memcpy(footer, &primary, sizeof(primary));
|
||||
|
||||
out:
|
||||
free(buf);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int
|
||||
vhd_util_check_header(int fd, vhd_footer_t *footer)
|
||||
{
|
||||
int err;
|
||||
off_t off;
|
||||
char *msg, *buf;
|
||||
vhd_header_t header;
|
||||
|
||||
err = posix_memalign((void **)&buf, VHD_SECTOR_SIZE, sizeof(header));
|
||||
if (err) {
|
||||
printf("error allocating header: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
off = footer->data_offset;
|
||||
off = lseek(fd, off, SEEK_SET);
|
||||
if (off == (off_t)-1) {
|
||||
err = -errno;
|
||||
printf("error seeking to header: %d\n", err);
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = read(fd, buf, sizeof(header));
|
||||
if (err != sizeof(header)) {
|
||||
err = (errno ? -errno : -EIO);
|
||||
printf("error reading header: %d\n", err);
|
||||
goto out;
|
||||
}
|
||||
|
||||
memcpy(&header, buf, sizeof(header));
|
||||
vhd_header_in(&header);
|
||||
|
||||
msg = vhd_util_check_validate_header(fd, &header);
|
||||
if (msg) {
|
||||
err = -EINVAL;
|
||||
printf("header is invalid: %s\n", msg);
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = 0;
|
||||
|
||||
out:
|
||||
free(buf);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int
|
||||
vhd_util_check_differencing_header(vhd_context_t *vhd)
|
||||
{
|
||||
char *msg;
|
||||
|
||||
msg = vhd_util_check_validate_differencing_header(vhd);
|
||||
if (msg) {
|
||||
printf("differencing header is invalid: %s\n", msg);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
vhd_util_check_bat(vhd_context_t *vhd)
|
||||
{
|
||||
off_t eof, eoh;
|
||||
int i, j, err, block_size;
|
||||
|
||||
err = vhd_seek(vhd, 0, SEEK_END);
|
||||
if (err) {
|
||||
printf("error calculating eof: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
eof = vhd_position(vhd);
|
||||
if (eof == (off_t)-1) {
|
||||
printf("error calculating eof: %d\n", -errno);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
/* adjust eof for vhds with short footers */
|
||||
if (eof % 512) {
|
||||
if (eof % 512 != 511) {
|
||||
printf("invalid file size: 0x%"PRIx64"\n", eof);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
eof++;
|
||||
}
|
||||
|
||||
err = vhd_get_bat(vhd);
|
||||
if (err) {
|
||||
printf("error reading bat: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = vhd_end_of_headers(vhd, &eoh);
|
||||
if (err) {
|
||||
printf("error calculating end of metadata: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
eof -= sizeof(vhd_footer_t);
|
||||
eof >>= VHD_SECTOR_SHIFT;
|
||||
eoh >>= VHD_SECTOR_SHIFT;
|
||||
block_size = vhd->spb + vhd->bm_secs;
|
||||
|
||||
for (i = 0; i < vhd->header.max_bat_size; i++) {
|
||||
uint32_t off = vhd->bat.bat[i];
|
||||
if (off == DD_BLK_UNUSED)
|
||||
continue;
|
||||
|
||||
if (off < eoh) {
|
||||
printf("block %d (offset 0x%x) clobbers headers\n",
|
||||
i, off);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (off + block_size > eof) {
|
||||
printf("block %d (offset 0x%x) clobbers footer\n",
|
||||
i, off);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (j = 0; j < vhd->header.max_bat_size; j++) {
|
||||
uint32_t joff = vhd->bat.bat[j];
|
||||
|
||||
if (i == j)
|
||||
continue;
|
||||
|
||||
if (joff == DD_BLK_UNUSED)
|
||||
continue;
|
||||
|
||||
if (off == joff)
|
||||
err = -EINVAL;
|
||||
|
||||
if (off > joff && off < joff + block_size)
|
||||
err = -EINVAL;
|
||||
|
||||
if (off + block_size > joff &&
|
||||
off + block_size < joff + block_size)
|
||||
err = -EINVAL;
|
||||
|
||||
if (err) {
|
||||
printf("block %d (offset 0x%x) clobbers "
|
||||
"block %d (offset 0x%x)\n",
|
||||
i, off, j, joff);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
vhd_util_check_batmap(vhd_context_t *vhd)
|
||||
{
|
||||
char *msg;
|
||||
int i, err;
|
||||
|
||||
err = vhd_get_bat(vhd);
|
||||
if (err) {
|
||||
printf("error reading bat: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = vhd_get_batmap(vhd);
|
||||
if (err) {
|
||||
printf("error reading batmap: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
msg = vhd_util_check_validate_batmap(vhd, &vhd->batmap);
|
||||
if (msg) {
|
||||
printf("batmap is invalid: %s\n", msg);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < vhd->header.max_bat_size; i++) {
|
||||
if (!vhd_batmap_test(vhd, &vhd->batmap, i))
|
||||
continue;
|
||||
|
||||
if (vhd->bat.bat[i] == DD_BLK_UNUSED) {
|
||||
printf("batmap shows unallocated block %d full\n", i);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
vhd_util_check_parent_locators(vhd_context_t *vhd)
|
||||
{
|
||||
int i, n, err;
|
||||
vhd_parent_locator_t *loc;
|
||||
char *file, *ppath, *location, *pname;
|
||||
const char *msg;
|
||||
int mac, macx, w2ku, w2ru, wi2r, wi2k, found;
|
||||
|
||||
mac = 0;
|
||||
macx = 0;
|
||||
w2ku = 0;
|
||||
w2ru = 0;
|
||||
wi2r = 0;
|
||||
wi2k = 0;
|
||||
found = 0;
|
||||
pname = NULL;
|
||||
ppath = NULL;
|
||||
location = NULL;
|
||||
|
||||
err = vhd_header_decode_parent(vhd, &vhd->header, &pname);
|
||||
if (err) {
|
||||
printf("error decoding parent name: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
n = sizeof(vhd->header.loc) / sizeof(vhd->header.loc[0]);
|
||||
for (i = 0; i < n; i++) {
|
||||
ppath = NULL;
|
||||
location = NULL;
|
||||
loc = vhd->header.loc + i;
|
||||
|
||||
msg = vhd_util_check_validate_parent_locator(vhd, loc);
|
||||
if (msg) {
|
||||
err = -EINVAL;
|
||||
printf("invalid parent locator %d: %s\n", i, msg);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (loc->code == PLAT_CODE_NONE)
|
||||
continue;
|
||||
|
||||
switch (loc->code) {
|
||||
case PLAT_CODE_MACX:
|
||||
if (macx++)
|
||||
goto dup;
|
||||
break;
|
||||
|
||||
case PLAT_CODE_MAC:
|
||||
if (mac++)
|
||||
goto dup;
|
||||
break;
|
||||
|
||||
case PLAT_CODE_W2KU:
|
||||
if (w2ku++)
|
||||
goto dup;
|
||||
break;
|
||||
|
||||
case PLAT_CODE_W2RU:
|
||||
if (w2ru++)
|
||||
goto dup;
|
||||
break;
|
||||
|
||||
case PLAT_CODE_WI2R:
|
||||
if (wi2r++)
|
||||
goto dup;
|
||||
break;
|
||||
|
||||
case PLAT_CODE_WI2K:
|
||||
if (wi2k++)
|
||||
goto dup;
|
||||
break;
|
||||
|
||||
default:
|
||||
err = -EINVAL;
|
||||
printf("invalid platform code for locator %d\n", i);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (loc->code != PLAT_CODE_MACX &&
|
||||
loc->code != PLAT_CODE_W2RU &&
|
||||
loc->code != PLAT_CODE_W2KU)
|
||||
continue;
|
||||
|
||||
err = vhd_parent_locator_read(vhd, loc, &ppath);
|
||||
if (err) {
|
||||
printf("error reading parent locator %d: %d\n", i, err);
|
||||
goto out;
|
||||
}
|
||||
|
||||
file = basename(ppath);
|
||||
if (strcmp(pname, file)) {
|
||||
err = -EINVAL;
|
||||
printf("parent locator %d name (%s) does not match "
|
||||
"header name (%s)\n", i, file, pname);
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = vhd_find_parent(vhd, ppath, &location);
|
||||
if (err) {
|
||||
printf("error resolving %s: %d\n", ppath, err);
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = access(location, R_OK);
|
||||
if (err && loc->code == PLAT_CODE_MACX) {
|
||||
err = -errno;
|
||||
printf("parent locator %d points to missing file %s "
|
||||
"(resolved to %s)\n", i, ppath, location);
|
||||
goto out;
|
||||
}
|
||||
|
||||
msg = vhd_util_check_validate_parent(vhd, location);
|
||||
if (msg) {
|
||||
err = -EINVAL;
|
||||
printf("invalid parent %s: %s\n", location, msg);
|
||||
goto out;
|
||||
}
|
||||
|
||||
found++;
|
||||
free(ppath);
|
||||
free(location);
|
||||
ppath = NULL;
|
||||
location = NULL;
|
||||
|
||||
continue;
|
||||
|
||||
dup:
|
||||
printf("duplicate platform code in locator %d: 0x%x\n",
|
||||
i, loc->code);
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
err = -EINVAL;
|
||||
printf("could not find parent %s\n", pname);
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = 0;
|
||||
|
||||
out:
|
||||
free(pname);
|
||||
free(ppath);
|
||||
free(location);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void
|
||||
vhd_util_dump_headers(const char *name)
|
||||
{
|
||||
char *argv[] = { "read", "-p", "-n", (char *)name };
|
||||
int argc = sizeof(argv) / sizeof(argv[0]);
|
||||
|
||||
printf("%s appears invalid; dumping metadata\n", name);
|
||||
vhd_util_read(argc, argv);
|
||||
}
|
||||
|
||||
static int
|
||||
vhd_util_check_vhd(const char *name, int ignore)
|
||||
{
|
||||
int fd, err;
|
||||
vhd_context_t vhd;
|
||||
struct stat stats;
|
||||
vhd_footer_t footer;
|
||||
|
||||
fd = -1;
|
||||
memset(&vhd, 0, sizeof(vhd));
|
||||
memset(&footer, 0, sizeof(footer));
|
||||
|
||||
err = stat(name, &stats);
|
||||
if (err == -1) {
|
||||
printf("cannot stat %s: %d\n", name, errno);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
if (!S_ISREG(stats.st_mode) && !S_ISBLK(stats.st_mode)) {
|
||||
printf("%s is not a regular file or block device\n", name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
fd = open(name, O_RDONLY | O_DIRECT | O_LARGEFILE);
|
||||
if (fd == -1) {
|
||||
printf("error opening %s\n", name);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
err = vhd_util_check_footer(fd, &footer, ignore);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
if (footer.type != HD_TYPE_DYNAMIC && footer.type != HD_TYPE_DIFF)
|
||||
goto out;
|
||||
|
||||
err = vhd_util_check_header(fd, &footer);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
err = vhd_open(&vhd, name, VHD_OPEN_RDONLY | VHD_OPEN_IGNORE_DISABLED);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
err = vhd_util_check_differencing_header(&vhd);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
err = vhd_util_check_bat(&vhd);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
if (vhd_has_batmap(&vhd)) {
|
||||
err = vhd_util_check_batmap(&vhd);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (vhd.footer.type == HD_TYPE_DIFF) {
|
||||
err = vhd_util_check_parent_locators(&vhd);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = 0;
|
||||
printf("%s is valid\n", name);
|
||||
|
||||
out:
|
||||
if (err)
|
||||
vhd_util_dump_headers(name);
|
||||
if (fd != -1)
|
||||
close(fd);
|
||||
vhd_close(&vhd);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int
|
||||
vhd_util_check_parents(const char *name, int ignore)
|
||||
{
|
||||
int err;
|
||||
vhd_context_t vhd;
|
||||
char *cur, *parent;
|
||||
|
||||
cur = (char *)name;
|
||||
|
||||
for (;;) {
|
||||
err = vhd_open(&vhd, cur,
|
||||
VHD_OPEN_RDONLY | VHD_OPEN_IGNORE_DISABLED);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
if (vhd.footer.type != HD_TYPE_DIFF || vhd_parent_raw(&vhd)) {
|
||||
vhd_close(&vhd);
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = vhd_parent_locator_get(&vhd, &parent);
|
||||
vhd_close(&vhd);
|
||||
|
||||
if (err) {
|
||||
printf("error getting parent: %d\n", err);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (cur != name)
|
||||
free(cur);
|
||||
cur = parent;
|
||||
|
||||
err = vhd_util_check_vhd(cur, ignore);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
if (err)
|
||||
printf("error checking parents: %d\n", err);
|
||||
if (cur != name)
|
||||
free(cur);
|
||||
return err;
|
||||
}
|
||||
|
||||
int
|
||||
vhd_util_check(int argc, char **argv)
|
||||
{
|
||||
char *name;
|
||||
vhd_context_t vhd;
|
||||
int c, err, ignore, parents;
|
||||
|
||||
if (!argc || !argv) {
|
||||
err = -EINVAL;
|
||||
goto usage;
|
||||
}
|
||||
|
||||
ignore = 0;
|
||||
parents = 0;
|
||||
name = NULL;
|
||||
|
||||
optind = 0;
|
||||
while ((c = getopt(argc, argv, "n:iph")) != -1) {
|
||||
switch (c) {
|
||||
case 'n':
|
||||
name = optarg;
|
||||
break;
|
||||
case 'i':
|
||||
ignore = 1;
|
||||
break;
|
||||
case 'p':
|
||||
parents = 1;
|
||||
break;
|
||||
case 'h':
|
||||
err = 0;
|
||||
goto usage;
|
||||
default:
|
||||
err = -EINVAL;
|
||||
goto usage;
|
||||
}
|
||||
}
|
||||
|
||||
if (!name || optind != argc) {
|
||||
err = -EINVAL;
|
||||
goto usage;
|
||||
}
|
||||
|
||||
err = vhd_util_check_vhd(name, ignore);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
if (parents)
|
||||
err = vhd_util_check_parents(name, ignore);
|
||||
|
||||
out:
|
||||
return err;
|
||||
|
||||
usage:
|
||||
printf("options: -n <file> [-i ignore missing primary footers] "
|
||||
"[-p check parents] [-h help]\n");
|
||||
return err;
|
||||
}
|
||||
218
tools/vhd-tools/vhd/lib/vhd-util-coalesce.c
Normal file
218
tools/vhd-tools/vhd/lib/vhd-util-coalesce.c
Normal file
@ -0,0 +1,218 @@
|
||||
/* 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>
|
||||
#include <unistd.h>
|
||||
|
||||
#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, 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, 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)
|
||||
{
|
||||
int i, 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;
|
||||
|
||||
err = posix_memalign((void **)&buf, 4096, vhd->header.block_size);
|
||||
if (err)
|
||||
return -err;
|
||||
|
||||
err = vhd_io_read(vhd, buf, sec, vhd->spb);
|
||||
if (err)
|
||||
goto done;
|
||||
|
||||
if (vhd_has_batmap(vhd) && vhd_batmap_test(vhd, &vhd->batmap, 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, 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 + secs))
|
||||
break;
|
||||
|
||||
if (parent->file)
|
||||
err = vhd_io_write(parent,
|
||||
buf + vhd_sectors_to_bytes(i),
|
||||
sec + i, secs);
|
||||
else
|
||||
err = __raw_io_write(parent_fd,
|
||||
buf + vhd_sectors_to_bytes(i),
|
||||
sec + i, secs);
|
||||
if (err)
|
||||
goto done;
|
||||
|
||||
i += secs;
|
||||
}
|
||||
|
||||
err = 0;
|
||||
|
||||
done:
|
||||
free(buf);
|
||||
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, 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;
|
||||
}
|
||||
80
tools/vhd-tools/vhd/lib/vhd-util-create.c
Normal file
80
tools/vhd-tools/vhd/lib/vhd-util-create.c
Normal file
@ -0,0 +1,80 @@
|
||||
/* 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 <unistd.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
105
tools/vhd-tools/vhd/lib/vhd-util-fill.c
Normal file
105
tools/vhd-tools/vhd/lib/vhd-util-fill.c
Normal file
@ -0,0 +1,105 @@
|
||||
/* 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>
|
||||
#include <unistd.h>
|
||||
|
||||
#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;
|
||||
|
||||
err = posix_memalign((void **)&buf, 4096, vhd.header.block_size);
|
||||
if (err) {
|
||||
err = -err;
|
||||
goto done;
|
||||
}
|
||||
|
||||
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, secs);
|
||||
if (err)
|
||||
goto done;
|
||||
|
||||
err = vhd_io_write(&vhd, buf, sec, secs);
|
||||
if (err)
|
||||
goto done;
|
||||
|
||||
sec += secs;
|
||||
}
|
||||
|
||||
err = 0;
|
||||
|
||||
done:
|
||||
free(buf);
|
||||
vhd_close(&vhd);
|
||||
return err;
|
||||
|
||||
usage:
|
||||
printf("options: <-n name> [-h help]\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
132
tools/vhd-tools/vhd/lib/vhd-util-modify.c
Normal file
132
tools/vhd-tools/vhd/lib/vhd-util-modify.c
Normal file
@ -0,0 +1,132 @@
|
||||
/* 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>
|
||||
#include <unistd.h>
|
||||
|
||||
#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_raw;
|
||||
off_t newsize = 0;
|
||||
char *newparent = NULL;
|
||||
|
||||
name = NULL;
|
||||
size = 0;
|
||||
parent = 0;
|
||||
parent_raw = 0;
|
||||
|
||||
optind = 0;
|
||||
while ((c = getopt(argc, argv, "n:s:p:mh")) != -1) {
|
||||
switch (c) {
|
||||
case 'n':
|
||||
name = optarg;
|
||||
break;
|
||||
case 's':
|
||||
size = 1;
|
||||
errno = 0;
|
||||
newsize = strtoll(optarg, NULL, 10);
|
||||
if (errno) {
|
||||
fprintf(stderr, "Invalid size '%s'\n", optarg);
|
||||
goto usage;
|
||||
}
|
||||
break;
|
||||
case 'p':
|
||||
parent = 1;
|
||||
newparent = optarg;
|
||||
break;
|
||||
case 'm':
|
||||
parent_raw = 1;
|
||||
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;
|
||||
}
|
||||
|
||||
if (size) {
|
||||
err = vhd_set_phys_size(&vhd, newsize);
|
||||
if (err)
|
||||
printf("failed to set physical size to %"PRIu64":"
|
||||
" %d\n", newsize, err);
|
||||
}
|
||||
|
||||
if (parent) {
|
||||
TEST_FAIL_AT(FAIL_REPARENT_BEGIN);
|
||||
err = vhd_change_parent(&vhd, newparent, parent_raw);
|
||||
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]] "
|
||||
"[-s NEW_SIZE set size] [-h help]\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
159
tools/vhd-tools/vhd/lib/vhd-util-query.c
Normal file
159
tools/vhd-tools/vhd/lib/vhd-util-query.c
Normal file
@ -0,0 +1,159 @@
|
||||
/* 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>
|
||||
#include <unistd.h>
|
||||
|
||||
#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", 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 ? : 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 ? : 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 ? : 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;
|
||||
}
|
||||
742
tools/vhd-tools/vhd/lib/vhd-util-read.c
Normal file
742
tools/vhd-tools/vhd/lib/vhd-util-read.c
Normal file
@ -0,0 +1,742 @@
|
||||
/* 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>
|
||||
#include <unistd.h>
|
||||
#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], out[512], *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, cksm_save;
|
||||
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" :
|
||||
"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 type!\n");
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
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 = 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 += 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, cur, &buf);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
write_full(STDOUT_FILENO, buf,
|
||||
vhd_sectors_to_bytes(vhd->bm_secs));
|
||||
free(buf);
|
||||
}
|
||||
|
||||
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 = 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);
|
||||
|
||||
print:
|
||||
printf("block %s: ", conv(hex, blk));
|
||||
printf("sec: %s: %d\n", conv(hex, sec), bit);
|
||||
}
|
||||
|
||||
err = 0;
|
||||
out:
|
||||
free(buf);
|
||||
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 = 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, 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, 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, max, secs;
|
||||
|
||||
if (vhd_sectors_to_bytes(sec + count) > vhd->footer.curr_size)
|
||||
return -ERANGE;
|
||||
|
||||
max = MIN(vhd_sectors_to_bytes(count), VHD_BLOCK_SIZE);
|
||||
err = posix_memalign((void **)&buf, VHD_SECTOR_SIZE, max);
|
||||
if (err)
|
||||
return -err;
|
||||
|
||||
cur = sec;
|
||||
while (count) {
|
||||
secs = MIN((max >> VHD_SECTOR_SHIFT), count);
|
||||
err = vhd_io_read(vhd, buf, cur, secs);
|
||||
if (err)
|
||||
break;
|
||||
|
||||
write_full(STDOUT_FILENO, buf, vhd_sectors_to_bytes(secs));
|
||||
|
||||
cur += secs;
|
||||
count -= secs;
|
||||
}
|
||||
|
||||
free(buf);
|
||||
return err;
|
||||
}
|
||||
|
||||
int
|
||||
vhd_util_read(int argc, char **argv)
|
||||
{
|
||||
char *name;
|
||||
vhd_context_t vhd;
|
||||
int c, err, headers, hex;
|
||||
uint64_t bat, bitmap, tbitmap, batmap, tbatmap, data, lsec, count, read;
|
||||
|
||||
err = 0;
|
||||
hex = 0;
|
||||
headers = 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:pt:b:m:i:aj:d:c:r:xh")) != -1) {
|
||||
switch(c) {
|
||||
case 'n':
|
||||
name = optarg;
|
||||
break;
|
||||
case 'p':
|
||||
headers = 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 (lsec != -1) {
|
||||
err = vhd_print_logical_to_physical(&vhd, lsec, count, hex);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (bat != -1) {
|
||||
err = vhd_print_bat(&vhd, bat, count, hex);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (bitmap != -1) {
|
||||
err = vhd_print_bitmap(&vhd, bitmap, count, hex);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (tbitmap != -1) {
|
||||
err = vhd_test_bitmap(&vhd, tbitmap, 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, count, hex);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (data != -1) {
|
||||
err = vhd_print_data(&vhd, data, count, hex);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (read != -1) {
|
||||
err = vhd_read_data(&vhd, read, 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"
|
||||
"-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;
|
||||
}
|
||||
84
tools/vhd-tools/vhd/lib/vhd-util-repair.c
Normal file
84
tools/vhd-tools/vhd/lib/vhd-util-repair.c
Normal file
@ -0,0 +1,84 @@
|
||||
/* 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>
|
||||
#include <unistd.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
1131
tools/vhd-tools/vhd/lib/vhd-util-resize.c
Normal file
1131
tools/vhd-tools/vhd/lib/vhd-util-resize.c
Normal file
File diff suppressed because it is too large
Load Diff
106
tools/vhd-tools/vhd/lib/vhd-util-revert.c
Normal file
106
tools/vhd-tools/vhd/lib/vhd-util-revert.c
Normal 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.
|
||||
*
|
||||
* 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>
|
||||
#include <unistd.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
1317
tools/vhd-tools/vhd/lib/vhd-util-scan.c
Normal file
1317
tools/vhd-tools/vhd/lib/vhd-util-scan.c
Normal file
File diff suppressed because it is too large
Load Diff
106
tools/vhd-tools/vhd/lib/vhd-util-set-field.c
Normal file
106
tools/vhd-tools/vhd/lib/vhd-util-set-field.c
Normal 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>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "libvhd.h"
|
||||
|
||||
int
|
||||
vhd_util_set_field(int argc, char **argv)
|
||||
{
|
||||
long value;
|
||||
int err, c;
|
||||
off_t eof;
|
||||
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);
|
||||
|
||||
done:
|
||||
vhd_close(&vhd);
|
||||
return err;
|
||||
|
||||
usage:
|
||||
printf("options: <-n name> <-f field> <-v value> [-h help]\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
216
tools/vhd-tools/vhd/lib/vhd-util-snapshot.c
Normal file
216
tools/vhd-tools/vhd/lib/vhd-util-snapshot.c
Normal file
@ -0,0 +1,216 @@
|
||||
/* 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>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "libvhd.h"
|
||||
|
||||
static int
|
||||
vhd_util_find_snapshot_target(const char *name, char **result, int *parent_raw)
|
||||
{
|
||||
int i, 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;
|
||||
|
||||
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, backing, flags);
|
||||
|
||||
out:
|
||||
free(ppath);
|
||||
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;
|
||||
}
|
||||
259
tools/vhd-tools/vhd/vhd-update.c
Normal file
259
tools/vhd-tools/vhd/vhd-update.c
Normal file
@ -0,0 +1,259 @@
|
||||
/* 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.
|
||||
*
|
||||
* Before updating a VHD file, we create a journal consisting of:
|
||||
* - all data at the beginning of the file, up to and including the BAT
|
||||
* - each allocated bitmap (existing at the same offset in the journal as
|
||||
* its corresponding bitmap in the original file)
|
||||
* Updates are performed in place by writing appropriately
|
||||
* transformed versions of journaled bitmaps to the original file.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "atomicio.h"
|
||||
#include "libvhd.h"
|
||||
#include "libvhd-journal.h"
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
printf("usage: vhd-update <-n name> [-j existing journal] [-h]\n");
|
||||
exit(EINVAL);
|
||||
}
|
||||
|
||||
/*
|
||||
* update vhd creator version to reflect its new bitmap ordering
|
||||
*/
|
||||
static inline int
|
||||
update_creator_version(vhd_journal_t *journal)
|
||||
{
|
||||
journal->vhd.footer.crtr_ver = VHD_VERSION(1, 1);
|
||||
return vhd_write_footer(&journal->vhd, &journal->vhd.footer);
|
||||
}
|
||||
|
||||
static int
|
||||
journal_bitmaps(vhd_journal_t *journal)
|
||||
{
|
||||
int i, err;
|
||||
|
||||
for (i = 0; i < journal->vhd.bat.entries; i++) {
|
||||
err = vhd_journal_add_block(journal, i, VHD_JOURNAL_METADATA);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* older VHD bitmaps were little endian
|
||||
* and bits within a word were set from right to left
|
||||
*/
|
||||
static inline int
|
||||
old_test_bit(int nr, volatile void * addr)
|
||||
{
|
||||
return (((unsigned long*)addr)[nr/(sizeof(unsigned long)*8)] >>
|
||||
(nr % (sizeof(unsigned long)*8))) & 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* new VHD bitmaps are big endian
|
||||
* and bits within a word are set from left to right
|
||||
*/
|
||||
#define BIT_MASK 0x80
|
||||
static inline void
|
||||
new_set_bit (int nr, volatile char *addr)
|
||||
{
|
||||
addr[nr >> 3] |= (BIT_MASK >> (nr & 7));
|
||||
}
|
||||
|
||||
static void
|
||||
convert_bitmap(char *in, char *out, int bytes)
|
||||
{
|
||||
int i;
|
||||
|
||||
memset(out, 0, bytes);
|
||||
|
||||
for (i = 0; i < bytes << 3; i++)
|
||||
if (old_test_bit(i, (void *)in))
|
||||
new_set_bit(i, out);
|
||||
}
|
||||
|
||||
static int
|
||||
update_vhd(vhd_journal_t *journal, int rollback)
|
||||
{
|
||||
int i, err;
|
||||
size_t size;
|
||||
char *buf, *converted;
|
||||
|
||||
buf = NULL;
|
||||
converted = NULL;
|
||||
|
||||
size = vhd_bytes_padded(journal->vhd.spb / 8);
|
||||
err = posix_memalign((void **)&converted, 512, size);
|
||||
if (err) {
|
||||
converted = NULL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; i < journal->vhd.bat.entries; i++) {
|
||||
if (journal->vhd.bat.bat[i] == DD_BLK_UNUSED)
|
||||
continue;
|
||||
|
||||
err = vhd_read_bitmap(&journal->vhd, i, &buf);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
if (rollback)
|
||||
memcpy(converted, buf, size);
|
||||
else
|
||||
convert_bitmap(buf, converted, size);
|
||||
|
||||
free(buf);
|
||||
|
||||
err = vhd_write_bitmap(&journal->vhd, i, converted);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = 0;
|
||||
out:
|
||||
free(converted);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int
|
||||
open_journal(vhd_journal_t *journal, const char *file, const char *jfile)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = vhd_journal_create(journal, file, jfile);
|
||||
if (err) {
|
||||
printf("error creating journal for %s: %d\n", file, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
close_journal(vhd_journal_t *journal, int err)
|
||||
{
|
||||
if (err)
|
||||
err = vhd_journal_revert(journal);
|
||||
else
|
||||
err = vhd_journal_commit(journal);
|
||||
|
||||
if (err)
|
||||
return vhd_journal_close(journal);
|
||||
else
|
||||
return vhd_journal_remove(journal);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
char *file, *jfile;
|
||||
int c, err, rollback;
|
||||
vhd_journal_t journal;
|
||||
|
||||
file = NULL;
|
||||
jfile = NULL;
|
||||
rollback = 0;
|
||||
|
||||
while ((c = getopt(argc, argv, "n:j:rh")) != -1) {
|
||||
switch(c) {
|
||||
case 'n':
|
||||
file = optarg;
|
||||
break;
|
||||
case 'j':
|
||||
jfile = optarg;
|
||||
err = access(jfile, R_OK);
|
||||
if (err == -1) {
|
||||
printf("invalid journal arg %s\n", jfile);
|
||||
return -errno;
|
||||
}
|
||||
break;
|
||||
case 'r':
|
||||
/* add a rollback option for debugging which
|
||||
* pushes journalled bitmaps to original file
|
||||
* without transforming them */
|
||||
rollback = 1;
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
}
|
||||
|
||||
if (!file)
|
||||
usage();
|
||||
|
||||
if (rollback && !jfile) {
|
||||
printf("rollback requires a journal argument\n");
|
||||
usage();
|
||||
}
|
||||
|
||||
err = open_journal(&journal, file, jfile);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (!vhd_creator_tapdisk(&journal.vhd) ||
|
||||
journal.vhd.footer.crtr_ver != VHD_VERSION(0, 1) ||
|
||||
journal.vhd.footer.type == HD_TYPE_FIXED) {
|
||||
err = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = journal_bitmaps(&journal);
|
||||
if (err) {
|
||||
/* no changes to vhd file yet,
|
||||
* so close the journal and bail */
|
||||
vhd_journal_close(&journal);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = update_vhd(&journal, rollback);
|
||||
if (err) {
|
||||
printf("update failed: %d; saving journal\n", err);
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = update_creator_version(&journal);
|
||||
if (err) {
|
||||
printf("failed to udpate creator version: %d\n", err);
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = 0;
|
||||
|
||||
out:
|
||||
err = close_journal(&journal, err);
|
||||
return err;
|
||||
}
|
||||
160
tools/vhd-tools/vhd/vhd-util.c
Normal file
160
tools/vhd-tools/vhd/vhd-util.c
Normal file
@ -0,0 +1,160 @@
|
||||
/* 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"
|
||||
|
||||
#if 1
|
||||
#define DFPRINTF(_f, _a...) fprintf(stdout, _f , ##_a)
|
||||
#else
|
||||
#define DFPRINTF(_f, _a...) ((void)0)
|
||||
#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 },
|
||||
{ .name = "scan", .func = vhd_util_scan },
|
||||
{ .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;
|
||||
|
||||
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);
|
||||
|
||||
return (ret >= 0 ? ret : -ret);
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user