Statistics
| Branch: | Revision:

root / vhd / lib / libvhd.c @ abdb293f

History | View | Annotate | Download (81.6 kB)

1
/*
2
 * Copyright (c) 2008, XenSource Inc.
3
 * Copyright (c) 2010, Citrix Systems, Inc.
4
 *
5
 * All rights reserved.
6
 *
7
 * Redistribution and use in source and binary forms, with or without
8
 * modification, are permitted provided that the following conditions are met:
9
 *     * Redistributions of source code must retain the above copyright
10
 *       notice, this list of conditions and the following disclaimer.
11
 *     * Redistributions in binary form must reproduce the above copyright
12
 *       notice, this list of conditions and the following disclaimer in the
13
 *       documentation and/or other materials provided with the distribution.
14
 *     * Neither the name of XenSource Inc. nor the names of its contributors
15
 *       may be used to endorse or promote products derived from this software
16
 *       without specific prior written permission.
17
 *
18
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
22
 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
 */
30

    
31
#ifdef HAVE_CONFIG_H
32
#include "config.h"
33
#endif
34

    
35
#ifndef _GNU_SOURCE
36
#define _GNU_SOURCE
37
#endif
38
#include <stdio.h>
39
#include <errno.h>
40
#include <fcntl.h>
41
#include <stdlib.h>
42
#include <unistd.h>
43
#include <string.h>
44
#include <libgen.h>
45
#include <iconv.h>
46
#include <limits.h>
47
#include <sys/mman.h>
48
#include <sys/stat.h>
49
#include <sys/types.h>
50

    
51
#include "libvhd.h"
52
#include "relative-path.h"
53

    
54
#define VHD_HEADER_MAX_RETRIES 10
55

    
56
static int libvhd_dbg = 0;
57

    
58
void
59
libvhd_set_log_level(int level)
60
{
61
        if (level)
62
                libvhd_dbg = 1;
63
}
64

    
65
#define VHDLOG(_f, _a...)                                                \
66
        do {                                                                \
67
                if (libvhd_dbg)                                                \
68
                        syslog(LOG_INFO, "libvhd::%s: "_f,                \
69
                               __func__, ##_a);                                \
70
        } while (0)
71

    
72
#define ASSERT(_p)                                                        \
73
        if (!(_p)) {                                                        \
74
                libvhd_set_log_level(1);                                \
75
                VHDLOG("%s:%d: FAILED ASSERTION: '%s'\n",                \
76
                        __FILE__, __LINE__, #_p);                        \
77
                *(int*)0 = 0;                                                \
78
        }
79

    
80
#ifdef ENABLE_FAILURE_TESTING
81
const char* ENV_VAR_FAIL[NUM_FAIL_TESTS] = {
82
        "VHD_UTIL_TEST_FAIL_REPARENT_BEGIN",
83
        "VHD_UTIL_TEST_FAIL_REPARENT_LOCATOR",
84
        "VHD_UTIL_TEST_FAIL_REPARENT_END",
85
        "VHD_UTIL_TEST_FAIL_RESIZE_BEGIN",
86
        "VHD_UTIL_TEST_FAIL_RESIZE_DATA_MOVED",
87
        "VHD_UTIL_TEST_FAIL_RESIZE_METADATA_MOVED",
88
        "VHD_UTIL_TEST_FAIL_RESIZE_END"
89
};
90
int TEST_FAIL[NUM_FAIL_TESTS];
91
#endif // ENABLE_FAILURE_TESTING
92

    
93
static void vhd_cache_init(vhd_context_t *);
94
static int vhd_cache_enabled(vhd_context_t *);
95
static int vhd_cache_load(vhd_context_t *);
96
static int vhd_cache_unload(vhd_context_t *);
97
static vhd_context_t * vhd_cache_get_parent(vhd_context_t *);
98

    
99
static inline int
100
old_test_bit(volatile char *addr, int nr)
101
{
102
        return (((uint32_t *)addr)[nr >> 5] >> (nr & 31)) & 1;
103
}
104

    
105
static inline void
106
old_set_bit(volatile char *addr, int nr)
107
{
108
        ((uint32_t *)addr)[nr >> 5] |= (1 << (nr & 31));
109
}
110

    
111
static inline void
112
old_clear_bit(volatile char *addr, int nr)
113
{
114
        ((uint32_t *)addr)[nr >> 5] &= ~(1 << (nr & 31));
115
}
116

    
117
void
118
vhd_footer_in(vhd_footer_t *footer)
119
{
120
        BE32_IN(&footer->features);
121
        BE32_IN(&footer->ff_version);
122
        BE64_IN(&footer->data_offset);
123
        BE32_IN(&footer->timestamp);
124
        BE32_IN(&footer->crtr_ver);
125
        BE32_IN(&footer->crtr_os);
126
        BE64_IN(&footer->orig_size);
127
        BE64_IN(&footer->curr_size);
128
        BE32_IN(&footer->geometry);
129
        BE32_IN(&footer->type);
130
        BE32_IN(&footer->checksum);
131
}
132

    
133
void
134
vhd_footer_out(vhd_footer_t *footer)
135
{
136
        BE32_OUT(&footer->features);
137
        BE32_OUT(&footer->ff_version);
138
        BE64_OUT(&footer->data_offset);
139
        BE32_OUT(&footer->timestamp);
140
        BE32_OUT(&footer->crtr_ver);
141
        BE32_OUT(&footer->crtr_os);
142
        BE64_OUT(&footer->orig_size);
143
        BE64_OUT(&footer->curr_size);
144
        BE32_OUT(&footer->geometry);
145
        BE32_OUT(&footer->type);
146
        BE32_OUT(&footer->checksum);
147
}
148

    
149
void
150
vhd_header_in(vhd_header_t *header)
151
{
152
        int i, n;
153

    
154
        BE64_IN(&header->data_offset);
155
        BE64_IN(&header->table_offset);
156
        BE32_IN(&header->hdr_ver);
157
        BE32_IN(&header->max_bat_size);
158
        BE32_IN(&header->block_size);
159
        BE32_IN(&header->checksum);
160
        BE32_IN(&header->prt_ts);
161

    
162
        n = sizeof(header->loc) / sizeof(vhd_parent_locator_t);
163

    
164
        for (i = 0; i < n; i++) {
165
                BE32_IN(&header->loc[i].code);
166
                BE32_IN(&header->loc[i].data_space);
167
                BE32_IN(&header->loc[i].data_len);
168
                BE64_IN(&header->loc[i].data_offset);
169
        }
170
}
171

    
172
void
173
vhd_header_out(vhd_header_t *header)
174
{
175
        int i, n;
176

    
177
        BE64_OUT(&header->data_offset);
178
        BE64_OUT(&header->table_offset);
179
        BE32_OUT(&header->hdr_ver);
180
        BE32_OUT(&header->max_bat_size);
181
        BE32_OUT(&header->block_size);
182
        BE32_OUT(&header->checksum);
183
        BE32_OUT(&header->prt_ts);
184

    
185
        n = sizeof(header->loc) / sizeof(vhd_parent_locator_t);
186

    
187
        for (i = 0; i < n; i++) {
188
                BE32_OUT(&header->loc[i].code);
189
                BE32_OUT(&header->loc[i].data_space);
190
                BE32_OUT(&header->loc[i].data_len);
191
                BE64_OUT(&header->loc[i].data_offset);
192
        }
193
}
194

    
195
void
196
vhd_batmap_header_in(vhd_batmap_t *batmap)
197
{
198
        BE64_IN(&batmap->header.batmap_offset);
199
        BE32_IN(&batmap->header.batmap_size);
200
        BE32_IN(&batmap->header.batmap_version);
201
        BE32_IN(&batmap->header.checksum);
202
}
203

    
204
void
205
vhd_batmap_header_out(vhd_batmap_t *batmap)
206
{
207
        BE64_OUT(&batmap->header.batmap_offset);
208
        BE32_OUT(&batmap->header.batmap_size);
209
        BE32_OUT(&batmap->header.batmap_version);
210
        BE32_OUT(&batmap->header.checksum);
211
}
212

    
213
void
214
vhd_bat_in(vhd_bat_t *bat)
215
{
216
        int i;
217

    
218
        for (i = 0; i < bat->entries; i++)
219
                BE32_IN(&bat->bat[i]);
220
}
221

    
222
void
223
vhd_bat_out(vhd_bat_t *bat)
224
{
225
        int i;
226

    
227
        for (i = 0; i < bat->entries; i++)
228
                BE32_OUT(&bat->bat[i]);
229
}
230

    
231
uint32_t
232
vhd_checksum_footer(vhd_footer_t *footer)
233
{
234
        int i;
235
        unsigned char *blob;
236
        uint32_t checksum, tmp;
237

    
238
        checksum         = 0;
239
        tmp              = footer->checksum;
240
        footer->checksum = 0;
241

    
242
        blob = (unsigned char *)footer;
243
        for (i = 0; i < sizeof(vhd_footer_t); i++)
244
                checksum += (uint32_t)blob[i];
245

    
246
        footer->checksum = tmp;
247
        return ~checksum;
248
}
249

    
250
int
251
vhd_validate_footer(vhd_footer_t *footer)
252
{
253
        int csize;
254
        uint32_t checksum;
255

    
256
        csize = sizeof(footer->cookie);
257
        if (memcmp(footer->cookie, HD_COOKIE, csize) != 0 &&
258
            memcmp(footer->cookie, VHD_POISON_COOKIE, csize) != 0) {
259
                char buf[9];
260
                memcpy(buf, footer->cookie, 8);
261
                buf[8]= '\0';
262
                VHDLOG("invalid footer cookie: %s\n", buf);
263
                return -EINVAL;
264
        }
265

    
266
        checksum = vhd_checksum_footer(footer);
267
        if (checksum != footer->checksum) {
268
                /*
269
                 * early td-util did not re-calculate
270
                 * checksum when marking vhds 'hidden'
271
                 */
272
                if (footer->hidden &&
273
                    !strncmp(footer->crtr_app, "tap", 3) &&
274
                    (footer->crtr_ver == VHD_VERSION(0, 1) ||
275
                     footer->crtr_ver == VHD_VERSION(1, 1))) {
276
                        char tmp = footer->hidden;
277
                        footer->hidden = 0;
278
                        checksum = vhd_checksum_footer(footer);
279
                        footer->hidden = tmp;
280

    
281
                        if (checksum == footer->checksum)
282
                                return 0;
283
                }
284

    
285
                VHDLOG("invalid footer checksum: "
286
                       "footer = 0x%08x, calculated = 0x%08x\n",
287
                       footer->checksum, checksum);
288
                return -EINVAL;
289
        }
290

    
291
        return 0;
292
}
293

    
294
uint32_t
295
vhd_checksum_header(vhd_header_t *header)
296
{
297
        int i;
298
        unsigned char *blob;
299
        uint32_t checksum, tmp;
300

    
301
        checksum         = 0;
302
        tmp              = header->checksum;
303
        header->checksum = 0;
304

    
305
        blob = (unsigned char *)header;
306
        for (i = 0; i < sizeof(vhd_header_t); i++)
307
                checksum += (uint32_t)blob[i];
308

    
309
        header->checksum = tmp;
310
        return ~checksum;
311
}
312

    
313
int
314
vhd_validate_header(vhd_header_t *header)
315
{
316
        int i, n;
317
        uint32_t checksum;
318

    
319
        if (memcmp(header->cookie, DD_COOKIE, 8) != 0) {
320
                char buf[9];
321
                memcpy(buf, header->cookie, 8);
322
                buf[8] = '\0';
323
                VHDLOG("invalid header cookie: %s\n", buf);
324
                return -EINVAL;
325
        }
326

    
327
        if (header->hdr_ver != 0x00010000) {
328
                VHDLOG("invalid header version 0x%08x\n", header->hdr_ver);
329
                return -EINVAL;
330
        }
331

    
332
        if (header->data_offset != 0xFFFFFFFFFFFFFFFFULL) {
333
                VHDLOG("invalid header data_offset 0x%016"PRIx64"\n",
334
                       header->data_offset);
335
                return -EINVAL;
336
        }
337

    
338
        n = sizeof(header->loc) / sizeof(vhd_parent_locator_t);
339
        for (i = 0; i < n; i++)
340
                if (vhd_validate_platform_code(header->loc[i].code))
341
                        return -EINVAL;
342

    
343
        checksum = vhd_checksum_header(header);
344
        if (checksum != header->checksum) {
345
                VHDLOG("invalid header checksum: "
346
                       "header = 0x%08x, calculated = 0x%08x\n",
347
                       header->checksum, checksum);
348
                return -EINVAL;
349
        }
350

    
351
        return 0;
352
}
353

    
354
static inline int
355
vhd_validate_bat(vhd_bat_t *bat)
356
{
357
        if (!bat->bat)
358
                return -EINVAL;
359

    
360
        return 0;
361
}
362

    
363
uint32_t
364
vhd_checksum_batmap(vhd_context_t *ctx, vhd_batmap_t *batmap)
365
{
366
        int i;
367
        char *blob;
368
        uint32_t checksum;
369
        size_t map_size;
370

    
371
        blob     = batmap->map;
372
        checksum = 0;
373

    
374
        map_size = vhd_sectors_to_bytes(secs_round_up_no_zero(
375
                        ctx->footer.curr_size >> (VHD_BLOCK_SHIFT + 3)));
376

    
377
        for (i = 0; i < map_size; i++) {
378
                if (batmap->header.batmap_version == VHD_BATMAP_VERSION(1, 1))
379
                        checksum += (uint32_t)blob[i];
380
                else
381
                        checksum += (uint32_t)(unsigned char)blob[i];
382
        }
383

    
384
        return ~checksum;
385
}
386

    
387
int
388
vhd_validate_batmap_header(vhd_batmap_t *batmap)
389
{
390
        if (memcmp(batmap->header.cookie, VHD_BATMAP_COOKIE, 8))
391
                return -EINVAL;
392

    
393
        if (batmap->header.batmap_version > VHD_BATMAP_CURRENT_VERSION)
394
                return -EINVAL;
395

    
396
        return 0;
397
}
398

    
399
int
400
vhd_validate_batmap(vhd_context_t *ctx, vhd_batmap_t *batmap)
401
{
402
        uint32_t checksum;
403

    
404
        if (!batmap->map)
405
                return -EINVAL;
406

    
407
        checksum = vhd_checksum_batmap(ctx, batmap);
408
        if (checksum != batmap->header.checksum)
409
                return -EINVAL;
410

    
411
        return 0;
412
}
413

    
414
int
415
vhd_batmap_header_offset(vhd_context_t *ctx, off64_t *_off)
416
{
417
        off64_t off;
418
        size_t  bat;
419

    
420
        *_off = 0;
421

    
422
        off  = ctx->header.table_offset;
423
        bat  = ctx->header.max_bat_size * sizeof(uint32_t);
424
        off += vhd_bytes_padded(bat);
425

    
426
        *_off = off;
427
        return 0;
428
}
429

    
430
int
431
vhd_validate_platform_code(uint32_t code)
432
{
433
        switch (code) {
434
        case PLAT_CODE_NONE:
435
        case PLAT_CODE_WI2R:
436
        case PLAT_CODE_WI2K:
437
        case PLAT_CODE_W2RU:
438
        case PLAT_CODE_W2KU:
439
        case PLAT_CODE_MAC:
440
        case PLAT_CODE_MACX:
441
                return 0;
442
        default:
443
                VHDLOG("invalid parent locator code %u\n", code);
444
                return -EINVAL;
445
        }
446
}
447

    
448
int
449
vhd_parent_locator_count(vhd_context_t *ctx)
450
{
451
        return (sizeof(ctx->header.loc) / sizeof(vhd_parent_locator_t));
452
}
453

    
454
int
455
vhd_hidden(vhd_context_t *ctx, int *hidden)
456
{
457
        int err;
458

    
459
        *hidden = 0;
460

    
461
        if (vhd_type_dynamic(ctx) && vhd_creator_tapdisk(ctx) &&
462
            (ctx->footer.crtr_ver == VHD_VERSION(0, 1) ||
463
             ctx->footer.crtr_ver == VHD_VERSION(1, 1))) {
464
                vhd_footer_t copy;
465

    
466
                err = vhd_read_footer_at(ctx, &copy, 0);
467
                if (err) {
468
                        VHDLOG("error reading backup footer of %s: %d\n",
469
                               ctx->file, err);
470
                        return err;
471
                }
472
                *hidden = copy.hidden;
473
        } else
474
                *hidden = ctx->footer.hidden;
475

    
476
        return 0;
477
}
478

    
479
int
480
vhd_chain_depth(vhd_context_t *ctx, int *depth)
481
{
482
        char *file;
483
        int err, cnt;
484
        vhd_context_t vhd, *cur;
485

    
486
        err    = 0;
487
        cnt    = 0;
488
        *depth = 0;
489
        file   = NULL;
490
        cur    = ctx;
491

    
492
        for (;;) {
493
                cnt++;
494

    
495
                if (cur->footer.type != HD_TYPE_DIFF)
496
                        break;
497

    
498
                if (vhd_parent_raw(cur)) {
499
                        cnt++;
500
                        break;
501
                }
502

    
503
                err = vhd_parent_locator_get(cur, &file);
504
                if (err) {
505
                        file = NULL;
506
                        break;
507
                }
508

    
509
                if (cur != ctx) {
510
                        vhd_close(cur);
511
                        cur = NULL;
512
                }
513

    
514
                err = vhd_open(&vhd, file, VHD_OPEN_RDONLY);
515
                if (err)
516
                        break;
517

    
518
                cur = &vhd;
519
                free(file);
520
                file = NULL;
521
        }
522

    
523
        free(file);
524
        if (cur && cur != ctx)
525
                vhd_close(cur);
526

    
527
        if (!err)
528
                *depth = cnt;
529

    
530
        return err;
531
}
532

    
533
int
534
vhd_batmap_test(vhd_context_t *ctx, vhd_batmap_t *batmap, uint32_t block)
535
{
536
        if (!vhd_has_batmap(ctx) || !batmap->map)
537
                return 0;
538

    
539
        if (block >= (batmap->header.batmap_size << (VHD_SECTOR_SHIFT + 3)))
540
                return 0;
541

    
542
        return test_bit(batmap->map, block);
543
}
544

    
545
void
546
vhd_batmap_set(vhd_context_t *ctx, vhd_batmap_t *batmap, uint32_t block)
547
{
548
        if (!vhd_has_batmap(ctx) || !batmap->map)
549
                return;
550

    
551
        if (block >= (batmap->header.batmap_size << (VHD_SECTOR_SHIFT + 3)))
552
                return;
553

    
554
        set_bit(batmap->map, block);
555
}
556

    
557
void
558
vhd_batmap_clear(vhd_context_t *ctx, vhd_batmap_t *batmap, uint32_t block)
559
{
560
        if (!vhd_has_batmap(ctx) || !batmap->map)
561
                return;
562

    
563
        if (block >= (batmap->header.batmap_size << (VHD_SECTOR_SHIFT + 3)))
564
                return;
565

    
566
        clear_bit(batmap->map, block);
567
}
568

    
569
int
570
vhd_bitmap_test(vhd_context_t *ctx, char *map, uint32_t block)
571
{
572
        if (vhd_creator_tapdisk(ctx) &&
573
            ctx->footer.crtr_ver == 0x00000001)
574
                return old_test_bit(map, block);
575

    
576
        return test_bit(map, block);
577
}
578

    
579
void
580
vhd_bitmap_set(vhd_context_t *ctx, char *map, uint32_t block)
581
{
582
        if (vhd_creator_tapdisk(ctx) &&
583
            ctx->footer.crtr_ver == 0x00000001)
584
                return old_set_bit(map, block);
585

    
586
        return set_bit(map, block);
587
}
588

    
589
void
590
vhd_bitmap_clear(vhd_context_t *ctx, char *map, uint32_t block)
591
{
592
        if (vhd_creator_tapdisk(ctx) &&
593
            ctx->footer.crtr_ver == 0x00000001)
594
                return old_clear_bit(map, block);
595

    
596
        return clear_bit(map, block);
597
}
598

    
599
/*
600
 * returns absolute offset of the first 
601
 * byte of the file which is not vhd metadata
602
 */
603
int
604
vhd_end_of_headers(vhd_context_t *ctx, off64_t *end)
605
{
606
        int err, i, n;
607
        uint32_t bat_bytes;
608
        off64_t eom, bat_end;
609
        vhd_parent_locator_t *loc;
610

    
611
        *end = 0;
612

    
613
        if (!vhd_type_dynamic(ctx))
614
                return 0;
615

    
616
        eom       = ctx->footer.data_offset + sizeof(vhd_header_t);
617

    
618
        bat_bytes = vhd_bytes_padded(ctx->header.max_bat_size * sizeof(uint32_t));
619
        bat_end   = ctx->header.table_offset + bat_bytes;
620

    
621
        eom       = MAX(eom, bat_end);
622

    
623
        if (vhd_has_batmap(ctx)) {
624
                off64_t hdr_end, hdr_secs, map_end, map_secs;
625

    
626
                err = vhd_get_batmap(ctx);
627
                if (err)
628
                        return err;
629

    
630
                hdr_secs = secs_round_up_no_zero(sizeof(vhd_batmap_header_t));
631
                err      = vhd_batmap_header_offset(ctx, &hdr_end);
632
                if (err)
633
                        return err;
634

    
635
                hdr_end += vhd_sectors_to_bytes(hdr_secs);
636
                eom      = MAX(eom, hdr_end);
637

    
638
                map_secs = ctx->batmap.header.batmap_size;
639
                map_end  = (ctx->batmap.header.batmap_offset +
640
                            vhd_sectors_to_bytes(map_secs));
641
                eom      = MAX(eom, map_end);
642
        }
643

    
644
        /* parent locators */
645
        n = sizeof(ctx->header.loc) / sizeof(vhd_parent_locator_t);
646

    
647
        for (i = 0; i < n; i++) {
648
                off64_t loc_end;
649

    
650
                loc = &ctx->header.loc[i];
651
                if (loc->code == PLAT_CODE_NONE)
652
                        continue;
653

    
654
                loc_end = loc->data_offset + vhd_parent_locator_size(loc);
655
                eom     = MAX(eom, loc_end);
656
        }
657

    
658
        *end = eom;
659
        return 0;
660
}
661

    
662
int
663
vhd_end_of_data(vhd_context_t *ctx, off64_t *end)
664
{
665
        int i, err;
666
        off64_t max;
667
        uint64_t blk;
668

    
669
        if (!vhd_type_dynamic(ctx)) {
670
                err = vhd_seek(ctx, 0, SEEK_END);
671
                if (err)
672
                        return err;
673

    
674
                max = vhd_position(ctx);
675
                if (max == (off64_t)-1)
676
                        return -errno;
677

    
678
                *end = max - sizeof(vhd_footer_t);
679
                return 0;
680
        }
681

    
682
        err = vhd_end_of_headers(ctx, &max);
683
        if (err)
684
                return err;
685

    
686
        err = vhd_get_bat(ctx);
687
        if (err)
688
                return err;
689

    
690
        max >>= VHD_SECTOR_SHIFT;
691

    
692
        for (i = 0; i < ctx->bat.entries; i++) {
693
                blk = ctx->bat.bat[i];
694

    
695
                if (blk != DD_BLK_UNUSED) {
696
                        blk += ctx->spb + ctx->bm_secs;
697
                        max  = MAX(blk, max);
698
                }
699
        }
700

    
701
        *end = vhd_sectors_to_bytes(max);
702
        return 0;
703
}
704

    
705
uint32_t
706
vhd_time(time_t time)
707
{
708
        struct tm tm;
709
        time_t micro_epoch;
710

    
711
        memset(&tm, 0, sizeof(struct tm));
712
        tm.tm_year   = 100;
713
        tm.tm_mon    = 0;
714
        tm.tm_mday   = 1;
715
        micro_epoch  = mktime(&tm);
716

    
717
        return (uint32_t)(time - micro_epoch);
718
}
719

    
720
/* 
721
 * Stringify the VHD timestamp for printing.
722
 * As with ctime_r, target must be >=26 bytes.
723
 */
724
size_t 
725
vhd_time_to_string(uint32_t timestamp, char *target)
726
{
727
        char *cr;
728
        struct tm tm;
729
        time_t t1, t2;
730

    
731
        memset(&tm, 0, sizeof(struct tm));
732

    
733
        /* VHD uses an epoch of 12:00AM, Jan 1, 2000.         */
734
        /* Need to adjust this to the expected epoch of 1970. */
735
        tm.tm_year  = 100;
736
        tm.tm_mon   = 0;
737
        tm.tm_mday  = 1;
738

    
739
        t1 = mktime(&tm);
740
        t2 = t1 + (time_t)timestamp;
741
        ctime_r(&t2, target);
742

    
743
        /* handle mad ctime_r newline appending. */
744
        if ((cr = strchr(target, '\n')) != NULL)
745
                *cr = '\0';
746

    
747
        return (strlen(target));
748
}
749

    
750
/*
751
 * nabbed from vhd specs.
752
 */
753
uint32_t
754
vhd_chs(uint64_t size)
755
{
756
        uint32_t secs, cylinders, heads, spt, cth;
757

    
758
        secs = secs_round_up_no_zero(size);
759

    
760
        if (secs > 65535 * 16 * 255)
761
                secs = 65535 * 16 * 255;
762

    
763
        if (secs >= 65535 * 16 * 63) {
764
                spt   = 255;
765
                cth   = secs / spt;
766
                heads = 16;
767
        } else {
768
                spt   = 17;
769
                cth   = secs / spt;
770
                heads = (cth + 1023) / 1024;
771

    
772
                if (heads < 4)
773
                        heads = 4;
774

    
775
                if (cth >= (heads * 1024) || heads > 16) {
776
                        spt   = 31;
777
                        cth   = secs / spt;
778
                        heads = 16;
779
                }
780

    
781
                if (cth >= heads * 1024) {
782
                        spt   = 63;
783
                        cth   = secs / spt;
784
                        heads = 16;
785
                }
786
        }
787

    
788
        cylinders = cth / heads;
789

    
790
        return GEOM_ENCODE(cylinders, heads, spt);
791
}
792

    
793
int
794
vhd_get_footer(vhd_context_t *ctx)
795
{
796
        if (!vhd_validate_footer(&ctx->footer))
797
                return 0;
798

    
799
        return vhd_read_footer(ctx, &ctx->footer);
800
}
801

    
802
int
803
vhd_get_header(vhd_context_t *ctx)
804
{
805
        if (!vhd_type_dynamic(ctx))
806
                return -EINVAL;
807

    
808
        if (!vhd_validate_header(&ctx->header))
809
                return 0;
810

    
811
        return vhd_read_header(ctx, &ctx->header);
812
}
813

    
814
int
815
vhd_get_bat(vhd_context_t *ctx)
816
{
817
        if (!vhd_type_dynamic(ctx))
818
                return -EINVAL;
819

    
820
        if (!vhd_validate_bat(&ctx->bat))
821
                return 0;
822

    
823
        vhd_put_bat(ctx);
824
        return vhd_read_bat(ctx, &ctx->bat);
825
}
826

    
827
int
828
vhd_get_batmap(vhd_context_t *ctx)
829
{
830
        if (!vhd_has_batmap(ctx))
831
                return -EINVAL;
832

    
833
        if (!vhd_validate_batmap(ctx, &ctx->batmap))
834
                return 0;
835

    
836
        vhd_put_batmap(ctx);
837
        return vhd_read_batmap(ctx, &ctx->batmap);
838
}
839

    
840
void
841
vhd_put_footer(vhd_context_t *ctx)
842
{
843
        memset(&ctx->footer, 0, sizeof(vhd_footer_t));
844
}
845

    
846
void
847
vhd_put_header(vhd_context_t *ctx)
848
{
849
        memset(&ctx->header, 0, sizeof(vhd_header_t));
850
}
851

    
852
void
853
vhd_put_bat(vhd_context_t *ctx)
854
{
855
        if (!vhd_type_dynamic(ctx))
856
                return;
857

    
858
        free(ctx->bat.bat);
859
        memset(&ctx->bat, 0, sizeof(vhd_bat_t));
860
}
861

    
862
void
863
vhd_put_batmap(vhd_context_t *ctx)
864
{
865
        if (!vhd_type_dynamic(ctx))
866
                return;
867

    
868
        if (!vhd_has_batmap(ctx))
869
                return;
870

    
871
        free(ctx->batmap.map);
872
        memset(&ctx->batmap, 0, sizeof(vhd_batmap_t));
873
}
874

    
875
/*
876
 * look for 511 byte footer at end of file
877
 */
878
int
879
vhd_read_short_footer(vhd_context_t *ctx, vhd_footer_t *footer)
880
{
881
        off64_t eof;
882
        void *buf;
883
        int err;
884

    
885
        buf = NULL;
886

    
887
        err = vhd_seek(ctx, 0, SEEK_END);
888
        if (err)
889
                goto out;
890

    
891
        eof = vhd_position(ctx);
892
        if (eof == (off64_t)-1) {
893
                err = -errno;
894
                goto out;
895
        }
896

    
897
        err = vhd_seek(ctx, eof - 511, SEEK_SET);
898
        if (err)
899
                goto out;
900

    
901
        err = posix_memalign(&buf, VHD_SECTOR_SIZE, sizeof(vhd_footer_t));
902
        if (err) {
903
                buf = NULL;
904
                err = -err;
905
                goto out;
906
        }
907

    
908
        memset(buf, 0, sizeof(vhd_footer_t));
909

    
910
        /*
911
         * expecting short read here
912
         */
913
        vhd_read(ctx, buf, sizeof(vhd_footer_t));
914

    
915
        memcpy(footer, buf, sizeof(vhd_footer_t));
916

    
917
        vhd_footer_in(footer);
918
        err = vhd_validate_footer(footer);
919

    
920
out:
921
        if (err)
922
                VHDLOG("%s: failed reading short footer: %d\n",
923
                       ctx->file, err);
924
        free(buf);
925
        return err;
926
}
927

    
928
int
929
vhd_read_footer_at(vhd_context_t *ctx, vhd_footer_t *footer, off64_t off)
930
{
931
        void *buf;
932
        int err;
933

    
934
        buf = NULL;
935

    
936
        err = vhd_seek(ctx, off, SEEK_SET);
937
        if (err)
938
                goto out;
939

    
940
        err = posix_memalign(&buf, VHD_SECTOR_SIZE, sizeof(vhd_footer_t));
941
        if (err) {
942
                buf = NULL;
943
                err = -err;
944
                goto out;
945
        }
946

    
947
        err = vhd_read(ctx, buf, sizeof(vhd_footer_t));
948
        if (err)
949
                goto out;
950

    
951
        memcpy(footer, buf, sizeof(vhd_footer_t));
952

    
953
        vhd_footer_in(footer);
954
        err = vhd_validate_footer(footer);
955

    
956
out:
957
        if (err)
958
                VHDLOG("%s: reading footer at 0x%08"PRIx64" failed: %d\n",
959
                       ctx->file, off, err);
960
        free(buf);
961
        return err;
962
}
963

    
964
int
965
vhd_read_footer(vhd_context_t *ctx, vhd_footer_t *footer)
966
{
967
        int err;
968
        off64_t off;
969

    
970
        err = vhd_seek(ctx, 0, SEEK_END);
971
        if (err)
972
                return err;
973

    
974
        off = vhd_position(ctx);
975
        if (off == (off64_t)-1)
976
                return -errno;
977

    
978
        err = vhd_read_footer_at(ctx, footer, off - 512);
979
        if (err != -EINVAL)
980
                return err;
981

    
982
        err = vhd_read_short_footer(ctx, footer);
983
        if (err != -EINVAL)
984
                return err;
985

    
986
        /* 
987
         * Disable the enforcement of VHD_OPEN_STRICT until we figure out how 
988
         * to recover from crashes. Note that we never enforced it before 
989
         * anyways due to a bug (CA-28285) and everything was ok.
990
         */
991
        /* if (ctx->oflags & VHD_OPEN_STRICT)
992
                return -EINVAL; */
993

    
994
        return vhd_read_footer_at(ctx, footer, 0);
995
}
996

    
997
int
998
vhd_read_header_at(vhd_context_t *ctx, vhd_header_t *header, off64_t off)
999
{
1000
        void *buf;
1001
        int err;
1002

    
1003
        buf = NULL;
1004

    
1005
        if (!vhd_type_dynamic(ctx)) {
1006
                err = -EINVAL;
1007
                goto out;
1008
        }
1009

    
1010
        err = vhd_seek(ctx, off, SEEK_SET);
1011
        if (err)
1012
                goto out;
1013

    
1014
        err = posix_memalign(&buf, VHD_SECTOR_SIZE, sizeof(vhd_header_t));
1015
        if (err) {
1016
                buf = NULL;
1017
                err = -err;
1018
                goto out;
1019
        }
1020

    
1021
        err = vhd_read(ctx, buf, sizeof(vhd_header_t));
1022
        if (err)
1023
                goto out;
1024

    
1025
        memcpy(header, buf, sizeof(vhd_header_t));
1026

    
1027
        vhd_header_in(header);
1028
        err = vhd_validate_header(header);
1029

    
1030
out:
1031
        if (err)
1032
                VHDLOG("%s: reading header at 0x%08"PRIx64" failed: %d\n",
1033
                       ctx->file, off, err);
1034
        free(buf);
1035
        return err;
1036
}
1037

    
1038
int
1039
vhd_read_header(vhd_context_t *ctx, vhd_header_t *header)
1040
{
1041
        off64_t off;
1042

    
1043
        if (!vhd_type_dynamic(ctx)) {
1044
                VHDLOG("%s is not dynamic!\n", ctx->file);
1045
                return -EINVAL;
1046
        }
1047

    
1048
        off = ctx->footer.data_offset;
1049
        return vhd_read_header_at(ctx, header, off);
1050
}
1051

    
1052
int
1053
vhd_read_bat(vhd_context_t *ctx, vhd_bat_t *bat)
1054
{
1055
        int err;
1056
        void *buf;
1057
        off64_t off;
1058
        uint32_t vhd_blks;
1059
        size_t size;
1060

    
1061
        buf  = NULL;
1062

    
1063
        if (!vhd_type_dynamic(ctx)) {
1064
                err = -EINVAL;
1065
                goto fail;
1066
        }
1067

    
1068
        off  = ctx->header.table_offset;
1069
        /* The BAT size is stored in ctx->header.max_bat_size. However, we
1070
         * sometimes preallocate BAT + batmap for max VHD size, so only read in
1071
         * the BAT entries that are in use for curr_size */
1072
        vhd_blks = ctx->footer.curr_size >> VHD_BLOCK_SHIFT;
1073
        ASSERT(ctx->header.max_bat_size >= vhd_blks);
1074
        size = vhd_bytes_padded(vhd_blks * sizeof(uint32_t));
1075

    
1076
        err  = posix_memalign(&buf, VHD_SECTOR_SIZE, size);
1077
        if (err) {
1078
                buf = NULL;
1079
                err = -err;
1080
                goto fail;
1081
        }
1082

    
1083
        err = vhd_seek(ctx, off, SEEK_SET);
1084
        if (err)
1085
                goto fail;
1086

    
1087
        err = vhd_read(ctx, buf, size);
1088
        if (err)
1089
                goto fail;
1090

    
1091
        bat->spb     = ctx->header.block_size >> VHD_SECTOR_SHIFT;
1092
        bat->entries = vhd_blks;
1093
        bat->bat     = (uint32_t *)buf;
1094

    
1095
        vhd_bat_in(bat);
1096

    
1097
        return 0;
1098

    
1099
fail:
1100
        free(buf);
1101
        memset(bat, 0, sizeof(vhd_bat_t));
1102
        VHDLOG("%s: failed to read bat: %d\n", ctx->file, err);
1103
        return err;
1104
}
1105

    
1106
static int
1107
vhd_read_batmap_header(vhd_context_t *ctx, vhd_batmap_t *batmap)
1108
{
1109
        int err;
1110
        void *buf;
1111
        off64_t off;
1112
        size_t size;
1113

    
1114
        buf = NULL;
1115

    
1116
        err = vhd_batmap_header_offset(ctx, &off);
1117
        if (err)
1118
                goto fail;
1119

    
1120
        err = vhd_seek(ctx, off, SEEK_SET);
1121
        if (err)
1122
                goto fail;
1123

    
1124
        size = vhd_bytes_padded(sizeof(vhd_batmap_header_t));
1125
        err  = posix_memalign(&buf, VHD_SECTOR_SIZE, size);
1126
        if (err) {
1127
                buf = NULL;
1128
                err = -err;
1129
                goto fail;
1130
        }
1131

    
1132
        err = vhd_read(ctx, buf, size);
1133
        if (err)
1134
                goto fail;
1135

    
1136
        memcpy(&batmap->header, buf, sizeof(vhd_batmap_header_t));
1137
        free(buf);
1138
        buf = NULL;
1139

    
1140
        vhd_batmap_header_in(batmap);
1141

    
1142
        return 0;
1143

    
1144
fail:
1145
        free(buf);
1146
        memset(&batmap->header, 0, sizeof(vhd_batmap_header_t));
1147
        VHDLOG("%s: failed to read batmap header: %d\n", ctx->file, err);
1148
        return err;
1149
}
1150

    
1151
static int
1152
vhd_read_batmap_map(vhd_context_t *ctx, vhd_batmap_t *batmap)
1153
{
1154
        int err;
1155
        void *buf;
1156
        off64_t off;
1157
        size_t map_size;
1158

    
1159
        map_size = vhd_sectors_to_bytes(secs_round_up_no_zero(
1160
                        ctx->footer.curr_size >> (VHD_BLOCK_SHIFT + 3)));
1161
        ASSERT(vhd_sectors_to_bytes(batmap->header.batmap_size) >= map_size);
1162

    
1163
        err = posix_memalign(&buf, VHD_SECTOR_SIZE, map_size);
1164
        if (err) {
1165
                buf = NULL;
1166
                err = -err;
1167
                goto fail;
1168
        }
1169

    
1170
        off  = batmap->header.batmap_offset;
1171
        err  = vhd_seek(ctx, off, SEEK_SET);
1172
        if (err)
1173
                goto fail;
1174

    
1175
        err  = vhd_read(ctx, buf, map_size);
1176
        if (err)
1177
                goto fail;
1178

    
1179
        batmap->map = buf;
1180
        return 0;
1181

    
1182
fail:
1183
        free(buf);
1184
        batmap->map = NULL;
1185
        VHDLOG("%s: failed to read batmap: %d\n", ctx->file, err);
1186
        return err;
1187
}
1188

    
1189
int
1190
vhd_read_batmap(vhd_context_t *ctx, vhd_batmap_t *batmap)
1191
{
1192
        int err;
1193

    
1194
        if (!vhd_has_batmap(ctx))
1195
                return -EINVAL;
1196

    
1197
        memset(batmap, 0, sizeof(vhd_batmap_t));
1198

    
1199
        err = vhd_read_batmap_header(ctx, batmap);
1200
        if (err)
1201
                return err;
1202

    
1203
        err = vhd_validate_batmap_header(batmap);
1204
        if (err)
1205
                return err;
1206

    
1207
        err = vhd_read_batmap_map(ctx, batmap);
1208
        if (err)
1209
                return err;
1210

    
1211
        err = vhd_validate_batmap(ctx, batmap);
1212
        if (err)
1213
                goto fail;
1214

    
1215
        return 0;
1216

    
1217
fail:
1218
        free(batmap->map);
1219
        memset(batmap, 0, sizeof(vhd_batmap_t));
1220
        return err;
1221
}
1222

    
1223
int
1224
vhd_has_batmap(vhd_context_t *ctx)
1225
{
1226
        if (!vhd_type_dynamic(ctx))
1227
                return 0;
1228

    
1229
        if (!vhd_creator_tapdisk(ctx))
1230
                return 0;
1231

    
1232
        if (ctx->footer.crtr_ver <= VHD_VERSION(0, 1))
1233
                return 0;
1234

    
1235
        if (ctx->footer.crtr_ver >= VHD_VERSION(1, 2))
1236
                return 1;
1237

    
1238
        /*
1239
         * VHDs of version 1.1 probably have a batmap, but may not 
1240
         * if they were updated from version 0.1 via vhd-update.
1241
         */
1242
        if (!vhd_validate_batmap_header(&ctx->batmap))
1243
                return 1;
1244

    
1245
        if (vhd_read_batmap_header(ctx, &ctx->batmap))
1246
                return 0;
1247

    
1248
        return (!vhd_validate_batmap_header(&ctx->batmap));
1249
}
1250

    
1251
/* 
1252
 * Is this a block device (with a fixed size)? This affects whether the file 
1253
 * can be truncated and where the footer is written for VHDs.
1254
 */
1255
int
1256
vhd_test_file_fixed(const char *file, int *is_block)
1257
{
1258
        int err;
1259
        struct stat stats;
1260

    
1261
        err = stat(file, &stats);
1262
        if (err == -1)
1263
                return -errno;
1264

    
1265
        *is_block = !!(S_ISBLK(stats.st_mode));
1266
        return err;
1267
}
1268

    
1269
int
1270
vhd_find_parent(vhd_context_t *ctx, const char *parent, char **_location)
1271
{
1272
        char *location, __location[PATH_MAX];
1273
        char *cpath, __cpath[PATH_MAX];
1274
        char *cdir, *path;
1275
        int err;
1276

    
1277
        err        = 0;
1278
        path       = NULL;
1279
        cpath      = NULL;
1280
        location   = NULL;
1281
        *_location = NULL;
1282

    
1283
        if (!parent)
1284
                return -EINVAL;
1285

    
1286
        if (parent[0] == '/') {
1287
                if (!access(parent, R_OK)) {
1288
                        *_location = strdup(parent);
1289
                        if (!*_location)
1290
                                return -errno;
1291
                        return 0;
1292
                }
1293
        }
1294

    
1295
        /* check parent path relative to child's directory */
1296
        cpath = realpath(ctx->file, __cpath);
1297
        if (!cpath) {
1298
                err = -errno;
1299
                goto out;
1300
        }
1301

    
1302
        cdir = dirname(cpath);
1303
        if (asprintf(&location, "%s/%s", cdir, parent) == -1) {
1304
                err = -errno;
1305
                location = NULL;
1306
                goto out;
1307
        }
1308

    
1309
        if (!access(location, R_OK)) {
1310
                path = realpath(location, __location);
1311
                if (path) {
1312
                        *_location = strdup(path);
1313
                        if (!*_location)
1314
                                return -errno;
1315
                        return 0;
1316
                }
1317
        }
1318

    
1319
out:
1320
        return err;
1321
}
1322

    
1323
int 
1324
vhd_macx_encode_location(char *name, char **out, int *outlen)
1325
{
1326
        iconv_t cd;
1327
        int len, err;
1328
        size_t ibl, obl;
1329
        char *uri, *urip, *uri_utf8, *uri_utf8p, *ret;
1330

    
1331
        err     = 0;
1332
        ret     = NULL;
1333
        *out    = NULL;
1334
        *outlen = 0;
1335
        len     = strlen(name) + strlen("file://");
1336

    
1337
        ibl     = len;
1338
        obl     = len;
1339

    
1340
        uri = urip = malloc(ibl + 1);
1341
        uri_utf8 = uri_utf8p = malloc(obl);
1342

    
1343
        if (!uri || !uri_utf8)
1344
                return -ENOMEM;
1345

    
1346
        cd = iconv_open("UTF-8", "ASCII");
1347
        if (cd == (iconv_t)-1) {
1348
                err = -errno;
1349
                goto out;
1350
        }
1351

    
1352
        sprintf(uri, "file://%s", name);
1353

    
1354
        if (iconv(cd, &urip, &ibl, &uri_utf8p, &obl) == (size_t)-1 ||
1355
            ibl || obl) {
1356
                err = (errno ? -errno : -EIO);
1357
                goto out;
1358
        }
1359

    
1360
        ret = malloc(len);
1361
        if (!ret) {
1362
                err = -ENOMEM;
1363
                goto out;
1364
        }
1365

    
1366
        memcpy(ret, uri_utf8, len);
1367
        *outlen = len;
1368
        *out    = ret;
1369

    
1370
 out:
1371
        free(uri);
1372
        free(uri_utf8);
1373
        if (cd != (iconv_t)-1)
1374
                iconv_close(cd);
1375

    
1376
        return err;
1377
}
1378

    
1379
int
1380
vhd_w2u_encode_location(char *name, char **out, int *outlen)
1381
{
1382
        iconv_t cd;
1383
        int len, err;
1384
        size_t ibl, obl;
1385
        char *uri, *urip, *uri_utf16, *uri_utf16p, *tmp, *ret;
1386

    
1387
        err     = 0;
1388
        ret     = NULL;
1389
        *out    = NULL;
1390
        *outlen = 0;
1391
        cd      = (iconv_t) -1;
1392

    
1393
        /* 
1394
         * MICROSOFT_COMPAT
1395
         * relative paths must start with ".\" 
1396
         */
1397
        if (name[0] != '/') {
1398
                tmp = strstr(name, "./");
1399
                if (tmp == name)
1400
                        tmp += strlen("./");
1401
                else
1402
                        tmp = name;
1403

    
1404
                err = asprintf(&uri, ".\\%s", tmp);
1405
        } else
1406
                err = asprintf(&uri, "%s", name);
1407

    
1408
        if (err == -1)
1409
                return -ENOMEM;
1410

    
1411
        tmp = uri;
1412
        while (*tmp != '\0') {
1413
                if (*tmp == '/')
1414
                        *tmp = '\\';
1415
                tmp++;
1416
        }
1417

    
1418
        len  = strlen(uri);
1419
        ibl  = len;
1420
        obl  = len * 2;
1421
        urip = uri;
1422

    
1423
        uri_utf16 = uri_utf16p = malloc(obl);
1424
        if (!uri_utf16) {
1425
                err = -ENOMEM;
1426
                goto out;
1427
        }
1428

    
1429
        /* 
1430
         * MICROSOFT_COMPAT
1431
         * little endian unicode here 
1432
         */
1433
        cd = iconv_open("UTF-16LE", "ASCII");
1434
        if (cd == (iconv_t)-1) {
1435
                err = -errno;
1436
                goto out;
1437
        }
1438

    
1439
        if (iconv(cd, &urip, &ibl, &uri_utf16p, &obl) == (size_t)-1 ||
1440
            ibl || obl) {
1441
                err = (errno ? -errno : -EIO);
1442
                goto out;
1443
        }
1444

    
1445
        len = len * 2;
1446
        ret = malloc(len);
1447
        if (!ret) {
1448
                err = -ENOMEM;
1449
                goto out;
1450
        }
1451

    
1452
        memcpy(ret, uri_utf16, len);
1453
        *outlen = len;
1454
        *out    = ret;
1455
        err     = 0;
1456

    
1457
 out:
1458
        free(uri);
1459
        free(uri_utf16);
1460
        if (cd != (iconv_t)-1)
1461
                iconv_close(cd);
1462

    
1463
        return err;
1464
}
1465

    
1466
static char *
1467
vhd_macx_decode_location(char *in, char *out, int len)
1468
{
1469
        iconv_t cd;
1470
        char *name;
1471
        size_t ibl, obl;
1472

    
1473
        name = out;
1474
        ibl  = obl = len;
1475

    
1476
        cd = iconv_open("ASCII", "UTF-8");
1477
        if (cd == (iconv_t)-1) 
1478
                return NULL;
1479

    
1480
        if (iconv(cd, &in, &ibl, &out, &obl) == (size_t)-1 || ibl)
1481
                return NULL;
1482

    
1483
        iconv_close(cd);
1484
        *out = '\0';
1485

    
1486
        if (strstr(name, "file://") != name)
1487
                return NULL;
1488

    
1489
        name += strlen("file://");
1490

    
1491
        return strdup(name);
1492
}
1493

    
1494
static char *
1495
vhd_w2u_decode_location(char *in, char *out, int len, char *utf_type)
1496
{
1497
        iconv_t cd;
1498
        char *name, *tmp;
1499
        size_t ibl, obl;
1500

    
1501
        tmp = name = out;
1502
        ibl = obl  = len;
1503

    
1504
        cd = iconv_open("ASCII", utf_type);
1505
        if (cd == (iconv_t)-1) 
1506
                return NULL;
1507

    
1508
        if (iconv(cd, &in, &ibl, &out, &obl) == (size_t)-1 || ibl)
1509
                return NULL;
1510

    
1511
        iconv_close(cd);
1512
        *out = '\0';
1513

    
1514
        /* TODO: spaces */
1515
        while (tmp != out) {
1516
                if (*tmp == '\\')
1517
                        *tmp = '/';
1518
                tmp++;
1519
        }
1520

    
1521
        if (strstr(name, "C:") == name || strstr(name, "c:") == name)
1522
                name += strlen("c:");
1523

    
1524
        return strdup(name);
1525
}
1526

    
1527
int
1528
vhd_header_decode_parent(vhd_context_t *ctx, vhd_header_t *header, char **buf)
1529
{
1530
        char *code, out[512];
1531

    
1532
        if (vhd_creator_tapdisk(ctx) &&
1533
            ctx->footer.crtr_ver == VHD_VERSION(0, 1))
1534
                code = UTF_16;
1535
        else
1536
                code = UTF_16BE;
1537

    
1538
        *buf = vhd_w2u_decode_location(header->prt_name, out, 512, code);
1539
        return (*buf == NULL ? -EINVAL : 0);
1540
}
1541

    
1542
int
1543
vhd_parent_locator_read(vhd_context_t *ctx,
1544
                        vhd_parent_locator_t *loc, char **parent)
1545
{
1546
        int err, size;
1547
        void *raw, *out, *name;
1548

    
1549
        raw     = NULL;
1550
        out     = NULL;
1551
        name    = NULL;
1552
        *parent = NULL;
1553

    
1554
        if (ctx->footer.type != HD_TYPE_DIFF) {
1555
                err = -EINVAL;
1556
                goto out;
1557
        }
1558

    
1559
        switch (loc->code) {
1560
        case PLAT_CODE_MACX:
1561
        case PLAT_CODE_W2KU:
1562
        case PLAT_CODE_W2RU:
1563
                break;
1564
        default:
1565
                err = -EINVAL;
1566
                goto out;
1567
        }
1568

    
1569
        err = vhd_seek(ctx, loc->data_offset, SEEK_SET);
1570
        if (err)
1571
                goto out;
1572

    
1573
        size = vhd_parent_locator_size(loc);
1574
        if (size <= 0) {
1575
                err = -EINVAL;
1576
                goto out;
1577
        }
1578

    
1579
        err = posix_memalign(&raw, VHD_SECTOR_SIZE, size);
1580
        if (err) {
1581
                raw = NULL;
1582
                err = -err;
1583
                goto out;
1584
        }
1585

    
1586
        err = vhd_read(ctx, raw, size);
1587
        if (err)
1588
                goto out;
1589

    
1590
        out = malloc(loc->data_len + 1);
1591
        if (!out) {
1592
                err = -ENOMEM;
1593
                goto out;
1594
        }
1595

    
1596
        switch (loc->code) {
1597
        case PLAT_CODE_MACX:
1598
                name = vhd_macx_decode_location(raw, out, loc->data_len);
1599
                break;
1600
        case PLAT_CODE_W2KU:
1601
        case PLAT_CODE_W2RU:
1602
                name = vhd_w2u_decode_location(raw, out,
1603
                                               loc->data_len, UTF_16LE);
1604
                break;
1605
        }
1606

    
1607
        if (!name) {
1608
                err = -EINVAL;
1609
                goto out;
1610
        }
1611

    
1612
        err     = 0;
1613
        *parent = name;
1614

    
1615
out:
1616
        free(raw);
1617
        free(out);
1618

    
1619
        if (err) {
1620
                VHDLOG("%s: error reading parent locator: %d\n",
1621
                       ctx->file, err);
1622
                VHDLOG("%s: locator: code %u, space 0x%x, len 0x%x, "
1623
                       "off 0x%"PRIx64"\n", ctx->file, loc->code, loc->data_space,
1624
                       loc->data_len, loc->data_offset);
1625
        }
1626

    
1627
        return err;
1628
}
1629

    
1630
int
1631
vhd_parent_locator_get(vhd_context_t *ctx, char **parent)
1632
{
1633
        int i, n, err;
1634
        char *name, *location;
1635
        vhd_parent_locator_t *loc;
1636

    
1637
        err     = -EINVAL;
1638
        *parent = NULL;
1639

    
1640
        if (ctx->footer.type != HD_TYPE_DIFF)
1641
                return -EINVAL;
1642

    
1643
        n = vhd_parent_locator_count(ctx);
1644
        for (i = 0; i < n; i++) {
1645
                int _err;
1646

    
1647
                loc = ctx->header.loc + i;
1648
                _err = vhd_parent_locator_read(ctx, loc, &name);
1649
                if (_err)
1650
                        continue;
1651

    
1652
                err = vhd_find_parent(ctx, name, &location);
1653
                if (err)
1654
                        VHDLOG("%s: couldn't find parent %s (%d)\n",
1655
                               ctx->file, name, err);
1656
                free(name);
1657

    
1658
                if (!err) {
1659
                        *parent = location;
1660
                        return 0;
1661
                }
1662
        }
1663

    
1664
        return err;
1665
}
1666

    
1667
int
1668
vhd_parent_locator_write_at(vhd_context_t *ctx,
1669
                            const char *parent, off64_t off, uint32_t code,
1670
                            size_t max_bytes, vhd_parent_locator_t *loc)
1671
{
1672
        struct stat stats;
1673
        int err, len, size;
1674
        char *absolute_path, *relative_path, *encoded;
1675
        char __parent[PATH_MAX];
1676
        void *block;
1677

    
1678
        memset(loc, 0, sizeof(vhd_parent_locator_t));
1679

    
1680
        if (ctx->footer.type != HD_TYPE_DIFF)
1681
                return -EINVAL;
1682

    
1683
        absolute_path = NULL;
1684
        relative_path = NULL;
1685
        encoded       = NULL;
1686
        block         = NULL;
1687
        size          = 0;
1688
        len           = 0;
1689

    
1690
        switch (code) {
1691
        case PLAT_CODE_MACX:
1692
        case PLAT_CODE_W2KU:
1693
        case PLAT_CODE_W2RU:
1694
                break;
1695
        default:
1696
                return -EINVAL;
1697
        }
1698

    
1699
        absolute_path = realpath(parent, __parent);
1700
        if (!absolute_path) {
1701
                err = -errno;
1702
                goto out;
1703
        }
1704

    
1705
        err = stat(absolute_path, &stats);
1706
        if (err) {
1707
                err = -errno;
1708
                goto out;
1709
        }
1710

    
1711
        if (!S_ISREG(stats.st_mode) && !S_ISBLK(stats.st_mode)) {
1712
                err = -EINVAL;
1713
                goto out;
1714
        }
1715

    
1716
        relative_path = relative_path_to(ctx->file, absolute_path, &err);
1717
        if (!relative_path || err) {
1718
                err = (err ? err : -EINVAL);
1719
                goto out;
1720
        }
1721

    
1722
        switch (code) {
1723
        case PLAT_CODE_MACX:
1724
                err = vhd_macx_encode_location(relative_path, &encoded, &len);
1725
                break;
1726
        case PLAT_CODE_W2KU:
1727
        case PLAT_CODE_W2RU:
1728
                err = vhd_w2u_encode_location(relative_path, &encoded, &len);
1729
                break;
1730
        default:
1731
                err = -EINVAL;
1732
        }
1733

    
1734
        if (err)
1735
                goto out;
1736

    
1737
        err = vhd_seek(ctx, off, SEEK_SET);
1738
        if (err)
1739
                goto out;
1740

    
1741
        size = vhd_bytes_padded(len);
1742

    
1743
        if (max_bytes && size > max_bytes) {
1744
                err = -ENAMETOOLONG;
1745
                goto out;
1746
        }
1747

    
1748
        err  = posix_memalign(&block, VHD_SECTOR_SIZE, size);
1749
        if (err) {
1750
                block = NULL;
1751
                err   = -err;
1752
                goto out;
1753
        }
1754

    
1755
        memset(block, 0, size);
1756
        memcpy(block, encoded, len);
1757

    
1758
        err = vhd_write(ctx, block, size);
1759
        if (err)
1760
                goto out;
1761

    
1762
        err = 0;
1763

    
1764
out:
1765
        free(relative_path);
1766
        free(encoded);
1767
        free(block);
1768

    
1769
        if (!err) {
1770
                loc->res         = 0;
1771
                loc->code        = code;
1772
                loc->data_len    = len;
1773
                /*
1774
                 * write number of bytes ('size') instead of number of sectors
1775
                 * into loc->data_space to be compatible with MSFT, even though
1776
                 * this goes against the specs
1777
                 */
1778
                loc->data_space  = size; 
1779
                loc->data_offset = off;
1780
        }
1781

    
1782
        return err;
1783
}
1784

    
1785
static int
1786
vhd_footer_offset_at_eof(vhd_context_t *ctx, off64_t *off)
1787
{
1788
        int err;
1789
        if ((err = vhd_seek(ctx, 0, SEEK_END)))
1790
                return errno;
1791
        *off = vhd_position(ctx) - sizeof(vhd_footer_t);
1792
        return 0;
1793
}
1794

    
1795
int
1796
vhd_read_bitmap(vhd_context_t *ctx, uint32_t block, char **bufp)
1797
{
1798
        int err;
1799
        void *buf;
1800
        size_t size;
1801
        off64_t off;
1802
        uint64_t blk;
1803

    
1804
        buf   = NULL;
1805
        *bufp = NULL;
1806

    
1807
        if (!vhd_type_dynamic(ctx))
1808
                return -EINVAL;
1809

    
1810
        err = vhd_get_bat(ctx);
1811
        if (err)
1812
                return err;
1813

    
1814
        if (block >= ctx->bat.entries)
1815
                return -ERANGE;
1816

    
1817
        blk  = ctx->bat.bat[block];
1818
        if (blk == DD_BLK_UNUSED)
1819
                return -EINVAL;
1820

    
1821
        off  = vhd_sectors_to_bytes(blk);
1822
        size = vhd_bytes_padded(ctx->spb >> 3);
1823

    
1824
        err  = vhd_seek(ctx, off, SEEK_SET);
1825
        if (err)
1826
                return err;
1827

    
1828
        err  = posix_memalign(&buf, VHD_SECTOR_SIZE, size);
1829
        if (err)
1830
                return -err;
1831

    
1832
        err  = vhd_read(ctx, buf, size);
1833
        if (err)
1834
                goto fail;
1835

    
1836
        *bufp = buf;
1837
        return 0;
1838

    
1839
fail:
1840
        free(buf);
1841
        return err;
1842
}
1843

    
1844
int
1845
vhd_read_block(vhd_context_t *ctx, uint32_t block, char **bufp)
1846
{
1847
        int err;
1848
        void *buf;
1849
        size_t size;
1850
        uint64_t blk;
1851
        off64_t end, off;
1852

    
1853
        buf   = NULL;
1854
        *bufp = NULL;
1855

    
1856
        if (!vhd_type_dynamic(ctx))
1857
                return -EINVAL;
1858

    
1859
        err = vhd_get_bat(ctx);
1860
        if (err)
1861
                return err;
1862

    
1863
        if (block >= ctx->bat.entries)
1864
                return -ERANGE;
1865

    
1866
        blk  = ctx->bat.bat[block];
1867
        if (blk == DD_BLK_UNUSED)
1868
                return -EINVAL;
1869

    
1870
        off  = vhd_sectors_to_bytes(blk + ctx->bm_secs);
1871
        size = vhd_sectors_to_bytes(ctx->spb);
1872

    
1873
        err  = vhd_footer_offset_at_eof(ctx, &end);
1874
        if (err)
1875
                return err;
1876

    
1877
        err  = posix_memalign(&buf, VHD_SECTOR_SIZE, size);
1878
        if (err) {
1879
                err = -err;
1880
                goto fail;
1881
        }
1882

    
1883
        if (end < off + ctx->header.block_size) {
1884
                size = end - off;
1885
                memset(buf + size, 0, ctx->header.block_size - size);
1886
        }
1887

    
1888
        err  = vhd_seek(ctx, off, SEEK_SET);
1889
        if (err)
1890
                goto fail;
1891

    
1892
        err  = vhd_read(ctx, buf, size);
1893
        if (err)
1894
                goto fail;
1895

    
1896
        *bufp = buf;
1897
        return 0;
1898

    
1899
fail:
1900
        free(buf);
1901
        return err;
1902
}
1903

    
1904
int
1905
vhd_write_footer_at(vhd_context_t *ctx, vhd_footer_t *footer, off64_t off)
1906
{
1907
        int err;
1908
        void *buf;
1909
        vhd_footer_t *f;
1910

    
1911
        f = NULL;
1912

    
1913
        err = posix_memalign(&buf, VHD_SECTOR_SIZE, sizeof(vhd_footer_t));
1914
        if (err) {
1915
                err = -err;
1916
                goto out;
1917
        }
1918
        f = buf;
1919

    
1920
        memcpy(f, footer, sizeof(vhd_footer_t));
1921
        f->checksum = vhd_checksum_footer(f);
1922

    
1923
        err = vhd_validate_footer(f);
1924
        if (err)
1925
                goto out;
1926

    
1927
        err = vhd_seek(ctx, off, SEEK_SET);
1928
        if (err)
1929
                goto out;
1930

    
1931
        vhd_footer_out(f);
1932

    
1933
        err = vhd_write(ctx, f, sizeof(vhd_footer_t));
1934

    
1935
out:
1936
        if (err)
1937
                VHDLOG("%s: failed writing footer at 0x%08"PRIx64": %d\n",
1938
                       ctx->file, off, err);
1939
        free(f);
1940
        return err;
1941
}
1942

    
1943
int
1944
vhd_write_footer(vhd_context_t *ctx, vhd_footer_t *footer)
1945
{
1946
        int err;
1947
        off64_t off;
1948

    
1949
        if (ctx->is_block)
1950
                err = vhd_footer_offset_at_eof(ctx, &off);
1951
        else
1952
                err = vhd_end_of_data(ctx, &off);
1953
        if (err)
1954
                return err;
1955

    
1956
        err = vhd_write_footer_at(ctx, footer, off);
1957
        if (err)
1958
                return err;
1959

    
1960
        if (!ctx->is_block) {
1961
                err = ftruncate(ctx->fd, off + sizeof(vhd_footer_t));
1962
                if (err)
1963
                        return -errno;
1964
        }
1965

    
1966
        if (!vhd_type_dynamic(ctx))
1967
                return 0;
1968

    
1969
        return vhd_write_footer_at(ctx, footer, 0);
1970
}
1971

    
1972
int
1973
vhd_write_header_at(vhd_context_t *ctx, vhd_header_t *header, off64_t off)
1974
{
1975
        int err;
1976
        vhd_header_t *h;
1977
        void *buf;
1978

    
1979
        h = NULL;
1980

    
1981
        if (!vhd_type_dynamic(ctx)) {
1982
                err = -EINVAL;
1983
                goto out;
1984
        }
1985

    
1986
        err = posix_memalign(&buf, VHD_SECTOR_SIZE, sizeof(vhd_header_t));
1987
        if (err) {
1988
                err = -err;
1989
                goto out;
1990
        }
1991
        h = buf;
1992

    
1993
        memcpy(h, header, sizeof(vhd_header_t));
1994

    
1995
        h->checksum = vhd_checksum_header(h);
1996
        err = vhd_validate_header(h);
1997
        if (err)
1998
                goto out;
1999

    
2000
        vhd_header_out(h);
2001

    
2002
        err = vhd_seek(ctx, off, SEEK_SET);
2003
        if (err)
2004
                goto out;
2005

    
2006
        err = vhd_write(ctx, h, sizeof(vhd_header_t));
2007

    
2008
out:
2009
        if (err)
2010
                VHDLOG("%s: failed writing header at 0x%08"PRIx64": %d\n",
2011
                       ctx->file, off, err);
2012
        free(h);
2013
        return err;
2014
}
2015

    
2016
int
2017
vhd_write_header(vhd_context_t *ctx, vhd_header_t *header)
2018
{
2019
        off64_t off;
2020

    
2021
        if (!vhd_type_dynamic(ctx))
2022
                return -EINVAL;
2023

    
2024
        off = ctx->footer.data_offset;
2025
        return vhd_write_header_at(ctx, header, off);
2026
}
2027

    
2028
int
2029
vhd_write_bat(vhd_context_t *ctx, vhd_bat_t *bat)
2030
{
2031
        int err;
2032
        off64_t off;
2033
        vhd_bat_t b;
2034
        void *buf;
2035
        size_t size;
2036

    
2037
        if (!vhd_type_dynamic(ctx))
2038
                return -EINVAL;
2039

    
2040
        err = vhd_validate_bat(&ctx->bat);
2041
        if (err)
2042
                return err;
2043

    
2044
        err = vhd_validate_bat(bat);
2045
        if (err)
2046
                return err;
2047

    
2048
        memset(&b, 0, sizeof(vhd_bat_t));
2049

    
2050
        off  = ctx->header.table_offset;
2051
        size = vhd_bytes_padded(bat->entries * sizeof(uint32_t));
2052

    
2053
        err  = vhd_seek(ctx, off, SEEK_SET);
2054
        if (err)
2055
                return err;
2056

    
2057
        err  = posix_memalign(&buf, VHD_SECTOR_SIZE, size);
2058
        if (err)
2059
                return -err;
2060
        b.bat = buf;
2061

    
2062
        memcpy(b.bat, bat->bat, size);
2063
        b.spb     = bat->spb;
2064
        b.entries = bat->entries;
2065
        vhd_bat_out(&b);
2066

    
2067
        err = vhd_write(ctx, b.bat, size);
2068
        free(b.bat);
2069

    
2070
        return err;
2071
}
2072

    
2073
static int
2074
vhd_write_batmap_header(vhd_context_t *ctx, vhd_batmap_t *batmap)
2075
{
2076
        int err;
2077
        size_t size;
2078
        off64_t off;
2079
        void *buf = NULL;
2080

    
2081
        err = vhd_batmap_header_offset(ctx, &off);
2082
        if (err)
2083
                goto out;
2084

    
2085
        size = vhd_bytes_padded(sizeof(*batmap));
2086

    
2087
        err = vhd_seek(ctx, off, SEEK_SET);
2088
        if (err)
2089
                goto out;
2090

    
2091
        err = posix_memalign(&buf, VHD_SECTOR_SIZE, size);
2092
        if (err) {
2093
                err = -err;
2094
                goto out;
2095
        }
2096

    
2097
        vhd_batmap_header_out(batmap);
2098
        memset(buf, 0, size);
2099
        memcpy(buf, &batmap->header, sizeof(batmap->header));
2100

    
2101
        err = vhd_write(ctx, buf, size);
2102

    
2103
out:
2104
        if (err)
2105
                VHDLOG("%s: failed writing batmap: %d\n", ctx->file, err);
2106
        free(buf);
2107
        return err;
2108
}
2109

    
2110
int
2111
vhd_write_batmap(vhd_context_t *ctx, vhd_batmap_t *batmap)
2112
{
2113
        int err;
2114
        off64_t off;
2115
        vhd_batmap_t b;
2116
        void *buf, *map;
2117
        size_t size, map_size;
2118

    
2119
        buf      = NULL;
2120
        map      = NULL;
2121

    
2122
        if (!vhd_has_batmap(ctx)) {
2123
                err = -EINVAL;
2124
                goto out;
2125
        }
2126

    
2127
        b.header = batmap->header;
2128
        b.map    = batmap->map;
2129

    
2130
        b.header.checksum = vhd_checksum_batmap(ctx, &b);
2131
        err = vhd_validate_batmap(ctx, &b);
2132
        if (err)
2133
                goto out;
2134

    
2135
        off      = b.header.batmap_offset;
2136
        map_size = vhd_sectors_to_bytes(secs_round_up_no_zero(
2137
                        ctx->footer.curr_size >> (VHD_BLOCK_SHIFT + 3)));
2138
        ASSERT(vhd_sectors_to_bytes(b.header.batmap_size) >= map_size);
2139

    
2140
        err  = vhd_seek(ctx, off, SEEK_SET);
2141
        if (err)
2142
                goto out;
2143

    
2144
        err  = posix_memalign(&map, VHD_SECTOR_SIZE, map_size);
2145
        if (err) {
2146
                map = NULL;
2147
                err = -err;
2148
                goto out;
2149
        }
2150

    
2151
        memcpy(map, b.map, map_size);
2152

    
2153
        err  = vhd_write(ctx, map, map_size);
2154
        if (err)
2155
                goto out;
2156

    
2157
        err  = vhd_batmap_header_offset(ctx, &off);
2158
        if (err)
2159
                goto out;
2160

    
2161
        size = vhd_bytes_padded(sizeof(vhd_batmap_header_t));
2162

    
2163
        err  = vhd_seek(ctx, off, SEEK_SET);
2164
        if (err)
2165
                goto out;
2166

    
2167
        err  = posix_memalign(&buf, VHD_SECTOR_SIZE, size);
2168
        if (err) {
2169
                err = -err;
2170
                buf = NULL;
2171
                goto out;
2172
        }
2173

    
2174
        vhd_batmap_header_out(&b);
2175
        memset(buf, 0, size);
2176
        memcpy(buf, &b.header, sizeof(vhd_batmap_header_t));
2177

    
2178
        err  = vhd_write(ctx, buf, size);
2179

    
2180
out:
2181
        if (err)
2182
                VHDLOG("%s: failed writing batmap: %d\n", ctx->file, err);
2183
        free(buf);
2184
        free(map);
2185
        return 0;
2186
}
2187

    
2188
int
2189
vhd_write_bitmap(vhd_context_t *ctx, uint32_t block, char *bitmap)
2190
{
2191
        int err;
2192
        off64_t off;
2193
        uint64_t blk;
2194
        size_t size;
2195

    
2196
        if (!vhd_type_dynamic(ctx))
2197
                return -EINVAL;
2198

    
2199
        err = vhd_validate_bat(&ctx->bat);
2200
        if (err)
2201
                return err;
2202

    
2203
        if (block >= ctx->bat.entries)
2204
                return -ERANGE;
2205

    
2206
        if ((unsigned long)bitmap & (VHD_SECTOR_SIZE - 1))
2207
                return -EINVAL;
2208

    
2209
        blk  = ctx->bat.bat[block];
2210
        if (blk == DD_BLK_UNUSED)
2211
                return -EINVAL;
2212

    
2213
        off  = vhd_sectors_to_bytes(blk);
2214
        size = vhd_sectors_to_bytes(ctx->bm_secs);
2215

    
2216
        err  = vhd_seek(ctx, off, SEEK_SET);
2217
        if (err)
2218
                return err;
2219

    
2220
        err  = vhd_write(ctx, bitmap, size);
2221
        if (err)
2222
                return err;
2223

    
2224
        return 0;
2225
}
2226

    
2227
int
2228
vhd_write_block(vhd_context_t *ctx, uint32_t block, char *data)
2229
{
2230
        int err;
2231
        off64_t off;
2232
        size_t size;
2233
        uint64_t blk;
2234

    
2235
        if (!vhd_type_dynamic(ctx))
2236
                return -EINVAL;
2237

    
2238
        err = vhd_validate_bat(&ctx->bat);
2239
        if (err)
2240
                return err;
2241

    
2242
        if (block >= ctx->bat.entries)
2243
                return -ERANGE;
2244

    
2245
        if ((unsigned long)data & ~(VHD_SECTOR_SIZE -1))
2246
                return -EINVAL;
2247

    
2248
        blk  = ctx->bat.bat[block];
2249
        if (blk == DD_BLK_UNUSED)
2250
                return -EINVAL;
2251

    
2252
        off  = vhd_sectors_to_bytes(blk + ctx->bm_secs);
2253
        size = vhd_sectors_to_bytes(ctx->spb);
2254

    
2255
        err  = vhd_seek(ctx, off, SEEK_SET);
2256
        if (err)
2257
                return err;
2258

    
2259
        err  = vhd_write(ctx, data, size);
2260
        if (err)
2261
                return err;
2262

    
2263
        return 0;
2264
}
2265

    
2266
static inline int
2267
namedup(char **dup, const char *name)
2268
{
2269
        *dup = NULL;
2270

    
2271
        if (strnlen(name, MAX_NAME_LEN) >= MAX_NAME_LEN)
2272
                return -ENAMETOOLONG;
2273
        
2274
        *dup = strdup(name);
2275
        if (*dup == NULL)
2276
                return -ENOMEM;
2277

    
2278
        return 0;
2279
}
2280

    
2281
#define vwrite (ssize_t (*)(int, void *, size_t))write
2282
#define vpwrite (ssize_t (*)(int, void *, size_t, off_t))pwrite
2283

    
2284
static ssize_t
2285
vhd_atomic_pio(ssize_t (*f) (int, void *, size_t, off_t),
2286
               int fd, void *_s, size_t n, off_t off)
2287
{
2288
        char *s = _s;
2289
        size_t pos = 0;
2290
        ssize_t res;
2291
        struct stat st;
2292

    
2293
        memset(&st, 0, sizeof(st));
2294

    
2295
        for (;;) {
2296
                res = (f) (fd, s + pos, n - pos, off + pos);
2297
                switch (res) {
2298
                case -1:
2299
                        if (errno == EINTR || errno == EAGAIN)
2300
                                continue;
2301
                        else
2302
                                return 0;
2303
                        break;
2304
                case 0:
2305
                        errno = EPIPE;
2306
                        return pos;
2307
                }
2308

    
2309
                if (pos + res == n)
2310
                        return n;
2311

    
2312
                if (!st.st_size)
2313
                        if (fstat(fd, &st) == -1)
2314
                                return -1;
2315

    
2316
                if (off + pos + res == st.st_size)
2317
                        return pos + res;
2318

    
2319
                pos += (res & ~(VHD_SECTOR_SIZE - 1));
2320
        }
2321

    
2322
        return -1;
2323
}
2324

    
2325
static ssize_t
2326
vhd_atomic_io(ssize_t (*f) (int, void *, size_t), int fd, void *_s, size_t n)
2327
{
2328
        off64_t off;
2329
        ssize_t res;
2330
        ssize_t (*pf) (int, void *, size_t, off_t);
2331

    
2332
        off = lseek64(fd, 0, SEEK_CUR);
2333
        if (off == (off_t)-1)
2334
                return -1;
2335

    
2336
        pf = (f == read ? pread : vpwrite);
2337
        res = vhd_atomic_pio(pf, fd, _s, n, off);
2338

    
2339
        if (res > 0)
2340
                if (lseek64(fd, off + res, SEEK_SET) == (off64_t)-1)
2341
                        return -1;
2342

    
2343
        return res;
2344
}
2345

    
2346
int
2347
vhd_seek(vhd_context_t *ctx, off64_t offset, int whence)
2348
{
2349
        off64_t off;
2350

    
2351
        off = lseek64(ctx->fd, offset, whence);
2352
        if (off == (off64_t)-1) {
2353
                VHDLOG("%s: seek(0x%08"PRIx64", %d) failed: %d\n",
2354
                       ctx->file, offset, whence, -errno);
2355
                return -errno;
2356
        }
2357

    
2358
        return 0;
2359
}
2360

    
2361
off64_t
2362
vhd_position(vhd_context_t *ctx)
2363
{
2364
        return lseek64(ctx->fd, 0, SEEK_CUR);
2365
}
2366

    
2367
int
2368
vhd_read(vhd_context_t *ctx, void *buf, size_t size)
2369
{
2370
        size_t ret;
2371

    
2372
        errno = 0;
2373

    
2374
        ret = vhd_atomic_io(read, ctx->fd, buf, size);
2375
        if (ret == size)
2376
                return 0;
2377

    
2378
        VHDLOG("%s: read of %zu returned %zd, errno: %d\n",
2379
               ctx->file, size, ret, -errno);
2380

    
2381
        return (errno ? -errno : -EIO);
2382
}
2383

    
2384
int
2385
vhd_write(vhd_context_t *ctx, void *buf, size_t size)
2386
{
2387
        size_t ret;
2388

    
2389
        errno = 0;
2390

    
2391
        ret = vhd_atomic_io(vwrite, ctx->fd, buf, size);
2392
        if (ret == size)
2393
                return 0;
2394

    
2395
        VHDLOG("%s: write of %zu returned %zd, errno: %d\n",
2396
               ctx->file, size, ret, -errno);
2397

    
2398
        return (errno ? -errno : -EIO);
2399
}
2400

    
2401
static int
2402
vhd_pread(vhd_context_t *ctx, void *buf, size_t size, off64_t offset)
2403
{
2404
        ssize_t ret;
2405

    
2406
        errno = 0;
2407

    
2408
        ret = vhd_atomic_pio(pread, ctx->fd, buf, size, offset);
2409
        if (ret == size)
2410
                return 0;
2411

    
2412
        VHDLOG("%s: pread of %zu returned %zd, errno: %d\n",
2413
               ctx->file, size, ret, -errno);
2414

    
2415
        return (errno ? -errno : -EIO);
2416
}
2417

    
2418
static int
2419
vhd_pwrite(vhd_context_t *ctx, void *buf, size_t size, off64_t offset)
2420
{
2421
        ssize_t ret;
2422

    
2423
        errno = 0;
2424

    
2425
        ret = vhd_atomic_pio(vpwrite, ctx->fd, buf, size, offset);
2426
        if (ret == size)
2427
                return 0;
2428

    
2429
        VHDLOG("%s: pwrite of %zu returned %zd, errno: %d\n",
2430
               ctx->file, size, ret, -errno);
2431

    
2432
        return (errno ? -errno : -EIO);
2433
}
2434

    
2435
int
2436
vhd_offset(vhd_context_t *ctx, uint32_t sector, uint32_t *offset)
2437
{
2438
        int err;
2439
        uint32_t block;
2440

    
2441
        if (!vhd_type_dynamic(ctx))
2442
                return sector;
2443

    
2444
        err = vhd_get_bat(ctx);
2445
        if (err)
2446
                return err;
2447

    
2448
        block = sector / ctx->spb;
2449
        if (ctx->bat.bat[block] == DD_BLK_UNUSED)
2450
                *offset = DD_BLK_UNUSED;
2451
        else
2452
                *offset = ctx->bat.bat[block] +
2453
                        ctx->bm_secs + (sector % ctx->spb);
2454

    
2455
        return 0;
2456
}
2457

    
2458
int
2459
vhd_open_fast(vhd_context_t *ctx)
2460
{
2461
        int err;
2462
        void *buf;
2463
        size_t size;
2464

    
2465
        size = sizeof(vhd_footer_t) + sizeof(vhd_header_t);
2466
        err  = posix_memalign(&buf, VHD_SECTOR_SIZE, size);
2467
        if (err) {
2468
                VHDLOG("failed allocating %s: %d\n", ctx->file, -err);
2469
                return -err;
2470
        }
2471

    
2472
        err = vhd_read(ctx, buf, size);
2473
        if (err) {
2474
                VHDLOG("failed reading %s: %d\n", ctx->file, err);
2475
                goto out;
2476
        }
2477

    
2478
        memcpy(&ctx->footer, buf, sizeof(vhd_footer_t));
2479
        vhd_footer_in(&ctx->footer);
2480
        err = vhd_validate_footer(&ctx->footer);
2481
        if (err)
2482
                goto out;
2483

    
2484
        if (vhd_type_dynamic(ctx)) {
2485
                if (ctx->footer.data_offset != sizeof(vhd_footer_t))
2486
                        err = vhd_read_header(ctx, &ctx->header);
2487
                else {
2488
                        memcpy(&ctx->header,
2489
                               buf + sizeof(vhd_footer_t),
2490
                               sizeof(vhd_header_t));
2491
                        vhd_header_in(&ctx->header);
2492
                        err = vhd_validate_header(&ctx->header);
2493
                }
2494

    
2495
                if (err)
2496
                        goto out;
2497

    
2498
                ctx->spb     = ctx->header.block_size >> VHD_SECTOR_SHIFT;
2499
                ctx->bm_secs = secs_round_up_no_zero(ctx->spb >> 3);
2500
        }
2501

    
2502
out:
2503
        free(buf);
2504
        return err;
2505
}
2506

    
2507
int
2508
vhd_open(vhd_context_t *ctx, const char *file, int flags)
2509
{
2510
        int i, err, oflags;
2511

    
2512
        if (flags & VHD_OPEN_STRICT)
2513
                vhd_flag_clear(flags, VHD_OPEN_FAST);
2514

    
2515
        memset(ctx, 0, sizeof(vhd_context_t));
2516
        vhd_cache_init(ctx);
2517

    
2518
        ctx->fd     = -1;
2519
        ctx->oflags = flags;
2520

    
2521
        err = namedup(&ctx->file, file);
2522
        if (err)
2523
                return err;
2524

    
2525
        oflags = O_LARGEFILE;
2526
        if (!(flags & VHD_OPEN_CACHED))
2527
                oflags |= O_DIRECT;
2528
        if (flags & VHD_OPEN_RDONLY)
2529
                oflags |= O_RDONLY;
2530
        if (flags & VHD_OPEN_RDWR)
2531
                oflags |= O_RDWR;
2532

    
2533
        ctx->fd = open(ctx->file, oflags, 0644);
2534
        if (ctx->fd == -1) {
2535
                err = -errno;
2536
                VHDLOG("failed to open %s: %d\n", ctx->file, err);
2537
                goto fail;
2538
        }
2539

    
2540
        err = vhd_test_file_fixed(ctx->file, &ctx->is_block);
2541
        if (err)
2542
                goto fail;
2543

    
2544
        if (flags & VHD_OPEN_FAST) {
2545
                err = vhd_open_fast(ctx);
2546
                if (err)
2547
                        goto fail;
2548

    
2549
                return 0;
2550
        }
2551

    
2552
        err = vhd_read_footer(ctx, &ctx->footer);
2553
        if (err)
2554
                goto fail;
2555

    
2556
        if (!(flags & VHD_OPEN_IGNORE_DISABLED) && vhd_disabled(ctx)) {
2557
                err = -EINVAL;
2558
                goto fail;
2559
        }
2560

    
2561
        if (vhd_type_dynamic(ctx)) {
2562
                for (i = 0; i < VHD_HEADER_MAX_RETRIES; i++) {
2563
                        err = vhd_read_header(ctx, &ctx->header);
2564
                        if (!err)
2565
                                break;
2566
                        VHDLOG("Error reading header, retry %d\n", i);
2567
                        sleep(1);
2568
                }
2569
                if (err)
2570
                        goto fail;
2571

    
2572
                ctx->spb     = ctx->header.block_size >> VHD_SECTOR_SHIFT;
2573
                ctx->bm_secs = secs_round_up_no_zero(ctx->spb >> 3);
2574
        }
2575

    
2576
        err = vhd_cache_load(ctx);
2577
        if (err) {
2578
                VHDLOG("failed to load cache: %d\n", err);
2579
                goto fail;
2580
        }
2581

    
2582
        return 0;
2583

    
2584
fail:
2585
        if (ctx->fd != -1)
2586
                close(ctx->fd);
2587
        free(ctx->file);
2588
        memset(ctx, 0, sizeof(vhd_context_t));
2589
        return err;
2590
}
2591

    
2592
void
2593
vhd_close(vhd_context_t *ctx)
2594
{
2595
        vhd_cache_unload(ctx);
2596

    
2597
        if (ctx->file) {
2598
                fsync(ctx->fd);
2599
                close(ctx->fd);
2600
        }
2601

    
2602
        free(ctx->file);
2603
        free(ctx->bat.bat);
2604
        free(ctx->batmap.map);
2605
        memset(ctx, 0, sizeof(vhd_context_t));
2606
}
2607

    
2608
static inline void
2609
vhd_initialize_footer(vhd_context_t *ctx, int type, uint64_t size)
2610
{
2611
        memset(&ctx->footer, 0, sizeof(vhd_footer_t));
2612
        memcpy(ctx->footer.cookie, HD_COOKIE, sizeof(ctx->footer.cookie));
2613
        ctx->footer.features     = HD_RESERVED;
2614
        ctx->footer.ff_version   = HD_FF_VERSION;
2615
        ctx->footer.timestamp    = vhd_time(time(NULL));
2616
        ctx->footer.crtr_ver     = VHD_CURRENT_VERSION;
2617
        ctx->footer.crtr_os      = 0x00000000;
2618
        ctx->footer.orig_size    = size;
2619
        ctx->footer.curr_size    = size;
2620
        ctx->footer.geometry     = vhd_chs(size);
2621
        ctx->footer.type         = type;
2622
        ctx->footer.saved        = 0;
2623
        ctx->footer.data_offset  = 0xFFFFFFFFFFFFFFFFULL;
2624
        strcpy(ctx->footer.crtr_app, "tap");
2625
        uuid_generate(ctx->footer.uuid);
2626
}
2627

    
2628
int
2629
vhd_initialize_header_parent_name(vhd_context_t *ctx, const char *parent_path)
2630
{
2631
        int err;
2632
        iconv_t cd;
2633
        size_t ibl, obl;
2634
        char *pname, *ppath, *dst;
2635

    
2636
        err   = 0;
2637
        pname = NULL;
2638
        ppath = NULL;
2639

    
2640
        /*
2641
         * MICROSOFT_COMPAT
2642
         * big endian unicode here 
2643
         */
2644
        cd = iconv_open(UTF_16BE, "ASCII");
2645
        if (cd == (iconv_t)-1) {
2646
                err = -errno;
2647
                goto out;
2648
        }
2649

    
2650
        ppath = strdup(parent_path);
2651
        if (!ppath) {
2652
                err = -ENOMEM;
2653
                goto out;
2654
        }
2655

    
2656
        pname = basename(ppath);
2657
        if (!strcmp(pname, "")) {
2658
                err = -EINVAL;
2659
                goto out;
2660
        }
2661

    
2662
        ibl = strlen(pname);
2663
        obl = sizeof(ctx->header.prt_name);
2664
        dst = ctx->header.prt_name;
2665

    
2666
        memset(dst, 0, obl);
2667

    
2668
        if (iconv(cd, &pname, &ibl, &dst, &obl) == (size_t)-1 || ibl)
2669
                err = (errno ? -errno : -EINVAL);
2670

    
2671
out:
2672
        iconv_close(cd);
2673
        free(ppath);
2674
        return err;
2675
}
2676

    
2677
static off64_t
2678
get_file_size(const char *name)
2679
{
2680
        int fd;
2681
        off64_t end;
2682

    
2683
        fd = open(name, O_LARGEFILE | O_RDONLY);
2684
        if (fd == -1) {
2685
                VHDLOG("unable to open '%s': %d\n", name, errno);
2686
                return -errno;
2687
        }
2688
        end = lseek64(fd, 0, SEEK_END);
2689
        close(fd); 
2690
        return end;
2691
}
2692

    
2693
static int
2694
vhd_initialize_header(vhd_context_t *ctx, const char *parent_path, 
2695
                uint64_t size, int raw, uint64_t *psize)
2696
{
2697
        int err;
2698
        struct stat stats;
2699
        vhd_context_t parent;
2700

    
2701
        if (!vhd_type_dynamic(ctx))
2702
                return -EINVAL;
2703

    
2704
        memset(&ctx->header, 0, sizeof(vhd_header_t));
2705
        memcpy(ctx->header.cookie, DD_COOKIE, sizeof(ctx->header.cookie));
2706
        ctx->header.data_offset  = (uint64_t)-1;
2707
        ctx->header.table_offset = VHD_SECTOR_SIZE * 3; /* 1 ftr + 2 hdr */
2708
        ctx->header.hdr_ver      = DD_VERSION;
2709
        ctx->header.block_size   = VHD_BLOCK_SIZE;
2710
        ctx->header.prt_ts       = 0;
2711
        ctx->header.res1         = 0;
2712
        ctx->header.max_bat_size = (ctx->footer.curr_size +
2713
                        VHD_BLOCK_SIZE - 1) >> VHD_BLOCK_SHIFT;
2714

    
2715
        ctx->footer.data_offset  = VHD_SECTOR_SIZE;
2716

    
2717
        if (ctx->footer.type == HD_TYPE_DYNAMIC)
2718
                return 0;
2719

    
2720
        err = stat(parent_path, &stats);
2721
        if (err == -1)
2722
                return -errno;
2723

    
2724
        if (raw) {
2725
                ctx->header.prt_ts = vhd_time(stats.st_mtime);
2726
                *psize = get_file_size(parent_path);
2727
                if (!size)
2728
                        size = *psize;
2729
        }
2730
        else {
2731
                err = vhd_open(&parent, parent_path, VHD_OPEN_RDONLY);
2732
                if (err)
2733
                        return err;
2734

    
2735
                ctx->header.prt_ts = vhd_time(stats.st_mtime);
2736
                uuid_copy(ctx->header.prt_uuid, parent.footer.uuid);
2737
                *psize = parent.footer.curr_size;
2738
                if (!size)
2739
                        size = *psize;
2740
                vhd_close(&parent);
2741
        }
2742
        if (size < *psize) {
2743
                VHDLOG("snapshot size (%"PRIu64") < parent size (%"PRIu64")\n",
2744
                                size, *psize);
2745
                return -EINVAL;
2746
        }
2747
        ctx->footer.orig_size    = size;
2748
        ctx->footer.curr_size    = size;
2749
        ctx->footer.geometry     = vhd_chs(size);
2750
        ctx->header.max_bat_size = 
2751
                (size + VHD_BLOCK_SIZE - 1) >> VHD_BLOCK_SHIFT;
2752

    
2753
        return vhd_initialize_header_parent_name(ctx, parent_path);
2754
}
2755

    
2756
int
2757
vhd_write_parent_locators(vhd_context_t *ctx, const char *parent)
2758
{
2759
        int i, err;
2760
        off64_t off;
2761
        uint32_t code;
2762

    
2763
        code = PLAT_CODE_NONE;
2764

    
2765
        if (ctx->footer.type != HD_TYPE_DIFF)
2766
                return -EINVAL;
2767

    
2768
        off = ctx->batmap.header.batmap_offset + 
2769
                vhd_sectors_to_bytes(ctx->batmap.header.batmap_size);
2770
        if (off & (VHD_SECTOR_SIZE - 1))
2771
                off = vhd_bytes_padded(off);
2772

    
2773
        for (i = 0; i < 3; i++) {
2774
                switch (i) {
2775
                case 0:
2776
                        code = PLAT_CODE_MACX;
2777
                        break;
2778
                case 1:
2779
                        code = PLAT_CODE_W2KU;
2780
                        break;
2781
                case 2:
2782
                        code = PLAT_CODE_W2RU;
2783
                        break;
2784
                }
2785

    
2786
                err = vhd_parent_locator_write_at(ctx, parent, off, code,
2787
                                                  0, ctx->header.loc + i);
2788
                if (err)
2789
                        return err;
2790

    
2791
                off += vhd_parent_locator_size(ctx->header.loc + i);
2792
        }
2793

    
2794
        return 0;
2795
}
2796

    
2797
int
2798
vhd_change_parent(vhd_context_t *child, char *parent_path, int raw)
2799
{
2800
        int i, err;
2801
        char *ppath;
2802
        struct stat stats;
2803
        vhd_context_t parent;
2804
        char __parent_path[PATH_MAX];
2805

    
2806
        ppath = realpath(parent_path, __parent_path);
2807
        if (!ppath) {
2808
                VHDLOG("error resolving parent path %s for %s: %d\n",
2809
                       parent_path, child->file, errno);
2810
                return -errno;
2811
        }
2812

    
2813
        err = stat(ppath, &stats);
2814
        if (err == -1) {
2815
                err = -errno;
2816
                goto out;
2817
        }
2818

    
2819
        if (!S_ISREG(stats.st_mode) && !S_ISBLK(stats.st_mode)) {
2820
                err = -EINVAL;
2821
                goto out;
2822
        }
2823

    
2824
        if (raw) {
2825
                uuid_clear(child->header.prt_uuid);
2826
        } else {
2827
                err = vhd_open(&parent, ppath, VHD_OPEN_RDONLY);
2828
                if (err) {
2829
                        VHDLOG("error opening parent %s for %s: %d\n",
2830
                               ppath, child->file, err);
2831
                        goto out;
2832
                }
2833
                uuid_copy(child->header.prt_uuid, parent.footer.uuid);
2834
                vhd_close(&parent);
2835
        }
2836

    
2837
        vhd_initialize_header_parent_name(child, ppath);
2838
        child->header.prt_ts = vhd_time(stats.st_mtime);
2839

    
2840
        for (i = 0; i < vhd_parent_locator_count(child); i++) {
2841
                vhd_parent_locator_t *loc = child->header.loc + i;
2842
                size_t max = vhd_parent_locator_size(loc);
2843

    
2844
                switch (loc->code) {
2845
                case PLAT_CODE_MACX:
2846
                case PLAT_CODE_W2KU:
2847
                case PLAT_CODE_W2RU:
2848
                        break;
2849
                default:
2850
                        continue;
2851
                }
2852

    
2853
                err = vhd_parent_locator_write_at(child, ppath,
2854
                                                  loc->data_offset,
2855
                                                  loc->code, max, loc);
2856
                if (err) {
2857
                        VHDLOG("error writing parent locator %d for %s: %d\n",
2858
                               i, child->file, err);
2859
                        goto out;
2860
                }
2861
        }
2862

    
2863
        TEST_FAIL_AT(FAIL_REPARENT_LOCATOR);
2864

    
2865
        err = vhd_write_header(child, &child->header);
2866
        if (err) {
2867
                VHDLOG("error writing header for %s: %d\n", child->file, err);
2868
                goto out;
2869
        }
2870

    
2871
        err = 0;
2872

    
2873
out:
2874
        return err;
2875
}
2876

    
2877
static int
2878
vhd_create_batmap(vhd_context_t *ctx)
2879
{
2880
        off64_t off;
2881
        int err, map_bytes;
2882
        vhd_batmap_header_t *header;
2883
        void *map;
2884

    
2885
        if (!vhd_type_dynamic(ctx))
2886
                return -EINVAL;
2887

    
2888
        map_bytes = (ctx->header.max_bat_size + 7) >> 3;
2889
        header    = &ctx->batmap.header;
2890

    
2891
        memset(header, 0, sizeof(vhd_batmap_header_t));
2892
        memcpy(header->cookie, VHD_BATMAP_COOKIE, sizeof(header->cookie));
2893

    
2894
        err = vhd_batmap_header_offset(ctx, &off);
2895
        if (err)
2896
                return err;
2897

    
2898
        header->batmap_offset  = off +
2899
                vhd_bytes_padded(sizeof(vhd_batmap_header_t));
2900
        header->batmap_size    = secs_round_up_no_zero(map_bytes);
2901
        header->batmap_version = VHD_BATMAP_CURRENT_VERSION;
2902

    
2903
        map_bytes = vhd_sectors_to_bytes(header->batmap_size);
2904

    
2905
        err = posix_memalign(&map, VHD_SECTOR_SIZE, map_bytes);
2906
        if (err)
2907
                return -err;
2908

    
2909
        memset(map, 0, map_bytes);
2910
        ctx->batmap.map = map;
2911

    
2912
        return vhd_write_batmap(ctx, &ctx->batmap);
2913
}
2914

    
2915
static int
2916
vhd_create_bat(vhd_context_t *ctx)
2917
{
2918
        int i, err;
2919
        size_t size;
2920
        void *bat;
2921

    
2922
        if (!vhd_type_dynamic(ctx))
2923
                return -EINVAL;
2924

    
2925
        size = vhd_bytes_padded(ctx->header.max_bat_size * sizeof(uint32_t));
2926
        err  = posix_memalign(&bat, VHD_SECTOR_SIZE, size);
2927
        if (err)
2928
                return err;
2929

    
2930
        ctx->bat.bat = bat;
2931

    
2932
        memset(ctx->bat.bat, 0, size);
2933
        for (i = 0; i < ctx->header.max_bat_size; i++)
2934
                ctx->bat.bat[i] = DD_BLK_UNUSED;
2935

    
2936
        err = vhd_seek(ctx, ctx->header.table_offset, SEEK_SET);
2937
        if (err)
2938
                return err;
2939

    
2940
        ctx->bat.entries = ctx->header.max_bat_size;
2941
        ctx->bat.spb     = ctx->header.block_size >> VHD_SECTOR_SHIFT;
2942

    
2943
        return vhd_write_bat(ctx, &ctx->bat);
2944
}
2945

    
2946
static int
2947
vhd_initialize_fixed_disk(vhd_context_t *ctx)
2948
{
2949
        char *buf;
2950
        int i, err;
2951

    
2952
        if (ctx->footer.type != HD_TYPE_FIXED)
2953
                return -EINVAL;
2954

    
2955
        err = vhd_seek(ctx, 0, SEEK_SET);
2956
        if (err)
2957
                return err;
2958

    
2959
        buf = mmap(0, VHD_BLOCK_SIZE, PROT_READ,
2960
                   MAP_SHARED | MAP_ANONYMOUS, -1, 0);
2961
        if (buf == MAP_FAILED)
2962
                return -errno;
2963

    
2964
        for (i = 0; i < ctx->footer.curr_size >> VHD_BLOCK_SHIFT; i++) {
2965
                err = vhd_write(ctx, buf, VHD_BLOCK_SIZE);
2966
                if (err)
2967
                        goto out;
2968
        }
2969

    
2970
        err = 0;
2971

    
2972
out:
2973
        munmap(buf, VHD_BLOCK_SIZE);
2974
        return err;
2975
}
2976

    
2977
int 
2978
vhd_get_phys_size(vhd_context_t *ctx, off64_t *size)
2979
{
2980
        int err;
2981

    
2982
        if ((err = vhd_end_of_data(ctx, size)))
2983
                return err;
2984
        *size += sizeof(vhd_footer_t);
2985
        return 0;
2986
}
2987

    
2988
int 
2989
vhd_set_phys_size(vhd_context_t *ctx, off64_t size)
2990
{
2991
        off64_t phys_size;
2992
        int err;
2993

    
2994
        err = vhd_get_phys_size(ctx, &phys_size);
2995
        if (err)
2996
                return err;
2997
        if (size < phys_size) {
2998
                // would result in data loss
2999
                VHDLOG("ERROR: new size (%"PRIu64") < phys size (%"PRIu64")\n",
3000
                                size, phys_size);
3001
                return -EINVAL;
3002
        }
3003
        return vhd_write_footer_at(ctx, &ctx->footer, 
3004
                        size - sizeof(vhd_footer_t));
3005
}
3006

    
3007
static int
3008
vhd_set_virt_size_no_write(vhd_context_t *ctx, uint64_t size)
3009
{
3010
        if ((size >> VHD_BLOCK_SHIFT) > ctx->header.max_bat_size) {
3011
                VHDLOG("not enough metadata space reserved for fast "
3012
                                "resize (BAT size %u, need %"PRIu64")\n",
3013
                                ctx->header.max_bat_size, 
3014
                                size >> VHD_BLOCK_SHIFT);
3015
                return -EINVAL;
3016
        }
3017

    
3018
        /* update footer */
3019
        ctx->footer.curr_size = size;
3020
        ctx->footer.geometry  = vhd_chs(ctx->footer.curr_size);
3021
        ctx->footer.checksum  = vhd_checksum_footer(&ctx->footer);
3022
        return 0;
3023
}
3024

    
3025
int
3026
vhd_set_virt_size(vhd_context_t *ctx, uint64_t size)
3027
{
3028
        int err;
3029

    
3030
        err = vhd_set_virt_size_no_write(ctx, size);
3031
        if (err)
3032
                return err;
3033
        return vhd_write_footer(ctx, &ctx->footer);
3034
}
3035

    
3036
static int
3037
__vhd_create(const char *name, const char *parent, uint64_t bytes, int type,
3038
                uint64_t mbytes, vhd_flag_creat_t flags)
3039
{
3040
        int err;
3041
        off64_t off;
3042
        vhd_context_t ctx;
3043
        uint64_t size, psize, blks;
3044

    
3045
        switch (type) {
3046
        case HD_TYPE_DIFF:
3047
                if (!parent)
3048
                        return -EINVAL;
3049
        case HD_TYPE_FIXED:
3050
        case HD_TYPE_DYNAMIC:
3051
                break;
3052
        default:
3053
                return -EINVAL;
3054
        }
3055

    
3056
        if (strnlen(name, VHD_MAX_NAME_LEN - 1) == VHD_MAX_NAME_LEN - 1)
3057
                return -ENAMETOOLONG;
3058

    
3059
        if (bytes && mbytes && mbytes < bytes)
3060
                return -EINVAL;
3061

    
3062
        memset(&ctx, 0, sizeof(vhd_context_t));
3063
        psize = 0;
3064
        blks   = (bytes + VHD_BLOCK_SIZE - 1) >> VHD_BLOCK_SHIFT;
3065
        /* If mbytes is provided (virtual-size-for-metadata-preallocation),
3066
         * create the VHD of size mbytes, which will create the BAT & the 
3067
         * batmap of the appropriate size. Once the BAT & batmap are 
3068
         * initialized, reset the virtual size to the requested one.
3069
         */
3070
        if (mbytes)
3071
                blks = (mbytes + VHD_BLOCK_SIZE - 1) >> VHD_BLOCK_SHIFT;
3072
        size = blks << VHD_BLOCK_SHIFT;
3073

    
3074
        ctx.fd = open(name, O_WRONLY | O_CREAT |
3075
                      O_TRUNC | O_LARGEFILE | O_DIRECT, 0644);
3076
        if (ctx.fd == -1)
3077
                return -errno;
3078

    
3079
        ctx.file = strdup(name);
3080
        if (!ctx.file) {
3081
                err = -ENOMEM;
3082
                goto out;
3083
        }
3084

    
3085
        err = vhd_test_file_fixed(ctx.file, &ctx.is_block);
3086
        if (err)
3087
                goto out;
3088

    
3089
        vhd_initialize_footer(&ctx, type, size);
3090

    
3091
        if (type == HD_TYPE_FIXED) {
3092
                err = vhd_initialize_fixed_disk(&ctx);
3093
                if (err)
3094
                        goto out;
3095
        } else {
3096
                int raw = vhd_flag_test(flags, VHD_FLAG_CREAT_PARENT_RAW);
3097
                err = vhd_initialize_header(&ctx, parent, size, raw, &psize);
3098
                if (err)
3099
                        goto out;
3100

    
3101
                err = vhd_create_batmap(&ctx);
3102
                if (err)
3103
                        goto out;
3104

    
3105
                err = vhd_create_bat(&ctx);
3106
                if (err)
3107
                        goto out;
3108

    
3109
                if (type == HD_TYPE_DIFF) {
3110
                        err = vhd_write_parent_locators(&ctx, parent);
3111
                        if (err)
3112
                                goto out;
3113
                }
3114
        }
3115

    
3116
        if (mbytes) {
3117
                /* set the virtual size to the requested size */
3118
                if (bytes) {
3119
                        blks = (bytes + VHD_BLOCK_SIZE - 1) >> VHD_BLOCK_SHIFT;
3120
                        size = blks << VHD_BLOCK_SHIFT;
3121

    
3122
                }
3123
                else {
3124
                        size = psize;
3125
                }
3126
                ctx.footer.orig_size = size;
3127
                err = vhd_set_virt_size_no_write(&ctx, size);
3128
                if (err)
3129
                        goto out;
3130
        }
3131

    
3132
        if (type != HD_TYPE_FIXED) {
3133
                err = vhd_write_footer_at(&ctx, &ctx.footer, 0);
3134
                if (err)
3135
                        goto out;
3136

    
3137
                err = vhd_write_header_at(&ctx, &ctx.header, VHD_SECTOR_SIZE);
3138
                if (err)
3139
                        goto out;
3140
        }
3141

    
3142
        err = vhd_seek(&ctx, 0, SEEK_END);
3143
        if (err)
3144
                goto out;
3145

    
3146
        off = vhd_position(&ctx);
3147
        if (off == (off64_t)-1) {
3148
                err = -errno;
3149
                goto out;
3150
        }
3151

    
3152
        if (ctx.is_block)
3153
                off -= sizeof(vhd_footer_t);
3154

    
3155
        err = vhd_write_footer_at(&ctx, &ctx.footer, off);
3156
        if (err)
3157
                goto out;
3158

    
3159
        err = 0;
3160

    
3161
out:
3162
        vhd_close(&ctx);
3163
        if (err && !ctx.is_block)
3164
                unlink(name);
3165
        return err;
3166
}
3167

    
3168
int
3169
vhd_create(const char *name, uint64_t bytes, int type, uint64_t mbytes,
3170
                vhd_flag_creat_t flags)
3171
{
3172
        return __vhd_create(name, NULL, bytes, type, mbytes, flags);
3173
}
3174

    
3175
int
3176
vhd_snapshot(const char *name, uint64_t bytes, const char *parent,
3177
                uint64_t mbytes, vhd_flag_creat_t flags)
3178
{
3179
        return __vhd_create(name, parent, bytes, HD_TYPE_DIFF, mbytes, flags);
3180
}
3181

    
3182
static int
3183
__vhd_io_fixed_read(vhd_context_t *ctx,
3184
                    char *buf, uint64_t sec, uint32_t secs)
3185
{
3186
        int err;
3187

    
3188
        err = vhd_seek(ctx, vhd_sectors_to_bytes(sec), SEEK_SET);
3189
        if (err)
3190
                return err;
3191

    
3192
        return vhd_read(ctx, buf, vhd_sectors_to_bytes(secs));
3193
}
3194

    
3195
static void
3196
__vhd_io_dynamic_copy_data(vhd_context_t *ctx,
3197
                           char *map, int map_off,
3198
                           char *bitmap, int bitmap_off,
3199
                           char *dst, char *src, int secs)
3200
{
3201
        int i;
3202

    
3203
        for (i = 0; i < secs; i++) {
3204
                if (test_bit(map, map_off + i))
3205
                        goto next;
3206

    
3207
                if (ctx && !vhd_bitmap_test(ctx, bitmap, bitmap_off + i))
3208
                        goto next;
3209

    
3210
                memcpy(dst, src, VHD_SECTOR_SIZE);
3211
                set_bit(map, map_off + i);
3212

    
3213
        next:
3214
                src += VHD_SECTOR_SIZE;
3215
                dst += VHD_SECTOR_SIZE;
3216
        }
3217
}
3218

    
3219
static int
3220
__vhd_io_dynamic_read_link(vhd_context_t *ctx, char *map,
3221
                           char *buf, uint64_t sector, uint32_t secs)
3222
{
3223
        off64_t off;
3224
        uint32_t blk, sec;
3225
        int err, cnt, map_off;
3226
        char *bitmap, *data, *src;
3227

    
3228
        map_off = 0;
3229

    
3230
        do {
3231
                blk    = sector / ctx->spb;
3232
                sec    = sector % ctx->spb;
3233
                off    = ctx->bat.bat[blk];
3234
                data   = NULL;
3235
                bitmap = NULL;
3236

    
3237
                if (off == DD_BLK_UNUSED) {
3238
                        cnt = MIN(secs, ctx->spb);
3239
                        goto next;
3240
                }
3241

    
3242
                err = vhd_read_bitmap(ctx, blk, &bitmap);
3243
                if (err)
3244
                        return err;
3245

    
3246
                err = vhd_read_block(ctx, blk, &data);
3247
                if (err) {
3248
                        free(bitmap);
3249
                        return err;
3250
                }
3251

    
3252
                cnt = MIN(secs, ctx->spb - sec);
3253
                src = data + vhd_sectors_to_bytes(sec);
3254

    
3255
                __vhd_io_dynamic_copy_data(ctx,
3256
                                           map, map_off,
3257
                                           bitmap, sec,
3258
                                           buf, src, cnt);
3259

    
3260
        next:
3261
                free(data);
3262
                free(bitmap);
3263

    
3264
                secs    -= cnt;
3265
                sector  += cnt;
3266
                map_off += cnt;
3267
                buf     += vhd_sectors_to_bytes(cnt);
3268

    
3269
        } while (secs);
3270

    
3271
        return 0;
3272
}
3273

    
3274
static int
3275
__raw_read_link(char *filename,
3276
                char *map, char *buf, uint64_t sec, uint32_t secs)
3277
{
3278
        int fd, err;
3279
        off64_t off;
3280
        uint64_t size;
3281
        void *data;
3282

    
3283
        err = 0;
3284
        errno = 0;
3285
        fd = open(filename, O_RDONLY | O_DIRECT | O_LARGEFILE);
3286
        if (fd == -1) {
3287
                VHDLOG("%s: failed to open: %d\n", filename, -errno);
3288
                return -errno;
3289
        }
3290

    
3291
        off = lseek64(fd, vhd_sectors_to_bytes(sec), SEEK_SET);
3292
        if (off == (off64_t)-1) {
3293
                VHDLOG("%s: seek(0x%08"PRIx64") failed: %d\n",
3294
                       filename, vhd_sectors_to_bytes(sec), -errno);
3295
                err = -errno;
3296
                goto close;
3297
        }
3298

    
3299
        size = vhd_sectors_to_bytes(secs);
3300
        err = posix_memalign(&data, VHD_SECTOR_SIZE, size);
3301
        if (err)
3302
                goto close;
3303

    
3304
        err = read(fd, data, size);
3305
        if (err != size) {
3306
                VHDLOG("%s: reading of %"PRIu64" returned %d, errno: %d\n",
3307
                                filename, size, err, -errno);
3308
                free(data);
3309
                err = errno ? -errno : -EIO;
3310
                goto close;
3311
        }
3312
        __vhd_io_dynamic_copy_data(NULL, map, 0, NULL, 0, buf, data, secs);
3313
        free(data);
3314
        err = 0;
3315

    
3316
close:
3317
        close(fd);
3318
        return err;
3319
}
3320

    
3321
static int
3322
__vhd_io_dynamic_read(vhd_context_t *ctx,
3323
                      char *buf, uint64_t sec, uint32_t secs)
3324
{
3325
        int err;
3326
        uint32_t i, done;
3327
        char *map, *next;
3328
        vhd_context_t parent, *vhd;
3329

    
3330
        err  = vhd_get_bat(ctx);
3331
        if (err)
3332
                return err;
3333

    
3334
        vhd  = ctx;
3335
        next = NULL;
3336
        map  = calloc(1, secs << (VHD_SECTOR_SHIFT - 3));
3337
        if (!map)
3338
                return -ENOMEM;
3339

    
3340
        memset(buf, 0, vhd_sectors_to_bytes(secs));
3341

    
3342
        for (;;) {
3343
                err = __vhd_io_dynamic_read_link(vhd, map, buf, sec, secs);
3344
                if (err)
3345
                        goto close;
3346

    
3347
                for (done = 0, i = 0; i < secs; i++)
3348
                        if (test_bit(map, i))
3349
                                done++;
3350

    
3351
                if (done == secs) {
3352
                        err = 0;
3353
                        goto close;
3354
                }
3355

    
3356
                if (vhd->footer.type == HD_TYPE_DIFF) {
3357
                        vhd_context_t *p;
3358
                        p = vhd_cache_get_parent(vhd);
3359
                        if (p) {
3360
                                vhd = p;
3361
                                err = vhd_get_bat(vhd);
3362
                                if (err)
3363
                                        goto out;
3364
                                continue;
3365
                        }
3366

    
3367
                        err = vhd_parent_locator_get(vhd, &next);
3368
                        if (err)
3369
                                goto close;
3370
                        if (vhd_parent_raw(vhd)) {
3371
                                err = __raw_read_link(next, map, buf, sec,
3372
                                                secs);
3373
                                goto close;
3374
                        }
3375
                } else {
3376
                        err = 0;
3377
                        goto close;
3378
                }
3379

    
3380
                if (vhd != ctx)
3381
                        vhd_close(vhd);
3382
                vhd = &parent;
3383

    
3384
                err = vhd_open(vhd, next, VHD_OPEN_RDONLY);
3385
                if (err)
3386
                        goto out;
3387

    
3388
                err = vhd_get_bat(vhd);
3389
                if (err)
3390
                        goto close;
3391

    
3392
                free(next);
3393
                next = NULL;
3394
        }
3395

    
3396
close:
3397
        if (vhd != ctx && !vhd_flag_test(vhd->oflags, VHD_OPEN_CACHED))
3398
                vhd_close(vhd);
3399
out:
3400
        free(map);
3401
        free(next);
3402
        return err;
3403
}
3404

    
3405
int
3406
vhd_io_read(vhd_context_t *ctx, char *buf, uint64_t sec, uint32_t secs)
3407
{
3408
        if (vhd_sectors_to_bytes(sec + secs) > ctx->footer.curr_size)
3409
                return -ERANGE;
3410

    
3411
        if (!vhd_type_dynamic(ctx))
3412
                return __vhd_io_fixed_read(ctx, buf, sec, secs);
3413

    
3414
        return __vhd_io_dynamic_read(ctx, buf, sec, secs);
3415
}
3416

    
3417
static int
3418
__vhd_io_fixed_write(vhd_context_t *ctx,
3419
                     char *buf, uint64_t sec, uint32_t secs)
3420
{
3421
        int err;
3422

    
3423
        err = vhd_seek(ctx, vhd_sectors_to_bytes(sec), SEEK_SET);
3424
        if (err)
3425
                return err;
3426

    
3427
        return vhd_write(ctx, buf, vhd_sectors_to_bytes(secs));
3428
}
3429

    
3430
static int
3431
__vhd_io_allocate_block(vhd_context_t *ctx, uint32_t block)
3432
{
3433
        char *buf;
3434
        size_t size;
3435
        off64_t off, max;
3436
        int err, gap, spp, secs;
3437

    
3438
        spp = getpagesize() >> VHD_SECTOR_SHIFT;
3439

    
3440
        err = vhd_end_of_data(ctx, &max);
3441
        if (err)
3442
                return err;
3443

    
3444
        gap   = 0;
3445
        off   = max;
3446
        max >>= VHD_SECTOR_SHIFT;
3447

    
3448
        /* data region of segment should begin on page boundary */
3449
        if ((max + ctx->bm_secs) % spp) {
3450
                gap  = (spp - ((max + ctx->bm_secs) % spp));
3451
                max += gap;
3452
        }
3453

    
3454
        err = vhd_seek(ctx, off, SEEK_SET);
3455
        if (err)
3456
                return err;
3457

    
3458
        secs = ctx->bm_secs + gap;
3459
        if (!vhd_flag_test(ctx->oflags, VHD_OPEN_IO_WRITE_SPARSE))
3460
                secs += ctx->spb;
3461

    
3462
        size = vhd_sectors_to_bytes(secs);
3463
        buf  = mmap(0, size, PROT_READ, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
3464
        if (buf == MAP_FAILED)
3465
                return -errno;
3466

    
3467
        err = vhd_write(ctx, buf, size);
3468
        if (err)
3469
                goto out;
3470

    
3471
        ctx->bat.bat[block] = max;
3472
        err = vhd_write_bat(ctx, &ctx->bat);
3473
        if (err)
3474
                goto out;
3475

    
3476
        err = 0;
3477

    
3478
out:
3479
        munmap(buf, size);
3480
        return err;
3481
}
3482

    
3483
static int
3484
__vhd_io_dynamic_write(vhd_context_t *ctx,
3485
                       char *buf, uint64_t sector, uint32_t secs)
3486
{
3487
        char *map;
3488
        off64_t off;
3489
        uint32_t blk, sec;
3490
        int i, err, cnt, ret;
3491

    
3492
        if (vhd_sectors_to_bytes(sector + secs) > ctx->footer.curr_size)
3493
                return -ERANGE;
3494

    
3495
        err = vhd_get_bat(ctx);
3496
        if (err)
3497
                return err;
3498

    
3499
        if (vhd_has_batmap(ctx)) {
3500
                err = vhd_get_batmap(ctx);
3501
                if (err)
3502
                        return err;
3503
        }
3504

    
3505
        do {
3506
                blk = sector / ctx->spb;
3507
                sec = sector % ctx->spb;
3508

    
3509
                off = ctx->bat.bat[blk];
3510
                if (off == DD_BLK_UNUSED) {
3511
                        err = __vhd_io_allocate_block(ctx, blk);
3512
                        if (err)
3513
                                return err;
3514

    
3515
                        off = ctx->bat.bat[blk];
3516
                }
3517

    
3518
                off += ctx->bm_secs + sec;
3519
                err  = vhd_seek(ctx, vhd_sectors_to_bytes(off), SEEK_SET);
3520
                if (err)
3521
                        return err;
3522

    
3523
                cnt = MIN(secs, ctx->spb - sec);
3524
                err = vhd_write(ctx, buf, vhd_sectors_to_bytes(cnt));
3525
                if (err)
3526
                        return err;
3527

    
3528
                if (vhd_has_batmap(ctx) &&
3529
                    vhd_batmap_test(ctx, &ctx->batmap, blk))
3530
                        goto next;
3531

    
3532
                err = vhd_read_bitmap(ctx, blk, &map);
3533
                if (err)
3534
                        return err;
3535

    
3536
                for (i = 0; i < cnt; i++)
3537
                        vhd_bitmap_set(ctx, map, sec + i);
3538

    
3539
                err = vhd_write_bitmap(ctx, blk, map);
3540
                if (err)
3541
                        goto fail;
3542

    
3543
                if (vhd_has_batmap(ctx)) {
3544
                        for (i = 0; i < ctx->spb; i++)
3545
                                if (!vhd_bitmap_test(ctx, map, i)) {
3546
                                        free(map);
3547
                                        goto next;
3548
                                }
3549

    
3550
                        vhd_batmap_set(ctx, &ctx->batmap, blk);
3551
                        err = vhd_write_batmap(ctx, &ctx->batmap);
3552
                        if (err)
3553
                                goto fail;
3554
                }
3555

    
3556
                free(map);
3557
                map = NULL;
3558

    
3559
        next:
3560
                secs   -= cnt;
3561
                sector += cnt;
3562
                buf    += vhd_sectors_to_bytes(cnt);
3563
        } while (secs);
3564

    
3565
        err = 0;
3566

    
3567
out:
3568
        ret = vhd_write_footer(ctx, &ctx->footer);
3569
        return (err ? err : ret);
3570

    
3571
fail:
3572
        free(map);
3573
        goto out;
3574
}
3575

    
3576
int
3577
vhd_io_write(vhd_context_t *ctx, char *buf, uint64_t sec, uint32_t secs)
3578
{
3579
        if (vhd_sectors_to_bytes(sec + secs) > ctx->footer.curr_size)
3580
                return -ERANGE;
3581

    
3582
        if (!vhd_type_dynamic(ctx))
3583
                return __vhd_io_fixed_write(ctx, buf, sec, secs);
3584

    
3585
        return __vhd_io_dynamic_write(ctx, buf, sec, secs);
3586
}
3587

    
3588
static void
3589
vhd_cache_init(vhd_context_t *ctx)
3590
{
3591
        INIT_LIST_HEAD(&ctx->next);
3592
}
3593

    
3594
static int
3595
vhd_cache_enabled(vhd_context_t *ctx)
3596
{
3597
        return vhd_flag_test(ctx->oflags, VHD_OPEN_CACHED);
3598
}
3599

    
3600
static int
3601
vhd_cache_load(vhd_context_t *ctx)
3602
{
3603
        char *next;
3604
        int err, pflags;
3605
        vhd_context_t *vhd;
3606

    
3607
        err    = 1;
3608
        pflags = ctx->oflags;
3609
        vhd    = ctx;
3610
        next   = NULL;
3611

    
3612
        vhd_flag_set(pflags, VHD_OPEN_RDONLY);
3613
        vhd_flag_clear(pflags, VHD_OPEN_CACHED);
3614

    
3615
        if (!vhd_cache_enabled(vhd))
3616
                goto done;
3617

    
3618
        while (vhd->footer.type == HD_TYPE_DIFF) {
3619
                vhd_context_t *parent;
3620

    
3621
                parent = NULL;
3622

    
3623
                if (vhd_parent_raw(vhd))
3624
                        goto done;
3625

    
3626
                err = vhd_parent_locator_get(vhd, &next);
3627
                if (err)
3628
                        goto out;
3629

    
3630
                parent = calloc(1, sizeof(*parent));
3631
                if (!parent)
3632
                        goto out;
3633

    
3634
                err = vhd_open(parent, next, pflags);
3635
                if (err) {
3636
                        free(parent);
3637
                        parent = NULL;
3638
                        goto out;
3639
                }
3640

    
3641
                fcntl(parent->fd, F_SETFL,
3642
                      fcntl(parent->fd, F_GETFL) & ~O_DIRECT);
3643
                vhd_flag_set(parent->oflags, VHD_OPEN_CACHED);
3644
                list_add(&parent->next, &vhd->next);
3645

    
3646
                free(next);
3647
                next = NULL;
3648
                vhd  = parent;
3649
        }
3650

    
3651
done:
3652
        err = 0;
3653
out:
3654
        free(next);
3655
        if (err)
3656
                vhd_cache_unload(vhd);
3657

    
3658
        return err;
3659
}
3660

    
3661
static int
3662
vhd_cache_unload(vhd_context_t *ctx)
3663
{
3664
        vhd_context_t *vhd, *tmp;
3665

    
3666
        if (!vhd_cache_enabled(ctx))
3667
                goto out;
3668

    
3669
        list_for_each_entry_safe(vhd, tmp, &ctx->next, next) {
3670
                list_del_init(&vhd->next);
3671
                vhd_close(vhd);
3672
                free(vhd);
3673
        }
3674

    
3675
        INIT_LIST_HEAD(&ctx->next);
3676

    
3677
out:
3678
        return 0;
3679
}
3680

    
3681
static vhd_context_t *
3682
vhd_cache_get_parent(vhd_context_t *ctx)
3683
{
3684
        vhd_context_t *vhd;
3685

    
3686
        vhd = NULL;
3687

    
3688
        if (!vhd_cache_enabled(ctx))
3689
                goto out;
3690

    
3691
        if (list_empty(&ctx->next))
3692
                goto out;
3693

    
3694
        vhd = list_entry(ctx->next.next, vhd_context_t, next);
3695

    
3696
out:
3697
        return vhd;
3698
}
3699

    
3700
typedef struct vhd_block_vector vhd_block_vector_t;
3701
typedef struct vhd_block_vector_entry vhd_block_vector_entry_t;
3702

    
3703
struct vhd_block_vector_entry {
3704
        uint64_t                   off;       /* byte offset from block */
3705
        uint32_t                   bytes;     /* size in bytes */
3706
        char                      *buf;       /* destination buffer */
3707
};
3708

    
3709
struct vhd_block_vector {
3710
        uint32_t                   block;     /* logical block in vhd */
3711
        int                        entries;   /* number of vector entries */
3712
        vhd_block_vector_entry_t  *array;     /* vector list */
3713
};
3714

    
3715
/**
3716
 * @vec: block vector describing read
3717
 *
3718
 * @vec describes a list of byte-spans within a given block
3719
 * and a corresponding list of destination buffers.
3720
 */
3721
static int
3722
vhd_block_vector_read(vhd_context_t *ctx, vhd_block_vector_t *vec)
3723
{
3724
        int err, i;
3725
        off64_t off;
3726
        uint32_t blk;
3727

    
3728
        err = vhd_get_bat(ctx);
3729
        if (err)
3730
                goto out;
3731

    
3732
        if (vec->block >= ctx->bat.entries) {
3733
                err = -ERANGE;
3734
                goto out;
3735
        }
3736

    
3737
        blk = ctx->bat.bat[vec->block];
3738
        if (blk == DD_BLK_UNUSED) {
3739
                err = -EINVAL;
3740
                goto out;
3741
        }
3742

    
3743
        off = vhd_sectors_to_bytes(blk + ctx->bm_secs);
3744

    
3745
        for (i = 0; i < vec->entries; i++) {
3746
                vhd_block_vector_entry_t *v = vec->array + i;
3747
                err = vhd_pread(ctx, v->buf, v->bytes, off + v->off);
3748
                if (err)
3749
                        goto out;
3750
        }
3751

    
3752
out:
3753
        return err;
3754
}
3755

    
3756
/**
3757
 * @vec: block vector to initialize
3758
 * @block: vhd block number
3759
 * @map: optional bitmap of sectors to map (relative to beginning of block)
3760
 * @buf: destination buffer
3761
 * @blk_start: byte offset relative to beginning of block
3762
 * @blk_end: byte offset relative to beginning of block
3763
 *
3764
 * initializes @vec to describe a read into a contiguous buffer
3765
 * of potentially non-contiguous byte ranges in a given vhd block.
3766
 * only sectors with corresponding bits set in @map (if it is not NULL)
3767
 * will be mapped; bits corresponding to unmapped sectors will be cleared.
3768
 * first and last sector maps may be smaller than vhd sector size.
3769
 */
3770
static int
3771
vhd_block_vector_init(vhd_context_t *ctx,
3772
                      vhd_block_vector_t *vec, uint32_t block, char *map,
3773
                      char *buf, uint64_t blk_start, uint64_t blk_end)
3774
{
3775
        int err, sec;
3776
        char *bitmap;
3777
        uint32_t first_sec, last_sec;
3778

    
3779
        bitmap = NULL;
3780
        memset(vec, 0, sizeof(*vec));
3781

    
3782
        first_sec = blk_start >> VHD_SECTOR_SHIFT;
3783
        last_sec  = secs_round_up_no_zero(blk_end);
3784

    
3785
        err = vhd_read_bitmap(ctx, block, &bitmap);
3786
        if (err)
3787
                goto out;
3788

    
3789
        vec->array = calloc(ctx->spb, sizeof(vhd_block_vector_entry_t));
3790
        if (!vec->array) {
3791
                err = -ENOMEM;
3792
                goto out;
3793
        }
3794

    
3795
        for (sec = first_sec; sec < last_sec; sec++) {
3796
                uint32_t cnt;
3797
                vhd_block_vector_entry_t *v;
3798

    
3799
                cnt = VHD_SECTOR_SIZE - (blk_start & (VHD_SECTOR_SIZE - 1));
3800
                if (cnt > blk_end - blk_start)
3801
                        cnt = blk_end - blk_start;
3802

    
3803
                if (map && !test_bit(map, sec))
3804
                        goto next;
3805

    
3806
                if (vhd_bitmap_test(ctx, bitmap, sec)) {
3807
                        if (vec->entries > 0) {
3808
                                v = vec->array + vec->entries - 1;
3809
                                if (v->off + v->bytes == blk_start) {
3810
                                        v->bytes += cnt;
3811
                                        goto next;
3812
                                }
3813
                        }
3814

    
3815
                        v        = vec->array + vec->entries;
3816
                        v->off   = blk_start;
3817
                        v->bytes = cnt;
3818
                        v->buf   = buf;
3819

    
3820
                        vec->entries++;
3821

    
3822
                } else if (map) {
3823
                        clear_bit(map, sec);
3824
                }
3825

    
3826
        next:
3827
                blk_start += cnt;
3828
                buf       += cnt;
3829
        }
3830

    
3831
        vec->block = block;
3832

    
3833
out:
3834
        free(bitmap);
3835
        return err;
3836
}
3837

    
3838
#if 0
3839
/**
3840
 * @block: vhd block number
3841
 * @buf: buffer to place data in
3842
 * @size: number of bytes to read
3843
 * @start: byte offset into block from which to start reading
3844
 * @end: byte offset in block at which to stop reading
3845
 *
3846
 * reads data (if it exists) into @buf.  partial reads may occur
3847
 * for the first and last sectors if @start and @end are not multiples
3848
 * of vhd sector size.
3849
 */
3850
static int
3851
vhd_block_vector_read_allocated(vhd_context_t *ctx, uint32_t block,
3852
                                char *buf, uint64_t start, uint64_t end)
3853
{
3854
        int err;
3855
        vhd_block_vector_t vec;
3856

3857
        vec.array = NULL;
3858

3859
        err = vhd_block_vector_init(ctx, &vec, block, NULL, buf, start, end);
3860
        if (err)
3861
                goto out;
3862

3863
        err = vhd_block_vector_read(ctx, &vec);
3864

3865
out:
3866
        free(vec.array);
3867
        return err;
3868
}
3869
#endif
3870

    
3871
/**
3872
 * @block: vhd block number
3873
 * @map: bitmap of sectors in block which should be read
3874
 * @buf: buffer to place data in
3875
 * @start: byte offset into block from which to start reading
3876
 * @end: byte offset in block at which to stop reading
3877
 *
3878
 * for every bit set in @map (corresponding to sectors in @block),
3879
 * reads data (if it exists) into @buf.  if data does not exist,
3880
 * clears corresponding bit in @map.  partial reads may occur
3881
 * for the first and last sectors if @start and @end are not multiples
3882
 * of vhd sector size.
3883
 */
3884
static int
3885
vhd_block_vector_read_allocated_selective(vhd_context_t *ctx,
3886
                                          uint32_t block, char *map, char *buf,
3887
                                          uint64_t start, uint64_t end)
3888
{
3889
        int err;
3890
        vhd_block_vector_t vec;
3891

    
3892
        vec.array = NULL;
3893

    
3894
        err = vhd_block_vector_init(ctx, &vec, block, map, buf, start, end);
3895
        if (err)
3896
                goto out;
3897

    
3898
        err = vhd_block_vector_read(ctx, &vec);
3899

    
3900
out:
3901
        free(vec.array);
3902
        return err;
3903
}
3904

    
3905
/**
3906
 * @map: bitmap of sectors which have already been read
3907
 * @buf: destination buffer
3908
 * @size: size in bytes to read
3909
 * @off: byte offset in virtual disk to read
3910
 *
3911
 * reads @size bytes into @buf, starting at @off, skipping sectors
3912
 * which have corresponding bits set in @map
3913
 */
3914
static int
3915
__vhd_io_dynamic_read_link_bytes(vhd_context_t *ctx, char *map,
3916
                                 char *buf, size_t size, uint64_t off)
3917
{
3918
        char *blkmap;
3919
        int i, err, map_off;
3920
        off64_t blk_off, blk_size;
3921
        uint32_t blk, bytes, first_sec, last_sec;
3922

    
3923
        blkmap = malloc((ctx->spb + 7) >> 3);
3924
        if (!blkmap) {
3925
                err = -ENOMEM;
3926
                goto out;
3927
        }
3928

    
3929
        map_off  = 0;
3930
        blk_size = vhd_sectors_to_bytes(ctx->spb);
3931

    
3932
        do {
3933
                blk     = off / blk_size;
3934
                blk_off = off % blk_size;
3935
                bytes   = MIN(blk_size - blk_off, size);
3936

    
3937
                first_sec = blk_off >> VHD_SECTOR_SHIFT;
3938
                last_sec  = secs_round_up_no_zero(blk_off + bytes);
3939

    
3940
                if (ctx->bat.bat[blk] == DD_BLK_UNUSED)
3941
                        goto next;
3942

    
3943
                memset(blkmap, 0, (ctx->spb + 7) >> 3);
3944

    
3945
                for (i = 0; i < (last_sec - first_sec); i++)
3946
                        if (!test_bit(map, map_off + i))
3947
                                set_bit(blkmap, first_sec + i);
3948

    
3949
                err = vhd_block_vector_read_allocated_selective(ctx, blk,
3950
                                                                blkmap, buf,
3951
                                                                blk_off,
3952
                                                                blk_off +
3953
                                                                bytes);
3954
                if (err)
3955
                        goto out;
3956

    
3957
                for (i = 0; i < (last_sec - first_sec); i++)
3958
                        if (test_bit(blkmap, first_sec + i))
3959
                                set_bit(map, map_off + i);
3960

    
3961
        next:
3962
                size    -= bytes;
3963
                off     += bytes;
3964
                map_off += (last_sec - first_sec);
3965
                buf     += bytes;
3966

    
3967
        } while (size);
3968

    
3969
        err = 0;
3970
out:
3971
        free(blkmap);
3972
        return err;
3973
}
3974

    
3975
static int
3976
__raw_read_link_bytes(const char *filename,
3977
                      char *map, char *buf, size_t size, uint64_t off)
3978
{
3979
        int fd, err;
3980
        uint32_t i, first_sec, last_sec;
3981

    
3982
        fd = open(filename, O_RDONLY | O_LARGEFILE);
3983
        if (fd == -1) {
3984
                VHDLOG("%s: failed to open: %d\n", filename, -errno);
3985
                return -errno;
3986
        }
3987

    
3988
        first_sec = off >> VHD_SECTOR_SHIFT;
3989
        last_sec  = secs_round_up_no_zero(off + size);
3990

    
3991
        for (i = first_sec; i < last_sec; i++) {
3992
                if (!test_bit(map, i - first_sec)) {
3993
                        uint32_t secs = 0;
3994
                        uint64_t coff, csize;
3995

    
3996
                        while (i + secs < last_sec &&
3997
                               !test_bit(map, i + secs - first_sec))
3998
                                secs++;
3999

    
4000
                        coff  = vhd_sectors_to_bytes(i);
4001
                        csize = vhd_sectors_to_bytes(secs);
4002

    
4003
                        if (i == first_sec)
4004
                                coff = off;
4005
                        if (secs == last_sec - 1)
4006
                                csize = (off + size) - coff;
4007

    
4008
                        if (pread(fd, buf + coff - off, csize, coff) != csize) {
4009
                                err = (errno ? -errno : -EIO);
4010
                                goto close;
4011
                        }
4012

    
4013
                        i += secs - 1;
4014
                }
4015
        }
4016

    
4017
        err = 0;
4018

    
4019
close:
4020
        close(fd);
4021
        return err;
4022
}
4023

    
4024
static int
4025
__vhd_io_dynamic_read_bytes(vhd_context_t *ctx,
4026
                            char *buf, size_t size, uint64_t off)
4027
{
4028
        int err;
4029
        char *next, *map;
4030
        vhd_context_t parent, *vhd;
4031
        uint32_t i, done, first_sec, last_sec;
4032

    
4033
        err  = vhd_get_bat(ctx);
4034
        if (err)
4035
                return err;
4036

    
4037
        first_sec = off >> VHD_SECTOR_SHIFT;
4038
        last_sec  = secs_round_up_no_zero(off + size);
4039

    
4040
        vhd  = ctx;
4041
        next = NULL;
4042
        map  = calloc(1, ((last_sec - first_sec) + 7) >> 3);
4043
        if (!map) {
4044
                err = -ENOMEM;
4045
                goto out;
4046
        }
4047

    
4048
        for (;;) {
4049
                err = __vhd_io_dynamic_read_link_bytes(vhd, map,
4050
                                                       buf, size, off);
4051
                if (err)
4052
                        goto close;
4053

    
4054
                for (done = 0, i = 0; i < (last_sec - first_sec); i++)
4055
                        if (test_bit(map, i))
4056
                                done++;
4057

    
4058
                if (done == last_sec - first_sec) {
4059
                        err = 0;
4060
                        goto close;
4061
                }
4062

    
4063
                if (vhd->footer.type == HD_TYPE_DIFF) {
4064
                        vhd_context_t *p;
4065
                        p = vhd_cache_get_parent(vhd);
4066
                        if (p) {
4067
                                vhd = p;
4068
                                err = vhd_get_bat(vhd);
4069
                                if (err)
4070
                                        goto out;
4071
                                continue;
4072
                        }
4073

    
4074
                        err = vhd_parent_locator_get(vhd, &next);
4075
                        if (err)
4076
                                goto close;
4077

    
4078
                        if (vhd_parent_raw(vhd)) {
4079
                                err = __raw_read_link_bytes(next, map,
4080
                                                            buf, size, off);
4081
                                goto close;
4082
                        }
4083
                } else {
4084
                        err = 0;
4085
                        goto close;
4086
                }
4087

    
4088
                if (vhd != ctx)
4089
                        vhd_close(vhd);
4090
                vhd = &parent;
4091

    
4092
                err = vhd_open(vhd, next, VHD_OPEN_RDONLY);
4093
                if (err)
4094
                        goto out;
4095

    
4096
                err = vhd_get_bat(vhd);
4097
                if (err)
4098
                        goto close;
4099

    
4100
                free(next);
4101
                next = NULL;
4102
        }
4103

    
4104
close:
4105
        if (!err) {
4106
                /*
4107
                 * clear any regions not present on disk
4108
                 */
4109
                for (i = first_sec; i < last_sec; i++) {
4110
                        if (!test_bit(map, i - first_sec)) {
4111
                                uint64_t coff  = vhd_sectors_to_bytes(i);
4112
                                uint32_t csize = VHD_SECTOR_SIZE;
4113

    
4114
                                if (i == first_sec)
4115
                                        coff = off;
4116
                                if (i == last_sec - 1)
4117
                                        csize = (off + size) - coff;
4118

    
4119
                                memset(buf + coff - off, 0, csize);
4120
                        }
4121
                }
4122
        }
4123

    
4124
        if (vhd != ctx && !vhd_flag_test(vhd->oflags, VHD_OPEN_CACHED))
4125
                vhd_close(vhd);
4126
out:
4127
        free(map);
4128
        free(next);
4129
        return err;
4130
}
4131

    
4132
int
4133
vhd_io_read_bytes(vhd_context_t *ctx, void *buf, size_t size, uint64_t off)
4134
{
4135
        if (off + size > ctx->footer.curr_size)
4136
                return -ERANGE;
4137

    
4138
        if (!vhd_type_dynamic(ctx))
4139
                return vhd_pread(ctx, buf, size, off);
4140

    
4141
        return __vhd_io_dynamic_read_bytes(ctx, buf, size, off);
4142
}
4143

    
4144
static int
4145
__vhd_io_dynamic_write_bytes_aligned(vhd_context_t *ctx,
4146
                                     char *buf, size_t size, uint64_t off)
4147
{
4148
        char *map;
4149
        int i, err, ret;
4150
        uint64_t blk_off, blk_size, blk_start;
4151
        uint32_t blk, bytes, first_sec, last_sec;
4152

    
4153
        if (off & (VHD_SECTOR_SIZE - 1) || size & (VHD_SECTOR_SIZE - 1))
4154
                return -EINVAL;
4155

    
4156
        err = vhd_get_bat(ctx);
4157
        if (err)
4158
                return err;
4159

    
4160
        if (vhd_has_batmap(ctx)) {
4161
                err = vhd_get_batmap(ctx);
4162
                if (err)
4163
                        return err;
4164
        }
4165

    
4166
        map      = NULL;
4167
        blk_size = vhd_sectors_to_bytes(ctx->spb);
4168

    
4169
        do {
4170
                blk     = off / blk_size;
4171
                blk_off = off % blk_size;
4172
                bytes   = MIN(blk_size - blk_off, size);
4173

    
4174
                first_sec = blk_off >> VHD_SECTOR_SHIFT;
4175
                last_sec  = secs_round_up_no_zero(blk_off + bytes);
4176

    
4177
                blk_start = ctx->bat.bat[blk];
4178
                if (blk_start == DD_BLK_UNUSED) {
4179
                        err = __vhd_io_allocate_block(ctx, blk);
4180
                        if (err)
4181
                                goto fail;
4182

    
4183
                        blk_start = ctx->bat.bat[blk];
4184
                }
4185

    
4186
                blk_start = vhd_sectors_to_bytes(blk_start + ctx->bm_secs);
4187

    
4188
                err = vhd_pwrite(ctx, buf, bytes, blk_start + blk_off);
4189
                if (err)
4190
                        goto fail;
4191

    
4192
                if (vhd_has_batmap(ctx) &&
4193
                    vhd_batmap_test(ctx, &ctx->batmap, blk))
4194
                        goto next;
4195

    
4196
                err = vhd_read_bitmap(ctx, blk, &map);
4197
                if (err) {
4198
                        map = NULL;
4199
                        goto fail;
4200
                }
4201

    
4202
                for (i = first_sec; i < last_sec; i++)
4203
                        vhd_bitmap_set(ctx, map, i);
4204

    
4205
                err = vhd_write_bitmap(ctx, blk, map);
4206
                if (err)
4207
                        goto fail;
4208

    
4209
                if (vhd_has_batmap(ctx)) {
4210
                        for (i = 0; i < ctx->spb; i++)
4211
                                if (!vhd_bitmap_test(ctx, map, i)) {
4212
                                        free(map);
4213
                                        map = NULL;
4214
                                        goto next;
4215
                                }
4216

    
4217
                        vhd_batmap_set(ctx, &ctx->batmap, blk);
4218
                        err = vhd_write_batmap(ctx, &ctx->batmap);
4219
                        if (err)
4220
                                goto fail;
4221
                }
4222

    
4223
                free(map);
4224
                map = NULL;
4225

    
4226
        next:
4227
                size   -= bytes;
4228
                off    += bytes;
4229
                buf    += bytes;
4230

    
4231
        } while (size);
4232

    
4233
        err = 0;
4234

    
4235
out:
4236
        ret = vhd_write_footer(ctx, &ctx->footer);
4237
        return (err ? err : ret);
4238

    
4239
fail:
4240
        free(map);
4241
        goto out;
4242
}
4243

    
4244
static int
4245
__vhd_io_dynamic_write_bytes(vhd_context_t *ctx,
4246
                             char *buf, size_t size, uint64_t off)
4247
{
4248
        int err;
4249
        char *tmp;
4250
        uint32_t first_sec, last_sec, first_sec_off, last_sec_off;
4251

    
4252
        err = 0;
4253
        tmp = NULL;
4254

    
4255
        first_sec = off >> VHD_SECTOR_SHIFT;
4256
        last_sec  = secs_round_up_no_zero(off + size);
4257

    
4258
        first_sec_off = off & (VHD_SECTOR_SIZE - 1);
4259
        last_sec_off  = (off + size) & (VHD_SECTOR_SIZE - 1);
4260

    
4261
        if (first_sec_off || last_sec_off) {
4262
                tmp = malloc(VHD_SECTOR_SIZE);
4263
                if (!tmp) {
4264
                        err = -ENOMEM;
4265
                        goto out;
4266
                }
4267

    
4268
                if (first_sec_off) {
4269
                        uint32_t new = VHD_SECTOR_SIZE - first_sec_off;
4270
                        if (new > size)
4271
                                new = size;
4272

    
4273
                        err = vhd_io_read_bytes(
4274
                                ctx, tmp, VHD_SECTOR_SIZE,
4275
                                vhd_sectors_to_bytes(first_sec));
4276
                        if (err)
4277
                                goto out;
4278

    
4279
                        memcpy(tmp + first_sec_off, buf, new);
4280

    
4281
                        err = __vhd_io_dynamic_write_bytes_aligned(
4282
                                ctx, tmp, VHD_SECTOR_SIZE,
4283
                                vhd_sectors_to_bytes(first_sec));
4284
                        if (err)
4285
                                goto out;
4286

    
4287
                        buf  += new;
4288
                        off  += new;
4289
                        size -= new;
4290
                }
4291

    
4292
                if (last_sec_off &&
4293
                    (last_sec - first_sec > 1 || !first_sec_off)) {
4294
                        uint32_t new = last_sec_off;
4295

    
4296
                        err = vhd_io_read_bytes(
4297
                                ctx, tmp, VHD_SECTOR_SIZE,
4298
                                vhd_sectors_to_bytes(last_sec - 1));
4299
                        if (err)
4300
                                goto out;
4301

    
4302
                        memcpy(tmp, buf + size - new, new);
4303

    
4304
                        err = __vhd_io_dynamic_write_bytes_aligned(
4305
                                ctx, tmp, VHD_SECTOR_SIZE,
4306
                                vhd_sectors_to_bytes(last_sec - 1));
4307
                        if (err)
4308
                                goto out;
4309

    
4310
                        size -= new;
4311
                }
4312
        }
4313

    
4314
        if (size)
4315
                err = __vhd_io_dynamic_write_bytes_aligned(ctx, buf, size, off);
4316

    
4317
out:
4318
        free(tmp);
4319
        return err;
4320
}
4321

    
4322
int
4323
vhd_io_write_bytes(vhd_context_t *ctx, void *buf, size_t size, uint64_t off)
4324
{
4325
        if (off + size > ctx->footer.curr_size)
4326
                return -ERANGE;
4327

    
4328
        if (!vhd_type_dynamic(ctx))
4329
                return vhd_pwrite(ctx, buf, size, off);
4330

    
4331
        return __vhd_io_dynamic_write_bytes(ctx, buf, size, off);
4332
}
4333

    
4334
int
4335
vhd_marker(vhd_context_t *ctx, char *marker)
4336
{
4337
        int err;
4338
        vhd_batmap_t batmap;
4339

    
4340
        *marker = 0;
4341

    
4342
        if (!vhd_has_batmap(ctx))
4343
                return -ENOSYS;
4344

    
4345
        err = vhd_read_batmap_header(ctx, &batmap);
4346
        if (err)
4347
                return err;
4348

    
4349
        *marker = batmap.header.marker;
4350
        return 0;
4351
}
4352

    
4353
int
4354
vhd_set_marker(vhd_context_t *ctx, char marker)
4355
{
4356
        int err;
4357
        vhd_batmap_t batmap;
4358

    
4359
        if (!vhd_has_batmap(ctx))
4360
                return -ENOSYS;
4361

    
4362
        err = vhd_read_batmap_header(ctx, &batmap);
4363
        if (err)
4364
                return err;
4365

    
4366
        batmap.header.marker = marker;
4367
        return vhd_write_batmap_header(ctx, &batmap);
4368
}