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