xref: /dflybsd-src/stand/lib/hammer2.c (revision dc3a1b4664b2a57847267e7da055e8a772359b70)
1479ab7f0SSascha Wildner /*
2479ab7f0SSascha Wildner  * Copyright (c) 2011-2013 The DragonFly Project.  All rights reserved.
3479ab7f0SSascha Wildner  *
4479ab7f0SSascha Wildner  * This code is derived from software contributed to The DragonFly Project
5479ab7f0SSascha Wildner  * by Matthew Dillon <dillon@dragonflybsd.org>
6479ab7f0SSascha Wildner  * by Venkatesh Srinivas <vsrinivas@dragonflybsd.org>
7479ab7f0SSascha Wildner  *
8479ab7f0SSascha Wildner  * Redistribution and use in source and binary forms, with or without
9479ab7f0SSascha Wildner  * modification, are permitted provided that the following conditions
10479ab7f0SSascha Wildner  * are met:
11479ab7f0SSascha Wildner  *
12479ab7f0SSascha Wildner  * 1. Redistributions of source code must retain the above copyright
13479ab7f0SSascha Wildner  *    notice, this list of conditions and the following disclaimer.
14479ab7f0SSascha Wildner  * 2. Redistributions in binary form must reproduce the above copyright
15479ab7f0SSascha Wildner  *    notice, this list of conditions and the following disclaimer in
16479ab7f0SSascha Wildner  *    the documentation and/or other materials provided with the
17479ab7f0SSascha Wildner  *    distribution.
18479ab7f0SSascha Wildner  * 3. Neither the name of The DragonFly Project nor the names of its
19479ab7f0SSascha Wildner  *    contributors may be used to endorse or promote products derived
20479ab7f0SSascha Wildner  *    from this software without specific, prior written permission.
21479ab7f0SSascha Wildner  *
22479ab7f0SSascha Wildner  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23479ab7f0SSascha Wildner  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24479ab7f0SSascha Wildner  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25479ab7f0SSascha Wildner  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
26479ab7f0SSascha Wildner  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27479ab7f0SSascha Wildner  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
28479ab7f0SSascha Wildner  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29479ab7f0SSascha Wildner  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
30479ab7f0SSascha Wildner  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31479ab7f0SSascha Wildner  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
32479ab7f0SSascha Wildner  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33479ab7f0SSascha Wildner  * SUCH DAMAGE.
34479ab7f0SSascha Wildner  */
35479ab7f0SSascha Wildner 
36479ab7f0SSascha Wildner #if !defined(BOOT2) && !defined(TESTING)
37479ab7f0SSascha Wildner #define LIBSTAND        1
38479ab7f0SSascha Wildner #endif
39479ab7f0SSascha Wildner 
40479ab7f0SSascha Wildner #ifdef BOOT2
41479ab7f0SSascha Wildner #include "boot2.h"
42479ab7f0SSascha Wildner #endif
43479ab7f0SSascha Wildner 
44*dc3a1b46SAaron LI #ifdef LIBSTAND
45*dc3a1b46SAaron LI #include "stand.h"
46*dc3a1b46SAaron LI #endif
47*dc3a1b46SAaron LI 
48479ab7f0SSascha Wildner #ifdef TESTING
49479ab7f0SSascha Wildner #include <sys/types.h>
50479ab7f0SSascha Wildner #include <sys/stat.h>
51479ab7f0SSascha Wildner #include <sys/uuid.h>
52479ab7f0SSascha Wildner #include <stdio.h>
53479ab7f0SSascha Wildner #include <stdlib.h>
54479ab7f0SSascha Wildner #include <stddef.h>
55479ab7f0SSascha Wildner #include <stdint.h>
56479ab7f0SSascha Wildner #include <unistd.h>
57479ab7f0SSascha Wildner #include <fcntl.h>
58479ab7f0SSascha Wildner #include <string.h>
59479ab7f0SSascha Wildner #include <strings.h>
60479ab7f0SSascha Wildner #include <errno.h>
61479ab7f0SSascha Wildner #endif
62479ab7f0SSascha Wildner 
63479ab7f0SSascha Wildner #include <machine/param.h>	/* for DEV_BSHIFT */
64479ab7f0SSascha Wildner #include <vfs/hammer2/hammer2_disk.h>
65479ab7f0SSascha Wildner 
66479ab7f0SSascha Wildner uint32_t iscsi_crc32(const void *buf, size_t size);
67479ab7f0SSascha Wildner uint32_t iscsi_crc32_ext(const void *buf, size_t size, uint32_t ocrc);
68479ab7f0SSascha Wildner 
69479ab7f0SSascha Wildner static hammer2_media_data_t media;
70479ab7f0SSascha Wildner static hammer2_blockref_t saved_base;
71479ab7f0SSascha Wildner 
72479ab7f0SSascha Wildner #define hammer2_icrc32(buf, size)	iscsi_crc32(buf, size)
73479ab7f0SSascha Wildner 
74479ab7f0SSascha Wildner struct hammer2_fs {
75479ab7f0SSascha Wildner 	hammer2_blockref_t		sroot;
76479ab7f0SSascha Wildner 	hammer2_blockset_t		sroot_blockset;
77479ab7f0SSascha Wildner #if defined(TESTING)
78479ab7f0SSascha Wildner 	int 				fd;
79479ab7f0SSascha Wildner #elif defined(LIBSTAND)
80479ab7f0SSascha Wildner 	struct open_file		*f;
81479ab7f0SSascha Wildner #elif defined(BOOT2)
82479ab7f0SSascha Wildner 	/* BOOT2 doesn't use a descriptor */
83479ab7f0SSascha Wildner #else
84479ab7f0SSascha Wildner #error "hammer2: unknown library API"
85479ab7f0SSascha Wildner #endif
86479ab7f0SSascha Wildner };
87479ab7f0SSascha Wildner 
88479ab7f0SSascha Wildner struct hammer2_inode {
89479ab7f0SSascha Wildner 	struct hammer2_inode_data	ino;	/* raw inode data */
90479ab7f0SSascha Wildner 	off_t				doff;	/* disk inode offset */
91479ab7f0SSascha Wildner };
92479ab7f0SSascha Wildner 
93479ab7f0SSascha Wildner #ifdef BOOT2
94479ab7f0SSascha Wildner 
95479ab7f0SSascha Wildner static void
bzero(void * buf,size_t size)96479ab7f0SSascha Wildner bzero(void *buf, size_t size)
97479ab7f0SSascha Wildner {
98479ab7f0SSascha Wildner 	for (size_t i = 0; i < size; i++)
99479ab7f0SSascha Wildner 		((char *)buf)[i] = 0;
100479ab7f0SSascha Wildner }
101479ab7f0SSascha Wildner 
102479ab7f0SSascha Wildner static void
bcopy(void * src,void * dst,size_t size)103479ab7f0SSascha Wildner bcopy(void *src, void *dst, size_t size)
104479ab7f0SSascha Wildner {
105479ab7f0SSascha Wildner 	memcpy(dst, src, size);
106479ab7f0SSascha Wildner }
107479ab7f0SSascha Wildner 
108479ab7f0SSascha Wildner #if 0
109479ab7f0SSascha Wildner static size_t
110479ab7f0SSascha Wildner strlen(const char *s)
111479ab7f0SSascha Wildner {
112479ab7f0SSascha Wildner 	size_t l = 0;
113479ab7f0SSascha Wildner 	for (; *s != 0; s++)
114479ab7f0SSascha Wildner 		l++;
115479ab7f0SSascha Wildner 	return (l);
116479ab7f0SSascha Wildner }
117479ab7f0SSascha Wildner #endif
118479ab7f0SSascha Wildner 
119479ab7f0SSascha Wildner static int
memcmp(const void * a,const void * b,size_t len)120479ab7f0SSascha Wildner memcmp(const void *a, const void *b, size_t len)
121479ab7f0SSascha Wildner {
122479ab7f0SSascha Wildner 	for (size_t p = 0; p < len; p++) {
123479ab7f0SSascha Wildner 		int r = ((const char *)a)[p] - ((const char *)b)[p];
124479ab7f0SSascha Wildner 		if (r != 0)
125479ab7f0SSascha Wildner 			return (r);
126479ab7f0SSascha Wildner 	}
127479ab7f0SSascha Wildner 
128479ab7f0SSascha Wildner 	return (0);
129479ab7f0SSascha Wildner }
130479ab7f0SSascha Wildner 
131479ab7f0SSascha Wildner #endif
132479ab7f0SSascha Wildner 
133479ab7f0SSascha Wildner static
134479ab7f0SSascha Wildner off_t
blockoff(hammer2_blockref_t * bref)135479ab7f0SSascha Wildner blockoff(hammer2_blockref_t *bref)
136479ab7f0SSascha Wildner {
137479ab7f0SSascha Wildner 	return(bref->data_off & ~HAMMER2_OFF_MASK_RADIX);
138479ab7f0SSascha Wildner }
139479ab7f0SSascha Wildner 
140479ab7f0SSascha Wildner static
141479ab7f0SSascha Wildner size_t
blocksize(hammer2_blockref_t * bref)142479ab7f0SSascha Wildner blocksize(hammer2_blockref_t *bref)
143479ab7f0SSascha Wildner {
144479ab7f0SSascha Wildner 	size_t bytes;
145479ab7f0SSascha Wildner 
146479ab7f0SSascha Wildner 	bytes = (size_t)(bref->data_off & HAMMER2_OFF_MASK_RADIX);
147479ab7f0SSascha Wildner 	if (bytes)
148479ab7f0SSascha Wildner 		bytes = (size_t)1 << bytes;
149479ab7f0SSascha Wildner 	return bytes;
150479ab7f0SSascha Wildner }
151479ab7f0SSascha Wildner 
152479ab7f0SSascha Wildner static
153479ab7f0SSascha Wildner hammer2_key_t
hammer2_dirhash(const unsigned char * name,size_t len)154479ab7f0SSascha Wildner hammer2_dirhash(const unsigned char *name, size_t len)
155479ab7f0SSascha Wildner {
156479ab7f0SSascha Wildner 	const unsigned char *aname = name;
157479ab7f0SSascha Wildner 	uint32_t crcx;
158479ab7f0SSascha Wildner 	uint64_t key;
159479ab7f0SSascha Wildner 	size_t i;
160479ab7f0SSascha Wildner 	size_t j;
161479ab7f0SSascha Wildner 
162479ab7f0SSascha Wildner 	key = 0;
163479ab7f0SSascha Wildner 
164479ab7f0SSascha Wildner 	/*
165479ab7f0SSascha Wildner 	 * m32
166479ab7f0SSascha Wildner 	 */
167479ab7f0SSascha Wildner 	crcx = 0;
168479ab7f0SSascha Wildner 	for (i = j = 0; i < len; ++i) {
169479ab7f0SSascha Wildner 		if (aname[i] == '.' ||
170479ab7f0SSascha Wildner 		    aname[i] == '-' ||
171479ab7f0SSascha Wildner 		    aname[i] == '_' ||
172479ab7f0SSascha Wildner 		    aname[i] == '~') {
173479ab7f0SSascha Wildner 			if (i != j)
174479ab7f0SSascha Wildner 				crcx += hammer2_icrc32(aname + j, i - j);
175479ab7f0SSascha Wildner 			j = i + 1;
176479ab7f0SSascha Wildner 		}
177479ab7f0SSascha Wildner 	}
178479ab7f0SSascha Wildner 	if (i != j)
179479ab7f0SSascha Wildner 		crcx += hammer2_icrc32(aname + j, i - j);
180479ab7f0SSascha Wildner 
181479ab7f0SSascha Wildner 	/*
182479ab7f0SSascha Wildner 	 * The directory hash utilizes the top 32 bits of the 64-bit key.
183479ab7f0SSascha Wildner 	 * Bit 63 must be set to 1.
184479ab7f0SSascha Wildner 	 */
185479ab7f0SSascha Wildner 	crcx |= 0x80000000U;
186479ab7f0SSascha Wildner 	key |= (uint64_t)crcx << 32;
187479ab7f0SSascha Wildner 
188479ab7f0SSascha Wildner 	/*
189479ab7f0SSascha Wildner 	 * l16 - crc of entire filename
190479ab7f0SSascha Wildner 	 *
191479ab7f0SSascha Wildner 	 * This crc reduces degenerate hash collision conditions
192479ab7f0SSascha Wildner 	 */
193479ab7f0SSascha Wildner 	crcx = hammer2_icrc32(aname, len);
194479ab7f0SSascha Wildner 	crcx = crcx ^ (crcx << 16);
195479ab7f0SSascha Wildner 	key |= crcx & 0xFFFF0000U;
196479ab7f0SSascha Wildner 
197479ab7f0SSascha Wildner 	/*
198479ab7f0SSascha Wildner 	 * Set bit 15.  This allows readdir to strip bit 63 so a positive
199479ab7f0SSascha Wildner 	 * 64-bit cookie/offset can always be returned, and still guarantee
200479ab7f0SSascha Wildner 	 * that the values 0x0000-0x7FFF are available for artificial entries.
201479ab7f0SSascha Wildner 	 * ('.' and '..').
202479ab7f0SSascha Wildner 	 */
203479ab7f0SSascha Wildner 	key |= 0x8000U;
204479ab7f0SSascha Wildner 
205479ab7f0SSascha Wildner 	return (key);
206479ab7f0SSascha Wildner }
207479ab7f0SSascha Wildner 
208479ab7f0SSascha Wildner /*
209479ab7f0SSascha Wildner  * Low level read
210479ab7f0SSascha Wildner  */
211479ab7f0SSascha Wildner static
212479ab7f0SSascha Wildner int
h2read(struct hammer2_fs * hfs,void * buf,size_t nbytes,off_t off)213479ab7f0SSascha Wildner h2read(struct hammer2_fs *hfs, void *buf, size_t nbytes, off_t off)
214479ab7f0SSascha Wildner {
215479ab7f0SSascha Wildner #if defined(LIBSTAND)
216479ab7f0SSascha Wildner 	size_t rlen;
217479ab7f0SSascha Wildner #endif
218479ab7f0SSascha Wildner 	int rc;
219479ab7f0SSascha Wildner 
220479ab7f0SSascha Wildner #if defined(TESTING)
221479ab7f0SSascha Wildner 	rc = pread(hfs->fd, &media, nbytes, off);
222479ab7f0SSascha Wildner 	if (rc == (int)nbytes)
223479ab7f0SSascha Wildner 		rc = 0;
224479ab7f0SSascha Wildner 	else
225479ab7f0SSascha Wildner 		rc = -1;
226479ab7f0SSascha Wildner #elif defined(LIBSTAND)
227479ab7f0SSascha Wildner 	rc = hfs->f->f_dev->dv_strategy(hfs->f->f_devdata, F_READ,
228479ab7f0SSascha Wildner 					off >> DEV_BSHIFT, nbytes,
229479ab7f0SSascha Wildner 					buf, &rlen);
230479ab7f0SSascha Wildner 	if (rc || rlen != nbytes)
231479ab7f0SSascha Wildner 		rc = -1;
232479ab7f0SSascha Wildner #elif defined(BOOT2)
233479ab7f0SSascha Wildner 	/* BIOS interface may barf on 64KB reads */
234479ab7f0SSascha Wildner 	rc = 0;
235479ab7f0SSascha Wildner 	while (nbytes > 16384) {
236479ab7f0SSascha Wildner 		rc = dskread(buf, off >> DEV_BSHIFT, 16384 >> DEV_BSHIFT);
237479ab7f0SSascha Wildner 		nbytes -= 16384;
238479ab7f0SSascha Wildner 		buf = (char *)buf + 16384;
239479ab7f0SSascha Wildner 		off += 16384;
240479ab7f0SSascha Wildner 	}
241479ab7f0SSascha Wildner 	if (nbytes)
242479ab7f0SSascha Wildner 		rc = dskread(buf, off >> DEV_BSHIFT, nbytes >> DEV_BSHIFT);
243479ab7f0SSascha Wildner 	if (rc)
244479ab7f0SSascha Wildner 		rc = -1;
245479ab7f0SSascha Wildner #else
246479ab7f0SSascha Wildner #error "hammer2: unknown library API"
247479ab7f0SSascha Wildner #endif
248479ab7f0SSascha Wildner 	return rc;
249479ab7f0SSascha Wildner }
250479ab7f0SSascha Wildner 
251479ab7f0SSascha Wildner /*
252479ab7f0SSascha Wildner  * Common code
253479ab7f0SSascha Wildner  *
254479ab7f0SSascha Wildner  * Initialize for HAMMER2 filesystem access given a hammer2_fs with
255479ab7f0SSascha Wildner  * its device file descriptor initialized.
256479ab7f0SSascha Wildner  */
257479ab7f0SSascha Wildner 
258479ab7f0SSascha Wildner /*
259479ab7f0SSascha Wildner  * Lookup within the block specified by (*base), loading the block from disk
260479ab7f0SSascha Wildner  * if necessary.  Locate the first key within the requested range and
261479ab7f0SSascha Wildner  * recursively run through indirect blocks as needed.  The caller may loop
262479ab7f0SSascha Wildner  * by setting key_beg to *key_ret.
263479ab7f0SSascha Wildner  *
264479ab7f0SSascha Wildner  * Returns 0 if nothing could be found and the key range has been exhausted.
265479ab7f0SSascha Wildner  * returns -1 if a disk error occured.  Otherwise returns the size of the
266479ab7f0SSascha Wildner  * data block and returns the data block in *pptr and bref in *bref_ret.
267479ab7f0SSascha Wildner  *
268479ab7f0SSascha Wildner  * NOTE! When reading file data, the returned bref's key will be the nearest
269479ab7f0SSascha Wildner  *	 data block we looked up.  The file read procedure must handle any
270479ab7f0SSascha Wildner  *       zero-fill or skip.  However, we will truncate the return value to
271479ab7f0SSascha Wildner  *	 the file size.
272479ab7f0SSascha Wildner  */
273479ab7f0SSascha Wildner static int
h2lookup(struct hammer2_fs * hfs,hammer2_blockref_t * base,hammer2_key_t key_beg,hammer2_key_t key_end,hammer2_blockref_t * bref_ret,void ** pptr)274479ab7f0SSascha Wildner h2lookup(struct hammer2_fs *hfs, hammer2_blockref_t *base,
275479ab7f0SSascha Wildner 	 hammer2_key_t key_beg, hammer2_key_t key_end,
276479ab7f0SSascha Wildner 	 hammer2_blockref_t *bref_ret, void **pptr)
277479ab7f0SSascha Wildner {
278479ab7f0SSascha Wildner 	hammer2_blockref_t *bref;
279479ab7f0SSascha Wildner 	hammer2_blockref_t best;
280479ab7f0SSascha Wildner 	hammer2_key_t scan_beg;
281479ab7f0SSascha Wildner 	hammer2_key_t scan_end;
282479ab7f0SSascha Wildner 	int i;
283479ab7f0SSascha Wildner 	int rc;
284479ab7f0SSascha Wildner 	int count;
285479ab7f0SSascha Wildner 	int dev_boff;
286479ab7f0SSascha Wildner 	int dev_bsize;
287479ab7f0SSascha Wildner 
288479ab7f0SSascha Wildner 	if (base == NULL) {
289479ab7f0SSascha Wildner 		saved_base.data_off = (hammer2_off_t)-1;
290479ab7f0SSascha Wildner 		return(0);
291479ab7f0SSascha Wildner 	}
292479ab7f0SSascha Wildner 	if (base->data_off == (hammer2_off_t)-1) {
293479ab7f0SSascha Wildner 		bref_ret->type = 0;
294479ab7f0SSascha Wildner 		return(-1);
295479ab7f0SSascha Wildner 	}
296479ab7f0SSascha Wildner 
297479ab7f0SSascha Wildner 	/*
298479ab7f0SSascha Wildner 	 * Calculate the number of blockrefs to scan
299479ab7f0SSascha Wildner 	 */
300479ab7f0SSascha Wildner 	switch(base->type) {
301479ab7f0SSascha Wildner 	case HAMMER2_BREF_TYPE_VOLUME:
302479ab7f0SSascha Wildner 		count = HAMMER2_SET_COUNT;
303479ab7f0SSascha Wildner 		break;
304479ab7f0SSascha Wildner 	case HAMMER2_BREF_TYPE_INODE:
305479ab7f0SSascha Wildner 		count = HAMMER2_SET_COUNT;
306479ab7f0SSascha Wildner 		break;
307479ab7f0SSascha Wildner 	case HAMMER2_BREF_TYPE_INDIRECT:
308479ab7f0SSascha Wildner 		count = blocksize(base) / sizeof(hammer2_blockref_t);
309479ab7f0SSascha Wildner 		break;
310479ab7f0SSascha Wildner 	default:
311479ab7f0SSascha Wildner 		count = 0;
312479ab7f0SSascha Wildner 		break;
313479ab7f0SSascha Wildner 	}
314479ab7f0SSascha Wildner 
315479ab7f0SSascha Wildner 	/*
316479ab7f0SSascha Wildner 	 * Find the best candidate (the lowest blockref within the specified
317479ab7f0SSascha Wildner 	 * range).  The array can be fully set associative so make no ordering
318479ab7f0SSascha Wildner 	 * assumptions.
319479ab7f0SSascha Wildner 	 */
320479ab7f0SSascha Wildner again:
321479ab7f0SSascha Wildner 	best.key = HAMMER2_KEY_MAX;
322479ab7f0SSascha Wildner 	best.type = 0;
323479ab7f0SSascha Wildner 
324479ab7f0SSascha Wildner 	for (i = 0; i < count; ++i) {
325479ab7f0SSascha Wildner 		/*
326479ab7f0SSascha Wildner 		 * [re]load when returning from our recursion
327479ab7f0SSascha Wildner 		 */
328479ab7f0SSascha Wildner 		if (base->type != HAMMER2_BREF_TYPE_VOLUME &&
329479ab7f0SSascha Wildner 		    base->data_off != saved_base.data_off) {
330479ab7f0SSascha Wildner 			if (blocksize(base) && h2read(hfs, &media,
331479ab7f0SSascha Wildner 						      blocksize(base),
332479ab7f0SSascha Wildner 						      blockoff(base))) {
333479ab7f0SSascha Wildner 				bref_ret->type = 0;
334479ab7f0SSascha Wildner 				return(-1);
335479ab7f0SSascha Wildner 			}
336479ab7f0SSascha Wildner 			saved_base = *base;
337479ab7f0SSascha Wildner 		}
338479ab7f0SSascha Wildner 
339479ab7f0SSascha Wildner 		/*
340479ab7f0SSascha Wildner 		 * Special case embedded file data
341479ab7f0SSascha Wildner 		 */
342479ab7f0SSascha Wildner 		if (base->type == HAMMER2_BREF_TYPE_INODE) {
343479ab7f0SSascha Wildner 			if (media.ipdata.meta.op_flags &
344479ab7f0SSascha Wildner 			    HAMMER2_OPFLAG_DIRECTDATA) {
345479ab7f0SSascha Wildner 				*pptr = media.ipdata.u.data;
346479ab7f0SSascha Wildner 				bref_ret->type = HAMMER2_BREF_TYPE_DATA;
347479ab7f0SSascha Wildner 				bref_ret->key = 0;
348479ab7f0SSascha Wildner 				return HAMMER2_EMBEDDED_BYTES;
349479ab7f0SSascha Wildner 			}
350479ab7f0SSascha Wildner 		}
351479ab7f0SSascha Wildner 
352479ab7f0SSascha Wildner 		/*
353479ab7f0SSascha Wildner 		 * Calculate the bref in our scan.
354479ab7f0SSascha Wildner 		 */
355479ab7f0SSascha Wildner 		switch(base->type) {
356479ab7f0SSascha Wildner 		case HAMMER2_BREF_TYPE_VOLUME:
357479ab7f0SSascha Wildner 			bref = &hfs->sroot_blockset.blockref[i];
358479ab7f0SSascha Wildner 			break;
359479ab7f0SSascha Wildner 		case HAMMER2_BREF_TYPE_INODE:
360479ab7f0SSascha Wildner 			bref = &media.ipdata.u.blockset.blockref[i];
361479ab7f0SSascha Wildner 			break;
362479ab7f0SSascha Wildner 		case HAMMER2_BREF_TYPE_INDIRECT:
363479ab7f0SSascha Wildner 			bref = &media.npdata[i];
364479ab7f0SSascha Wildner 			break;
365479ab7f0SSascha Wildner 		}
366479ab7f0SSascha Wildner 		if (bref->type == 0)
367479ab7f0SSascha Wildner 			continue;
368479ab7f0SSascha Wildner 		if (bref->key > best.key)
369479ab7f0SSascha Wildner 			continue;
370479ab7f0SSascha Wildner 		scan_beg = bref->key;
371479ab7f0SSascha Wildner 		scan_end = scan_beg + ((hammer2_key_t)1 << bref->keybits) - 1;
372479ab7f0SSascha Wildner 		if (scan_end >= key_beg && scan_beg <= key_end) {
373479ab7f0SSascha Wildner 			best = *bref;
374479ab7f0SSascha Wildner 		}
375479ab7f0SSascha Wildner 	}
376479ab7f0SSascha Wildner 
377479ab7f0SSascha Wildner 	/*
378479ab7f0SSascha Wildner 	 * Figure out what to do with the results.
379479ab7f0SSascha Wildner 	 */
380479ab7f0SSascha Wildner 	switch(best.type) {
381479ab7f0SSascha Wildner 	case 0:
382479ab7f0SSascha Wildner 		/*
383479ab7f0SSascha Wildner 		 * Return 0
384479ab7f0SSascha Wildner 		 */
385479ab7f0SSascha Wildner 		bref_ret->type = 0;
386479ab7f0SSascha Wildner 		rc = 0;
387479ab7f0SSascha Wildner 		break;
388479ab7f0SSascha Wildner 	case HAMMER2_BREF_TYPE_INDIRECT:
389479ab7f0SSascha Wildner 		/*
390479ab7f0SSascha Wildner 		 * Matched an indirect block.  If the block turns out to
391479ab7f0SSascha Wildner 		 * contain nothing we continue the iteration, otherwise
392479ab7f0SSascha Wildner 		 * we return the data from the recursion.
393479ab7f0SSascha Wildner 		 *
394479ab7f0SSascha Wildner 		 * Be sure to handle the overflow case when recalculating
395479ab7f0SSascha Wildner 		 * key_beg.
396479ab7f0SSascha Wildner 		 */
397479ab7f0SSascha Wildner 		rc = h2lookup(hfs, &best, key_beg, key_end, bref_ret, pptr);
398479ab7f0SSascha Wildner 		if (rc == 0) {
399479ab7f0SSascha Wildner 			key_beg = best.key +
400479ab7f0SSascha Wildner 				  ((hammer2_key_t)1 << best.keybits);
401479ab7f0SSascha Wildner 			if (key_beg > best.key && key_beg <= key_end)
402479ab7f0SSascha Wildner 				goto again;
403479ab7f0SSascha Wildner 		}
404479ab7f0SSascha Wildner 		break;
405479ab7f0SSascha Wildner 	case HAMMER2_BREF_TYPE_DIRENT:
406479ab7f0SSascha Wildner 	case HAMMER2_BREF_TYPE_INODE:
407479ab7f0SSascha Wildner 	case HAMMER2_BREF_TYPE_DATA:
408479ab7f0SSascha Wildner 		/*
409479ab7f0SSascha Wildner 		 * Terminal match.  Leaf elements might not be data-aligned.
410479ab7f0SSascha Wildner 		 */
411479ab7f0SSascha Wildner 		dev_bsize = blocksize(&best);
412479ab7f0SSascha Wildner 		if (dev_bsize) {
413479ab7f0SSascha Wildner 			if (dev_bsize < HAMMER2_LBUFSIZE)
414479ab7f0SSascha Wildner 				dev_bsize = HAMMER2_LBUFSIZE;
415479ab7f0SSascha Wildner 			dev_boff = blockoff(&best) -
416479ab7f0SSascha Wildner 				   (blockoff(&best) & ~HAMMER2_LBUFMASK64);
417479ab7f0SSascha Wildner 			if (h2read(hfs, &media,
418479ab7f0SSascha Wildner 				   dev_bsize,
419479ab7f0SSascha Wildner 				   blockoff(&best) - dev_boff)) {
420479ab7f0SSascha Wildner 				return(-1);
421479ab7f0SSascha Wildner 			}
422479ab7f0SSascha Wildner 		}
423479ab7f0SSascha Wildner 		saved_base.data_off = (hammer2_off_t)-1;
424479ab7f0SSascha Wildner 		*bref_ret = best;
425479ab7f0SSascha Wildner 		*pptr = media.buf + dev_boff;
426479ab7f0SSascha Wildner 		rc = blocksize(&best);
427479ab7f0SSascha Wildner 		break;
428479ab7f0SSascha Wildner 	}
429479ab7f0SSascha Wildner 	return(rc);
430479ab7f0SSascha Wildner }
431479ab7f0SSascha Wildner 
432479ab7f0SSascha Wildner static
433479ab7f0SSascha Wildner void
h2resolve(struct hammer2_fs * hfs,const char * path,hammer2_blockref_t * bref,hammer2_inode_data_t ** inop)434479ab7f0SSascha Wildner h2resolve(struct hammer2_fs *hfs, const char *path,
435479ab7f0SSascha Wildner 	  hammer2_blockref_t *bref, hammer2_inode_data_t **inop)
436479ab7f0SSascha Wildner {
437479ab7f0SSascha Wildner 	hammer2_blockref_t bres;
438479ab7f0SSascha Wildner 	hammer2_inode_data_t *ino;
439479ab7f0SSascha Wildner 	hammer2_key_t key;
440479ab7f0SSascha Wildner 	void *data;
441479ab7f0SSascha Wildner 	ssize_t bytes;
442479ab7f0SSascha Wildner 	size_t len;
443479ab7f0SSascha Wildner 
444479ab7f0SSascha Wildner 	/*
445479ab7f0SSascha Wildner 	 * Start point (superroot)
446479ab7f0SSascha Wildner 	 */
447479ab7f0SSascha Wildner 	ino = NULL;
448479ab7f0SSascha Wildner 	*bref = hfs->sroot;
449479ab7f0SSascha Wildner 	if (inop)
450479ab7f0SSascha Wildner 		*inop = NULL;
451479ab7f0SSascha Wildner 
452479ab7f0SSascha Wildner 	/*
453479ab7f0SSascha Wildner 	 * Iterate path elements
454479ab7f0SSascha Wildner 	 */
455479ab7f0SSascha Wildner 	while (*path) {
456479ab7f0SSascha Wildner 		while (*path == '/')
457479ab7f0SSascha Wildner 			++path;
458479ab7f0SSascha Wildner 		if (*path == 0)	/* terminal */
459479ab7f0SSascha Wildner 			break;
460479ab7f0SSascha Wildner 
461479ab7f0SSascha Wildner 		/*
462479ab7f0SSascha Wildner 		 * Calculate path element and look for it in the directory
463479ab7f0SSascha Wildner 		 */
464479ab7f0SSascha Wildner 		for (len = 0; path[len]; ++len) {
465479ab7f0SSascha Wildner 			if (path[len] == '/')
466479ab7f0SSascha Wildner 				break;
467479ab7f0SSascha Wildner 		}
468479ab7f0SSascha Wildner 		key = hammer2_dirhash(path, len);
469479ab7f0SSascha Wildner 		for (;;) {
470479ab7f0SSascha Wildner 			bytes = h2lookup(hfs, bref,
4712ad4d0e4SMatthew Dillon 					 key,
4722ad4d0e4SMatthew Dillon 					 key | HAMMER2_DIRHASH_LOMASK,
473479ab7f0SSascha Wildner 					 &bres, (void **)&data);
474479ab7f0SSascha Wildner 			if (bytes < 0)
475479ab7f0SSascha Wildner 				break;
476479ab7f0SSascha Wildner 			if (bres.type == 0)
477479ab7f0SSascha Wildner 				break;
478479ab7f0SSascha Wildner 			switch (bres.type) {
479479ab7f0SSascha Wildner 			case HAMMER2_BREF_TYPE_DIRENT:
480479ab7f0SSascha Wildner 				if (bres.embed.dirent.namlen != len)
481479ab7f0SSascha Wildner 					break;
482479ab7f0SSascha Wildner 				if (bres.embed.dirent.namlen <=
483479ab7f0SSascha Wildner 				    sizeof(bres.check.buf)) {
484479ab7f0SSascha Wildner 					if (memcmp(path, bres.check.buf, len))
485479ab7f0SSascha Wildner 						break;
486479ab7f0SSascha Wildner 				} else {
487479ab7f0SSascha Wildner 					if (memcmp(path, data, len))
488479ab7f0SSascha Wildner 						break;
489479ab7f0SSascha Wildner 				}
490479ab7f0SSascha Wildner 
491479ab7f0SSascha Wildner 				/*
492479ab7f0SSascha Wildner 				 * Found, resolve inode.  This will set
493479ab7f0SSascha Wildner 				 * ino similarly to HAMMER2_BREF_TYPE_INODE
494479ab7f0SSascha Wildner 				 * and adjust bres, which path continuation
495479ab7f0SSascha Wildner 				 * needs.
496479ab7f0SSascha Wildner 				 */
497479ab7f0SSascha Wildner 				*bref = hfs->sroot;
498479ab7f0SSascha Wildner 				bytes = h2lookup(hfs, bref,
499479ab7f0SSascha Wildner 						 bres.embed.dirent.inum,
500479ab7f0SSascha Wildner 						 bres.embed.dirent.inum,
501479ab7f0SSascha Wildner 						 &bres, (void **)&ino);
502479ab7f0SSascha Wildner 				if (inop)
503479ab7f0SSascha Wildner 					*inop = ino;
504479ab7f0SSascha Wildner 				goto found;
505479ab7f0SSascha Wildner 				break;	/* NOT REACHED */
506479ab7f0SSascha Wildner 			case HAMMER2_BREF_TYPE_INODE:
507479ab7f0SSascha Wildner 				ino = data;
508479ab7f0SSascha Wildner 				if (ino->meta.name_len != len)
509479ab7f0SSascha Wildner 					break;
510479ab7f0SSascha Wildner 				if (memcmp(path, ino->filename, len) == 0) {
511479ab7f0SSascha Wildner 					if (inop)
512479ab7f0SSascha Wildner 						*inop = ino;
513479ab7f0SSascha Wildner 					goto found;
514479ab7f0SSascha Wildner 				}
515479ab7f0SSascha Wildner 				break;
516479ab7f0SSascha Wildner 			}
517479ab7f0SSascha Wildner 			if ((bres.key & 0xFFFF) == 0xFFFF) {
518479ab7f0SSascha Wildner 				bres.type = 0;
519479ab7f0SSascha Wildner 				break;
520479ab7f0SSascha Wildner 			}
521479ab7f0SSascha Wildner 			key = bres.key + 1;
522479ab7f0SSascha Wildner 		}
523479ab7f0SSascha Wildner found:
524479ab7f0SSascha Wildner 
525479ab7f0SSascha Wildner 		/*
526479ab7f0SSascha Wildner 		 * Lookup failure
527479ab7f0SSascha Wildner 		 */
528479ab7f0SSascha Wildner 		if (bytes < 0 || bres.type == 0) {
529479ab7f0SSascha Wildner 			bref->data_off = (hammer2_off_t)-1;
530479ab7f0SSascha Wildner 			ino = NULL;
531479ab7f0SSascha Wildner 			break;
532479ab7f0SSascha Wildner 		}
533479ab7f0SSascha Wildner 
534479ab7f0SSascha Wildner 		/*
535479ab7f0SSascha Wildner 		 * Check path continuance, inode must be a directory or
536479ab7f0SSascha Wildner 		 * we fail.
537479ab7f0SSascha Wildner 		 */
538479ab7f0SSascha Wildner 		path += len;
539479ab7f0SSascha Wildner 		if (*path && ino->meta.type != HAMMER2_OBJTYPE_DIRECTORY) {
540479ab7f0SSascha Wildner 			bref->data_off = (hammer2_off_t)-1;
541479ab7f0SSascha Wildner 			break;
542479ab7f0SSascha Wildner 		}
543479ab7f0SSascha Wildner 		*bref = bres;
544479ab7f0SSascha Wildner 	}
545479ab7f0SSascha Wildner }
546479ab7f0SSascha Wildner 
547479ab7f0SSascha Wildner static
548479ab7f0SSascha Wildner ssize_t
h2readfile(struct hammer2_fs * hfs,hammer2_blockref_t * bref,off_t off,off_t filesize,void * buf,size_t len)549479ab7f0SSascha Wildner h2readfile(struct hammer2_fs *hfs, hammer2_blockref_t *bref,
550479ab7f0SSascha Wildner 	   off_t off, off_t filesize, void *buf, size_t len)
551479ab7f0SSascha Wildner {
552479ab7f0SSascha Wildner 	hammer2_blockref_t bres;
553479ab7f0SSascha Wildner 	ssize_t total;
554479ab7f0SSascha Wildner 	ssize_t bytes;
555479ab7f0SSascha Wildner 	ssize_t zfill;
556479ab7f0SSascha Wildner 	char *data;
557479ab7f0SSascha Wildner 
558479ab7f0SSascha Wildner 	/*
559479ab7f0SSascha Wildner 	 * EOF edge cases
560479ab7f0SSascha Wildner 	 */
561479ab7f0SSascha Wildner 	if (off >= filesize)
562479ab7f0SSascha Wildner 		return (0);
563479ab7f0SSascha Wildner 	if (off + len > filesize)
564479ab7f0SSascha Wildner 		len = filesize - off;
565479ab7f0SSascha Wildner 
566479ab7f0SSascha Wildner 	/*
567479ab7f0SSascha Wildner 	 * Loop until done
568479ab7f0SSascha Wildner 	 */
569479ab7f0SSascha Wildner 	total = 0;
570479ab7f0SSascha Wildner 	while (len) {
571479ab7f0SSascha Wildner 		/*
572479ab7f0SSascha Wildner 		 * Find closest bres >= requested offset.
573479ab7f0SSascha Wildner 		 */
574479ab7f0SSascha Wildner 		bytes = h2lookup(hfs, bref, off, off + len - 1,
575479ab7f0SSascha Wildner 				 &bres, (void **)&data);
576479ab7f0SSascha Wildner 
577479ab7f0SSascha Wildner 		if (bytes < 0) {
578479ab7f0SSascha Wildner 			if (total == 0)
579479ab7f0SSascha Wildner 				total = -1;
580479ab7f0SSascha Wildner 			break;
581479ab7f0SSascha Wildner 		}
582479ab7f0SSascha Wildner 
583479ab7f0SSascha Wildner 		/*
584479ab7f0SSascha Wildner 		 * Load the data into the buffer.  First handle a degenerate
585479ab7f0SSascha Wildner 		 * zero-fill case.
586479ab7f0SSascha Wildner 		 */
587479ab7f0SSascha Wildner 		if (bytes == 0) {
588479ab7f0SSascha Wildner 			bzero(buf, len);
589479ab7f0SSascha Wildner 			total += len;
590479ab7f0SSascha Wildner 			break;
591479ab7f0SSascha Wildner 		}
592479ab7f0SSascha Wildner 
593479ab7f0SSascha Wildner 		/*
594479ab7f0SSascha Wildner 		 * Returned record overlaps to the left of the requested
595479ab7f0SSascha Wildner 		 * position.  It must overlap in this case or h2lookup()
596479ab7f0SSascha Wildner 		 * would have returned something else.
597479ab7f0SSascha Wildner 		 */
598479ab7f0SSascha Wildner 		if (bres.key < off) {
599479ab7f0SSascha Wildner 			data += off - bres.key;
600479ab7f0SSascha Wildner 			bytes -= off - bres.key;
601479ab7f0SSascha Wildner 		}
602479ab7f0SSascha Wildner 
603479ab7f0SSascha Wildner 		/*
604479ab7f0SSascha Wildner 		 * Returned record overlaps to the right of the requested
605479ab7f0SSascha Wildner 		 * position, handle zero-fill.  Again h2lookup() only returns
606479ab7f0SSascha Wildner 		 * this case if there is an actual overlap.
607479ab7f0SSascha Wildner 		 */
608479ab7f0SSascha Wildner 		if (bres.key > off) {
609479ab7f0SSascha Wildner 			zfill = (ssize_t)(bres.key - off);
610479ab7f0SSascha Wildner 			bzero(buf, zfill);
611479ab7f0SSascha Wildner 			len -= zfill;
612479ab7f0SSascha Wildner 			off += zfill;
613479ab7f0SSascha Wildner 			total += zfill;
614479ab7f0SSascha Wildner 			buf = (char *)buf + zfill;
615479ab7f0SSascha Wildner 		}
616479ab7f0SSascha Wildner 
617479ab7f0SSascha Wildner 		/*
618479ab7f0SSascha Wildner 		 * Trim returned request before copying.
619479ab7f0SSascha Wildner 		 */
620479ab7f0SSascha Wildner 		if (bytes > len)
621479ab7f0SSascha Wildner 			bytes = len;
622479ab7f0SSascha Wildner 		bcopy(data, buf, bytes);
623479ab7f0SSascha Wildner 		len -= bytes;
624479ab7f0SSascha Wildner 		off += bytes;
625479ab7f0SSascha Wildner 		total += bytes;
626479ab7f0SSascha Wildner 		buf = (char *)buf + bytes;
627479ab7f0SSascha Wildner 	}
628479ab7f0SSascha Wildner 	return (total);
629479ab7f0SSascha Wildner }
630479ab7f0SSascha Wildner 
631479ab7f0SSascha Wildner static
632479ab7f0SSascha Wildner int
h2init(struct hammer2_fs * hfs)633479ab7f0SSascha Wildner h2init(struct hammer2_fs *hfs)
634479ab7f0SSascha Wildner {
635479ab7f0SSascha Wildner #if 0
636479ab7f0SSascha Wildner 	uint32_t crc0;
637479ab7f0SSascha Wildner #endif
638479ab7f0SSascha Wildner 	hammer2_tid_t best_tid = 0;
639479ab7f0SSascha Wildner 	void *data;
640479ab7f0SSascha Wildner 	off_t off;
641479ab7f0SSascha Wildner 	int best;
642479ab7f0SSascha Wildner 	int i;
643479ab7f0SSascha Wildner 	int r;
644479ab7f0SSascha Wildner 
645479ab7f0SSascha Wildner 	/*
646479ab7f0SSascha Wildner 	 * Find the best volume header.
647479ab7f0SSascha Wildner 	 *
648479ab7f0SSascha Wildner 	 * WARNING BIOS BUGS: It looks like some BIOSes will implode when
649479ab7f0SSascha Wildner 	 * given a disk offset beyond the EOM.  XXX We need to probe the
650479ab7f0SSascha Wildner 	 * size of the media and limit our accesses, until then we have
651479ab7f0SSascha Wildner 	 * to give up if the first volume header does not have a hammer2
652479ab7f0SSascha Wildner 	 * signature.
653479ab7f0SSascha Wildner 	 *
654479ab7f0SSascha Wildner 	 * XXX Probably still going to be problems w/ HAMMER2 volumes on
655479ab7f0SSascha Wildner 	 *     media which is too small w/certain BIOSes.
656479ab7f0SSascha Wildner 	 */
657479ab7f0SSascha Wildner 	best = -1;
658479ab7f0SSascha Wildner 	for (i = 0; i < HAMMER2_NUM_VOLHDRS; ++i) {
659479ab7f0SSascha Wildner 		off = i * HAMMER2_ZONE_BYTES64;
660479ab7f0SSascha Wildner 		if (i)
661479ab7f0SSascha Wildner 			no_io_error = 1;
662479ab7f0SSascha Wildner 		if (h2read(hfs, &media, sizeof(media.voldata), off))
663479ab7f0SSascha Wildner 			break;
664479ab7f0SSascha Wildner 		if (media.voldata.magic != HAMMER2_VOLUME_ID_HBO)
665479ab7f0SSascha Wildner 			break;
666479ab7f0SSascha Wildner 		if (best < 0 || best_tid < media.voldata.mirror_tid) {
667479ab7f0SSascha Wildner 			best = i;
668479ab7f0SSascha Wildner 			best_tid = media.voldata.mirror_tid;
669479ab7f0SSascha Wildner 		}
670479ab7f0SSascha Wildner 	}
671479ab7f0SSascha Wildner 	no_io_error = 0;
672479ab7f0SSascha Wildner 	if (best < 0)
673479ab7f0SSascha Wildner 		return(-1);
674479ab7f0SSascha Wildner 
675479ab7f0SSascha Wildner 	/*
676479ab7f0SSascha Wildner 	 * Reload the best volume header and set up the blockref.
677479ab7f0SSascha Wildner 	 * We messed with media, clear the cache before continuing.
678479ab7f0SSascha Wildner 	 */
679479ab7f0SSascha Wildner 	off = best * HAMMER2_ZONE_BYTES64;
680479ab7f0SSascha Wildner 	if (h2read(hfs, &media, sizeof(media.voldata), off))
681479ab7f0SSascha Wildner 		return(-1);
682479ab7f0SSascha Wildner 	hfs->sroot.type = HAMMER2_BREF_TYPE_VOLUME;
683479ab7f0SSascha Wildner 	hfs->sroot.data_off = off;
684479ab7f0SSascha Wildner 	hfs->sroot_blockset = media.voldata.sroot_blockset;
685479ab7f0SSascha Wildner 	h2lookup(hfs, NULL, 0, 0, NULL, NULL);
686479ab7f0SSascha Wildner 
687479ab7f0SSascha Wildner 	/*
688479ab7f0SSascha Wildner 	 * Lookup sroot/BOOT and clear the cache again.
689479ab7f0SSascha Wildner 	 */
690479ab7f0SSascha Wildner 	r = h2lookup(hfs, &hfs->sroot,
691479ab7f0SSascha Wildner 		     HAMMER2_SROOT_KEY, HAMMER2_SROOT_KEY,
692479ab7f0SSascha Wildner 		     &hfs->sroot, &data);
693479ab7f0SSascha Wildner 	if (r <= 0)
694479ab7f0SSascha Wildner 		return(-1);
695479ab7f0SSascha Wildner 	h2lookup(hfs, NULL, 0, 0, NULL, NULL);
696479ab7f0SSascha Wildner 	r = h2lookup(hfs, &hfs->sroot,
6972ad4d0e4SMatthew Dillon 		     HAMMER2_BOOT_KEY,
6982ad4d0e4SMatthew Dillon 		     HAMMER2_BOOT_KEY | HAMMER2_DIRHASH_LOMASK,
699479ab7f0SSascha Wildner 		     &hfs->sroot, &data);
700479ab7f0SSascha Wildner 	if (r <= 0) {
701479ab7f0SSascha Wildner 		printf("hammer2: 'BOOT' PFS not found\n");
702479ab7f0SSascha Wildner 		return(-1);
703479ab7f0SSascha Wildner 	}
704479ab7f0SSascha Wildner 	h2lookup(hfs, NULL, 0, 0, NULL, NULL);
705479ab7f0SSascha Wildner 
706479ab7f0SSascha Wildner 	return (0);
707479ab7f0SSascha Wildner }
708479ab7f0SSascha Wildner 
709479ab7f0SSascha Wildner /************************************************************************
710479ab7f0SSascha Wildner  * 				BOOT2 SUPPORT				*
711479ab7f0SSascha Wildner  ************************************************************************
712479ab7f0SSascha Wildner  *
713479ab7f0SSascha Wildner  */
714479ab7f0SSascha Wildner #ifdef BOOT2
715479ab7f0SSascha Wildner 
716479ab7f0SSascha Wildner static struct hammer2_fs hfs;
717479ab7f0SSascha Wildner 
718479ab7f0SSascha Wildner static int
boot2_hammer2_init(void)719479ab7f0SSascha Wildner boot2_hammer2_init(void)
720479ab7f0SSascha Wildner {
721479ab7f0SSascha Wildner 	if (h2init(&hfs))
722479ab7f0SSascha Wildner 		return(-1);
723479ab7f0SSascha Wildner 	return(0);
724479ab7f0SSascha Wildner }
725479ab7f0SSascha Wildner 
726479ab7f0SSascha Wildner static boot2_ino_t
boot2_hammer2_lookup(const char * path)727479ab7f0SSascha Wildner boot2_hammer2_lookup(const char *path)
728479ab7f0SSascha Wildner {
729479ab7f0SSascha Wildner 	hammer2_blockref_t bref;
730479ab7f0SSascha Wildner 
731479ab7f0SSascha Wildner 	h2resolve(&hfs, path, &bref, NULL);
732479ab7f0SSascha Wildner 	return ((boot2_ino_t)bref.data_off);
733479ab7f0SSascha Wildner }
734479ab7f0SSascha Wildner 
735479ab7f0SSascha Wildner static ssize_t
boot2_hammer2_read(boot2_ino_t ino,void * buf,size_t len)736479ab7f0SSascha Wildner boot2_hammer2_read(boot2_ino_t ino, void *buf, size_t len)
737479ab7f0SSascha Wildner {
738479ab7f0SSascha Wildner 	hammer2_blockref_t bref;
739479ab7f0SSascha Wildner 	ssize_t total;
740479ab7f0SSascha Wildner 
741479ab7f0SSascha Wildner 	bzero(&bref, sizeof(bref));
742479ab7f0SSascha Wildner 	bref.type = HAMMER2_BREF_TYPE_INODE;
743479ab7f0SSascha Wildner 	bref.data_off = ino;
744479ab7f0SSascha Wildner 
745479ab7f0SSascha Wildner 	total = h2readfile(&hfs, &bref, fs_off, 0x7FFFFFFF, buf, len);
746479ab7f0SSascha Wildner 	if (total > 0)
747479ab7f0SSascha Wildner 		fs_off += total;
748479ab7f0SSascha Wildner 	return total;
749479ab7f0SSascha Wildner }
750479ab7f0SSascha Wildner 
751479ab7f0SSascha Wildner const struct boot2_fsapi boot2_hammer2_api = {
752479ab7f0SSascha Wildner         .fsinit = boot2_hammer2_init,
753479ab7f0SSascha Wildner         .fslookup = boot2_hammer2_lookup,
754479ab7f0SSascha Wildner         .fsread = boot2_hammer2_read
755479ab7f0SSascha Wildner };
756479ab7f0SSascha Wildner 
757479ab7f0SSascha Wildner #endif
758479ab7f0SSascha Wildner 
759479ab7f0SSascha Wildner /************************************************************************
760*dc3a1b46SAaron LI  * 				LIBSTAND SUPPORT			*
761479ab7f0SSascha Wildner  ************************************************************************
762479ab7f0SSascha Wildner  *
763479ab7f0SSascha Wildner  */
764479ab7f0SSascha Wildner #ifdef LIBSTAND
765479ab7f0SSascha Wildner 
766479ab7f0SSascha Wildner struct hfile {
767479ab7f0SSascha Wildner 	struct hammer2_fs hfs;
768479ab7f0SSascha Wildner 	hammer2_blockref_t bref;
769479ab7f0SSascha Wildner 	int64_t		fsize;
770479ab7f0SSascha Wildner 	uint32_t	mode;
771479ab7f0SSascha Wildner 	uint8_t		type;
772479ab7f0SSascha Wildner };
773479ab7f0SSascha Wildner 
774479ab7f0SSascha Wildner static
775479ab7f0SSascha Wildner int
hammer2_get_dtype(uint8_t type)776479ab7f0SSascha Wildner hammer2_get_dtype(uint8_t type)
777479ab7f0SSascha Wildner {
778479ab7f0SSascha Wildner 	switch(type) {
779479ab7f0SSascha Wildner 	case HAMMER2_OBJTYPE_DIRECTORY:
780479ab7f0SSascha Wildner 		return(DT_DIR);
781479ab7f0SSascha Wildner 	case HAMMER2_OBJTYPE_REGFILE:
782479ab7f0SSascha Wildner 		return(DT_REG);
783479ab7f0SSascha Wildner 	case HAMMER2_OBJTYPE_FIFO:
784479ab7f0SSascha Wildner 		return(DT_FIFO);
785479ab7f0SSascha Wildner 	case HAMMER2_OBJTYPE_CDEV:
786479ab7f0SSascha Wildner 		return(DT_CHR);
787479ab7f0SSascha Wildner 	case HAMMER2_OBJTYPE_BDEV:
788479ab7f0SSascha Wildner 		return(DT_BLK);
789479ab7f0SSascha Wildner 	case HAMMER2_OBJTYPE_SOFTLINK:
790479ab7f0SSascha Wildner 		return(DT_LNK);
791479ab7f0SSascha Wildner 	case HAMMER2_OBJTYPE_SOCKET:
792479ab7f0SSascha Wildner 		return(DT_SOCK);
793479ab7f0SSascha Wildner 	default:
794479ab7f0SSascha Wildner 		return(DT_UNKNOWN);
795479ab7f0SSascha Wildner 	}
796479ab7f0SSascha Wildner }
797479ab7f0SSascha Wildner 
798479ab7f0SSascha Wildner static
799479ab7f0SSascha Wildner mode_t
hammer2_get_mode(uint8_t type)800479ab7f0SSascha Wildner hammer2_get_mode(uint8_t type)
801479ab7f0SSascha Wildner {
802479ab7f0SSascha Wildner 	switch(type) {
803479ab7f0SSascha Wildner 	case HAMMER2_OBJTYPE_DIRECTORY:
804479ab7f0SSascha Wildner 		return(S_IFDIR);
805479ab7f0SSascha Wildner 	case HAMMER2_OBJTYPE_REGFILE:
806479ab7f0SSascha Wildner 		return(S_IFREG);
807479ab7f0SSascha Wildner 	case HAMMER2_OBJTYPE_FIFO:
808479ab7f0SSascha Wildner 		return(S_IFIFO);
809479ab7f0SSascha Wildner 	case HAMMER2_OBJTYPE_CDEV:
810479ab7f0SSascha Wildner 		return(S_IFCHR);
811479ab7f0SSascha Wildner 	case HAMMER2_OBJTYPE_BDEV:
812479ab7f0SSascha Wildner 		return(S_IFBLK);
813479ab7f0SSascha Wildner 	case HAMMER2_OBJTYPE_SOFTLINK:
814479ab7f0SSascha Wildner 		return(S_IFLNK);
815479ab7f0SSascha Wildner 	case HAMMER2_OBJTYPE_SOCKET:
816479ab7f0SSascha Wildner 		return(S_IFSOCK);
817479ab7f0SSascha Wildner 	default:
818479ab7f0SSascha Wildner 		return(0);
819479ab7f0SSascha Wildner 	}
820479ab7f0SSascha Wildner }
821479ab7f0SSascha Wildner 
822479ab7f0SSascha Wildner static int
hammer2_open(const char * path,struct open_file * f)823479ab7f0SSascha Wildner hammer2_open(const char *path, struct open_file *f)
824479ab7f0SSascha Wildner {
825479ab7f0SSascha Wildner 	struct hfile *hf = malloc(sizeof(*hf));
826479ab7f0SSascha Wildner 	hammer2_inode_data_t *ipdata;
827479ab7f0SSascha Wildner 
828479ab7f0SSascha Wildner 	bzero(hf, sizeof(*hf));
829479ab7f0SSascha Wildner 	f->f_offset = 0;
830479ab7f0SSascha Wildner 	f->f_fsdata = hf;
831479ab7f0SSascha Wildner 	hf->hfs.f = f;
832479ab7f0SSascha Wildner 
833479ab7f0SSascha Wildner 	if (h2init(&hf->hfs)) {
834479ab7f0SSascha Wildner 		f->f_fsdata = NULL;
835479ab7f0SSascha Wildner 		free(hf);
836479ab7f0SSascha Wildner 		errno = ENOENT;
837479ab7f0SSascha Wildner 		return(-1);
838479ab7f0SSascha Wildner 	}
839479ab7f0SSascha Wildner 	h2resolve(&hf->hfs, path, &hf->bref, &ipdata);
840479ab7f0SSascha Wildner 	if (hf->bref.data_off == (hammer2_off_t)-1 ||
841479ab7f0SSascha Wildner 	    (hf->bref.type != HAMMER2_BREF_TYPE_INODE &&
842479ab7f0SSascha Wildner 	    hf->bref.type != HAMMER2_BREF_TYPE_VOLUME)) {
843479ab7f0SSascha Wildner 		f->f_fsdata = NULL;
844479ab7f0SSascha Wildner 		free(hf);
845479ab7f0SSascha Wildner 		errno = ENOENT;
846479ab7f0SSascha Wildner 		return(-1);
847479ab7f0SSascha Wildner 	}
848479ab7f0SSascha Wildner 	if (ipdata) {
849479ab7f0SSascha Wildner 		hf->fsize = ipdata->meta.size;
850479ab7f0SSascha Wildner 		hf->type = ipdata->meta.type;
851479ab7f0SSascha Wildner 		hf->mode = ipdata->meta.mode |
852479ab7f0SSascha Wildner 			   hammer2_get_mode(ipdata->meta.type);
853479ab7f0SSascha Wildner 	} else {
854479ab7f0SSascha Wildner 		hf->fsize = 0;
855479ab7f0SSascha Wildner 		hf->type = HAMMER2_OBJTYPE_DIRECTORY;
856479ab7f0SSascha Wildner 		hf->mode = 0755 | S_IFDIR;
857479ab7f0SSascha Wildner 	}
858479ab7f0SSascha Wildner 	return(0);
859479ab7f0SSascha Wildner }
860479ab7f0SSascha Wildner 
861479ab7f0SSascha Wildner static int
hammer2_close(struct open_file * f)862479ab7f0SSascha Wildner hammer2_close(struct open_file *f)
863479ab7f0SSascha Wildner {
864479ab7f0SSascha Wildner 	struct hfile *hf = f->f_fsdata;
865479ab7f0SSascha Wildner 
866479ab7f0SSascha Wildner 	f->f_fsdata = NULL;
867479ab7f0SSascha Wildner 	if (hf)
868479ab7f0SSascha Wildner 		free(hf);
869479ab7f0SSascha Wildner 	return (0);
870479ab7f0SSascha Wildner }
871479ab7f0SSascha Wildner 
872479ab7f0SSascha Wildner static int
hammer2_read(struct open_file * f,void * buf,size_t len,size_t * resid)873479ab7f0SSascha Wildner hammer2_read(struct open_file *f, void *buf, size_t len, size_t *resid)
874479ab7f0SSascha Wildner {
875479ab7f0SSascha Wildner 	struct hfile *hf = f->f_fsdata;
876479ab7f0SSascha Wildner 	ssize_t total;
877479ab7f0SSascha Wildner 	int rc = 0;
878479ab7f0SSascha Wildner 
879479ab7f0SSascha Wildner 	total = h2readfile(&hf->hfs, &hf->bref,
880479ab7f0SSascha Wildner 			   f->f_offset, hf->fsize, buf, len);
881479ab7f0SSascha Wildner 	if (total < 0) {
882479ab7f0SSascha Wildner 		rc = EIO;
883479ab7f0SSascha Wildner 		total = 0;
884479ab7f0SSascha Wildner 	} else {
885479ab7f0SSascha Wildner 		f->f_offset += total;
886479ab7f0SSascha Wildner 		rc = 0;
887479ab7f0SSascha Wildner 	}
888479ab7f0SSascha Wildner 	*resid = len - total;
889479ab7f0SSascha Wildner 	return rc;
890479ab7f0SSascha Wildner }
891479ab7f0SSascha Wildner 
892479ab7f0SSascha Wildner static off_t
hammer2_seek(struct open_file * f,off_t offset,int whence)893479ab7f0SSascha Wildner hammer2_seek(struct open_file *f, off_t offset, int whence)
894479ab7f0SSascha Wildner {
895479ab7f0SSascha Wildner 	struct hfile *hf = f->f_fsdata;
896479ab7f0SSascha Wildner 
897479ab7f0SSascha Wildner 	switch (whence) {
898479ab7f0SSascha Wildner 	case SEEK_SET:
899479ab7f0SSascha Wildner 		f->f_offset = offset;
900479ab7f0SSascha Wildner 		break;
901479ab7f0SSascha Wildner 	case SEEK_CUR:
902479ab7f0SSascha Wildner 		f->f_offset += offset;
903479ab7f0SSascha Wildner 		break;
904479ab7f0SSascha Wildner 	case SEEK_END:
905479ab7f0SSascha Wildner 		f->f_offset = hf->fsize - offset;
906479ab7f0SSascha Wildner 		break;
907479ab7f0SSascha Wildner 	default:
908479ab7f0SSascha Wildner 		return (-1);
909479ab7f0SSascha Wildner 	}
910479ab7f0SSascha Wildner 	return (f->f_offset);
911479ab7f0SSascha Wildner }
912479ab7f0SSascha Wildner 
913479ab7f0SSascha Wildner static int
hammer2_stat(struct open_file * f,struct stat * st)914479ab7f0SSascha Wildner hammer2_stat(struct open_file *f, struct stat *st)
915479ab7f0SSascha Wildner {
916479ab7f0SSascha Wildner 	struct hfile *hf = f->f_fsdata;
917479ab7f0SSascha Wildner 
918479ab7f0SSascha Wildner 	st->st_mode = hf->mode;
919479ab7f0SSascha Wildner 	st->st_uid = 0;
920479ab7f0SSascha Wildner 	st->st_gid = 0;
921479ab7f0SSascha Wildner 	st->st_size = hf->fsize;
922479ab7f0SSascha Wildner 
923479ab7f0SSascha Wildner 	return (0);
924479ab7f0SSascha Wildner }
925479ab7f0SSascha Wildner 
926479ab7f0SSascha Wildner static int
hammer2_readdir(struct open_file * f,struct dirent * den)927479ab7f0SSascha Wildner hammer2_readdir(struct open_file *f, struct dirent *den)
928479ab7f0SSascha Wildner {
929479ab7f0SSascha Wildner 	struct hfile *hf = f->f_fsdata;
930479ab7f0SSascha Wildner 	hammer2_blockref_t bres;
931479ab7f0SSascha Wildner 	hammer2_inode_data_t *ipdata;
932479ab7f0SSascha Wildner 	void *data;
933479ab7f0SSascha Wildner 	int bytes;
934479ab7f0SSascha Wildner 
935479ab7f0SSascha Wildner 	for (;;) {
936479ab7f0SSascha Wildner 		bytes = h2lookup(&hf->hfs, &hf->bref,
937479ab7f0SSascha Wildner 				 f->f_offset | HAMMER2_DIRHASH_VISIBLE,
938479ab7f0SSascha Wildner 				 HAMMER2_KEY_MAX,
939479ab7f0SSascha Wildner 				 &bres, (void **)&data);
940479ab7f0SSascha Wildner 		if (bytes < 0)
941479ab7f0SSascha Wildner 			break;
942479ab7f0SSascha Wildner 		switch (bres.type) {
943479ab7f0SSascha Wildner 		case HAMMER2_BREF_TYPE_INODE:
944479ab7f0SSascha Wildner 			ipdata = data;
945479ab7f0SSascha Wildner 			den->d_namlen = ipdata->meta.name_len;
946479ab7f0SSascha Wildner 			den->d_type = hammer2_get_dtype(ipdata->meta.type);
947479ab7f0SSascha Wildner 			den->d_ino = ipdata->meta.inum;
948479ab7f0SSascha Wildner 			bcopy(ipdata->filename, den->d_name, den->d_namlen);
949479ab7f0SSascha Wildner 			den->d_name[den->d_namlen] = 0;
950479ab7f0SSascha Wildner 			break;
951479ab7f0SSascha Wildner 		case HAMMER2_BREF_TYPE_DIRENT:
952479ab7f0SSascha Wildner 			den->d_namlen = bres.embed.dirent.namlen;
953479ab7f0SSascha Wildner 			den->d_type = hammer2_get_dtype(bres.embed.dirent.type);
954479ab7f0SSascha Wildner 			den->d_ino = bres.embed.dirent.inum;
955479ab7f0SSascha Wildner 			if (den->d_namlen <= sizeof(bres.check.buf)) {
956479ab7f0SSascha Wildner 				bcopy(bres.check.buf,
957479ab7f0SSascha Wildner 				      den->d_name,
958479ab7f0SSascha Wildner 				      den->d_namlen);
959479ab7f0SSascha Wildner 			} else {
960479ab7f0SSascha Wildner 				bcopy(data, den->d_name, den->d_namlen);
961479ab7f0SSascha Wildner 			}
962479ab7f0SSascha Wildner 			den->d_name[den->d_namlen] = 0;
963479ab7f0SSascha Wildner 			break;
964479ab7f0SSascha Wildner 		default:
965479ab7f0SSascha Wildner 			den->d_namlen = 1;
966479ab7f0SSascha Wildner 			den->d_type =
967479ab7f0SSascha Wildner 				hammer2_get_dtype(HAMMER2_OBJTYPE_REGFILE);
968479ab7f0SSascha Wildner 			den->d_name[0] = '?';
969479ab7f0SSascha Wildner 			den->d_name[1] = 0;
970479ab7f0SSascha Wildner 			break;
971479ab7f0SSascha Wildner 		}
972479ab7f0SSascha Wildner 
973479ab7f0SSascha Wildner 		f->f_offset = bres.key + 1;
974479ab7f0SSascha Wildner 
975479ab7f0SSascha Wildner 		return(0);
976479ab7f0SSascha Wildner 	}
977479ab7f0SSascha Wildner 	return ENOENT;
978479ab7f0SSascha Wildner }
979479ab7f0SSascha Wildner 
980479ab7f0SSascha Wildner struct fs_ops hammer2_fsops = {
981479ab7f0SSascha Wildner 	"hammer2",
982479ab7f0SSascha Wildner 	hammer2_open,
983479ab7f0SSascha Wildner 	hammer2_close,
984479ab7f0SSascha Wildner 	hammer2_read,
985479ab7f0SSascha Wildner 	null_write,
986479ab7f0SSascha Wildner 	hammer2_seek,
987479ab7f0SSascha Wildner 	hammer2_stat,
988479ab7f0SSascha Wildner 	hammer2_readdir
989479ab7f0SSascha Wildner };
990479ab7f0SSascha Wildner 
991479ab7f0SSascha Wildner #endif
992