1*509798eaSPedro F. Giffuni /*- 2*509798eaSPedro F. Giffuni * Copyright (c) 2017-2019 The DragonFly Project 3*509798eaSPedro F. Giffuni * All rights reserved. 4*509798eaSPedro F. Giffuni * 5*509798eaSPedro F. Giffuni * This software was developed by Edward Tomasz Napierala under sponsorship 6*509798eaSPedro F. Giffuni * from the FreeBSD Foundation. 7*509798eaSPedro F. Giffuni * 8*509798eaSPedro F. Giffuni * Redistribution and use in source and binary forms, with or without 9*509798eaSPedro F. Giffuni * modification, are permitted provided that the following conditions 10*509798eaSPedro F. Giffuni * are met: 11*509798eaSPedro F. Giffuni * 1. Redistributions of source code must retain the above copyright 12*509798eaSPedro F. Giffuni * notice, this list of conditions and the following disclaimer. 13*509798eaSPedro F. Giffuni * 2. Redistributions in binary form must reproduce the above copyright 14*509798eaSPedro F. Giffuni * notice, this list of conditions and the following disclaimer in the 15*509798eaSPedro F. Giffuni * documentation and/or other materials provided with the distribution. 16*509798eaSPedro F. Giffuni * 17*509798eaSPedro F. Giffuni * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 18*509798eaSPedro F. Giffuni * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19*509798eaSPedro F. Giffuni * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20*509798eaSPedro F. Giffuni * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 21*509798eaSPedro F. Giffuni * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22*509798eaSPedro F. Giffuni * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23*509798eaSPedro F. Giffuni * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24*509798eaSPedro F. Giffuni * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25*509798eaSPedro F. Giffuni * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26*509798eaSPedro F. Giffuni * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27*509798eaSPedro F. Giffuni * SUCH DAMAGE. 28*509798eaSPedro F. Giffuni */ 29*509798eaSPedro F. Giffuni 30*509798eaSPedro F. Giffuni #include <sys/cdefs.h> 31*509798eaSPedro F. Giffuni __FBSDID("$FreeBSD$"); 32*509798eaSPedro F. Giffuni 33*509798eaSPedro F. Giffuni #include <stdio.h> 34*509798eaSPedro F. Giffuni #include <stdlib.h> 35*509798eaSPedro F. Giffuni #include <string.h> 36*509798eaSPedro F. Giffuni #include <err.h> 37*509798eaSPedro F. Giffuni 38*509798eaSPedro F. Giffuni #include <sys/types.h> 39*509798eaSPedro F. Giffuni 40*509798eaSPedro F. Giffuni #include "hammer2_disk.h" 41*509798eaSPedro F. Giffuni 42*509798eaSPedro F. Giffuni #include "fstyp.h" 43*509798eaSPedro F. Giffuni 44*509798eaSPedro F. Giffuni static hammer2_volume_data_t* 45*509798eaSPedro F. Giffuni __read_voldata(FILE *fp) 46*509798eaSPedro F. Giffuni { 47*509798eaSPedro F. Giffuni hammer2_volume_data_t *voldata; 48*509798eaSPedro F. Giffuni 49*509798eaSPedro F. Giffuni voldata = read_buf(fp, 0, sizeof(*voldata)); 50*509798eaSPedro F. Giffuni if (voldata == NULL) 51*509798eaSPedro F. Giffuni err(1, "failed to read volume data"); 52*509798eaSPedro F. Giffuni 53*509798eaSPedro F. Giffuni return (voldata); 54*509798eaSPedro F. Giffuni } 55*509798eaSPedro F. Giffuni 56*509798eaSPedro F. Giffuni static int 57*509798eaSPedro F. Giffuni __test_voldata(const hammer2_volume_data_t *voldata) 58*509798eaSPedro F. Giffuni { 59*509798eaSPedro F. Giffuni if (voldata->magic != HAMMER2_VOLUME_ID_HBO && 60*509798eaSPedro F. Giffuni voldata->magic != HAMMER2_VOLUME_ID_ABO) 61*509798eaSPedro F. Giffuni return (1); 62*509798eaSPedro F. Giffuni 63*509798eaSPedro F. Giffuni return (0); 64*509798eaSPedro F. Giffuni } 65*509798eaSPedro F. Giffuni 66*509798eaSPedro F. Giffuni static int 67*509798eaSPedro F. Giffuni __read_label(FILE *fp, char *label, size_t size) 68*509798eaSPedro F. Giffuni { 69*509798eaSPedro F. Giffuni hammer2_blockref_t broot, best, *bref; 70*509798eaSPedro F. Giffuni hammer2_media_data_t *vols[HAMMER2_NUM_VOLHDRS], *media; 71*509798eaSPedro F. Giffuni hammer2_off_t io_off, io_base; 72*509798eaSPedro F. Giffuni size_t bytes, io_bytes, boff; 73*509798eaSPedro F. Giffuni int i, best_i, error = 0; 74*509798eaSPedro F. Giffuni 75*509798eaSPedro F. Giffuni best_i = -1; 76*509798eaSPedro F. Giffuni memset(&best, 0, sizeof(best)); 77*509798eaSPedro F. Giffuni 78*509798eaSPedro F. Giffuni for (i = 0; i < HAMMER2_NUM_VOLHDRS; i++) { 79*509798eaSPedro F. Giffuni memset(&broot, 0, sizeof(broot)); 80*509798eaSPedro F. Giffuni broot.type = HAMMER2_BREF_TYPE_VOLUME; 81*509798eaSPedro F. Giffuni broot.data_off = (i * HAMMER2_ZONE_BYTES64) | HAMMER2_PBUFRADIX; 82*509798eaSPedro F. Giffuni vols[i] = read_buf(fp, broot.data_off & ~HAMMER2_OFF_MASK_RADIX, 83*509798eaSPedro F. Giffuni sizeof(*vols[i])); 84*509798eaSPedro F. Giffuni broot.mirror_tid = vols[i]->voldata.mirror_tid; 85*509798eaSPedro F. Giffuni if (best_i < 0 || best.mirror_tid < broot.mirror_tid) { 86*509798eaSPedro F. Giffuni best_i = i; 87*509798eaSPedro F. Giffuni best = broot; 88*509798eaSPedro F. Giffuni } 89*509798eaSPedro F. Giffuni } 90*509798eaSPedro F. Giffuni if (best_i == -1) { 91*509798eaSPedro F. Giffuni warnx("Failed to find volume header from zones"); 92*509798eaSPedro F. Giffuni error = 1; 93*509798eaSPedro F. Giffuni goto done; 94*509798eaSPedro F. Giffuni } 95*509798eaSPedro F. Giffuni 96*509798eaSPedro F. Giffuni bref = &vols[best_i]->voldata.sroot_blockset.blockref[0]; 97*509798eaSPedro F. Giffuni if (bref->type != HAMMER2_BREF_TYPE_INODE) { 98*509798eaSPedro F. Giffuni warnx("Superroot blockref type is not inode"); 99*509798eaSPedro F. Giffuni error = 2; 100*509798eaSPedro F. Giffuni goto done; 101*509798eaSPedro F. Giffuni } 102*509798eaSPedro F. Giffuni 103*509798eaSPedro F. Giffuni bytes = bref->data_off & HAMMER2_OFF_MASK_RADIX; 104*509798eaSPedro F. Giffuni if (bytes) 105*509798eaSPedro F. Giffuni bytes = (size_t)1 << bytes; 106*509798eaSPedro F. Giffuni if (bytes != sizeof(hammer2_inode_data_t)) { 107*509798eaSPedro F. Giffuni warnx("Superroot blockref size does not match inode size"); 108*509798eaSPedro F. Giffuni error = 3; 109*509798eaSPedro F. Giffuni goto done; 110*509798eaSPedro F. Giffuni } 111*509798eaSPedro F. Giffuni 112*509798eaSPedro F. Giffuni io_off = bref->data_off & ~HAMMER2_OFF_MASK_RADIX; 113*509798eaSPedro F. Giffuni io_base = io_off & ~(hammer2_off_t)(HAMMER2_MINIOSIZE - 1); 114*509798eaSPedro F. Giffuni boff = io_off - io_base; 115*509798eaSPedro F. Giffuni 116*509798eaSPedro F. Giffuni io_bytes = HAMMER2_MINIOSIZE; 117*509798eaSPedro F. Giffuni while (io_bytes + boff < bytes) 118*509798eaSPedro F. Giffuni io_bytes <<= 1; 119*509798eaSPedro F. Giffuni if (io_bytes > sizeof(*media)) { 120*509798eaSPedro F. Giffuni warnx("Invalid I/O bytes"); 121*509798eaSPedro F. Giffuni error = 4; 122*509798eaSPedro F. Giffuni goto done; 123*509798eaSPedro F. Giffuni } 124*509798eaSPedro F. Giffuni 125*509798eaSPedro F. Giffuni media = read_buf(fp, io_base, io_bytes); 126*509798eaSPedro F. Giffuni if (boff) 127*509798eaSPedro F. Giffuni memcpy(media, (char*)media + boff, bytes); 128*509798eaSPedro F. Giffuni 129*509798eaSPedro F. Giffuni strlcpy(label, (char*)media->ipdata.filename, size); 130*509798eaSPedro F. Giffuni free(media); 131*509798eaSPedro F. Giffuni done: 132*509798eaSPedro F. Giffuni for (i = 0; i < HAMMER2_NUM_VOLHDRS; i++) 133*509798eaSPedro F. Giffuni free(vols[i]); 134*509798eaSPedro F. Giffuni 135*509798eaSPedro F. Giffuni return (error); 136*509798eaSPedro F. Giffuni } 137*509798eaSPedro F. Giffuni 138*509798eaSPedro F. Giffuni int 139*509798eaSPedro F. Giffuni fstyp_hammer2(FILE *fp, char *label, size_t size) 140*509798eaSPedro F. Giffuni { 141*509798eaSPedro F. Giffuni hammer2_volume_data_t *voldata; 142*509798eaSPedro F. Giffuni int error = 1; 143*509798eaSPedro F. Giffuni 144*509798eaSPedro F. Giffuni voldata = __read_voldata(fp); 145*509798eaSPedro F. Giffuni if (__test_voldata(voldata)) 146*509798eaSPedro F. Giffuni goto done; 147*509798eaSPedro F. Giffuni 148*509798eaSPedro F. Giffuni error = __read_label(fp, label, size); 149*509798eaSPedro F. Giffuni done: 150*509798eaSPedro F. Giffuni free(voldata); 151*509798eaSPedro F. Giffuni return (error); 152*509798eaSPedro F. Giffuni } 153