Add hammer read support for loader.
authorSimon Schubert <corecode@dragonflybsd.org>
Sat, 13 Sep 2008 11:38:58 +0000 (11:38 +0000)
committerSimon Schubert <corecode@dragonflybsd.org>
Sat, 13 Sep 2008 11:38:58 +0000 (11:38 +0000)
lib/libstand/Makefile
lib/libstand/hammerread.c [new file with mode: 0644]
lib/libstand/stand.h

index 7bfdfae..ae04b19 100644 (file)
@@ -1,5 +1,5 @@
 # $FreeBSD: src/lib/libstand/Makefile,v 1.14.2.10 2002/07/22 14:21:50 ru Exp $
-# $DragonFly: src/lib/libstand/Makefile,v 1.10 2005/06/30 15:55:17 corecode Exp $
+# $DragonFly: src/lib/libstand/Makefile,v 1.11 2008/09/13 11:38:58 corecode Exp $
 #
 # Originally from      $NetBSD: Makefile,v 1.21 1997/10/26 22:08:38 lukem Exp $
 #
@@ -15,7 +15,7 @@ INCS=         stand.h
 MAN=           libstand.3
 
 # Mostly OK, some of the libc imports are a bit noisy
-CFLAGS+=       -Wall -ffreestanding
+CFLAGS+=       -Wall -ffreestanding -std=c99
 
 .if ${MACHINE_ARCH} == "amd64"
 CFLAGS+=       -m32 -mpreferred-stack-boundary=2
@@ -86,5 +86,6 @@ SRCS+=        ufs.c nfs.c cd9660.c tftp.c zipfs.c bzipfs.c gzipfs.c
 SRCS+= netif.c nfs.c
 SRCS+= dosfs.c ext2fs.c
 SRCS+= splitfs.c
+SRCS+= hammerread.c
 
 .include <bsd.lib.mk>
