Home | History | Annotate | Line # | Download | only in fstyp
hammer2.c revision 1.6
      1  1.6  tkusumi /*        $NetBSD: hammer2.c,v 1.6 2020/09/23 14:39:23 tkusumi 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.6  tkusumi __KERNEL_RCSID(0, "$NetBSD: hammer2.c,v 1.6 2020/09/23 14:39:23 tkusumi Exp $");
     31  1.1  tkusumi 
     32  1.1  tkusumi #include <stdio.h>
     33  1.1  tkusumi #include <stdlib.h>
     34  1.1  tkusumi #include <stdbool.h>
     35  1.1  tkusumi #include <string.h>
     36  1.1  tkusumi #include <err.h>
     37  1.1  tkusumi #include <assert.h>
     38  1.1  tkusumi 
     39  1.1  tkusumi #include "fstyp.h"
     40  1.1  tkusumi #include "hammer2_disk.h"
     41  1.1  tkusumi 
     42  1.1  tkusumi static hammer2_volume_data_t*
     43  1.1  tkusumi read_voldata(FILE *fp)
     44  1.1  tkusumi {
     45  1.1  tkusumi 	hammer2_volume_data_t *voldata;
     46  1.1  tkusumi 
     47  1.1  tkusumi 	voldata = read_buf(fp, 0, sizeof(*voldata));
     48  1.1  tkusumi 	if (voldata == NULL)
     49  1.1  tkusumi 		err(1, "failed to read volume data");
     50  1.1  tkusumi 
     51  1.1  tkusumi 	return (voldata);
     52  1.1  tkusumi }
     53  1.1  tkusumi 
     54  1.1  tkusumi static int
     55  1.1  tkusumi test_voldata(const hammer2_volume_data_t *voldata)
     56  1.1  tkusumi {
     57  1.1  tkusumi 	if (voldata->magic != HAMMER2_VOLUME_ID_HBO &&
     58  1.1  tkusumi 	    voldata->magic != HAMMER2_VOLUME_ID_ABO)
     59  1.1  tkusumi 		return (1);
     60  1.1  tkusumi 
     61  1.1  tkusumi 	return (0);
     62  1.1  tkusumi }
     63  1.1  tkusumi 
     64  1.1  tkusumi static hammer2_media_data_t*
     65  1.1  tkusumi read_media(FILE *fp, const hammer2_blockref_t *bref, size_t *media_bytes)
     66  1.1  tkusumi {
     67  1.1  tkusumi 	hammer2_media_data_t *media;
     68  1.1  tkusumi 	hammer2_off_t io_off, io_base;
     69  1.1  tkusumi 	size_t bytes, io_bytes, boff;
     70  1.1  tkusumi 
     71  1.1  tkusumi 	bytes = (bref->data_off & HAMMER2_OFF_MASK_RADIX);
     72  1.1  tkusumi 	if (bytes)
     73  1.1  tkusumi 		bytes = (size_t)1 << bytes;
     74  1.1  tkusumi 	*media_bytes = bytes;
     75  1.1  tkusumi 
     76  1.1  tkusumi 	if (!bytes) {
     77  1.3  tkusumi 		warnx("blockref has no data");
     78  1.1  tkusumi 		return (NULL);
     79  1.1  tkusumi 	}
     80  1.1  tkusumi 
     81  1.1  tkusumi 	io_off = bref->data_off & ~HAMMER2_OFF_MASK_RADIX;
     82  1.6  tkusumi 	io_base = io_off & ~(hammer2_off_t)(HAMMER2_LBUFSIZE - 1);
     83  1.2  tkusumi 	boff = (size_t)(io_off - io_base);
     84  1.1  tkusumi 
     85  1.6  tkusumi 	io_bytes = HAMMER2_LBUFSIZE;
     86  1.1  tkusumi 	while (io_bytes + boff < bytes)
     87  1.1  tkusumi 		io_bytes <<= 1;
     88  1.1  tkusumi 
     89  1.1  tkusumi 	if (io_bytes > sizeof(hammer2_media_data_t)) {
     90  1.3  tkusumi 		warnx("invalid I/O bytes");
     91  1.1  tkusumi 		return (NULL);
     92  1.1  tkusumi 	}
     93  1.1  tkusumi 
     94  1.1  tkusumi 	if (fseek(fp, (long int)io_base, SEEK_SET) == -1) {
     95  1.3  tkusumi 		warnx("failed to seek media");
     96  1.1  tkusumi 		return (NULL);
     97  1.1  tkusumi 	}
     98  1.1  tkusumi 	media = read_buf(fp, (off_t)io_base, io_bytes);
     99  1.1  tkusumi 	if (media == NULL) {
    100  1.3  tkusumi 		warnx("failed to read media");
    101  1.1  tkusumi 		return (NULL);
    102  1.1  tkusumi 	}
    103  1.1  tkusumi 	if (boff)
    104  1.1  tkusumi 		memcpy(media, (char *)media + boff, bytes);
    105  1.1  tkusumi 
    106  1.1  tkusumi 	return (media);
    107  1.1  tkusumi }
    108  1.1  tkusumi 
    109  1.1  tkusumi static int
    110  1.1  tkusumi find_pfs(FILE *fp, const hammer2_blockref_t *bref, const char *pfs, bool *res)
    111  1.1  tkusumi {
    112  1.1  tkusumi 	hammer2_media_data_t *media;
    113  1.1  tkusumi 	hammer2_inode_data_t ipdata;
    114  1.1  tkusumi 	hammer2_blockref_t *bscan;
    115  1.1  tkusumi 	size_t bytes;
    116  1.1  tkusumi 	int i, bcount;
    117  1.1  tkusumi 
    118  1.1  tkusumi 	media = read_media(fp, bref, &bytes);
    119  1.1  tkusumi 	if (media == NULL)
    120  1.1  tkusumi 		return (-1);
    121  1.1  tkusumi 
    122  1.1  tkusumi 	switch (bref->type) {
    123  1.1  tkusumi 	case HAMMER2_BREF_TYPE_INODE:
    124  1.1  tkusumi 		ipdata = media->ipdata;
    125  1.5  tkusumi 		if (ipdata.meta.pfs_type == HAMMER2_PFSTYPE_SUPROOT) {
    126  1.1  tkusumi 			bscan = &ipdata.u.blockset.blockref[0];
    127  1.1  tkusumi 			bcount = HAMMER2_SET_COUNT;
    128  1.1  tkusumi 		} else {
    129  1.1  tkusumi 			bscan = NULL;
    130  1.1  tkusumi 			bcount = 0;
    131  1.1  tkusumi 			if (ipdata.meta.op_flags & HAMMER2_OPFLAG_PFSROOT) {
    132  1.1  tkusumi 				if (memchr(ipdata.filename, 0,
    133  1.1  tkusumi 				    sizeof(ipdata.filename))) {
    134  1.1  tkusumi 					if (!strcmp(
    135  1.1  tkusumi 					    (const char*)ipdata.filename, pfs))
    136  1.1  tkusumi 						*res = true;
    137  1.1  tkusumi 				} else {
    138  1.1  tkusumi 					if (strlen(pfs) > 0 &&
    139  1.1  tkusumi 					    !memcmp(ipdata.filename, pfs,
    140  1.1  tkusumi 					    strlen(pfs)))
    141  1.1  tkusumi 						*res = true;
    142  1.1  tkusumi 				}
    143  1.1  tkusumi 			} else
    144  1.1  tkusumi 				assert(0);
    145  1.1  tkusumi 		}
    146  1.1  tkusumi 		break;
    147  1.1  tkusumi 	case HAMMER2_BREF_TYPE_INDIRECT:
    148  1.1  tkusumi 		bscan = &media->npdata[0];
    149  1.1  tkusumi 		bcount = (int)(bytes / sizeof(hammer2_blockref_t));
    150  1.1  tkusumi 		break;
    151  1.1  tkusumi 	default:
    152  1.1  tkusumi 		bscan = NULL;
    153  1.1  tkusumi 		bcount = 0;
    154  1.1  tkusumi 		break;
    155  1.1  tkusumi 	}
    156  1.1  tkusumi 
    157  1.1  tkusumi 	for (i = 0; i < bcount; ++i) {
    158  1.1  tkusumi 		if (bscan[i].type != HAMMER2_BREF_TYPE_EMPTY) {
    159  1.1  tkusumi 			if (find_pfs(fp, &bscan[i], pfs, res) == -1) {
    160  1.1  tkusumi 				free(media);
    161  1.1  tkusumi 				return (-1);
    162  1.1  tkusumi 			}
    163  1.1  tkusumi 		}
    164  1.1  tkusumi 	}
    165  1.1  tkusumi 	free(media);
    166  1.1  tkusumi 
    167  1.1  tkusumi 	return (0);
    168  1.1  tkusumi }
    169  1.1  tkusumi 
    170  1.1  tkusumi static char*
    171  1.1  tkusumi extract_device_name(const char *devpath)
    172  1.1  tkusumi {
    173  1.1  tkusumi 	char *p, *head;
    174  1.1  tkusumi 
    175  1.1  tkusumi 	if (!devpath)
    176  1.1  tkusumi 		return NULL;
    177  1.1  tkusumi 
    178  1.1  tkusumi 	p = strdup(devpath);
    179  1.1  tkusumi 	head = p;
    180  1.1  tkusumi 
    181  1.1  tkusumi 	p = strchr(p, '@');
    182  1.1  tkusumi 	if (p)
    183  1.1  tkusumi 		*p = 0;
    184  1.1  tkusumi 
    185  1.1  tkusumi 	p = strrchr(head, '/');
    186  1.1  tkusumi 	if (p) {
    187  1.1  tkusumi 		p++;
    188  1.1  tkusumi 		if (*p == 0) {
    189  1.1  tkusumi 			free(head);
    190  1.1  tkusumi 			return NULL;
    191  1.1  tkusumi 		}
    192  1.1  tkusumi 		p = strdup(p);
    193  1.1  tkusumi 		free(head);
    194  1.1  tkusumi 		return p;
    195  1.1  tkusumi 	}
    196  1.1  tkusumi 
    197  1.1  tkusumi 	return head;
    198  1.1  tkusumi }
    199  1.1  tkusumi 
    200  1.1  tkusumi static int
    201  1.1  tkusumi read_label(FILE *fp, char *label, size_t size)
    202  1.1  tkusumi {
    203  1.1  tkusumi 	hammer2_blockref_t broot, best, *bref;
    204  1.1  tkusumi 	hammer2_media_data_t *vols[HAMMER2_NUM_VOLHDRS], *media;
    205  1.1  tkusumi 	size_t bytes;
    206  1.1  tkusumi 	bool res = false;
    207  1.3  tkusumi 	int i, best_i, error = 1;
    208  1.1  tkusumi 	const char *pfs;
    209  1.1  tkusumi 	char *devname;
    210  1.1  tkusumi 
    211  1.1  tkusumi 	best_i = -1;
    212  1.1  tkusumi 	memset(&best, 0, sizeof(best));
    213  1.1  tkusumi 
    214  1.1  tkusumi 	for (i = 0; i < HAMMER2_NUM_VOLHDRS; i++) {
    215  1.1  tkusumi 		memset(&broot, 0, sizeof(broot));
    216  1.1  tkusumi 		broot.type = HAMMER2_BREF_TYPE_VOLUME;
    217  1.1  tkusumi 		broot.data_off = ((hammer2_off_t)i *
    218  1.1  tkusumi 		    (hammer2_off_t)HAMMER2_ZONE_BYTES64) | HAMMER2_PBUFRADIX;
    219  1.1  tkusumi 		vols[i] = read_buf(fp,
    220  1.1  tkusumi 		    (off_t)(broot.data_off & ~HAMMER2_OFF_MASK_RADIX),
    221  1.1  tkusumi 		    sizeof(*vols[i]));
    222  1.1  tkusumi 		broot.mirror_tid = vols[i]->voldata.mirror_tid;
    223  1.1  tkusumi 		if (best_i < 0 || best.mirror_tid < broot.mirror_tid) {
    224  1.1  tkusumi 			best_i = i;
    225  1.1  tkusumi 			best = broot;
    226  1.1  tkusumi 		}
    227  1.1  tkusumi 	}
    228  1.1  tkusumi 
    229  1.1  tkusumi 	bref = &vols[best_i]->voldata.sroot_blockset.blockref[0];
    230  1.1  tkusumi 	if (bref->type != HAMMER2_BREF_TYPE_INODE) {
    231  1.3  tkusumi 		warnx("blockref type is not inode");
    232  1.3  tkusumi 		goto fail;
    233  1.1  tkusumi 	}
    234  1.1  tkusumi 
    235  1.1  tkusumi 	media = read_media(fp, bref, &bytes);
    236  1.1  tkusumi 	if (media == NULL) {
    237  1.3  tkusumi 		goto fail;
    238  1.1  tkusumi 	}
    239  1.1  tkusumi 
    240  1.1  tkusumi 	/*
    241  1.1  tkusumi 	 * fstyp_function in DragonFly takes an additional devpath argument
    242  1.1  tkusumi 	 * which doesn't exist in FreeBSD and NetBSD.
    243  1.1  tkusumi 	 */
    244  1.1  tkusumi #ifdef HAS_DEVPATH
    245  1.1  tkusumi 	pfs = strchr(devpath, '@');
    246  1.1  tkusumi 	if (!pfs) {
    247  1.1  tkusumi 		assert(strlen(devpath));
    248  1.1  tkusumi 		switch (devpath[strlen(devpath) - 1]) {
    249  1.1  tkusumi 		case 'a':
    250  1.1  tkusumi 			pfs = "BOOT";
    251  1.1  tkusumi 			break;
    252  1.1  tkusumi 		case 'd':
    253  1.1  tkusumi 			pfs = "ROOT";
    254  1.1  tkusumi 			break;
    255  1.1  tkusumi 		default:
    256  1.1  tkusumi 			pfs = "DATA";
    257  1.1  tkusumi 			break;
    258  1.1  tkusumi 		}
    259  1.1  tkusumi 	} else
    260  1.1  tkusumi 		pfs++;
    261  1.1  tkusumi 
    262  1.1  tkusumi 	if (strlen(pfs) > HAMMER2_INODE_MAXNAME) {
    263  1.3  tkusumi 		goto fail;
    264  1.1  tkusumi 	}
    265  1.1  tkusumi 	devname = extract_device_name(devpath);
    266  1.1  tkusumi #else
    267  1.1  tkusumi 	pfs = "";
    268  1.1  tkusumi 	devname = extract_device_name(NULL);
    269  1.1  tkusumi 	assert(!devname);
    270  1.1  tkusumi #endif
    271  1.1  tkusumi 
    272  1.1  tkusumi 	/* Add device name to help support multiple autofs -media mounts. */
    273  1.1  tkusumi 	if (find_pfs(fp, bref, pfs, &res) == 0 && res) {
    274  1.1  tkusumi 		if (devname)
    275  1.1  tkusumi 			snprintf(label, size, "%s_%s", pfs, devname);
    276  1.1  tkusumi 		else
    277  1.1  tkusumi 			strlcpy(label, pfs, size);
    278  1.1  tkusumi 	} else {
    279  1.1  tkusumi 		memset(label, 0, size);
    280  1.1  tkusumi 		memcpy(label, media->ipdata.filename,
    281  1.1  tkusumi 		    sizeof(media->ipdata.filename));
    282  1.1  tkusumi 		if (devname) {
    283  1.1  tkusumi 			strlcat(label, "_", size);
    284  1.1  tkusumi 			strlcat(label, devname, size);
    285  1.1  tkusumi 		}
    286  1.1  tkusumi 	}
    287  1.1  tkusumi 	if (devname)
    288  1.1  tkusumi 		free(devname);
    289  1.1  tkusumi 	free(media);
    290  1.3  tkusumi 	error = 0;
    291  1.3  tkusumi fail:
    292  1.1  tkusumi 	for (i = 0; i < HAMMER2_NUM_VOLHDRS; i++)
    293  1.1  tkusumi 		free(vols[i]);
    294  1.1  tkusumi 
    295  1.1  tkusumi 	return (error);
    296  1.1  tkusumi }
    297  1.1  tkusumi 
    298  1.1  tkusumi int
    299  1.1  tkusumi fstyp_hammer2(FILE *fp, char *label, size_t size)
    300  1.1  tkusumi {
    301  1.1  tkusumi 	hammer2_volume_data_t *voldata;
    302  1.1  tkusumi 	int error = 1;
    303  1.1  tkusumi 
    304  1.1  tkusumi 	voldata = read_voldata(fp);
    305  1.1  tkusumi 	if (test_voldata(voldata))
    306  1.3  tkusumi 		goto fail;
    307  1.1  tkusumi 
    308  1.1  tkusumi 	error = read_label(fp, label, size);
    309  1.3  tkusumi fail:
    310  1.1  tkusumi 	free(voldata);
    311  1.1  tkusumi 	return (error);
    312  1.1  tkusumi }
    313