1 1.9 christos /* $NetBSD: hammer2.c,v 1.9 2021/12/02 14:26:42 christos Exp $ */ 2 1.1 tkusumi 3 1.1 tkusumi /*- 4 1.1 tkusumi * Copyright (c) 2017-2019 The DragonFly Project 5 1.1 tkusumi * Copyright (c) 2017-2019 Tomohiro Kusumi <tkusumi (at) netbsd.org> 6 1.1 tkusumi * All rights reserved. 7 1.1 tkusumi * 8 1.1 tkusumi * Redistribution and use in source and binary forms, with or without 9 1.1 tkusumi * modification, are permitted provided that the following conditions 10 1.1 tkusumi * are met: 11 1.1 tkusumi * 1. Redistributions of source code must retain the above copyright 12 1.1 tkusumi * notice, this list of conditions and the following disclaimer. 13 1.1 tkusumi * 2. Redistributions in binary form must reproduce the above copyright 14 1.1 tkusumi * notice, this list of conditions and the following disclaimer in the 15 1.1 tkusumi * documentation and/or other materials provided with the distribution. 16 1.1 tkusumi * 17 1.1 tkusumi * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 18 1.1 tkusumi * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 1.1 tkusumi * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 1.1 tkusumi * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 21 1.1 tkusumi * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 1.1 tkusumi * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 1.1 tkusumi * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 1.1 tkusumi * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 1.1 tkusumi * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 1.1 tkusumi * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 1.1 tkusumi * SUCH DAMAGE. 28 1.1 tkusumi */ 29 1.1 tkusumi #include <sys/cdefs.h> 30 1.9 christos __KERNEL_RCSID(0, "$NetBSD: hammer2.c,v 1.9 2021/12/02 14:26:42 christos Exp $"); 31 1.9 christos 32 1.9 christos #include <sys/param.h> 33 1.9 christos #include <sys/ioctl.h> 34 1.9 christos #include <sys/disk.h> 35 1.1 tkusumi 36 1.1 tkusumi #include <stdio.h> 37 1.1 tkusumi #include <stdlib.h> 38 1.1 tkusumi #include <stdbool.h> 39 1.1 tkusumi #include <string.h> 40 1.1 tkusumi #include <err.h> 41 1.1 tkusumi #include <assert.h> 42 1.7 tkusumi #include <uuid.h> 43 1.1 tkusumi 44 1.1 tkusumi #include "fstyp.h" 45 1.1 tkusumi #include "hammer2_disk.h" 46 1.1 tkusumi 47 1.7 tkusumi static ssize_t 48 1.7 tkusumi get_file_size(FILE *fp) 49 1.1 tkusumi { 50 1.7 tkusumi ssize_t siz; 51 1.9 christos struct dkwedge_info dkw; 52 1.9 christos 53 1.9 christos if (ioctl(fileno(fp), DIOCGWEDGEINFO, &dkw) != -1) { 54 1.9 christos return (ssize_t)dkw.dkw_size * DEV_BSIZE; 55 1.9 christos } 56 1.7 tkusumi 57 1.7 tkusumi if (fseek(fp, 0, SEEK_END) == -1) { 58 1.7 tkusumi warnx("hammer2: failed to seek media end"); 59 1.9 christos return -1; 60 1.7 tkusumi } 61 1.7 tkusumi 62 1.7 tkusumi siz = ftell(fp); 63 1.7 tkusumi if (siz == -1) { 64 1.7 tkusumi warnx("hammer2: failed to tell media end"); 65 1.9 christos return -1; 66 1.7 tkusumi } 67 1.7 tkusumi 68 1.9 christos return siz; 69 1.7 tkusumi } 70 1.7 tkusumi 71 1.7 tkusumi static hammer2_volume_data_t * 72 1.7 tkusumi read_voldata(FILE *fp, int i) 73 1.7 tkusumi { 74 1.7 tkusumi if (i < 0 || i >= HAMMER2_NUM_VOLHDRS) 75 1.9 christos return NULL; 76 1.1 tkusumi 77 1.7 tkusumi if ((hammer2_off_t)i * (hammer2_off_t)HAMMER2_ZONE_BYTES64 >= (hammer2_off_t)get_file_size(fp)) 78 1.9 christos return NULL; 79 1.1 tkusumi 80 1.9 christos return read_buf(fp, (off_t)i * (off_t)HAMMER2_ZONE_BYTES64, 81 1.9 christos sizeof(hammer2_volume_data_t)); 82 1.1 tkusumi } 83 1.1 tkusumi 84 1.1 tkusumi static int 85 1.7 tkusumi test_voldata(FILE *fp) 86 1.1 tkusumi { 87 1.7 tkusumi hammer2_volume_data_t *voldata; 88 1.7 tkusumi int i; 89 1.7 tkusumi static int count = 0; 90 1.7 tkusumi static uuid_t fsid, fstype; 91 1.7 tkusumi 92 1.7 tkusumi for (i = 0; i < HAMMER2_NUM_VOLHDRS; i++) { 93 1.7 tkusumi if ((hammer2_off_t)i * (hammer2_off_t)HAMMER2_ZONE_BYTES64 >= (hammer2_off_t)get_file_size(fp)) 94 1.7 tkusumi break; 95 1.7 tkusumi voldata = read_voldata(fp, i); 96 1.7 tkusumi if (voldata == NULL) { 97 1.7 tkusumi warnx("hammer2: failed to read volume data"); 98 1.9 christos return 1; 99 1.7 tkusumi } 100 1.7 tkusumi if (voldata->magic != HAMMER2_VOLUME_ID_HBO && 101 1.7 tkusumi voldata->magic != HAMMER2_VOLUME_ID_ABO) { 102 1.7 tkusumi free(voldata); 103 1.9 christos return 1; 104 1.7 tkusumi } 105 1.7 tkusumi if (voldata->volu_id > HAMMER2_MAX_VOLUMES - 1) { 106 1.7 tkusumi free(voldata); 107 1.9 christos return 1; 108 1.7 tkusumi } 109 1.7 tkusumi if (voldata->nvolumes > HAMMER2_MAX_VOLUMES) { 110 1.7 tkusumi free(voldata); 111 1.9 christos return 1; 112 1.7 tkusumi } 113 1.7 tkusumi 114 1.7 tkusumi if (count == 0) { 115 1.7 tkusumi count = voldata->nvolumes; 116 1.7 tkusumi memcpy(&fsid, &voldata->fsid, sizeof(fsid)); 117 1.7 tkusumi memcpy(&fstype, &voldata->fstype, sizeof(fstype)); 118 1.7 tkusumi } else { 119 1.7 tkusumi if (voldata->nvolumes != count) { 120 1.7 tkusumi free(voldata); 121 1.9 christos return 1; 122 1.7 tkusumi } 123 1.7 tkusumi if (!uuid_equal(&fsid, &voldata->fsid, NULL)) { 124 1.7 tkusumi free(voldata); 125 1.9 christos return 1; 126 1.7 tkusumi } 127 1.7 tkusumi if (!uuid_equal(&fstype, &voldata->fstype, NULL)) { 128 1.7 tkusumi free(voldata); 129 1.9 christos return 1; 130 1.7 tkusumi } 131 1.7 tkusumi } 132 1.7 tkusumi free(voldata); 133 1.7 tkusumi } 134 1.1 tkusumi 135 1.9 christos return 0; 136 1.1 tkusumi } 137 1.1 tkusumi 138 1.1 tkusumi static hammer2_media_data_t* 139 1.1 tkusumi read_media(FILE *fp, const hammer2_blockref_t *bref, size_t *media_bytes) 140 1.1 tkusumi { 141 1.1 tkusumi hammer2_media_data_t *media; 142 1.1 tkusumi hammer2_off_t io_off, io_base; 143 1.7 tkusumi size_t bytes, io_bytes, boff, fbytes; 144 1.1 tkusumi 145 1.1 tkusumi bytes = (bref->data_off & HAMMER2_OFF_MASK_RADIX); 146 1.1 tkusumi if (bytes) 147 1.1 tkusumi bytes = (size_t)1 << bytes; 148 1.1 tkusumi *media_bytes = bytes; 149 1.1 tkusumi 150 1.1 tkusumi if (!bytes) { 151 1.7 tkusumi warnx("hammer2: blockref has no data"); 152 1.9 christos return NULL; 153 1.1 tkusumi } 154 1.1 tkusumi 155 1.1 tkusumi io_off = bref->data_off & ~HAMMER2_OFF_MASK_RADIX; 156 1.6 tkusumi io_base = io_off & ~(hammer2_off_t)(HAMMER2_LBUFSIZE - 1); 157 1.8 martin boff = (size_t)((hammer2_off_t)io_off - io_base); 158 1.1 tkusumi 159 1.6 tkusumi io_bytes = HAMMER2_LBUFSIZE; 160 1.1 tkusumi while (io_bytes + boff < bytes) 161 1.1 tkusumi io_bytes <<= 1; 162 1.1 tkusumi 163 1.1 tkusumi if (io_bytes > sizeof(hammer2_media_data_t)) { 164 1.7 tkusumi warnx("hammer2: invalid I/O bytes"); 165 1.9 christos return NULL; 166 1.1 tkusumi } 167 1.1 tkusumi 168 1.7 tkusumi /* 169 1.7 tkusumi * XXX fp is currently always root volume, so read fails if io_base is 170 1.7 tkusumi * beyond root volume limit. Fail with a message before read_buf() then. 171 1.7 tkusumi */ 172 1.7 tkusumi fbytes = (size_t)get_file_size(fp); 173 1.7 tkusumi if ((ssize_t)fbytes == -1) { 174 1.7 tkusumi warnx("hammer2: failed to get media size"); 175 1.9 christos return NULL; 176 1.7 tkusumi } 177 1.7 tkusumi if (io_base >= fbytes) { 178 1.7 tkusumi warnx("hammer2: XXX read beyond HAMMER2 root volume limit unsupported"); 179 1.9 christos return NULL; 180 1.7 tkusumi } 181 1.7 tkusumi 182 1.7 tkusumi if (fseeko(fp, (off_t)io_base, SEEK_SET) == -1) { 183 1.7 tkusumi warnx("hammer2: failed to seek media"); 184 1.9 christos return NULL; 185 1.1 tkusumi } 186 1.1 tkusumi media = read_buf(fp, (off_t)io_base, io_bytes); 187 1.1 tkusumi if (media == NULL) { 188 1.7 tkusumi warnx("hammer2: failed to read media"); 189 1.9 christos return NULL; 190 1.1 tkusumi } 191 1.1 tkusumi if (boff) 192 1.1 tkusumi memcpy(media, (char *)media + boff, bytes); 193 1.1 tkusumi 194 1.9 christos return media; 195 1.1 tkusumi } 196 1.1 tkusumi 197 1.1 tkusumi static int 198 1.1 tkusumi find_pfs(FILE *fp, const hammer2_blockref_t *bref, const char *pfs, bool *res) 199 1.1 tkusumi { 200 1.1 tkusumi hammer2_media_data_t *media; 201 1.1 tkusumi hammer2_inode_data_t ipdata; 202 1.1 tkusumi hammer2_blockref_t *bscan; 203 1.1 tkusumi size_t bytes; 204 1.1 tkusumi int i, bcount; 205 1.1 tkusumi 206 1.1 tkusumi media = read_media(fp, bref, &bytes); 207 1.1 tkusumi if (media == NULL) 208 1.9 christos return -1; 209 1.1 tkusumi 210 1.1 tkusumi switch (bref->type) { 211 1.1 tkusumi case HAMMER2_BREF_TYPE_INODE: 212 1.1 tkusumi ipdata = media->ipdata; 213 1.5 tkusumi if (ipdata.meta.pfs_type == HAMMER2_PFSTYPE_SUPROOT) { 214 1.1 tkusumi bscan = &ipdata.u.blockset.blockref[0]; 215 1.1 tkusumi bcount = HAMMER2_SET_COUNT; 216 1.1 tkusumi } else { 217 1.1 tkusumi bscan = NULL; 218 1.1 tkusumi bcount = 0; 219 1.1 tkusumi if (ipdata.meta.op_flags & HAMMER2_OPFLAG_PFSROOT) { 220 1.1 tkusumi if (memchr(ipdata.filename, 0, 221 1.1 tkusumi sizeof(ipdata.filename))) { 222 1.1 tkusumi if (!strcmp( 223 1.1 tkusumi (const char*)ipdata.filename, pfs)) 224 1.1 tkusumi *res = true; 225 1.1 tkusumi } else { 226 1.1 tkusumi if (strlen(pfs) > 0 && 227 1.1 tkusumi !memcmp(ipdata.filename, pfs, 228 1.1 tkusumi strlen(pfs))) 229 1.1 tkusumi *res = true; 230 1.1 tkusumi } 231 1.7 tkusumi } else { 232 1.7 tkusumi free(media); 233 1.9 christos return -1; 234 1.7 tkusumi } 235 1.1 tkusumi } 236 1.1 tkusumi break; 237 1.1 tkusumi case HAMMER2_BREF_TYPE_INDIRECT: 238 1.1 tkusumi bscan = &media->npdata[0]; 239 1.1 tkusumi bcount = (int)(bytes / sizeof(hammer2_blockref_t)); 240 1.1 tkusumi break; 241 1.1 tkusumi default: 242 1.1 tkusumi bscan = NULL; 243 1.1 tkusumi bcount = 0; 244 1.1 tkusumi break; 245 1.1 tkusumi } 246 1.1 tkusumi 247 1.1 tkusumi for (i = 0; i < bcount; ++i) { 248 1.1 tkusumi if (bscan[i].type != HAMMER2_BREF_TYPE_EMPTY) { 249 1.1 tkusumi if (find_pfs(fp, &bscan[i], pfs, res) == -1) { 250 1.1 tkusumi free(media); 251 1.9 christos return -1; 252 1.1 tkusumi } 253 1.1 tkusumi } 254 1.1 tkusumi } 255 1.1 tkusumi free(media); 256 1.1 tkusumi 257 1.9 christos return 0; 258 1.1 tkusumi } 259 1.1 tkusumi 260 1.1 tkusumi static char* 261 1.1 tkusumi extract_device_name(const char *devpath) 262 1.1 tkusumi { 263 1.1 tkusumi char *p, *head; 264 1.1 tkusumi 265 1.1 tkusumi if (!devpath) 266 1.9 christos return NULL; 267 1.1 tkusumi 268 1.1 tkusumi p = strdup(devpath); 269 1.1 tkusumi head = p; 270 1.1 tkusumi 271 1.1 tkusumi p = strchr(p, '@'); 272 1.1 tkusumi if (p) 273 1.1 tkusumi *p = 0; 274 1.1 tkusumi 275 1.1 tkusumi p = strrchr(head, '/'); 276 1.1 tkusumi if (p) { 277 1.1 tkusumi p++; 278 1.1 tkusumi if (*p == 0) { 279 1.1 tkusumi free(head); 280 1.9 christos return NULL; 281 1.1 tkusumi } 282 1.1 tkusumi p = strdup(p); 283 1.1 tkusumi free(head); 284 1.9 christos return p; 285 1.1 tkusumi } 286 1.1 tkusumi 287 1.9 christos return head; 288 1.1 tkusumi } 289 1.1 tkusumi 290 1.1 tkusumi static int 291 1.7 tkusumi read_label(FILE *fp, char *label, size_t size, const char *devpath) 292 1.1 tkusumi { 293 1.1 tkusumi hammer2_blockref_t broot, best, *bref; 294 1.1 tkusumi hammer2_media_data_t *vols[HAMMER2_NUM_VOLHDRS], *media; 295 1.1 tkusumi size_t bytes; 296 1.1 tkusumi bool res = false; 297 1.3 tkusumi int i, best_i, error = 1; 298 1.1 tkusumi const char *pfs; 299 1.1 tkusumi char *devname; 300 1.1 tkusumi 301 1.1 tkusumi best_i = -1; 302 1.7 tkusumi memset(vols, 0, sizeof(vols)); 303 1.1 tkusumi memset(&best, 0, sizeof(best)); 304 1.1 tkusumi 305 1.1 tkusumi for (i = 0; i < HAMMER2_NUM_VOLHDRS; i++) { 306 1.7 tkusumi if ((hammer2_off_t)i * (hammer2_off_t)HAMMER2_ZONE_BYTES64 >= (hammer2_off_t)get_file_size(fp)) 307 1.7 tkusumi break; 308 1.1 tkusumi memset(&broot, 0, sizeof(broot)); 309 1.1 tkusumi broot.type = HAMMER2_BREF_TYPE_VOLUME; 310 1.7 tkusumi broot.data_off = ((hammer2_off_t)i * (hammer2_off_t)HAMMER2_ZONE_BYTES64) | HAMMER2_PBUFRADIX; 311 1.7 tkusumi vols[i] = (void*)read_voldata(fp, i); 312 1.7 tkusumi if (vols[i] == NULL) { 313 1.7 tkusumi warnx("hammer2: failed to read volume data"); 314 1.7 tkusumi goto fail; 315 1.7 tkusumi } 316 1.1 tkusumi broot.mirror_tid = vols[i]->voldata.mirror_tid; 317 1.1 tkusumi if (best_i < 0 || best.mirror_tid < broot.mirror_tid) { 318 1.1 tkusumi best_i = i; 319 1.1 tkusumi best = broot; 320 1.1 tkusumi } 321 1.1 tkusumi } 322 1.1 tkusumi 323 1.1 tkusumi bref = &vols[best_i]->voldata.sroot_blockset.blockref[0]; 324 1.1 tkusumi if (bref->type != HAMMER2_BREF_TYPE_INODE) { 325 1.7 tkusumi /* Don't print error as devpath could be non-root volume. */ 326 1.3 tkusumi goto fail; 327 1.1 tkusumi } 328 1.1 tkusumi 329 1.1 tkusumi media = read_media(fp, bref, &bytes); 330 1.1 tkusumi if (media == NULL) { 331 1.3 tkusumi goto fail; 332 1.1 tkusumi } 333 1.1 tkusumi 334 1.1 tkusumi /* 335 1.1 tkusumi * fstyp_function in DragonFly takes an additional devpath argument 336 1.1 tkusumi * which doesn't exist in FreeBSD and NetBSD. 337 1.1 tkusumi */ 338 1.1 tkusumi #ifdef HAS_DEVPATH 339 1.1 tkusumi pfs = strchr(devpath, '@'); 340 1.1 tkusumi if (!pfs) { 341 1.1 tkusumi assert(strlen(devpath)); 342 1.1 tkusumi switch (devpath[strlen(devpath) - 1]) { 343 1.1 tkusumi case 'a': 344 1.1 tkusumi pfs = "BOOT"; 345 1.1 tkusumi break; 346 1.1 tkusumi case 'd': 347 1.1 tkusumi pfs = "ROOT"; 348 1.1 tkusumi break; 349 1.1 tkusumi default: 350 1.1 tkusumi pfs = "DATA"; 351 1.1 tkusumi break; 352 1.1 tkusumi } 353 1.1 tkusumi } else 354 1.1 tkusumi pfs++; 355 1.1 tkusumi 356 1.1 tkusumi if (strlen(pfs) > HAMMER2_INODE_MAXNAME) { 357 1.3 tkusumi goto fail; 358 1.1 tkusumi } 359 1.1 tkusumi devname = extract_device_name(devpath); 360 1.1 tkusumi #else 361 1.1 tkusumi pfs = ""; 362 1.1 tkusumi devname = extract_device_name(NULL); 363 1.1 tkusumi assert(!devname); 364 1.1 tkusumi #endif 365 1.1 tkusumi 366 1.1 tkusumi /* Add device name to help support multiple autofs -media mounts. */ 367 1.1 tkusumi if (find_pfs(fp, bref, pfs, &res) == 0 && res) { 368 1.1 tkusumi if (devname) 369 1.1 tkusumi snprintf(label, size, "%s_%s", pfs, devname); 370 1.1 tkusumi else 371 1.1 tkusumi strlcpy(label, pfs, size); 372 1.1 tkusumi } else { 373 1.1 tkusumi memset(label, 0, size); 374 1.1 tkusumi memcpy(label, media->ipdata.filename, 375 1.1 tkusumi sizeof(media->ipdata.filename)); 376 1.1 tkusumi if (devname) { 377 1.1 tkusumi strlcat(label, "_", size); 378 1.1 tkusumi strlcat(label, devname, size); 379 1.1 tkusumi } 380 1.1 tkusumi } 381 1.1 tkusumi if (devname) 382 1.1 tkusumi free(devname); 383 1.1 tkusumi free(media); 384 1.3 tkusumi error = 0; 385 1.3 tkusumi fail: 386 1.1 tkusumi for (i = 0; i < HAMMER2_NUM_VOLHDRS; i++) 387 1.1 tkusumi free(vols[i]); 388 1.1 tkusumi 389 1.9 christos return error; 390 1.1 tkusumi } 391 1.1 tkusumi 392 1.1 tkusumi int 393 1.1 tkusumi fstyp_hammer2(FILE *fp, char *label, size_t size) 394 1.1 tkusumi { 395 1.7 tkusumi hammer2_volume_data_t *voldata = read_voldata(fp, 0); 396 1.1 tkusumi int error = 1; 397 1.1 tkusumi 398 1.9 christos if (voldata == NULL) 399 1.9 christos goto fail; 400 1.7 tkusumi if (voldata->volu_id != HAMMER2_ROOT_VOLUME) 401 1.7 tkusumi goto fail; 402 1.7 tkusumi if (voldata->nvolumes != 0) 403 1.7 tkusumi goto fail; 404 1.7 tkusumi if (test_voldata(fp)) 405 1.7 tkusumi goto fail; 406 1.7 tkusumi 407 1.7 tkusumi error = read_label(fp, label, size, NULL); 408 1.7 tkusumi fail: 409 1.7 tkusumi free(voldata); 410 1.9 christos return error; 411 1.7 tkusumi } 412 1.7 tkusumi 413 1.7 tkusumi static int 414 1.7 tkusumi __fsvtyp_hammer2(const char *blkdevs, char *label, size_t size, int partial) 415 1.7 tkusumi { 416 1.7 tkusumi hammer2_volume_data_t *voldata = NULL; 417 1.7 tkusumi FILE *fp = NULL; 418 1.7 tkusumi char *dup = NULL, *target_label = NULL, *p, *volpath, *rootvolpath; 419 1.7 tkusumi char x[HAMMER2_MAX_VOLUMES]; 420 1.7 tkusumi int i, volid, error = 1; 421 1.7 tkusumi 422 1.7 tkusumi if (!blkdevs) 423 1.7 tkusumi goto fail; 424 1.7 tkusumi 425 1.7 tkusumi memset(x, 0, sizeof(x)); 426 1.7 tkusumi p = dup = strdup(blkdevs); 427 1.7 tkusumi if ((p = strchr(p, '@')) != NULL) { 428 1.7 tkusumi *p++ = '\0'; 429 1.7 tkusumi target_label = p; 430 1.7 tkusumi } 431 1.7 tkusumi p = dup; 432 1.7 tkusumi 433 1.7 tkusumi volpath = NULL; 434 1.7 tkusumi rootvolpath = NULL; 435 1.7 tkusumi volid = -1; 436 1.7 tkusumi while (p) { 437 1.7 tkusumi volpath = p; 438 1.7 tkusumi if ((p = strchr(p, ':')) != NULL) 439 1.7 tkusumi *p++ = '\0'; 440 1.7 tkusumi if ((fp = fopen(volpath, "r")) == NULL) { 441 1.7 tkusumi warnx("hammer2: failed to open %s", volpath); 442 1.7 tkusumi goto fail; 443 1.7 tkusumi } 444 1.7 tkusumi if (test_voldata(fp)) 445 1.7 tkusumi break; 446 1.7 tkusumi voldata = read_voldata(fp, 0); 447 1.7 tkusumi fclose(fp); 448 1.7 tkusumi if (voldata == NULL) { 449 1.7 tkusumi warnx("hammer2: failed to read volume data"); 450 1.7 tkusumi goto fail; 451 1.7 tkusumi } 452 1.7 tkusumi volid = voldata->volu_id; 453 1.7 tkusumi free(voldata); 454 1.7 tkusumi voldata = NULL; 455 1.7 tkusumi if (volid < 0 || volid >= HAMMER2_MAX_VOLUMES) 456 1.7 tkusumi goto fail; 457 1.7 tkusumi x[volid]++; 458 1.7 tkusumi if (volid == HAMMER2_ROOT_VOLUME) 459 1.7 tkusumi rootvolpath = volpath; 460 1.7 tkusumi } 461 1.7 tkusumi 462 1.7 tkusumi /* If no rootvolpath, proceed only if partial mode with volpath. */ 463 1.7 tkusumi if (rootvolpath) 464 1.7 tkusumi volpath = rootvolpath; 465 1.7 tkusumi else if (!partial || !volpath) 466 1.7 tkusumi goto fail; 467 1.7 tkusumi if ((fp = fopen(volpath, "r")) == NULL) { 468 1.7 tkusumi warnx("hammer2: failed to open %s", volpath); 469 1.7 tkusumi goto fail; 470 1.7 tkusumi } 471 1.7 tkusumi voldata = read_voldata(fp, 0); 472 1.7 tkusumi if (voldata == NULL) { 473 1.7 tkusumi warnx("hammer2: failed to read volume data"); 474 1.7 tkusumi goto fail; 475 1.7 tkusumi } 476 1.7 tkusumi 477 1.7 tkusumi if (volid == -1) 478 1.3 tkusumi goto fail; 479 1.7 tkusumi if (partial) 480 1.7 tkusumi goto success; 481 1.1 tkusumi 482 1.7 tkusumi for (i = 0; i < HAMMER2_MAX_VOLUMES; i++) 483 1.7 tkusumi if (x[i] > 1) 484 1.7 tkusumi goto fail; 485 1.7 tkusumi for (i = 0; i < HAMMER2_MAX_VOLUMES; i++) 486 1.7 tkusumi if (x[i] == 0) 487 1.7 tkusumi break; 488 1.7 tkusumi if (voldata->nvolumes != i) 489 1.7 tkusumi goto fail; 490 1.7 tkusumi for (; i < HAMMER2_MAX_VOLUMES; i++) 491 1.7 tkusumi if (x[i] != 0) 492 1.7 tkusumi goto fail; 493 1.7 tkusumi success: 494 1.7 tkusumi /* Reconstruct @label format path using only root volume. */ 495 1.7 tkusumi if (target_label) { 496 1.7 tkusumi size_t siz = strlen(volpath) + strlen(target_label) + 2; 497 1.7 tkusumi p = calloc(1, siz); 498 1.7 tkusumi snprintf(p, siz, "%s@%s", volpath, target_label); 499 1.7 tkusumi volpath = p; 500 1.7 tkusumi } 501 1.7 tkusumi error = read_label(fp, label, size, volpath); 502 1.7 tkusumi if (target_label) 503 1.7 tkusumi free(p); 504 1.7 tkusumi /* If in partial mode, read label but ignore error. */ 505 1.7 tkusumi if (partial) 506 1.7 tkusumi error = 0; 507 1.3 tkusumi fail: 508 1.7 tkusumi if (fp) 509 1.7 tkusumi fclose(fp); 510 1.1 tkusumi free(voldata); 511 1.7 tkusumi free(dup); 512 1.9 christos return error; 513 1.1 tkusumi } 514 1.7 tkusumi 515 1.7 tkusumi int 516 1.7 tkusumi fsvtyp_hammer2(const char *blkdevs, char *label, size_t size) 517 1.7 tkusumi { 518 1.9 christos return __fsvtyp_hammer2(blkdevs, label, size, 0); 519 1.7 tkusumi } 520 1.7 tkusumi 521 1.7 tkusumi int 522 1.7 tkusumi fsvtyp_hammer2_partial(const char *blkdevs, char *label, size_t size) 523 1.7 tkusumi { 524 1.9 christos return __fsvtyp_hammer2(blkdevs, label, size, 1); 525 1.7 tkusumi } 526