aboutsummaryrefslogtreecommitdiffstats
path: root/tools/blktap2/include/libvhd.h
blob: 8e854e413f7aa8b867b28c35500ec33ac2eedb9c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
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 "vhd-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 vhd_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