1 /* 2 * Copyright (c) 2020 Tomohiro Kusumi <tkusumi@netbsd.org> 3 * Copyright (c) 2020 The DragonFly Project 4 * All rights reserved. 5 * 6 * This code is derived from software contributed to The DragonFly Project 7 * by Matthew Dillon <dillon@dragonflybsd.org> 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in 17 * the documentation and/or other materials provided with the 18 * distribution. 19 * 3. Neither the name of The DragonFly Project nor the names of its 20 * contributors may be used to endorse or promote products derived 21 * from this software without specific, prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 26 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 27 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 28 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 29 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 30 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 31 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 32 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 33 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 */ 36 37 #include <sys/types.h> 38 #include <sys/stat.h> 39 #include <unistd.h> 40 #include <fcntl.h> 41 #include <stdio.h> 42 #include <stdlib.h> 43 #include <stdint.h> 44 #include <string.h> 45 #include <fstab.h> 46 #include <assert.h> 47 #include <errno.h> 48 #include <err.h> 49 50 #include <vfs/hammer2/hammer2_disk.h> 51 52 #include "hammer2_subs.h" 53 54 static hammer2_ondisk_t fso; 55 static int hammer2_volumes_initialized; 56 57 static void 58 hammer2_init_volume(hammer2_volume_t *vol) 59 { 60 vol->fd = -1; 61 vol->id = -1; 62 vol->offset = (hammer2_off_t)-1; 63 vol->size = (hammer2_off_t)-1; 64 } 65 66 void 67 hammer2_init_ondisk(hammer2_ondisk_t *fsp) 68 { 69 int i; 70 71 bzero(fsp, sizeof(*fsp)); 72 fsp->version = -1; 73 for (i = 0; i < HAMMER2_MAX_VOLUMES; ++i) 74 hammer2_init_volume(&fsp->volumes[i]); 75 } 76 77 void 78 hammer2_install_volume(hammer2_volume_t *vol, int fd, int id, const char *path, 79 hammer2_off_t offset, hammer2_off_t size) 80 { 81 bzero(vol, sizeof(*vol)); 82 vol->fd = fd; 83 vol->id = id; 84 vol->path = strdup(path); 85 vol->offset = offset; 86 vol->size = size; 87 } 88 89 void 90 hammer2_uninstall_volume(hammer2_volume_t *vol) 91 { 92 fsync(vol->fd); 93 close(vol->fd); 94 free(vol->path); 95 hammer2_init_volume(vol); 96 } 97 98 /* 99 * Locate a valid volume header. If any of the four volume headers is good, 100 * we have a valid volume header and choose the best one based on mirror_tid. 101 */ 102 static int 103 hammer2_read_volume_header(int fd, const char *path, 104 hammer2_volume_data_t *voldata) 105 { 106 hammer2_volume_data_t vd; 107 hammer2_tid_t mirror_tid = -1; 108 hammer2_off_t size = check_volume(fd); 109 hammer2_crc32_t crc0, crc1; 110 const char *p; 111 int i, zone = -1; 112 ssize_t ret; 113 114 for (i = 0; i < HAMMER2_NUM_VOLHDRS; ++i) { 115 if (i * HAMMER2_ZONE_BYTES64 >= size) 116 break; 117 if (lseek(fd, i * HAMMER2_ZONE_BYTES64, SEEK_SET) == -1) 118 break; 119 ret = read(fd, &vd, HAMMER2_VOLUME_BYTES); 120 if (ret == -1) { 121 fprintf(stderr, "%s #%d: read %s\n", 122 path, i, strerror(errno)); 123 continue; 124 } 125 if (ret != HAMMER2_VOLUME_BYTES) { 126 fprintf(stderr, "%s #%d: read %s\n", 127 path, i, strerror(errno)); 128 continue; 129 } 130 131 p = (const char*)&vd; 132 /* verify volume header magic */ 133 if ((vd.magic != HAMMER2_VOLUME_ID_HBO) && 134 (vd.magic != HAMMER2_VOLUME_ID_ABO)) { 135 fprintf(stderr, "%s #%d: bad magic\n", path, i); 136 continue; 137 } 138 139 if (vd.magic == HAMMER2_VOLUME_ID_ABO) { 140 /* XXX: Reversed-endianness filesystem */ 141 fprintf(stderr, 142 "%s #%d: reverse-endian filesystem detected", 143 path, i); 144 continue; 145 } 146 147 /* verify volume header CRC's */ 148 crc0 = vd.icrc_sects[HAMMER2_VOL_ICRC_SECT0]; 149 crc1 = hammer2_icrc32(p + HAMMER2_VOLUME_ICRC0_OFF, 150 HAMMER2_VOLUME_ICRC0_SIZE); 151 if (crc0 != crc1) { 152 fprintf(stderr, 153 "%s #%d: volume header crc mismatch " 154 "sect0 %08x/%08x\n", 155 path, i, crc0, crc1); 156 continue; 157 } 158 159 crc0 = vd.icrc_sects[HAMMER2_VOL_ICRC_SECT1]; 160 crc1 = hammer2_icrc32(p + HAMMER2_VOLUME_ICRC1_OFF, 161 HAMMER2_VOLUME_ICRC1_SIZE); 162 if (crc0 != crc1) { 163 fprintf(stderr, 164 "%s #%d: volume header crc mismatch " 165 "sect1 %08x/%08x", 166 path, i, crc0, crc1); 167 continue; 168 } 169 170 crc0 = vd.icrc_volheader; 171 crc1 = hammer2_icrc32(p + HAMMER2_VOLUME_ICRCVH_OFF, 172 HAMMER2_VOLUME_ICRCVH_SIZE); 173 if (crc0 != crc1) { 174 fprintf(stderr, 175 "%s #%d: volume header crc mismatch " 176 "vh %08x/%08x", 177 path, i, crc0, crc1); 178 continue; 179 } 180 if (zone == -1 || mirror_tid < vd.mirror_tid) { 181 bcopy(&vd, voldata, sizeof(vd)); 182 mirror_tid = vd.mirror_tid; 183 zone = i; 184 } 185 } 186 return(zone); 187 } 188 189 static void 190 hammer2_err_uuid_mismatch(uuid_t *uuid1, uuid_t *uuid2, const char *id) 191 { 192 char *p1 = NULL, *p2 = NULL; 193 194 hammer2_uuid_to_str(uuid1, &p1); 195 hammer2_uuid_to_str(uuid2, &p2); 196 197 errx(1, "%s uuid mismatch %s vs %s", id, p1, p2); 198 199 free(p1); 200 free(p2); 201 } 202 203 static void 204 hammer2_add_volume(const char *path, int rdonly) 205 { 206 hammer2_volume_data_t voldata; 207 hammer2_volume_t *vol; 208 struct stat st; 209 int fd, i; 210 uuid_t uuid; 211 212 fd = open(path, rdonly ? O_RDONLY : O_RDWR); 213 if (fd == -1) 214 err(1, "open"); 215 216 if (fstat(fd, &st) == -1) 217 err(1, "fstat"); 218 if (!S_ISCHR(st.st_mode) && !S_ISREG(st.st_mode)) 219 errx(1, "Unsupported file type"); 220 221 if (hammer2_read_volume_header(fd, path, &voldata) >= 0) { 222 i = voldata.volu_id; 223 if (i < 0 || i >= HAMMER2_MAX_VOLUMES) 224 errx(1, "%s has bad volume id %d", path, i); 225 vol = &fso.volumes[i]; 226 if (vol->id != -1) 227 errx(1, "volume id %d already initialized", i); 228 /* all headers must have the same version, nvolumes and uuid */ 229 if (!fso.nvolumes) { 230 fso.version = voldata.version; 231 fso.nvolumes = voldata.nvolumes; 232 fso.fsid = voldata.fsid; 233 fso.fstype = voldata.fstype; 234 } else { 235 if (fso.version != (int)voldata.version) 236 errx(1, "Volume version mismatch %d vs %d", 237 fso.version, (int)voldata.version); 238 if (fso.nvolumes != voldata.nvolumes) 239 errx(1, "Volume count mismatch %d vs %d", 240 fso.nvolumes, voldata.nvolumes); 241 uuid = voldata.fsid; 242 if (!uuid_equal(&fso.fsid, &uuid, NULL)) 243 hammer2_err_uuid_mismatch(&fso.fsid, 244 &uuid, 245 "fsid"); 246 uuid = voldata.fstype; 247 if (!uuid_equal(&fso.fstype, &uuid, NULL)) 248 hammer2_err_uuid_mismatch(&fso.fstype, 249 &uuid, 250 "fstype"); 251 } 252 /* all per-volume tests passed */ 253 hammer2_install_volume(vol, fd, i, path, 254 voldata.volu_loff[i], voldata.volu_size); 255 fso.total_size += vol->size; 256 } else { 257 errx(1, "No valid volume headers found!"); 258 } 259 } 260 261 static void 262 hammer2_verify_volumes_common(const hammer2_ondisk_t *fsp) 263 { 264 const hammer2_volume_t *vol; 265 hammer2_off_t size; 266 struct stat *st; 267 const char *path; 268 int i, j, nvolumes = 0; 269 270 if (fsp->version == -1) 271 errx(1, "Bad volume version %d", fsp->version); 272 273 /* check initialized volume count */ 274 for (i = 0; i < HAMMER2_MAX_VOLUMES; ++i) { 275 vol = &fsp->volumes[i]; 276 if (vol->id != -1) 277 nvolumes++; 278 } 279 280 /* fsp->nvolumes hasn't been verified yet, use nvolumes */ 281 st = calloc(nvolumes, sizeof(*st)); 282 283 for (i = 0; i < HAMMER2_MAX_VOLUMES; ++i) { 284 vol = &fsp->volumes[i]; 285 if (vol->id == -1) 286 continue; 287 path = vol->path; 288 /* check volumes are unique */ 289 if (stat(path, &st[i]) != 0) 290 errx(1, "Failed to stat %s", path); 291 if (fstat(vol->fd, &st[i]) != 0) 292 errx(1, "Failed to fstat %d", vol->fd); 293 for (j = 0; j < i; ++j) { 294 if ((st[i].st_ino == st[j].st_ino) && 295 (st[i].st_dev == st[j].st_dev)) 296 errx(1, "%s specified more than once", path); 297 } 298 /* check volume fields are initialized */ 299 if (vol->fd == -1) 300 errx(1, "%s has bad fd %d", path, vol->fd); 301 if (vol->offset == (hammer2_off_t)-1) 302 errx(1, "%s has bad offset 0x%016jx", path, 303 (intmax_t)vol->offset); 304 if (vol->size == (hammer2_off_t)-1) 305 errx(1, "%s has bad size 0x%016jx", path, 306 (intmax_t)vol->size); 307 /* check volume size vs block device size */ 308 size = check_volume(vol->fd); 309 printf("checkvolu header %d %016jx/%016jx\n", i, vol->size, size); 310 if (vol->size > size) 311 errx(1, "%s's size 0x%016jx exceeds device size 0x%016jx", 312 path, (intmax_t)vol->size, size); 313 } 314 free(st); 315 } 316 317 static void 318 hammer2_verify_volumes_1(hammer2_ondisk_t *fsp, 319 const hammer2_volume_data_t *rootvoldata) 320 { 321 const hammer2_volume_t *vol; 322 hammer2_off_t off; 323 const char *path; 324 int i, nvolumes = 0; 325 326 /* check initialized volume count */ 327 for (i = 0; i < HAMMER2_MAX_VOLUMES; ++i) { 328 vol = &fsp->volumes[i]; 329 if (vol->id != -1) 330 nvolumes++; 331 } 332 if (nvolumes != 1) 333 errx(1, "Only 1 volume supported"); 334 fsp->nvolumes = nvolumes; /* adjust with actual count */ 335 336 /* check volume header */ 337 if (rootvoldata) { 338 if (rootvoldata->volu_id) 339 errx(1, "Volume id %d must be 0", rootvoldata->volu_id); 340 if (rootvoldata->nvolumes) 341 errx(1, "Volume count %d must be 0", 342 rootvoldata->nvolumes); 343 if (rootvoldata->total_size) 344 errx(1, "Total size 0x%016jx must be 0", 345 (intmax_t)rootvoldata->total_size); 346 for (i = 0; i < HAMMER2_MAX_VOLUMES; ++i) { 347 off = rootvoldata->volu_loff[i]; 348 if (off) 349 errx(1, "Volume offset[%d] 0x%016jx must be 0", 350 i, (intmax_t)off); 351 } 352 } 353 354 /* check volume */ 355 vol = &fsp->volumes[HAMMER2_ROOT_VOLUME]; 356 path = vol->path; 357 if (vol->id) 358 errx(1, "%s has non zero id %d", path, vol->id); 359 if (vol->offset) 360 errx(1, "%s has non zero offset 0x%016jx", path, 361 (intmax_t)vol->offset); 362 if (vol->size & HAMMER2_VOLUME_ALIGNMASK64) 363 errx(1, "%s's size is not 0x%016jx aligned", path, 364 (intmax_t)HAMMER2_VOLUME_ALIGN); 365 } 366 367 static void 368 hammer2_verify_volumes_2(const hammer2_ondisk_t *fsp, 369 const hammer2_volume_data_t *rootvoldata) 370 { 371 const hammer2_volume_t *vol; 372 hammer2_off_t off; 373 const char *path; 374 int i, nvolumes = 0; 375 376 /* check initialized volume count */ 377 for (i = 0; i < HAMMER2_MAX_VOLUMES; ++i) { 378 vol = &fsp->volumes[i]; 379 if (vol->id != -1) 380 nvolumes++; 381 } 382 if (fsp->nvolumes != nvolumes) 383 errx(1, "Volume count mismatch %d vs %d", 384 fsp->nvolumes, nvolumes); 385 386 /* check volume header */ 387 if (rootvoldata) { 388 if (rootvoldata->volu_id != HAMMER2_ROOT_VOLUME) 389 errx(1, "Volume id %d must be %d", 390 rootvoldata->volu_id, HAMMER2_ROOT_VOLUME); 391 if (rootvoldata->nvolumes != fso.nvolumes) 392 errx(1, "Volume header requires %d devices, %d specified", 393 rootvoldata->nvolumes, fso.nvolumes); 394 if (rootvoldata->total_size != fso.total_size) 395 errx(1, "Total size 0x%016jx does not equal sum of " 396 "volumes 0x%016jx", 397 rootvoldata->total_size, fso.total_size); 398 for (i = 0; i < nvolumes; ++i) { 399 off = rootvoldata->volu_loff[i]; 400 if (off == (hammer2_off_t)-1) 401 errx(1, "Volume offset[%d] 0x%016jx must not be -1", 402 i, (intmax_t)off); 403 } 404 for (i = nvolumes; i < HAMMER2_MAX_VOLUMES; ++i) { 405 off = rootvoldata->volu_loff[i]; 406 if (off != (hammer2_off_t)-1) 407 errx(1, "Volume offset[%d] 0x%016jx must be -1", 408 i, (intmax_t)off); 409 } 410 } 411 412 /* check volumes */ 413 for (i = 0; i < HAMMER2_MAX_VOLUMES; ++i) { 414 vol = &fsp->volumes[i]; 415 if (vol->id == -1) 416 continue; 417 path = vol->path; 418 /* check offset */ 419 if (vol->offset & HAMMER2_FREEMAP_LEVEL1_MASK) 420 errx(1, "%s's offset 0x%016jx not 0x%016jx aligned", 421 path, (intmax_t)vol->offset, 422 HAMMER2_FREEMAP_LEVEL1_SIZE); 423 /* check vs previous volume */ 424 if (i) { 425 if (vol->id != (vol-1)->id + 1) 426 errx(1, "%s has inconsistent id %d", path, 427 vol->id); 428 if (vol->offset != (vol-1)->offset + (vol-1)->size) 429 errx(1, "%s has inconsistent offset 0x%016jx", 430 path, (intmax_t)vol->offset); 431 } else { /* first */ 432 if (vol->offset) 433 errx(1, "%s has non zero offset 0x%016jx", path, 434 (intmax_t)vol->offset); 435 } 436 /* check size for non-last and last volumes */ 437 if (i != fsp->nvolumes - 1) { 438 if (vol->size < HAMMER2_FREEMAP_LEVEL1_SIZE) 439 errx(1, "%s's size must be >= 0x%016jx", path, 440 (intmax_t)HAMMER2_FREEMAP_LEVEL1_SIZE); 441 if (vol->size & HAMMER2_FREEMAP_LEVEL1_MASK) 442 errx(1, "%s's size is not 0x%016jx aligned", 443 path, 444 (intmax_t)HAMMER2_FREEMAP_LEVEL1_SIZE); 445 } else { /* last */ 446 if (vol->size & HAMMER2_VOLUME_ALIGNMASK64) 447 errx(1, "%s's size is not 0x%016jx aligned", 448 path, (intmax_t)HAMMER2_VOLUME_ALIGN); 449 } 450 } 451 } 452 453 void 454 hammer2_verify_volumes(hammer2_ondisk_t *fsp, 455 const hammer2_volume_data_t *rootvoldata) 456 { 457 hammer2_verify_volumes_common(fsp); 458 if (fsp->version >= HAMMER2_VOL_VERSION_MULTI_VOLUMES) 459 hammer2_verify_volumes_2(fsp, rootvoldata); 460 else 461 hammer2_verify_volumes_1(fsp, rootvoldata); 462 assert(fsp->nvolumes > 0); 463 } 464 465 void 466 hammer2_print_volumes(const hammer2_ondisk_t *fsp) 467 { 468 const hammer2_volume_t *vol; 469 int i, n, w = 0; 470 471 for (i = 0; i < fsp->nvolumes; ++i) { 472 vol = &fsp->volumes[i]; 473 n = (int)strlen(vol->path); 474 if (n > w) 475 w = n; 476 } 477 478 printf("total %-*.*s 0x%016jx 0x%016jx\n", 479 w, w, "", (intmax_t)0, (intmax_t)fsp->total_size); 480 481 for (i = 0; i < fsp->nvolumes; ++i) { 482 vol = &fsp->volumes[i]; 483 printf("volume%-2d %-*.*s 0x%016jx 0x%016jx%s\n", 484 vol->id, w, w, vol->path, (intmax_t)vol->offset, 485 (intmax_t)vol->size, 486 (vol->id == HAMMER2_ROOT_VOLUME ? 487 " (root volume)" : "")); 488 } 489 } 490 491 void 492 hammer2_init_volumes(const char *blkdevs, int rdonly) 493 { 494 hammer2_volume_data_t *rootvoldata; 495 char *o, *p, *devpath; 496 497 if (hammer2_volumes_initialized) 498 errx(1, "Already initialized"); 499 if (!blkdevs) 500 errx(1, "NULL blkdevs"); 501 502 hammer2_init_ondisk(&fso); 503 o = p = strdup(blkdevs); 504 while ((devpath = p) != NULL) { 505 if ((p = strchr(p, ':')) != NULL) 506 *p++ = 0; 507 devpath = getdevpath(devpath, 0); 508 if (strchr(devpath, ':')) 509 hammer2_init_volumes(devpath, rdonly); 510 else 511 hammer2_add_volume(devpath, rdonly); 512 free(devpath); 513 } 514 free(o); 515 hammer2_volumes_initialized = 1; 516 517 rootvoldata = hammer2_read_root_volume_header(); 518 hammer2_verify_volumes(&fso, rootvoldata); 519 free(rootvoldata); 520 } 521 522 void 523 hammer2_cleanup_volumes(void) 524 { 525 hammer2_volume_t *vol; 526 int i; 527 528 for (i = 0; i < HAMMER2_MAX_VOLUMES; ++i) { 529 vol = &fso.volumes[i]; 530 if (vol->id == -1) 531 continue; 532 hammer2_uninstall_volume(vol); 533 } 534 hammer2_volumes_initialized = 0; 535 } 536 537 typedef void (*callback)(const hammer2_volume_t*, void *data); 538 539 hammer2_volume_t * 540 hammer2_get_volume(hammer2_off_t offset) 541 { 542 hammer2_volume_t *vol; 543 int i; 544 545 assert(hammer2_volumes_initialized == 1); 546 offset &= ~HAMMER2_OFF_MASK_RADIX; 547 548 /* do binary search if users really use this many supported volumes */ 549 for (i = 0; i < fso.nvolumes; ++i) { 550 vol = &fso.volumes[i]; 551 if ((offset >= vol->offset) && 552 (offset < vol->offset + vol->size)) 553 { 554 return vol; 555 } 556 } 557 return NULL; 558 } 559 560 static int 561 hammer2_get_volume_attr(hammer2_off_t offset, callback fn, void *data) 562 { 563 hammer2_volume_t *vol; 564 int i; 565 566 assert(hammer2_volumes_initialized == 1); 567 offset &= ~HAMMER2_OFF_MASK_RADIX; 568 569 /* do binary search if users really use this many supported volumes */ 570 for (i = 0; i < fso.nvolumes; ++i) { 571 vol = &fso.volumes[i]; 572 if ((offset >= vol->offset) && 573 (offset < vol->offset + vol->size)) { 574 fn(vol, data); 575 return(0); 576 } 577 } 578 579 return(-1); 580 } 581 582 /* fd */ 583 static void 584 hammer2_volume_fd_cb(const hammer2_volume_t *vol, void *data) 585 { 586 *(int*)data = vol->fd; 587 } 588 589 int 590 hammer2_get_volume_fd(hammer2_off_t offset) 591 { 592 int ret = 0; 593 594 if (hammer2_get_volume_attr(offset, hammer2_volume_fd_cb, &ret) < 0) 595 return(-1); 596 return(ret); 597 } 598 599 int 600 hammer2_get_root_volume_fd(void) 601 { 602 return(hammer2_get_volume_fd(0)); 603 } 604 605 /* id */ 606 static void 607 hammer2_volume_id_cb(const hammer2_volume_t *vol, void *data) 608 { 609 *(int*)data = vol->id; 610 } 611 612 int 613 hammer2_get_volume_id(hammer2_off_t offset) 614 { 615 int ret = 0; 616 617 if (hammer2_get_volume_attr(offset, hammer2_volume_id_cb, &ret) < 0) 618 return(-1); 619 return(ret); 620 } 621 622 int 623 hammer2_get_root_volume_id(void) 624 { 625 return(hammer2_get_volume_id(0)); 626 } 627 628 /* path */ 629 static void 630 hammer2_volume_path_cb(const hammer2_volume_t *vol, void *data) 631 { 632 *(const char**)data = vol->path; 633 } 634 635 const char * 636 hammer2_get_volume_path(hammer2_off_t offset) 637 { 638 const char *ret = NULL; 639 640 if (hammer2_get_volume_attr(offset, hammer2_volume_path_cb, &ret) < 0) 641 return(NULL); 642 return(ret); 643 } 644 645 const char * 646 hammer2_get_root_volume_path(void) 647 { 648 return(hammer2_get_volume_path(0)); 649 } 650 651 /* offset */ 652 static void 653 hammer2_volume_offset_cb(const hammer2_volume_t *vol, void *data) 654 { 655 *(hammer2_off_t*)data = vol->offset; 656 } 657 658 hammer2_off_t 659 hammer2_get_volume_offset(hammer2_off_t offset) 660 { 661 hammer2_off_t ret = 0; 662 663 if (hammer2_get_volume_attr(offset, hammer2_volume_offset_cb, &ret) < 0) 664 return(-1); 665 return(ret); 666 } 667 668 hammer2_off_t 669 hammer2_get_root_volume_offset(void) 670 { 671 return(hammer2_get_volume_offset(0)); 672 } 673 674 /* size */ 675 static void 676 hammer2_volume_size_cb(const hammer2_volume_t *vol, void *data) 677 { 678 *(hammer2_off_t*)data = vol->size; 679 } 680 681 hammer2_off_t 682 hammer2_get_volume_size(hammer2_off_t offset) 683 { 684 hammer2_off_t ret = 0; 685 686 if (hammer2_get_volume_attr(offset, hammer2_volume_size_cb, &ret) < 0) 687 return(-1); 688 return(ret); 689 } 690 691 hammer2_off_t 692 hammer2_get_root_volume_size(void) 693 { 694 return(hammer2_get_volume_size(0)); 695 } 696 697 /* total size */ 698 hammer2_off_t 699 hammer2_get_total_size(void) 700 { 701 return(fso.total_size); 702 } 703 704 hammer2_volume_data_t* 705 hammer2_read_root_volume_header(void) 706 { 707 hammer2_volume_data_t *voldata; 708 int fd = hammer2_get_root_volume_fd(); 709 const char *path = hammer2_get_root_volume_path(); 710 711 if (fd == -1) 712 return(NULL); 713 714 voldata = calloc(1, sizeof(*voldata)); 715 if (hammer2_read_volume_header(fd, path, voldata) >= 0) 716 return(voldata); 717 else 718 errx(1, "Failed to read volume header"); 719 } 720