Home | History | Annotate | Line # | Download | only in fstyp
hammer2.c revision 1.4.4.2
      1  1.4.4.2  martin /*        $NetBSD: hammer2.c,v 1.4.4.2 2020/04/08 14:09:20 martin Exp $      */
      2  1.4.4.2  martin 
      3  1.4.4.2  martin /*-
      4  1.4.4.2  martin  * Copyright (c) 2017-2019 The DragonFly Project
      5  1.4.4.2  martin  * Copyright (c) 2017-2019 Tomohiro Kusumi <tkusumi (at) netbsd.org>
      6  1.4.4.2  martin  * All rights reserved.
      7  1.4.4.2  martin  *
      8  1.4.4.2  martin  * Redistribution and use in source and binary forms, with or without
      9  1.4.4.2  martin  * modification, are permitted provided that the following conditions
     10  1.4.4.2  martin  * are met:
     11  1.4.4.2  martin  * 1. Redistributions of source code must retain the above copyright
     12  1.4.4.2  martin  *    notice, this list of conditions and the following disclaimer.
     13  1.4.4.2  martin  * 2. Redistributions in binary form must reproduce the above copyright
     14  1.4.4.2  martin  *    notice, this list of conditions and the following disclaimer in the
     15  1.4.4.2  martin  *    documentation and/or other materials provided with the distribution.
     16  1.4.4.2  martin  *
     17  1.4.4.2  martin  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
     18  1.4.4.2  martin  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     19  1.4.4.2  martin  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     20  1.4.4.2  martin  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
     21  1.4.4.2  martin  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     22  1.4.4.2  martin  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     23  1.4.4.2  martin  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     24  1.4.4.2  martin  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     25  1.4.4.2  martin  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     26  1.4.4.2  martin  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     27  1.4.4.2  martin  * SUCH DAMAGE.
     28  1.4.4.2  martin  */
     29  1.4.4.2  martin #include <sys/cdefs.h>
     30  1.4.4.2  martin __KERNEL_RCSID(0, "$NetBSD: hammer2.c,v 1.4.4.2 2020/04/08 14:09:20 martin Exp $");
     31  1.4.4.2  martin 
     32  1.4.4.2  martin #include <stdio.h>
     33  1.4.4.2  martin #include <stdlib.h>
     34  1.4.4.2  martin #include <stdbool.h>
     35  1.4.4.2  martin #include <string.h>
     36  1.4.4.2  martin #include <err.h>
     37  1.4.4.2  martin #include <assert.h>
     38  1.4.4.2  martin 
     39  1.4.4.2  martin #include "fstyp.h"
     40  1.4.4.2  martin #include "hammer2_disk.h"
     41  1.4.4.2  martin 
     42  1.4.4.2  martin static hammer2_volume_data_t*
     43  1.4.4.2  martin read_voldata(FILE *fp)
     44  1.4.4.2  martin {
     45  1.4.4.2  martin 	hammer2_volume_data_t *voldata;
     46  1.4.4.2  martin 
     47  1.4.4.2  martin 	voldata = read_buf(fp, 0, sizeof(*voldata));
     48  1.4.4.2  martin 	if (voldata == NULL)
     49  1.4.4.2  martin 		err(1, "failed to read volume data");
     50  1.4.4.2  martin 
     51  1.4.4.2  martin 	return (voldata);
     52  1.4.4.2  martin }
     53  1.4.4.2  martin 
     54  1.4.4.2  martin static int
     55  1.4.4.2  martin test_voldata(const hammer2_volume_data_t *voldata)
     56  1.4.4.2  martin {
     57  1.4.4.2  martin 	if (voldata->magic != HAMMER2_VOLUME_ID_HBO &&
     58  1.4.4.2  martin 	    voldata->magic != HAMMER2_VOLUME_ID_ABO)
     59  1.4.4.2  martin 		return (1);
     60  1.4.4.2  martin 
     61  1.4.4.2  martin 	return (0);
     62  1.4.4.2  martin }
     63  1.4.4.2  martin 
     64  1.4.4.2  martin static hammer2_media_data_t*
     65  1.4.4.2  martin read_media(FILE *fp, const hammer2_blockref_t *bref, size_t *media_bytes)
     66  1.4.4.2  martin {
     67  1.4.4.2  martin 	hammer2_media_data_t *media;
     68  1.4.4.2  martin 	hammer2_off_t io_off, io_base;
     69  1.4.4.2  martin 	size_t bytes, io_bytes, boff;
     70  1.4.4.2  martin 
     71  1.4.4.2  martin 	bytes = (bref->data_off & HAMMER2_OFF_MASK_RADIX);
     72  1.4.4.2  martin 	if (bytes)
     73  1.4.4.2  martin 		bytes = (size_t)1 << bytes;
     74  1.4.4.2  martin 	*media_bytes = bytes;
     75  1.4.4.2  martin 
     76  1.4.4.2  martin 	if (!bytes) {
     77  1.4.4.2  martin 		warnx("blockref has no data");
     78  1.4.4.2  martin 		return (NULL);
     79  1.4.4.2  martin 	}
     80  1.4.4.2  martin 
     81  1.4.4.2  martin 	io_off = bref->data_off & ~HAMMER2_OFF_MASK_RADIX;
     82  1.4.4.2  martin 	io_base = io_off & ~(hammer2_off_t)(HAMMER2_MINIOSIZE - 1);
     83  1.4.4.2  martin 	boff = (size_t)(io_off - io_base);
     84  1.4.4.2  martin 
     85  1.4.4.2  martin 	io_bytes = HAMMER2_MINIOSIZE;
     86  1.4.4.2  martin 	while (io_bytes + boff < bytes)
     87  1.4.4.2  martin 		io_bytes <<= 1;
     88  1.4.4.2  martin 
     89  1.4.4.2  martin 	if (io_bytes > sizeof(hammer2_media_data_t)) {
     90  1.4.4.2  martin 		warnx("invalid I/O bytes");
     91  1.4.4.2  martin 		return (NULL);
     92  1.4.4.2  martin 	}
     93  1.4.4.2  martin 
     94  1.4.4.2  martin 	if (fseek(fp, (long int)io_base, SEEK_SET) == -1) {
     95  1.4.4.2  martin 		warnx("failed to seek media");
     96  1.4.4.2  martin 		return (NULL);
     97  1.4.4.2  martin 	}
     98  1.4.4.2  martin 	media = read_buf(fp, (off_t)io_base, io_bytes);
     99  1.4.4.2  martin 	if (media == NULL) {
    100  1.4.4.2  martin 		warnx("failed to read media");
    101  1.4.4.2  martin 		return (NULL);
    102  1.4.4.2  martin 	}
    103  1.4.4.2  martin 	if (boff)
    104  1.4.4.2  martin 		memcpy(media, (char *)media + boff, bytes);
    105  1.4.4.2  martin 
    106  1.4.4.2  martin 	return (media);
    107  1.4.4.2  martin }
    108  1.4.4.2  martin 
    109  1.4.4.2  martin static int
    110  1.4.4.2  martin find_pfs(FILE *fp, const hammer2_blockref_t *bref, const char *pfs, bool *res)
    111  1.4.4.2  martin {
    112  1.4.4.2  martin 	hammer2_media_data_t *media;
    113  1.4.4.2  martin 	hammer2_inode_data_t ipdata;
    114  1.4.4.2  martin 	hammer2_blockref_t *bscan;
    115  1.4.4.2  martin 	size_t bytes;
    116  1.4.4.2  martin 	int i, bcount;
    117  1.4.4.2  martin 
    118  1.4.4.2  martin 	media = read_media(fp, bref, &bytes);
    119  1.4.4.2  martin 	if (media == NULL)
    120  1.4.4.2  martin 		return (-1);
    121  1.4.4.2  martin 
    122  1.4.4.2  martin 	switch (bref->type) {
    123  1.4.4.2  martin 	case HAMMER2_BREF_TYPE_INODE:
    124  1.4.4.2  martin 		ipdata = media->ipdata;
    125  1.4.4.2  martin 		if (ipdata.meta.pfs_type & HAMMER2_PFSTYPE_SUPROOT) {
    126  1.4.4.2  martin 			bscan = &ipdata.u.blockset.blockref[0];
    127  1.4.4.2  martin 			bcount = HAMMER2_SET_COUNT;
    128  1.4.4.2  martin 		} else {
    129  1.4.4.2  martin 			bscan = NULL;
    130  1.4.4.2  martin 			bcount = 0;
    131  1.4.4.2  martin 			if (ipdata.meta.op_flags & HAMMER2_OPFLAG_PFSROOT) {
    132  1.4.4.2  martin 				if (memchr(ipdata.filename, 0,
    133  1.4.4.2  martin 				    sizeof(ipdata.filename))) {
    134  1.4.4.2  martin 					if (!strcmp(
    135  1.4.4.2  martin 					    (const char*)ipdata.filename, pfs))
    136  1.4.4.2  martin 						*res = true;
    137  1.4.4.2  martin 				} else {
    138  1.4.4.2  martin 					if (strlen(pfs) > 0 &&
    139  1.4.4.2  martin 					    !memcmp(ipdata.filename, pfs,
    140  1.4.4.2  martin 					    strlen(pfs)))
    141  1.4.4.2  martin 						*res = true;
    142  1.4.4.2  martin 				}
    143  1.4.4.2  martin 			} else
    144  1.4.4.2  martin 				assert(0);
    145  1.4.4.2  martin 		}
    146  1.4.4.2  martin 		break;
    147  1.4.4.2  martin 	case HAMMER2_BREF_TYPE_INDIRECT:
    148  1.4.4.2  martin 		bscan = &media->npdata[0];
    149  1.4.4.2  martin 		bcount = (int)(bytes / sizeof(hammer2_blockref_t));
    150  1.4.4.2  martin 		break;
    151  1.4.4.2  martin 	default:
    152  1.4.4.2  martin 		bscan = NULL;
    153  1.4.4.2  martin 		bcount = 0;
    154  1.4.4.2  martin 		break;
    155  1.4.4.2  martin 	}
    156  1.4.4.2  martin 
    157  1.4.4.2  martin 	for (i = 0; i < bcount; ++i) {
    158  1.4.4.2  martin 		if (bscan[i].type != HAMMER2_BREF_TYPE_EMPTY) {
    159  1.4.4.2  martin 			if (find_pfs(fp, &bscan[i], pfs, res) == -1) {
    160  1.4.4.2  martin 				free(media);
    161  1.4.4.2  martin 				return (-1);
    162  1.4.4.2  martin 			}
    163  1.4.4.2  martin 		}
    164  1.4.4.2  martin 	}
    165  1.4.4.2  martin 	free(media);
    166  1.4.4.2  martin 
    167  1.4.4.2  martin 	return (0);
    168  1.4.4.2  martin }
    169  1.4.4.2  martin 
    170  1.4.4.2  martin static char*
    171  1.4.4.2  martin extract_device_name(const char *devpath)
    172  1.4.4.2  martin {
    173  1.4.4.2  martin 	char *p, *head;
    174  1.4.4.2  martin 
    175  1.4.4.2  martin 	if (!devpath)
    176  1.4.4.2  martin 		return NULL;
    177  1.4.4.2  martin 
    178  1.4.4.2  martin 	p = strdup(devpath);
    179  1.4.4.2  martin 	head = p;
    180  1.4.4.2  martin 
    181  1.4.4.2  martin 	p = strchr(p, '@');
    182  1.4.4.2  martin 	if (p)
    183  1.4.4.2  martin 		*p = 0;
    184  1.4.4.2  martin 
    185  1.4.4.2  martin 	p = strrchr(head, '/');
    186  1.4.4.2  martin 	if (p) {
    187  1.4.4.2  martin 		p++;
    188  1.4.4.2  martin 		if (*p == 0) {
    189  1.4.4.2  martin 			free(head);
    190  1.4.4.2  martin 			return NULL;
    191  1.4.4.2  martin 		}
    192  1.4.4.2  martin 		p = strdup(p);
    193  1.4.4.2  martin 		free(head);
    194  1.4.4.2  martin 		return p;
    195  1.4.4.2  martin 	}
    196  1.4.4.2  martin 
    197  1.4.4.2  martin 	return head;
    198  1.4.4.2  martin }
    199  1.4.4.2  martin 
    200  1.4.4.2  martin static int
    201  1.4.4.2  martin read_label(FILE *fp, char *label, size_t size)
    202  1.4.4.2  martin {
    203  1.4.4.2  martin 	hammer2_blockref_t broot, best, *bref;
    204  1.4.4.2  martin 	hammer2_media_data_t *vols[HAMMER2_NUM_VOLHDRS], *media;
    205  1.4.4.2  martin 	size_t bytes;
    206  1.4.4.2  martin 	bool res = false;
    207  1.4.4.2  martin 	int i, best_i, error = 1;
    208  1.4.4.2  martin 	const char *pfs;
    209  1.4.4.2  martin 	char *devname;
    210  1.4.4.2  martin 
    211  1.4.4.2  martin 	best_i = -1;
    212  1.4.4.2  martin 	memset(&best, 0, sizeof(best));
    213  1.4.4.2  martin 
    214  1.4.4.2  martin 	for (i = 0; i < HAMMER2_NUM_VOLHDRS; i++) {
    215  1.4.4.2  martin 		memset(&broot, 0, sizeof(broot));
    216  1.4.4.2  martin 		broot.type = HAMMER2_BREF_TYPE_VOLUME;
    217  1.4.4.2  martin 		broot.data_off = ((hammer2_off_t)i *
    218  1.4.4.2  martin 		    (hammer2_off_t)HAMMER2_ZONE_BYTES64) | HAMMER2_PBUFRADIX;
    219  1.4.4.2  martin 		vols[i] = read_buf(fp,
    220  1.4.4.2  martin 		    (off_t)(broot.data_off & ~HAMMER2_OFF_MASK_RADIX),
    221  1.4.4.2  martin 		    sizeof(*vols[i]));
    222  1.4.4.2  martin 		broot.mirror_tid = vols[i]->voldata.mirror_tid;
    223  1.4.4.2  martin 		if (best_i < 0 || best.mirror_tid < broot.mirror_tid) {
    224  1.4.4.2  martin 			best_i = i;
    225  1.4.4.2  martin 			best = broot;
    226  1.4.4.2  martin 		}
    227  1.4.4.2  martin 	}
    228  1.4.4.2  martin 
    229  1.4.4.2  martin 	bref = &vols[best_i]->voldata.sroot_blockset.blockref[0];
    230  1.4.4.2  martin 	if (bref->type != HAMMER2_BREF_TYPE_INODE) {
    231  1.4.4.2  martin 		warnx("blockref type is not inode");
    232  1.4.4.2  martin 		goto fail;
    233  1.4.4.2  martin 	}
    234  1.4.4.2  martin 
    235  1.4.4.2  martin 	media = read_media(fp, bref, &bytes);
    236  1.4.4.2  martin 	if (media == NULL) {
    237  1.4.4.2  martin 		goto fail;
    238  1.4.4.2  martin 	}
    239  1.4.4.2  martin 
    240  1.4.4.2  martin 	/*
    241  1.4.4.2  martin 	 * fstyp_function in DragonFly takes an additional devpath argument
    242  1.4.4.2  martin 	 * which doesn't exist in FreeBSD and NetBSD.
    243  1.4.4.2  martin 	 */
    244  1.4.4.2  martin #ifdef HAS_DEVPATH
    245  1.4.4.2  martin 	pfs = strchr(devpath, '@');
    246  1.4.4.2  martin 	if (!pfs) {
    247  1.4.4.2  martin 		assert(strlen(devpath));
    248  1.4.4.2  martin 		switch (devpath[strlen(devpath) - 1]) {
    249  1.4.4.2  martin 		case 'a':
    250  1.4.4.2  martin 			pfs = "BOOT";
    251  1.4.4.2  martin 			break;
    252  1.4.4.2  martin 		case 'd':
    253  1.4.4.2  martin 			pfs = "ROOT";
    254  1.4.4.2  martin 			break;
    255  1.4.4.2  martin 		default:
    256  1.4.4.2  martin 			pfs = "DATA";
    257  1.4.4.2  martin 			break;
    258  1.4.4.2  martin 		}
    259  1.4.4.2  martin 	} else
    260  1.4.4.2  martin 		pfs++;
    261  1.4.4.2  martin 
    262  1.4.4.2  martin 	if (strlen(pfs) > HAMMER2_INODE_MAXNAME) {
    263  1.4.4.2  martin 		goto fail;
    264  1.4.4.2  martin 	}
    265  1.4.4.2  martin 	devname = extract_device_name(devpath);
    266  1.4.4.2  martin #else
    267  1.4.4.2  martin 	pfs = "";
    268  1.4.4.2  martin 	devname = extract_device_name(NULL);
    269  1.4.4.2  martin 	assert(!devname);
    270  1.4.4.2  martin #endif
    271  1.4.4.2  martin 
    272  1.4.4.2  martin 	/* Add device name to help support multiple autofs -media mounts. */
    273  1.4.4.2  martin 	if (find_pfs(fp, bref, pfs, &res) == 0 && res) {
    274  1.4.4.2  martin 		if (devname)
    275  1.4.4.2  martin 			snprintf(label, size, "%s_%s", pfs, devname);
    276  1.4.4.2  martin 		else
    277  1.4.4.2  martin 			strlcpy(label, pfs, size);
    278  1.4.4.2  martin 	} else {
    279  1.4.4.2  martin 		memset(label, 0, size);
    280  1.4.4.2  martin 		memcpy(label, media->ipdata.filename,
    281  1.4.4.2  martin 		    sizeof(media->ipdata.filename));
    282  1.4.4.2  martin 		if (devname) {
    283  1.4.4.2  martin 			strlcat(label, "_", size);
    284  1.4.4.2  martin 			strlcat(label, devname, size);
    285  1.4.4.2  martin 		}
    286  1.4.4.2  martin 	}
    287  1.4.4.2  martin 	if (devname)
    288  1.4.4.2  martin 		free(devname);
    289  1.4.4.2  martin 	free(media);
    290  1.4.4.2  martin 	error = 0;
    291  1.4.4.2  martin fail:
    292  1.4.4.2  martin 	for (i = 0; i < HAMMER2_NUM_VOLHDRS; i++)
    293  1.4.4.2  martin 		free(vols[i]);
    294  1.4.4.2  martin 
    295  1.4.4.2  martin 	return (error);
    296  1.4.4.2  martin }
    297  1.4.4.2  martin 
    298  1.4.4.2  martin int
    299  1.4.4.2  martin fstyp_hammer2(FILE *fp, char *label, size_t size)
    300  1.4.4.2  martin {
    301  1.4.4.2  martin 	hammer2_volume_data_t *voldata;
    302  1.4.4.2  martin 	int error = 1;
    303  1.4.4.2  martin 
    304  1.4.4.2  martin 	voldata = read_voldata(fp);
    305  1.4.4.2  martin 	if (test_voldata(voldata))
    306  1.4.4.2  martin 		goto fail;
    307  1.4.4.2  martin 
    308  1.4.4.2  martin 	error = read_label(fp, label, size);
    309  1.4.4.2  martin fail:
    310  1.4.4.2  martin 	free(voldata);
    311  1.4.4.2  martin 	return (error);
    312  1.4.4.2  martin }
    313