Branch data Line data Source code
1 : : /*
2 : : * Copyright (c) 2016, Citrix Systems, Inc.
3 : : *
4 : : * All rights reserved.
5 : : *
6 : : * Redistribution and use in source and binary forms, with or without
7 : : * modification, are permitted provided that the following conditions are met:
8 : : *
9 : : * 1. Redistributions of source code must retain the above copyright
10 : : * notice, this list of conditions and the following disclaimer.
11 : : * 2. 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 : : * 3. Neither the name of the copyright holder nor the names of its
15 : : * contributors may be used to endorse or promote products derived from
16 : : * this software 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 : : #include <stdio.h>
36 : : #include <errno.h>
37 : : #include <fcntl.h>
38 : : #include <stdlib.h>
39 : : #include <unistd.h>
40 : : #include <string.h>
41 : : #include <limits.h>
42 : :
43 : : #include "libvhd.h"
44 : : #include "libvhd-index.h"
45 : : #include "util.h"
46 : :
47 : : static void
48 : 0 : usage(void)
49 : : {
50 : : printf("usage: vhd-index <command>\n"
51 : : "commands:\n"
52 : : "\t index: <-i index name> <-v vhd file>\n"
53 : : "\t summary: <-s index name> [-v vhd file [-b block]]\n");
54 : 0 : exit(-EINVAL);
55 : : }
56 : :
57 : : typedef struct vhdi_name vhdi_name_t;
58 : :
59 : : struct vhdi_name {
60 : : char *vhd;
61 : : char *bat;
62 : :
63 : : char *base;
64 : : char *index;
65 : : char *files;
66 : : };
67 : :
68 : : static int
69 : 0 : vhd_index_get_name(const char *index, const char *vhd, vhdi_name_t *name)
70 : : {
71 : : int err, len;
72 : :
73 : : memset(name, 0, sizeof(vhdi_name_t));
74 : :
75 : 0 : len = strnlen(index, VHD_MAX_NAME_LEN);
76 : 0 : if (len + 5 >= VHD_MAX_NAME_LEN - 1)
77 : : return -ENAMETOOLONG;
78 : :
79 : 0 : if (vhd) {
80 : 0 : len = strnlen(vhd, VHD_MAX_NAME_LEN);
81 : 0 : if (len >= VHD_MAX_NAME_LEN - 1)
82 : : return -ENAMETOOLONG;
83 : :
84 : 0 : err = asprintf(&name->vhd, "%s", vhd);
85 : 0 : if (err == -1) {
86 : 0 : name->vhd = NULL;
87 : 0 : goto fail;
88 : : }
89 : :
90 : 0 : err = asprintf(&name->bat, "%s.bat", vhd);
91 : 0 : if (err == -1) {
92 : 0 : name->bat = NULL;
93 : 0 : goto fail;
94 : : }
95 : : }
96 : :
97 : 0 : err = asprintf(&name->base, "%s", index);
98 : 0 : if (err == -1) {
99 : 0 : name->base = NULL;
100 : 0 : goto fail;
101 : : }
102 : :
103 : 0 : err = asprintf(&name->index, "%s.index", index);
104 : 0 : if (err == -1) {
105 : 0 : name->index = NULL;
106 : 0 : goto fail;
107 : : }
108 : :
109 : 0 : err = asprintf(&name->files, "%s.files", index);
110 : 0 : if (err == -1) {
111 : 0 : name->files = NULL;
112 : 0 : goto fail;
113 : : }
114 : :
115 : : return 0;
116 : :
117 : : fail:
118 : 0 : free(name->vhd);
119 : 0 : free(name->bat);
120 : 0 : free(name->base);
121 : 0 : free(name->index);
122 : 0 : free(name->files);
123 : :
124 : 0 : return -ENOMEM;
125 : : }
126 : :
127 : : static inline void
128 : 0 : vhd_index_free_name(vhdi_name_t *name)
129 : : {
130 : 0 : free(name->vhd);
131 : 0 : free(name->bat);
132 : 0 : free(name->base);
133 : 0 : free(name->index);
134 : 0 : free(name->files);
135 : 0 : }
136 : :
137 : : static inline int
138 : 0 : vhd_index_add_file_table_entry(vhdi_name_t *name, const char *file,
139 : : vhdi_file_table_t *files, vhdi_file_id_t *fid)
140 : : {
141 : : int err;
142 : :
143 : 0 : vhdi_file_table_free(files);
144 : :
145 : 0 : err = vhdi_file_table_add(name->files, file, fid);
146 : 0 : if (err)
147 : : return err;
148 : :
149 : 0 : return vhdi_file_table_load(name->files, files);
150 : : }
151 : :
152 : : static inline int
153 : 0 : vhd_index_get_file_id(vhdi_name_t *name, const char *file,
154 : : vhdi_file_table_t *files, vhdi_file_id_t *fid)
155 : : {
156 : : char *path, __path[PATH_MAX];
157 : : int i;
158 : :
159 : 0 : path = realpath(file, __path);
160 : 0 : if (!path)
161 : 0 : return -errno;
162 : :
163 : 0 : for (i = 0; i < files->entries; i++)
164 : 0 : if (!strcmp(files->table[i].path, path)) {
165 : 0 : *fid = files->table[i].file_id;
166 : 0 : return 0;
167 : : }
168 : :
169 : 0 : return vhd_index_add_file_table_entry(name, file, files, fid);
170 : : }
171 : :
172 : : static inline int
173 : 0 : vhd_index_get_block(vhdi_context_t *vhdi, vhd_context_t *vhd,
174 : : uint32_t block, vhdi_block_t *vhdi_block)
175 : : {
176 : : int i;
177 : :
178 : 0 : if (block)
179 : 0 : return vhdi_read_block(vhdi, vhdi_block, block);
180 : :
181 : 0 : vhdi_block->entries = vhd->spb;
182 : 0 : vhdi_block->table = calloc(vhd->spb, sizeof(vhdi_entry_t));
183 : 0 : if (!vhdi_block->table)
184 : : return -ENOMEM;
185 : :
186 : 0 : for (i = 0; i < vhdi_block->entries; i++)
187 : 0 : vhdi_block->table[i].offset = DD_BLK_UNUSED;
188 : :
189 : : return 0;
190 : : }
191 : :
192 : : static int
193 : 0 : vhd_index_add_bat_entry(vhdi_name_t *name, vhdi_context_t *vhdi,
194 : : vhdi_bat_t *bat, vhdi_file_table_t *files,
195 : : vhd_context_t *vhd, uint32_t block, char *finished)
196 : : {
197 : : char *map;
198 : : vhdi_file_id_t fid;
199 : : uint32_t i, count, off;
200 : : vhdi_block_t vhdi_block;
201 : : int err, update, append;
202 : :
203 : 0 : fid = 0;
204 : 0 : count = 0;
205 : 0 : update = 0;
206 : 0 : append = (bat->table[block] == 0);
207 : :
208 : 0 : if (vhd->bat.bat[block] == DD_BLK_UNUSED)
209 : 0 : return 0;
210 : :
211 : 0 : err = vhd_index_get_block(vhdi, vhd, bat->table[block], &vhdi_block);
212 : 0 : if (err)
213 : : return err;
214 : :
215 : 0 : err = vhd_read_bitmap(vhd, block, &map);
216 : 0 : if (err)
217 : : goto out;
218 : :
219 : 0 : err = vhd_index_get_file_id(name, vhd->file, files, &fid);
220 : 0 : if (err)
221 : : goto out;
222 : :
223 : 0 : for (i = 0; i < vhd->spb; i++) {
224 : 0 : if (vhdi_block.table[i].file_id) {
225 : 0 : count++;
226 : 0 : continue;
227 : : }
228 : :
229 : 0 : if (!vhd_bitmap_test(vhd, map, i))
230 : 0 : continue;
231 : :
232 : 0 : err = vhd_offset(vhd, (uint64_t)block * vhd->spb + i, &off);
233 : 0 : if (err)
234 : : goto out;
235 : :
236 : 0 : vhdi_block.table[i].file_id = fid;
237 : 0 : vhdi_block.table[i].offset = off;
238 : 0 : count++;
239 : 0 : update++;
240 : : }
241 : :
242 : 0 : if (update) {
243 : 0 : if (append) {
244 : : uint32_t location;
245 : :
246 : 0 : err = vhdi_append_block(vhdi, &vhdi_block, &location);
247 : 0 : if (err)
248 : : goto out;
249 : :
250 : 0 : bat->table[block] = location;
251 : : } else {
252 : 0 : err = vhdi_write_block(vhdi, &vhdi_block,
253 : 0 : bat->table[block]);
254 : 0 : if (err)
255 : : goto out;
256 : : }
257 : : }
258 : :
259 : 0 : if (count == vhd->spb)
260 : 0 : *finished = 1;
261 : :
262 : : err = 0;
263 : :
264 : : out:
265 : 0 : free(vhdi_block.table);
266 : 0 : free(map);
267 : :
268 : 0 : return err;
269 : : }
270 : :
271 : : static int
272 : 0 : vhd_index_clone_bat_entry(vhdi_name_t *name, vhdi_context_t *vhdi,
273 : : vhdi_bat_t *bat, vhdi_file_table_t *files,
274 : : vhd_context_t *vhd, uint32_t block)
275 : : {
276 : : char *map;
277 : : int err, update;
278 : : uint32_t i, off;
279 : : vhdi_file_id_t fid;
280 : : vhdi_block_t vhdi_block;
281 : :
282 : 0 : fid = 0;
283 : 0 : update = 0;
284 : :
285 : 0 : if (vhd->bat.bat[block] == DD_BLK_UNUSED)
286 : 0 : return 0;
287 : :
288 : 0 : err = vhd_index_get_block(vhdi, vhd, bat->table[block], &vhdi_block);
289 : 0 : if (err)
290 : : return err;
291 : :
292 : 0 : err = vhd_read_bitmap(vhd, block, &map);
293 : 0 : if (err)
294 : : goto out;
295 : :
296 : 0 : err = vhd_index_get_file_id(name, vhd->file, files, &fid);
297 : 0 : if (err)
298 : : goto out;
299 : :
300 : 0 : for (i = 0; i < vhd->spb; i++) {
301 : 0 : if (!vhd_bitmap_test(vhd, map, i))
302 : 0 : continue;
303 : :
304 : 0 : err = vhd_offset(vhd, (uint64_t)block * vhd->spb + i, &off);
305 : 0 : if (err)
306 : : goto out;
307 : :
308 : 0 : vhdi_block.table[i].file_id = fid;
309 : 0 : vhdi_block.table[i].offset = off;
310 : 0 : update++;
311 : : }
312 : :
313 : 0 : if (update) {
314 : : uint32_t location;
315 : :
316 : 0 : err = vhdi_append_block(vhdi, &vhdi_block, &location);
317 : 0 : if (err)
318 : : goto out;
319 : :
320 : 0 : bat->table[block] = location;
321 : : }
322 : :
323 : : err = 0;
324 : :
325 : : out:
326 : 0 : free(vhdi_block.table);
327 : 0 : free(map);
328 : :
329 : 0 : return err;
330 : : }
331 : :
332 : : static int
333 : 0 : vhd_index_update_bat_entry(vhdi_name_t *name, vhdi_context_t *vhdi,
334 : : vhdi_bat_t *bat, vhdi_file_table_t *files,
335 : : vhd_context_t *vhd, uint32_t block)
336 : : {
337 : : char *map;
338 : : int err, update;
339 : : uint32_t i, off;
340 : : vhdi_file_id_t fid;
341 : : vhdi_block_t vhdi_block;
342 : :
343 : 0 : fid = 0;
344 : 0 : update = 0;
345 : :
346 : 0 : if (vhd->bat.bat[block] == DD_BLK_UNUSED)
347 : 0 : return 0;
348 : :
349 : 0 : err = vhd_index_get_block(vhdi, vhd, bat->table[block], &vhdi_block);
350 : 0 : if (err)
351 : : return err;
352 : :
353 : 0 : err = vhd_read_bitmap(vhd, block, &map);
354 : 0 : if (err)
355 : : goto out;
356 : :
357 : 0 : err = vhd_index_get_file_id(name, vhd->file, files, &fid);
358 : 0 : if (err)
359 : : goto out;
360 : :
361 : 0 : for (i = 0; i < vhd->spb; i++) {
362 : 0 : if (!vhd_bitmap_test(vhd, map, i))
363 : 0 : continue;
364 : :
365 : 0 : err = vhd_offset(vhd, (uint64_t)block * vhd->spb + i, &off);
366 : 0 : if (err)
367 : : goto out;
368 : :
369 : 0 : if (vhdi_block.table[i].file_id == fid &&
370 : 0 : vhdi_block.table[i].offset == off)
371 : 0 : continue;
372 : :
373 : 0 : vhdi_block.table[i].file_id = fid;
374 : 0 : vhdi_block.table[i].offset = off;
375 : 0 : update++;
376 : : }
377 : :
378 : 0 : if (update) {
379 : : uint32_t location;
380 : :
381 : 0 : err = vhdi_append_block(vhdi, &vhdi_block, &location);
382 : 0 : if (err)
383 : : goto out;
384 : :
385 : 0 : bat->table[block] = location;
386 : : }
387 : :
388 : : err = 0;
389 : :
390 : : out:
391 : 0 : free(vhdi_block.table);
392 : 0 : free(map);
393 : :
394 : 0 : return err;
395 : : }
396 : :
397 : : static int
398 : 0 : vhd_index_add_bat(vhdi_name_t *name,
399 : : uint64_t vhd_blocks, uint32_t vhd_block_size)
400 : : {
401 : : int err;
402 : : vhdi_bat_t bat;
403 : : vhd_context_t vhd;
404 : : vhdi_context_t vhdi;
405 : : vhdi_file_table_t files;
406 : : char *vhd_file, *finished;
407 : : uint32_t block, remaining;
408 : :
409 : : memset(&bat, 0, sizeof(vhdi_bat_t));
410 : : memset(&files, 0, sizeof(vhdi_file_table_t));
411 : :
412 : 0 : vhd_file = NULL;
413 : 0 : finished = NULL;
414 : 0 : bat.vhd_blocks = vhd_blocks;
415 : 0 : bat.vhd_block_size = vhd_block_size;
416 : :
417 : 0 : safe_strncpy(bat.vhd_path, name->vhd, sizeof(bat.vhd_path));
418 : 0 : safe_strncpy(bat.index_path, name->index, sizeof(bat.index_path));
419 : 0 : safe_strncpy(bat.file_table_path, name->files, sizeof(bat.file_table_path));
420 : :
421 : 0 : err = vhdi_open(&vhdi, name->index, O_RDWR);
422 : 0 : if (err)
423 : 0 : return err;
424 : :
425 : 0 : err = vhdi_file_table_load(name->files, &files);
426 : 0 : if (err) {
427 : 0 : vhdi_close(&vhdi);
428 : : return err;
429 : : }
430 : :
431 : 0 : err = vhdi_bat_create(name->bat, name->vhd, name->index, name->files);
432 : 0 : if (err)
433 : : goto out;
434 : :
435 : 0 : bat.table = calloc(vhd_blocks, sizeof(uint32_t));
436 : 0 : if (!bat.table) {
437 : : err = -ENOMEM;
438 : : goto out;
439 : : }
440 : :
441 : 0 : vhd_file = strdup(name->vhd);
442 : 0 : if (!vhd_file)
443 : : goto out;
444 : :
445 : 0 : remaining = vhd_blocks;
446 : 0 : finished = calloc(remaining, sizeof(char));
447 : 0 : if (!finished) {
448 : : err = -ENOMEM;
449 : : goto out;
450 : : }
451 : :
452 : : for (;;) {
453 : 0 : err = vhd_open(&vhd, vhd_file, VHD_OPEN_RDONLY);
454 : 0 : if (err)
455 : : goto out;
456 : :
457 : 0 : err = vhd_get_bat(&vhd);
458 : 0 : if (err)
459 : : goto out_vhd;
460 : :
461 : 0 : for (block = 0; block < vhd.bat.entries; block++) {
462 : 0 : if (finished[block])
463 : 0 : continue;
464 : :
465 : 0 : err = vhd_index_add_bat_entry(name, &vhdi, &bat,
466 : : &files, &vhd, block,
467 : : &finished[block]);
468 : 0 : if (err)
469 : : goto out_bat;
470 : :
471 : 0 : if (finished[block])
472 : 0 : remaining--;
473 : : }
474 : :
475 : 0 : free(vhd_file);
476 : 0 : vhd_file = NULL;
477 : :
478 : 0 : if (!remaining || vhd.footer.type != HD_TYPE_DIFF) {
479 : 0 : vhd_put_bat(&vhd);
480 : 0 : vhd_close(&vhd);
481 : : break;
482 : : }
483 : :
484 : 0 : err = vhd_parent_locator_get(&vhd, &vhd_file);
485 : : if (err)
486 : : goto out_bat;
487 : :
488 : : out_bat:
489 : 0 : vhd_put_bat(&vhd);
490 : : out_vhd:
491 : 0 : vhd_close(&vhd);
492 : 0 : if (err)
493 : : goto out;
494 : : }
495 : :
496 : 0 : err = vhdi_bat_write(name->bat, &bat);
497 : 0 : if (err)
498 : : goto out;
499 : :
500 : 0 : err = 0;
501 : :
502 : : out:
503 : 0 : if (err)
504 : 0 : unlink(name->bat);
505 : :
506 : 0 : vhdi_file_table_free(&files);
507 : 0 : vhdi_close(&vhdi);
508 : 0 : free(bat.table);
509 : 0 : free(finished);
510 : 0 : free(vhd_file);
511 : :
512 : 0 : return err;
513 : : }
514 : :
515 : : static int
516 : 0 : vhd_index_clone_bat(vhdi_name_t *name, const char *parent)
517 : : {
518 : : int err;
519 : 0 : char *pbat = NULL;
520 : : uint32_t block;
521 : : vhdi_bat_t bat;
522 : : vhd_context_t vhd;
523 : : vhdi_context_t vhdi;
524 : : vhdi_file_table_t files;
525 : :
526 : : memset(&bat, 0, sizeof(vhdi_bat_t));
527 : : memset(&files, 0, sizeof(vhdi_file_table_t));
528 : :
529 : 0 : err = asprintf(&pbat, "%s.bat", parent);
530 : 0 : if (err == -1) {
531 : 0 : free(pbat);
532 : 0 : return -ENOMEM;
533 : : }
534 : :
535 : 0 : err = access(pbat, R_OK);
536 : 0 : if (err == -1) {
537 : 0 : free(pbat);
538 : 0 : return -errno;
539 : : }
540 : :
541 : 0 : err = vhdi_open(&vhdi, name->index, O_RDWR);
542 : 0 : if (err)
543 : : goto out;
544 : :
545 : 0 : err = vhdi_bat_load(pbat, &bat);
546 : 0 : if (err)
547 : : goto out_vhdi;
548 : :
549 : 0 : err = vhdi_file_table_load(name->files, &files);
550 : 0 : if (err)
551 : : goto out_vhdi;
552 : :
553 : 0 : err = vhdi_bat_create(name->bat, name->vhd, name->index, name->files);
554 : 0 : if (err)
555 : : goto out_ft;
556 : :
557 : 0 : err = vhdi_bat_write(name->bat, &bat);
558 : 0 : if (err)
559 : : goto out_ft;
560 : :
561 : 0 : err = vhd_open(&vhd, name->vhd, VHD_OPEN_RDONLY);
562 : 0 : if (err)
563 : : goto out_ft;
564 : :
565 : 0 : err = vhd_get_bat(&vhd);
566 : 0 : if (err)
567 : : goto out_vhd;
568 : :
569 : 0 : for (block = 0; block < vhd.bat.entries; block++) {
570 : 0 : err = vhd_index_clone_bat_entry(name, &vhdi, &bat,
571 : : &files, &vhd, block);
572 : 0 : if (err)
573 : : goto out_bat;
574 : : }
575 : :
576 : 0 : err = vhdi_bat_write(name->bat, &bat);
577 : 0 : if (err)
578 : : goto out_bat;
579 : :
580 : 0 : err = 0;
581 : :
582 : : out_bat:
583 : 0 : vhd_put_bat(&vhd);
584 : : out_vhd:
585 : 0 : vhd_close(&vhd);
586 : : out_ft:
587 : 0 : vhdi_file_table_free(&files);
588 : : out_vhdi:
589 : 0 : vhdi_close(&vhdi);
590 : : out:
591 : 0 : if (err)
592 : 0 : unlink(name->bat);
593 : 0 : free(bat.table);
594 : 0 : free(pbat);
595 : 0 : return err;
596 : : }
597 : :
598 : : static int
599 : 0 : vhd_index_update_bat(vhdi_name_t *name)
600 : : {
601 : : int err;
602 : : uint32_t block;
603 : : vhdi_bat_t bat;
604 : : vhd_context_t vhd;
605 : : vhdi_context_t vhdi;
606 : : vhdi_file_table_t files;
607 : :
608 : : memset(&bat, 0, sizeof(vhdi_bat_t));
609 : : memset(&files, 0, sizeof(vhdi_file_table_t));
610 : :
611 : 0 : err = access(name->bat, R_OK);
612 : 0 : if (err == -1)
613 : 0 : return -errno;
614 : :
615 : 0 : err = vhdi_open(&vhdi, name->index, O_RDWR);
616 : 0 : if (err)
617 : : goto out;
618 : :
619 : 0 : err = vhdi_bat_load(name->bat, &bat);
620 : 0 : if (err)
621 : : goto out_vhdi;
622 : :
623 : 0 : err = vhdi_file_table_load(name->files, &files);
624 : 0 : if (err)
625 : : goto out_vhdi;
626 : :
627 : 0 : err = vhd_open(&vhd, name->vhd, VHD_OPEN_RDONLY);
628 : 0 : if (err)
629 : : goto out_ft;
630 : :
631 : 0 : err = vhd_get_bat(&vhd);
632 : 0 : if (err)
633 : : goto out_vhd;
634 : :
635 : 0 : for (block = 0; block < vhd.bat.entries; block++) {
636 : 0 : err = vhd_index_update_bat_entry(name, &vhdi, &bat,
637 : : &files, &vhd, block);
638 : 0 : if (err)
639 : : goto out_bat;
640 : : }
641 : :
642 : 0 : err = vhdi_bat_write(name->bat, &bat);
643 : 0 : if (err)
644 : : goto out_bat;
645 : :
646 : 0 : err = 0;
647 : :
648 : : out_bat:
649 : 0 : vhd_put_bat(&vhd);
650 : : out_vhd:
651 : 0 : vhd_close(&vhd);
652 : : out_ft:
653 : 0 : vhdi_file_table_free(&files);
654 : : out_vhdi:
655 : 0 : vhdi_close(&vhdi);
656 : : out:
657 : 0 : free(bat.table);
658 : 0 : return err;
659 : : }
660 : :
661 : : static int
662 : 0 : vhd_index_create(vhdi_name_t *name)
663 : : {
664 : : int err;
665 : : vhd_context_t ctx;
666 : : uint32_t block_size;
667 : :
668 : 0 : if (!access(name->index, F_OK) || !access(name->files, F_OK))
669 : 0 : return -EEXIST;
670 : :
671 : 0 : err = vhd_open(&ctx, name->vhd, VHD_OPEN_RDONLY);
672 : 0 : if (err)
673 : : return err;
674 : :
675 : 0 : err = vhd_get_header(&ctx);
676 : 0 : if (err) {
677 : 0 : vhd_close(&ctx);
678 : : return err;
679 : : }
680 : :
681 : 0 : block_size = ctx.header.block_size;
682 : 0 : vhd_close(&ctx);
683 : :
684 : 0 : err = vhdi_create(name->index, block_size);
685 : 0 : if (err)
686 : : goto out;
687 : :
688 : 0 : err = vhdi_file_table_create(name->files);
689 : 0 : if (err)
690 : : goto out;
691 : :
692 : 0 : err = 0;
693 : :
694 : : out:
695 : 0 : if (err) {
696 : 0 : unlink(name->index);
697 : 0 : unlink(name->files);
698 : : }
699 : :
700 : 0 : return err;
701 : : }
702 : :
703 : : static int
704 : 0 : vhd_index(vhdi_name_t *name)
705 : : {
706 : : char *parent;
707 : : vhd_context_t ctx;
708 : : uint64_t vhd_blocks;
709 : : uint32_t vhd_block_size;
710 : : int err, new_index, new_bat;
711 : :
712 : 0 : parent = NULL;
713 : 0 : new_bat = 0;
714 : 0 : new_index = 0;
715 : :
716 : : /* find vhd's parent -- we only index read-only vhds */
717 : 0 : err = vhd_open(&ctx, name->vhd, VHD_OPEN_RDONLY);
718 : 0 : if (err)
719 : 0 : return err;
720 : :
721 : 0 : err = vhd_parent_locator_get(&ctx, &parent);
722 : 0 : vhd_close(&ctx);
723 : :
724 : 0 : if (err)
725 : : return err;
726 : :
727 : : /* update name to point to parent */
728 : 0 : free(name->vhd);
729 : 0 : name->vhd = parent;
730 : 0 : parent = NULL;
731 : :
732 : 0 : free(name->bat);
733 : 0 : name->bat = NULL;
734 : 0 : err = asprintf(&name->bat, "%s.bat", name->vhd);
735 : 0 : if (err == -1) {
736 : 0 : free(name->bat);
737 : 0 : name->bat = NULL;
738 : 0 : return -ENOMEM;
739 : : }
740 : :
741 : : /* create index if it doesn't already exist */
742 : 0 : err = access(name->index, R_OK | W_OK);
743 : 0 : if (err == -1 && errno == ENOENT) {
744 : 0 : new_index = 1;
745 : 0 : err = vhd_index_create(name);
746 : : }
747 : :
748 : 0 : if (err)
749 : : return err;
750 : :
751 : : /* get basic vhd info */
752 : 0 : err = vhd_open(&ctx, name->vhd, VHD_OPEN_RDONLY);
753 : 0 : if (err)
754 : : goto out;
755 : :
756 : 0 : err = vhd_get_header(&ctx);
757 : 0 : if (err) {
758 : 0 : vhd_close(&ctx);
759 : : goto out;
760 : : }
761 : :
762 : 0 : vhd_blocks = ctx.header.max_bat_size;
763 : 0 : vhd_block_size = ctx.header.block_size;
764 : :
765 : 0 : if (vhd_parent_locator_get(&ctx, &parent))
766 : 0 : parent = NULL;
767 : :
768 : 0 : vhd_close(&ctx);
769 : :
770 : : /* update existing bat if it exists */
771 : 0 : err = vhd_index_update_bat(name);
772 : 0 : if (err != -ENOENT)
773 : : goto out;
774 : :
775 : 0 : new_bat = 1;
776 : :
777 : 0 : if (parent) {
778 : : /* clone parent bat if it exists */
779 : 0 : err = vhd_index_clone_bat(name, parent);
780 : 0 : if (err != -ENOENT)
781 : : goto out;
782 : : }
783 : :
784 : : /* create new bat from scratch */
785 : 0 : err = vhd_index_add_bat(name, vhd_blocks, vhd_block_size);
786 : 0 : if (err)
787 : : goto out;
788 : :
789 : 0 : err = 0;
790 : :
791 : : out:
792 : 0 : if (err) {
793 : 0 : if (new_bat)
794 : 0 : unlink(name->bat);
795 : 0 : if (new_index) {
796 : 0 : unlink(name->index);
797 : 0 : unlink(name->files);
798 : : }
799 : : }
800 : 0 : free(parent);
801 : 0 : return err;
802 : : }
803 : :
804 : : static void
805 : 0 : vhd_index_print_summary(vhdi_name_t *name,
806 : : uint32_t block_size, vhdi_file_table_t *files)
807 : : {
808 : : int i;
809 : : char time[26], uuid[37];
810 : :
811 : 0 : printf("VHD INDEX : %s\n", name->index);
812 : : printf("--------------------\n");
813 : : printf("block size : %u\n", block_size);
814 : 0 : printf("files : %d\n", files->entries);
815 : :
816 : : printf("\n");
817 : 0 : for (i = 0; i < files->entries; i++) {
818 : 0 : uuid_unparse(files->table[i].vhd_uuid, uuid);
819 : 0 : vhd_time_to_string(files->table[i].vhd_timestamp, time);
820 : :
821 : 0 : printf(" fid 0x%04x : %s, %s, %s\n",
822 : 0 : files->table[i].file_id, files->table[i].path, uuid, time);
823 : : }
824 : :
825 : : printf("\n");
826 : 0 : }
827 : :
828 : : static inline void
829 : 0 : vhd_index_print_bat_header(const char *name, vhdi_bat_t *bat)
830 : : {
831 : : printf("VHD INDEX BAT : %s\n", name);
832 : : printf("--------------------\n");
833 : 0 : printf("blocks : %"PRIu64"\n", bat->vhd_blocks);
834 : 0 : printf("block size : %u\n", bat->vhd_block_size);
835 : 0 : printf("vhd path : %s\n", bat->vhd_path);
836 : 0 : printf("index path : %s\n", bat->index_path);
837 : 0 : printf("file table path : %s\n", bat->file_table_path);
838 : 0 : }
839 : :
840 : : static int
841 : 0 : vhd_index_print_vhd_summary(vhdi_name_t *name)
842 : : {
843 : : int err;
844 : : uint32_t i;
845 : : vhdi_bat_t bat;
846 : :
847 : 0 : err = vhdi_bat_load(name->bat, &bat);
848 : 0 : if (err)
849 : 0 : return err;
850 : :
851 : 0 : vhd_index_print_bat_header(name->bat, &bat);
852 : :
853 : : printf("\n");
854 : 0 : for (i = 0; i < bat.vhd_blocks; i++)
855 : 0 : printf(" block 0x%04x : offset 0x%08x\n", i, bat.table[i]);
856 : :
857 : 0 : free(bat.table);
858 : 0 : return 0;
859 : : }
860 : :
861 : : static int
862 : 0 : vhd_index_print_vhd_block_summary(vhdi_name_t *name, uint32_t block)
863 : : {
864 : : int err;
865 : : uint32_t i;
866 : : uint32_t off;
867 : : vhdi_bat_t bat;
868 : : vhdi_context_t vhdi;
869 : : vhdi_block_t vhdi_block;
870 : :
871 : 0 : err = vhdi_bat_load(name->bat, &bat);
872 : 0 : if (err)
873 : 0 : return err;
874 : :
875 : 0 : vhd_index_print_bat_header(name->bat, &bat);
876 : :
877 : 0 : if (block > bat.vhd_blocks) {
878 : 0 : printf("block %u past end of bat (%"PRIu64")\n",
879 : : block, bat.vhd_blocks);
880 : : err = -EINVAL;
881 : : goto out;
882 : : }
883 : :
884 : 0 : off = bat.table[block];
885 : 0 : if (off == DD_BLK_UNUSED) {
886 : : printf("block %u is unallocated\n", block);
887 : : err = 0;
888 : : goto out;
889 : : }
890 : :
891 : 0 : err = vhdi_open(&vhdi, name->index, O_RDWR);
892 : 0 : if (err)
893 : : goto out;
894 : :
895 : 0 : err = vhdi_read_block(&vhdi, &vhdi_block, off);
896 : 0 : vhdi_close(&vhdi);
897 : 0 : if (err)
898 : : goto out;
899 : :
900 : : printf("\nBLOCK 0x%08x\n", block);
901 : 0 : for (i = 0; i < vhdi_block.entries; i++)
902 : 0 : printf(" sec 0x%04x : fid 0x%04x, offset 0x%08x\n", i,
903 : : vhdi_block.table[i].file_id,
904 : 0 : vhdi_block.table[i].offset);
905 : :
906 : 0 : free(vhdi_block.table);
907 : 0 : err = 0;
908 : :
909 : : out:
910 : 0 : free(bat.table);
911 : 0 : return err;
912 : : }
913 : :
914 : : static int
915 : 0 : vhd_index_summary(vhdi_name_t *name, uint32_t block)
916 : : {
917 : : int err;
918 : : uint32_t block_size;
919 : : vhdi_context_t vhdi;
920 : : vhdi_file_table_t files;
921 : :
922 : : memset(&files, 0, sizeof(vhdi_file_table_t));
923 : :
924 : 0 : err = vhdi_open(&vhdi, name->index, O_RDWR);
925 : 0 : if (err)
926 : 0 : return err;
927 : :
928 : 0 : block_size = vhdi.vhd_block_size;
929 : 0 : vhdi_close(&vhdi);
930 : :
931 : 0 : err = vhdi_file_table_load(name->files, &files);
932 : 0 : if (err)
933 : : return err;
934 : :
935 : 0 : vhd_index_print_summary(name, block_size, &files);
936 : :
937 : 0 : if (name->vhd) {
938 : 0 : if (block == (uint32_t)-1)
939 : 0 : err = vhd_index_print_vhd_summary(name);
940 : : else
941 : 0 : err = vhd_index_print_vhd_block_summary(name, block);
942 : :
943 : 0 : if (err)
944 : : goto out;
945 : : }
946 : :
947 : : err = 0;
948 : :
949 : : out:
950 : 0 : vhdi_file_table_free(&files);
951 : : return err;
952 : : }
953 : :
954 : : int
955 : 0 : main(int argc, char *argv[])
956 : : {
957 : : int err;
958 : : uint32_t block;
959 : : vhdi_name_t name;
960 : : char *vhd, *index;
961 : : int c, update, summary;
962 : :
963 : 0 : vhd = NULL;
964 : 0 : index = NULL;
965 : 0 : block = (uint32_t)-1;
966 : 0 : update = 0;
967 : 0 : summary = 0;
968 : :
969 : 0 : while ((c = getopt(argc, argv, "i:v:s:b:h")) != -1) {
970 : 0 : switch (c) {
971 : : case 'i':
972 : 0 : index = optarg;
973 : 0 : update = 1;
974 : 0 : break;
975 : :
976 : : case 'v':
977 : 0 : vhd = optarg;
978 : 0 : break;
979 : :
980 : : case 's':
981 : 0 : index = optarg;
982 : 0 : summary = 1;
983 : 0 : break;
984 : :
985 : : case 'b':
986 : 0 : block = strtoul(optarg, NULL, 10);
987 : 0 : break;
988 : :
989 : : default:
990 : 0 : usage();
991 : : }
992 : : }
993 : :
994 : 0 : if (optind != argc)
995 : 0 : usage();
996 : :
997 : 0 : if (!(update ^ summary))
998 : 0 : usage();
999 : :
1000 : 0 : if (block != (uint32_t)-1 && (!summary || !vhd))
1001 : 0 : usage();
1002 : :
1003 : 0 : err = vhd_index_get_name(index, vhd, &name);
1004 : 0 : if (err)
1005 : : goto out;
1006 : :
1007 : 0 : if (summary)
1008 : 0 : err = vhd_index_summary(&name, block);
1009 : 0 : else if (update) {
1010 : 0 : if (!vhd)
1011 : 0 : usage();
1012 : :
1013 : 0 : err = vhd_index(&name);
1014 : : }
1015 : :
1016 : : out:
1017 : 0 : vhd_index_free_name(&name);
1018 : 0 : return -err;
1019 : : }
|