diff --git a/lib/libstand/hammerread.c b/lib/libstand/hammerread.c
new file mode 100644 (file)
index 0000000..272a16f
--- /dev/null
@@ -0,0 +1,1009 @@
+/*
+ * Copyright (c) 2008 The DragonFly Project.  All rights reserved.
+ *
+ * This code is derived from software contributed to The DragonFly Project
+ * by Simon Schubert <corecode@fs.ei.tum.de>
+ * and Matthew Dillon <dillon@backplane.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ * 3. Neither the name of The DragonFly Project nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific, prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $DragonFly: src/lib/libstand/hammerread.c,v 1.1 2008/09/13 11:38:58 corecode Exp $
+ */
+
+/*
+ * This file is being used by boot2 and libstand (loader).
+ * Compile with -DTESTING to obtain a binary.
+ */
+
+
+#if !defined(BOOT2) && !defined(TESTING)
+#define        LIBSTAND        1
+#endif
+
+#include <sys/param.h>
+
+#include <stddef.h>
+#include <stdint.h>
+
+#ifdef TESTING
+#include <sys/fcntl.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <dirent.h>
+#endif
+
+#ifdef LIBSTAND
+#include "stand.h"
+#endif
+
+#include <vfs/hammer/hammer_disk.h>
+
+#ifndef BOOT2
+struct blockentry {
+       hammer_off_t    off;
+       int             use;
+       char            *data;
+};
+
+#ifdef TESTING
+#define NUMCACHE       16
+#else
+#define        NUMCACHE        6
+#endif
+
+struct hfs {
+#ifdef TESTING
+       int             fd;
+#else  // libstand
+       struct open_file *f;
+#endif
+       hammer_off_t    root;
+       int64_t         buf_beg;
+       int             lru;
+       struct blockentry cache[NUMCACHE];
+};
+
+static void *
+hread(struct hfs *hfs, hammer_off_t off)
+{
+       hammer_off_t boff = off & ~HAMMER_BUFMASK;
+
+       boff &= HAMMER_OFF_LONG_MASK;
+
+       if (HAMMER_ZONE_DECODE(off) != HAMMER_ZONE_RAW_VOLUME_INDEX)
+               boff += hfs->buf_beg;
+
+       struct blockentry *be = NULL;
+       for (int i = 0; i < NUMCACHE; i++) {
+               if (be == NULL || be->use > hfs->cache[i].use)
+                       be = &hfs->cache[i];
+               if (hfs->cache[i].off == boff) {
+                       be = &hfs->cache[i];
+                       break;
+               }
+       }
+       if (be->off != boff) {
+               // Didn't find any match
+               be->off = boff;
+#ifdef TESTING
+               ssize_t res = pread(hfs->fd, be->data, HAMMER_BUFSIZE,
+                                   boff & HAMMER_OFF_SHORT_MASK);
+               if (res != HAMMER_BUFSIZE)
+                       err(1, "short read on off %llx", boff);
+#else  // libstand
+               size_t rlen;
+               int rv = hfs->f->f_dev->dv_strategy(hfs->f->f_devdata, F_READ,
+                       boff >> DEV_BSHIFT, HAMMER_BUFSIZE,
+                       be->data, &rlen);
+               if (rv || rlen != HAMMER_BUFSIZE)
+                       return (NULL);
+#endif
+       }
+
+       be->use = ++hfs->lru;
+       return &be->data[off & HAMMER_BUFMASK];
+}
+
+#else  /* BOOT2 */
+
+struct dmadat {
+       char            secbuf[DEV_BSIZE];
+       char            buf[HAMMER_BUFSIZE];
+};
+
+static struct dmadat *dmadat;
+
+struct hfs {
+       hammer_off_t    root;
+       int64_t         buf_beg;
+};
+
+static void *
+hread(struct hfs *hfs, hammer_off_t off)
+{
+       char *buf = dmadat->buf;
+
+       hammer_off_t boff = off & ~HAMMER_BUFMASK;
+       boff &= HAMMER_OFF_LONG_MASK;
+       if (HAMMER_ZONE_DECODE(off) != HAMMER_ZONE_RAW_VOLUME_INDEX)
+               boff += hfs->buf_beg;
+       boff &= HAMMER_OFF_SHORT_MASK;
+       boff >>= DEV_BSHIFT;
+       if (dskread(buf, boff, HAMMER_BUFSIZE >> DEV_BSHIFT))
+               return (NULL);
+       return (&buf[off & HAMMER_BUFMASK]);
+}
+
+static void
+bzero(void *buf, size_t size)
+{
+       for (size_t i = 0; i < size; i++)
+               ((char *)buf)[i] = 0;
+}
+
+static void
+bcopy(void *src, void *dst, size_t size)
+{
+       memcpy(dst, src, size);
+}
+
+static size_t
+strlen(const char *s)
+{
+       size_t l = 0;
+       for (; *s != 0; s++)
+               l++;
+       return (l);
+}
+
+static int
+memcmp(const void *a, const void *b, size_t len)
+{
+       for (size_t p = 0; p < len; p++) {
+               int r = ((const char *)a)[p] - ((const char *)b)[p];
+               if (r != 0)
+                       return (r);
+       }
+
+       return (0);
+}
+
+#endif
+
+/*
+ * (from hammer_btree.c)
+ *
+ * Compare two B-Tree elements, return -N, 0, or +N (e.g. similar to strcmp).
+ *
+ * Note that for this particular function a return value of -1, 0, or +1
+ * can denote a match if create_tid is otherwise discounted.  A create_tid
+ * of zero is considered to be 'infinity' in comparisons.
+ *
+ * See also hammer_rec_rb_compare() and hammer_rec_cmp() in hammer_object.c.
+ */
+static int
+hammer_btree_cmp(hammer_base_elm_t key1, hammer_base_elm_t key2)
+{
+       if (key1->localization < key2->localization)
+               return(-5);
+       if (key1->localization > key2->localization)
+               return(5);
+
+       if (key1->obj_id < key2->obj_id)
+               return(-4);
+       if (key1->obj_id > key2->obj_id)
+               return(4);
+
+       if (key1->rec_type < key2->rec_type)
+               return(-3);
+       if (key1->rec_type > key2->rec_type)
+               return(3);
+
+       if (key1->key < key2->key)
+               return(-2);
+       if (key1->key > key2->key)
+               return(2);
+
+       /*
+        * A create_tid of zero indicates a record which is undeletable
+        * and must be considered to have a value of positive infinity.
+        */
+       if (key1->create_tid == 0) {
+               if (key2->create_tid == 0)
+                       return(0);
+               return(1);
+       }
+       if (key2->create_tid == 0)
+               return(-1);
+       if (key1->create_tid < key2->create_tid)
+               return(-1);
+       if (key1->create_tid > key2->create_tid)
+               return(1);
+       return(0);
+}
+
+/*
+ * Heuristical search for the first element whos comparison is <= 1.  May
+ * return an index whos compare result is > 1 but may only return an index
+ * whos compare result is <= 1 if it is the first element with that result.
+ */
+static int
+hammer_btree_search_node(hammer_base_elm_t elm, hammer_node_ondisk_t node)
+{
+       int b;
+       int s;
+       int i;
+       int r;
+
+       /*
+        * Don't bother if the node does not have very many elements
+        */
+       b = 0;
+       s = node->count;
+       while (s - b > 4) {
+               i = b + (s - b) / 2;
+               r = hammer_btree_cmp(elm, &node->elms[i].leaf.base);
+               if (r <= 1) {
+                       s = i;
+               } else {
+                       b = i;
+               }
+       }
+       return(b);
+}
+
+#if 0
+/*
+ * (from hammer_subs.c)
+ *
+ * Return a namekey hash.   The 64 bit namekey hash consists of a 32 bit
+ * crc in the MSB and 0 in the LSB.  The caller will use the low bits to
+ * generate a unique key and will scan all entries with the same upper
+ * 32 bits when issuing a lookup.
+ *
+ * We strip bit 63 in order to provide a positive key, this way a seek
+ * offset of 0 will represent the base of the directory.
+ *
+ * This function can never return 0.  We use the MSB-0 space to synthesize
+ * artificial directory entries such as "." and "..".
+ */
+static int64_t
+hammer_directory_namekey(const void *name, int len)
+{
+       int64_t key;
+
+       key = (int64_t)(crc32(name, len) & 0x7FFFFFFF) << 32;
+       if (key == 0)
+               key |= 0x100000000LL;
+       return(key);
+}
+#else
+static int64_t
+hammer_directory_namekey(const void *name __unused, int len __unused)
+{
+       return (0);
+}
+#endif
+
+
+#ifndef BOOT2
+/*
+ * Misc
+ */
+static u_int32_t
+hammer_to_unix_xid(uuid_t *uuid)
+{
+       return(*(u_int32_t *)&uuid->node[2]);
+}
+
+static int
+hammer_get_dtype(u_int8_t obj_type)
+{
+       switch(obj_type) {
+       case HAMMER_OBJTYPE_DIRECTORY:
+               return(DT_DIR);
+       case HAMMER_OBJTYPE_REGFILE:
+               return(DT_REG);
+       case HAMMER_OBJTYPE_DBFILE:
+               return(DT_DBF);
+       case HAMMER_OBJTYPE_FIFO:
+               return(DT_FIFO);
+       case HAMMER_OBJTYPE_SOCKET:
+               return(DT_SOCK);
+       case HAMMER_OBJTYPE_CDEV:
+               return(DT_CHR);
+       case HAMMER_OBJTYPE_BDEV:
+               return(DT_BLK);
+       case HAMMER_OBJTYPE_SOFTLINK:
+               return(DT_LNK);
+       default:
+               return(DT_UNKNOWN);
+       }
+       /* not reached */
+}
+
+static int
+hammer_get_mode(u_int8_t obj_type)
+{
+       switch(obj_type) {
+       case HAMMER_OBJTYPE_DIRECTORY:
+               return(S_IFDIR);
+       case HAMMER_OBJTYPE_REGFILE:
+               return(S_IFREG);
+       case HAMMER_OBJTYPE_DBFILE:
+               return(S_IFDB);
+       case HAMMER_OBJTYPE_FIFO:
+               return(S_IFIFO);
+       case HAMMER_OBJTYPE_SOCKET:
+               return(S_IFSOCK);
+       case HAMMER_OBJTYPE_CDEV:
+               return(S_IFCHR);
+       case HAMMER_OBJTYPE_BDEV:
+               return(S_IFBLK);
+       case HAMMER_OBJTYPE_SOFTLINK:
+               return(S_IFLNK);
+       default:
+               return(0);
+       }
+       /* not reached */
+}
+
+static void
+hprintb(hammer_base_elm_t e)
+{
+       printf("%d/", e->localization);
+       if (e->obj_id >> 32 != 0)
+               printf("%lx%08lx",
+                      (long)(e->obj_id >> 32),
+                      (long)(e->obj_id & 0xffffffff));
+       else
+               printf("%lx", (long)e->obj_id);
+       printf("/%d/", e->rec_type);
+       if (e->key >> 32 != 0)
+               printf("%lx%08lx",
+                      (long)(e->key >> 32),
+                      (long)(e->key & 0xffffffff));
+       else
+               printf("%lx", (long)e->key);
+#ifdef TESTING
+       printf("/%llx/%llx", e->create_tid, e->delete_tid);
+#endif
+}
+#endif
+
+static hammer_btree_leaf_elm_t
+hfind(struct hfs *hfs, hammer_base_elm_t key, hammer_base_elm_t end)
+{
+#if DEBUG > 1
+       printf("searching for ");
+       hprintb(key);
+       printf("\n");
+#endif
+
+       int n;
+       int r;
+       struct hammer_base_elm search = *key;
+       struct hammer_base_elm backtrack;
+       hammer_off_t nodeoff = hfs->root;
+       hammer_node_ondisk_t node;
+       hammer_btree_elm_t e;
+
+loop:
+       node = hread(hfs, nodeoff);
+       if (node == NULL)
+               return (NULL);
+
+#if 0
+       for (int i = 0; i < node->count; i++) {
+               printf("E: ");
+               hprintb(&node->elms[i].base);
+               printf("\n");
+       }
+#endif
+
+       n = hammer_btree_search_node(&search, node);
+
+       for (; n < node->count; n++) {
+               e = &node->elms[n];
+               r = hammer_btree_cmp(&search, &e->base);
+
+               if (r < 0)
+                       break;
+       }
+
+       // unless we stopped right on the left side, we need to back off a bit
+       if (n > 0)
+               e = &node->elms[n - 1];
+
+#if DEBUG > 2
+       printf("  found: ");
+       hprintb(&e->base);
+       printf("\n");
+#endif
+
+       if (node->type == HAMMER_BTREE_TYPE_INTERNAL) {
+               nodeoff = e->internal.subtree_offset;
+               backtrack = (e+1)->base;
+               goto loop;
+       }
+
+       r = hammer_btree_cmp(key, &e->base);
+       // If we're more off than the createtid, take the next elem
+       if (r > 1) {
+               e++;
+               n++;
+       }
+
+       // Skip deleted elements
+       while (n < node->count && e->base.delete_tid != 0) {
+               e++;
+               n++;
+       }
+
+       // In the unfortunate event when there is no next
+       // element in this node, we repeat the search with
+       // a key beyond the right boundary
+       if (n == node->count) {
+               search = backtrack;
+               nodeoff = hfs->root;
+
+#if DEBUG > 2
+               printf("hit right boundary (%d), resetting search to ",
+                      node->count);
+               hprintb(&search);
+               printf("\n");
+#endif
+               goto loop;
+       }
+
+#if DEBUG > 1
+       printf("  result: ");
+       hprintb(&e->base);
+       printf("\n");
+#endif
+
+       if (end != NULL)
+               if (hammer_btree_cmp(end, &e->base) < -1)
+                       goto fail;
+
+       return (&e->leaf);
+
+fail:
+#if DEBUG > 1
+       printf("  fail.\n");
+#endif
+       return (NULL);
+}
+
+#ifndef BOOT2
+static int
+hreaddir(struct hfs *hfs, ino_t ino, int64_t *off, struct dirent *de)
+{
+       struct hammer_base_elm key, end;
+
+       bzero(&key, sizeof(key));
+       key.obj_id = ino;
+       key.localization = HAMMER_LOCALIZE_MISC;
+       key.rec_type = HAMMER_RECTYPE_DIRENTRY;
+       key.key = *off;
+
+       end = key;
+       end.key = HAMMER_MAX_KEY;
+
+       hammer_btree_leaf_elm_t e;
+
+       e = hfind(hfs, &key, &end);
+       if (e == NULL) {
+               errno = ENOENT;
+               return (-1);
+       }
+
+       *off = e->base.key + 1;         // remember next pos
+
+       de->d_namlen = e->data_len - HAMMER_ENTRY_NAME_OFF;
+       de->d_type = hammer_get_dtype(e->base.obj_type);
+       hammer_data_ondisk_t ed = hread(hfs, e->data_offset);
+       if (ed == NULL)
+               return (-1);
+       de->d_ino = ed->entry.obj_id;
+       bcopy(ed->entry.name, de->d_name, de->d_namlen);
+       de->d_name[de->d_namlen] = 0;
+
+       return (0);
+}
+#endif
+
+static ino_t
+hresolve(struct hfs *hfs, ino_t dirino, const char *name)
+{
+       struct hammer_base_elm key, end;
+       size_t namel = strlen(name);
+
+       bzero(&key, sizeof(key));
+       key.obj_id = dirino;
+       key.localization = HAMMER_LOCALIZE_MISC;
+       key.key = hammer_directory_namekey(name, namel);
+       key.rec_type = HAMMER_RECTYPE_DIRENTRY;
+       end = key;
+       end.key = HAMMER_MAX_KEY;
+
+       hammer_btree_leaf_elm_t e;
+       while ((e = hfind(hfs, &key, &end)) != NULL) {
+               key.key = e->base.key + 1;
+
+               size_t elen = e->data_len - HAMMER_ENTRY_NAME_OFF;
+               hammer_data_ondisk_t ed = hread(hfs, e->data_offset);
+               if (ed == NULL)
+                       return (-1);
+#ifdef BOOT2
+               if (ls) {
+                       for (int i = 0; i < elen; i++)
+                               putchar(ed->entry.name[i]);
+                       putchar(' ');
+                       ls = 2;
+                       continue;
+               }
+#endif
+               if (elen == namel && memcmp(ed->entry.name, name, MIN(elen, namel)) == 0)
+                       return (ed->entry.obj_id);
+       }
+
+#if BOOT2
+       if (ls == 2)
+               printf("\n");
+#endif
+
+       return -1;
+}
+
+static ino_t
+hlookup(struct hfs *hfs, const char *path)
+{
+#ifdef BOOT2
+       ls = 0;
+#endif
+       ino_t ino = 1;
+       do {
+               char name[MAXPATHLEN + 1];
+               while (*path == '/')
+                       path++;
+               for (char *n = name; *path != 0 && *path != '/'; path++, n++) {
+                       n[0] = *path;
+                       n[1] = 0;
+               }
+
+#ifdef BOOT2
+               // A single ? means "list"
+               if (name[0] == '?' && name[1] == 0)
+                       ls = 1;
+#endif
+
+               ino = hresolve(hfs, ino, name);
+       } while (ino != (ino_t)-1 && *path != 0);
+
+       return (ino);
+}
+
+
+#ifndef BOOT2
+static int
+hstat(struct hfs *hfs, ino_t ino, struct stat* st)
+{
+       struct hammer_base_elm key;
+
+       bzero(&key, sizeof(key));
+       key.obj_id = ino;
+       key.localization = HAMMER_LOCALIZE_INODE;
+       key.rec_type = HAMMER_RECTYPE_INODE;
+
+       hammer_btree_leaf_elm_t e = hfind(hfs, &key, &key);
+       if (e == NULL) {
+#ifndef BOOT2
+               errno = ENOENT;
+#endif
+               return -1;
+       }
+
+       hammer_data_ondisk_t ed = hread(hfs, e->data_offset);
+       if (ed == NULL)
+               return (-1);
+
+       st->st_mode = ed->inode.mode | hammer_get_mode(ed->inode.obj_type);
+       st->st_uid = hammer_to_unix_xid(&ed->inode.uid);
+       st->st_gid = hammer_to_unix_xid(&ed->inode.gid);
+       st->st_size = ed->inode.size;
+
+       return (0);
+}
+#endif
+
+static ssize_t
+hreadf(struct hfs *hfs, ino_t ino, int64_t off, int64_t len, char *buf)
+{
+       int64_t startoff = off;
+       struct hammer_base_elm key, end;
+
+       bzero(&key, sizeof(key));
+       key.obj_id = ino;
+       key.localization = HAMMER_LOCALIZE_MISC;
+       key.rec_type = HAMMER_RECTYPE_DATA;
+       end = key;
+       end.key = HAMMER_MAX_KEY;
+
+       while (len > 0) {
+               key.key = off + 1;
+               hammer_btree_leaf_elm_t e = hfind(hfs, &key, &end);
+               int64_t dlen;
+
+               if (e == NULL || off > e->base.key) {
+                       bzero(buf, len);
+                       off += len;
+                       len = 0;
+                       break;
+               }
+
+               int64_t doff = e->base.key - e->data_len;
+               if (off < doff) {
+                       // sparse file, beginning
+                       dlen = doff - off;
+                       dlen = MIN(dlen, len);
+                       bzero(buf, dlen);
+               } else {
+                       int64_t boff = off - doff;
+                       hammer_off_t roff = e->data_offset;
+
+                       dlen = e->data_len;
+                       dlen -= boff;
+                       dlen = MIN(dlen, len);
+
+                       while (boff >= HAMMER_BUFSIZE) {
+                               boff -= HAMMER_BUFSIZE;
+                               roff += HAMMER_BUFSIZE;
+                       }
+
+                       // cut to HAMMER_BUFSIZE
+                       if ((roff & ~HAMMER_BUFMASK) != ((roff + dlen - 1) & ~HAMMER_BUFMASK))
+                               dlen = HAMMER_BUFSIZE - ((boff + roff) & HAMMER_BUFMASK);
+
+                       char *data = hread(hfs, roff);
+                       if (data == NULL)
+                               return (-1);
+                       bcopy(data + boff, buf, dlen);
+               }
+
+               buf += dlen;
+               off += dlen;
+               len -= dlen;
+       }
+
+       return (off - startoff);
+}
+
+#ifdef BOOT2
+struct hfs hfs;
+
+static int
+hammerinit(void)
+{
+       if (dsk_meta)
+               return (0);
+
+       hammer_volume_ondisk_t volhead = hread(&hfs, HAMMER_ZONE_ENCODE(1, 0));
+       if (volhead == NULL)
+               return (-1);
+       if (volhead->vol_signature != HAMMER_FSBUF_VOLUME)
+               return (-1);
+       hfs.root = volhead->vol0_btree_root;
+       hfs.buf_beg = volhead->vol_buf_beg;
+       dsk_meta++;
+       return (0);
+}
+
+static ino_t
+lookup(const char *path)
+{
+       hammerinit();
+
+       ino_t ino = hlookup(&hfs, path);
+
+       if (ino == -1)
+               ino = 0;
+       return (ino);
+}
+
+static ssize_t
+fsread(ino_t ino, void *buf, size_t len)
+{
+       hammerinit();
+
+       ssize_t rlen = hreadf(&hfs, ino, fs_off, len, buf);
+       if (rlen != -1)
+               fs_off += rlen;
+       return (rlen);
+}
+#endif
+
+#ifndef BOOT2
+static int
+hinit(struct hfs *hfs)
+{
+#if DEBUG
+       printf("hinit\n");
+#endif
+       for (int i = 0; i < NUMCACHE; i++) {
+               hfs->cache[i].data = malloc(HAMMER_BUFSIZE);
+               hfs->cache[i].off = -1; // invalid
+               hfs->cache[i].use = 0;
+
+#if DEBUG
+               if (hfs->cache[i].data == NULL)
+                       printf("malloc failed\n");
+#endif
+       }
+       hfs->lru = 0;
+
+       hammer_volume_ondisk_t volhead = hread(hfs, HAMMER_ZONE_ENCODE(1, 0));
+       if (volhead == NULL)
+               return (-1);
+
+#ifdef TESTING
+       printf("signature: %svalid\n",
+              volhead->vol_signature != HAMMER_FSBUF_VOLUME ?
+                       "in" :
+                       "");
+       printf("name: %s\n", volhead->vol_name);
+#endif
+
+       if (volhead->vol_signature != HAMMER_FSBUF_VOLUME) {
+               for (int i = 0; i < NUMCACHE; i++)
+                       free(hfs->cache[i].data);
+               errno = ENODEV;
+               return (-1);
+       }
+
+       hfs->root = volhead->vol0_btree_root;
+       hfs->buf_beg = volhead->vol_buf_beg;
+
+       return (0);
+}
+
+static void
+hclose(struct hfs *hfs)
+{
+#if DEBUG
+       printf("hclose\n");
+#endif
+       for (int i = 0; i < NUMCACHE; i++)
+               free(hfs->cache[i].data);
+}
+#endif
+
+#ifdef LIBSTAND
+struct hfile {
+       struct hfs      hfs;
+       ino_t           ino;
+       int64_t         fsize;
+};
+
+static int
+hammer_open(const char *path, struct open_file *f)
+{
+       struct hfile *hf = malloc(sizeof(*hf));
+       bzero(hf, sizeof(*hf));
+
+       f->f_fsdata = hf;
+       hf->hfs.f = f;
+       f->f_offset = 0;
+
+       int rv = hinit(&hf->hfs);
+       if (rv) {
+               free(hf);
+               return (rv);
+       }
+
+#if DEBUG
+       printf("hammer_open %s %p %ld\n", path, f);
+#endif
+
+       hf->ino = hlookup(&hf->hfs, path);
+       if (hf->ino == -1)
+               goto fail;
+
+       struct stat st;
+       if (hstat(&hf->hfs, hf->ino, &st) == -1)
+               goto fail;
+       hf->fsize = st.st_size;
+
+#if DEBUG
+       printf("        %ld\n", (long)hf->fsize);
+#endif
+
+       return (0);
+
+fail:
+#if DEBUG
+       printf("hammer_open fail\n");
+#endif
+       hclose(&hf->hfs);
+       free(hf);
+       return (ENOENT);
+}
+
+static int
+hammer_close(struct open_file *f)
+{
+       struct hfile *hf = f->f_fsdata;
+
+       hclose(&hf->hfs);
+       f->f_fsdata = NULL;
+       free(hf);
+       return (0);
+}
+
+static int
+hammer_read(struct open_file *f, void *buf, size_t len, size_t *resid)
+{
+       struct hfile *hf = f->f_fsdata;
+
+#if DEBUG
+       printf("hammer_read %p %ld %ld\n", f, f->f_offset, len);
+#endif
+
+       if (f->f_offset >= hf->fsize)
+               return (EINVAL);
+
+       size_t maxlen = len;
+       if (f->f_offset + len > hf->fsize)
+               maxlen = hf->fsize - f->f_offset;
+
+       ssize_t rlen = hreadf(&hf->hfs, hf->ino, f->f_offset, maxlen, buf);
+       if (rlen == -1)
+               return (EINVAL);
+
+       f->f_offset += rlen;
+
+       *resid = len - rlen;
+       return (0);
+}
+
+static off_t
+hammer_seek(struct open_file *f, off_t offset, int whence)
+{
+       struct hfile *hf = f->f_fsdata;
+
+       switch (whence) {
+       case SEEK_SET:
+               f->f_offset = offset;
+               break;
+       case SEEK_CUR:
+               f->f_offset += offset;
+               break;
+       case SEEK_END:
+               f->f_offset = hf->fsize - offset;
+               break;
+       default:
+               return (-1);
+       }
+       return (f->f_offset);
+}
+
+static int
+hammer_stat(struct open_file *f, struct stat *st)
+{
+       struct hfile *hf = f->f_fsdata;
+
+       return (hstat(&hf->hfs, hf->ino, st));
+}
+
+static int
+hammer_readdir(struct open_file *f, struct dirent *d)
+{
+       struct hfile *hf = f->f_fsdata;
+
+       int64_t off = f->f_offset;
+       int rv = hreaddir(&hf->hfs, hf->ino, &off, d);
+       f->f_offset = off;
+       return (rv);
+}
+
+// libstand
+struct fs_ops hammer_fsops = {
+       "hammer",
+       hammer_open,
+       hammer_close,
+       hammer_read,
+       null_write,
+       hammer_seek,
+       hammer_stat,
+       hammer_readdir
+};
+#endif // LIBSTAND
+
+#ifdef TESTING
+int
+main(int argc, char **argv)
+{
+       if (argc < 2) {
+               fprintf(stderr, "usage: hammerread <dev>\n");
+               return (1);
+       }
+
+       struct hfs hfs;
+       hfs.fd = open(argv[1], O_RDONLY);
+       if (hfs.fd == -1)
+               err(1, "unable to open %s", argv[1]);
+
+       if (hinit(&hfs) == -1)
+               err(1, "invalid hammerfs");
+
+       for (int i = 2; i < argc; i++) {
+               ino_t ino = hlookup(&hfs, argv[i]);
+               if (ino == (ino_t)-1) {
+                       warn("hlookup %s", argv[i]);
+                       continue;
+               }
+
+               struct stat st;
+               if (hstat(&hfs, ino, &st)) {
+                       warn("hstat %s", argv[i]);
+                       continue;
+               }
+
+               printf("%s %d/%d %o %lld\n",
+                      argv[i],
+                      st.st_uid, st.st_gid,
+                      st.st_mode, st.st_size);
+
+               if (S_ISDIR(st.st_mode)) {
+                       int64_t off = 0;
+                       struct dirent de;
+                       while (hreaddir(&hfs, ino, &off, &de) == 0) {
+                               printf("%s %d %llx\n",
+                                      de.d_name, de.d_type, de.d_ino);
+                       }
+               } else if (S_ISREG(st.st_mode)) {
+                       char *buf = malloc(100000);
+                       int64_t off = 0;
+                       while (off < st.st_size) {
+                               int64_t len = MIN(100000, st.st_size - off);
+                               int64_t rl = hreadf(&hfs, ino, off, len, buf);
+                               fwrite(buf, rl, 1, stdout);
+                               off += rl;
+                       }
+                       free(buf);
+               }
+       }
+
+       return 0;
+}
+#endif
index 1594d8b..17a3b96 100644 (file)
@@ -24,7 +24,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/lib/libstand/stand.h,v 1.18.2.8 2002/06/17 11:22:39 sobomax Exp $
- * $DragonFly: src/lib/libstand/stand.h,v 1.10 2008/06/05 18:01:49 swildner Exp $
+ * $DragonFly: src/lib/libstand/stand.h,v 1.11 2008/09/13 11:38:58 corecode Exp $
  * From        $NetBSD: stand.h,v 1.22 1997/06/26 19:17:40 drochner Exp $      
  */
 
@@ -118,6 +118,7 @@ struct fs_ops {
  * libstand-supplied filesystems
  */
 extern struct fs_ops ufs_fsops;
+extern struct fs_ops hammer_fsops;
 extern struct fs_ops tftp_fsops;
 extern struct fs_ops nfs_fsops;
 extern struct fs_ops cd9660_fsops;