[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [PATCH 1/2] introduce libfsimage for reading filesystem images



# HG changeset patch
# User john.levon@xxxxxxx
# Date 1162945967 28800
# Node ID f93406ba0c73b3193e216fec7fcd876ef0f081f0
# Parent  d27d399bb3882320345e403cfb221dcf7681146b
Add libfsimage, a C library for reading files from filesystem images. Initial
support is provided for Solaris UFS, ext2 (both using libext2fs and not), and
reiserfs.

Signed-off-by: John Levon <john.levon@xxxxxxx>

diff --git a/tools/Makefile b/tools/Makefile
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -18,6 +18,7 @@ SUBDIRS-y += xenstat
 SUBDIRS-y += xenstat
 SUBDIRS-$(CONFIG_Linux) += libaio
 SUBDIRS-$(CONFIG_Linux) += blktap
+SUBDIRS-y += libfsimage
 
 # These don't cross-compile
 ifeq ($(XEN_COMPILE_ARCH),$(XEN_TARGET_ARCH))
diff --git a/tools/libfsimage/Makefile b/tools/libfsimage/Makefile
new file mode 100644
--- /dev/null
+++ b/tools/libfsimage/Makefile
@@ -0,0 +1,13 @@
+XEN_ROOT = ../..
+include $(XEN_ROOT)/tools/Rules.mk
+
+SUBDIRS-y = common ufs reiserfs
+SUBDIRS-y += $(shell ./check-libext2fs)
+
+.PHONY: all
+all install clean:
+       @set -e; for subdir in $(SUBDIRS-y); do \
+               $(MAKE) -C $$subdir $@; \
+       done
+
+distclean: clean
diff --git a/tools/libfsimage/Rules.mk b/tools/libfsimage/Rules.mk
new file mode 100644
--- /dev/null
+++ b/tools/libfsimage/Rules.mk
@@ -0,0 +1,32 @@
+include $(XEN_ROOT)/tools/Rules.mk
+
+DEPS = .*.d
+
+CFLAGS += -I$(XEN_ROOT)/tools/libfsimage/common/ -Werror -D_LARGEFILE_SOURCE 
-D_FILE_OFFSET_BITS=64 -Wp,-MD,.$(@F).d
+LDFLAGS += -L../common/
+
+PIC_OBJS := $(patsubst %.c,%.opic,$(LIB_SRCS-y))
+
+FSDIR-$(CONFIG_Linux) = $(LIBDIR)/fs/$(FS)
+FSDIR-$(CONFIG_SunOS)-x86_64 = lib/fs/$(FS)/64
+FSDIR-$(CONFIG_SunOS)-x86_32 = lib/fs/$(FS)/
+FSDIR-$(CONFIG_SunOS) = $(FSDIR-$(CONFIG_SunOS)-$(XEN_TARGET_ARCH))
+FSDIR = $(FSDIR-y)
+
+FSLIB = fsimage.so
+
+.PHONY: fs-all
+fs-all: $(FSLIB)
+
+.PHONY: fs-install
+fs-install: fs-all
+       $(INSTALL_DIR) $(DESTDIR)/usr/$(FSDIR)
+       $(INSTALL_PROG) $(FSLIB) $(DESTDIR)/usr/$(FSDIR)
+
+$(FSLIB): $(PIC_OBJS)
+       $(CC) $(CFLAGS) $(LDFLAGS) $(SHLIB_CFLAGS) -o $@ $^ -lfsimage 
$(FS_LIBDEPS)
+
+clean distclean:
+       rm -f $(PIC_OBJS) $(FSLIB)
+
+-include $(DEPS)
diff --git a/tools/libfsimage/check-libext2fs b/tools/libfsimage/check-libext2fs
new file mode 100755
--- /dev/null
+++ b/tools/libfsimage/check-libext2fs
@@ -0,0 +1,21 @@
+#!/bin/bash
+
+cat >ext2-test.c <<EOF
+#include <ext2fs/ext2fs.h>
+
+int main()
+{
+       ext2fs_open2;
+}
+EOF
+
+gcc -o ext2-test ext2-test.c -lext2fs >/dev/null 2>&1
+if [ $? = 0 ]; then
+       echo ext2fs-lib
+else
+       echo ext2fs
+fi
+
+rm -f ext2-test ext2-test.c
+
+exit 0
diff --git a/tools/libfsimage/common/Makefile b/tools/libfsimage/common/Makefile
new file mode 100644
--- /dev/null
+++ b/tools/libfsimage/common/Makefile
@@ -0,0 +1,46 @@
+XEN_ROOT = ../../..
+include $(XEN_ROOT)/tools/Rules.mk
+
+MAJOR = 1.0
+MINOR = 0
+
+CFLAGS += -Werror -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -Wp,-MD,.$(@F).d
+DEPS = .*.d
+
+LDFLAGS-$(CONFIG_SunOS) = -Wl,-M -Wl,mapfile-SunOS
+LDFLAGS-$(CONFIG_Linux) = -Wl,mapfile-GNU
+LDFLAGS = $(LDFLAGS-y)
+
+LIB_SRCS-y = fsimage.c fsimage_plugin.c fsimage_grub.c
+
+PIC_OBJS := $(patsubst %.c,%.opic,$(LIB_SRCS-y))
+
+LIB = libfsimage.so libfsimage.so.$(MAJOR) libfsimage.so.$(MAJOR).$(MINOR)
+
+.PHONY: all
+all: $(LIB)
+
+.PHONY: install
+install: all
+       [ -d $(DESTDIR)/usr/$(LIBDIR) ] || $(INSTALL_DIR) 
$(DESTDIR)/usr/$(LIBDIR)
+       [ -d $(DESTDIR)/usr/include ] || $(INSTALL_DIR) $(DESTDIR)/usr/include
+       $(INSTALL_PROG) libfsimage.so.$(MAJOR).$(MINOR) $(DESTDIR)/usr/$(LIBDIR)
+       ln -sf libfsimage.so.$(MAJOR).$(MINOR) 
$(DESTDIR)/usr/$(LIBDIR)/libfsimage.so.$(MAJOR)
+       ln -sf libfsimage.so.$(MAJOR) $(DESTDIR)/usr/$(LIBDIR)/libfsimage.so
+       $(INSTALL_DATA) fsimage.h $(DESTDIR)/usr/include
+       $(INSTALL_DATA) fsimage_plugin.h $(DESTDIR)/usr/include
+       $(INSTALL_DATA) fsimage_grub.h $(DESTDIR)/usr/include
+
+clean distclean:
+       rm -f $(PIC_OBJS) $(LIB)
+
+libfsimage.so: libfsimage.so.$(MAJOR)
+       ln -sf $< $@
+libfsimage.so.$(MAJOR): libfsimage.so.$(MAJOR).$(MINOR)
+       ln -sf $< $@
+
+libfsimage.so.$(MAJOR).$(MINOR): $(PIC_OBJS)
+       $(CC) $(CFLAGS) $(LDFLAGS) -Wl,$(SONAME_LDFLAG) 
-Wl,libfsimage.so.$(MAJOR) $(SHLIB_CFLAGS) -o $@ $^ -lpthread
+
+-include $(DEPS)
+
diff --git a/tools/libfsimage/common/fsimage.c 
b/tools/libfsimage/common/fsimage.c
new file mode 100644
--- /dev/null
+++ b/tools/libfsimage/common/fsimage.c
@@ -0,0 +1,140 @@
+/*
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <strings.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <pthread.h>
+
+#include "fsimage_plugin.h"
+#include "fsimage_priv.h"
+
+static pthread_mutex_t fsi_lock = PTHREAD_MUTEX_INITIALIZER;
+
+fsi_t *fsi_open_fsimage(const char *path, uint64_t off)
+{
+       fsi_t *fsi = NULL;
+       int fd;
+       int err;
+
+       if ((fd = open(path, O_RDONLY)) == -1)
+               goto fail;
+
+       if ((fsi = malloc(sizeof(*fsi))) == NULL)
+               goto fail;
+
+       fsi->f_fd = fd;
+       fsi->f_off = off;
+       fsi->f_data = NULL;
+
+       pthread_mutex_lock(&fsi_lock);
+       err = find_plugin(fsi, path);
+       pthread_mutex_unlock(&fsi_lock);
+       if (err != 0)
+               goto fail;
+
+       return (fsi);
+
+fail:
+       err = errno;
+       if (fd != -1)
+               (void) close(fd);
+       free(fsi);
+       errno = err;
+       return (NULL);
+}
+
+void fsi_close_fsimage(fsi_t *fsi)
+{
+       pthread_mutex_lock(&fsi_lock);
+       fsip_fs_free(fsi);
+       pthread_mutex_unlock(&fsi_lock);
+}
+
+int fsi_file_exists(fsi_t *fsi, const char *path)
+{
+       fsi_file_t *ffi;
+
+       if ((ffi = fsi_open_file(fsi, path)) == NULL)
+               return (0);
+
+       fsi_close_file(ffi);
+       return (1);
+}
+
+fsi_file_t *fsi_open_file(fsi_t *fsi, const char *path)
+{
+       fsi_plugin_ops_t *ops;
+       fsi_file_t *ffi;
+
+       pthread_mutex_lock(&fsi_lock);
+       ops = fsi->f_plugin->fp_ops;
+       ffi = ops->fpo_open(fsi, path);
+       pthread_mutex_unlock(&fsi_lock);
+
+       return (ffi);
+}
+
+int fsi_close_file(fsi_file_t *ffi)
+{
+       fsi_plugin_ops_t *ops;
+       int err;
+ 
+       pthread_mutex_lock(&fsi_lock);
+       ops = ffi->ff_fsi->f_plugin->fp_ops;
+       err = ops->fpo_close(ffi);
+       pthread_mutex_unlock(&fsi_lock);
+
+       return (err);
+}
+
+ssize_t fsi_read_file(fsi_file_t *ffi, void *buf, size_t nbytes)
+{
+       fsi_plugin_ops_t *ops;
+       ssize_t ret;
+ 
+       pthread_mutex_lock(&fsi_lock);
+       ops = ffi->ff_fsi->f_plugin->fp_ops;
+       ret = ops->fpo_read(ffi, buf, nbytes);
+       pthread_mutex_unlock(&fsi_lock);
+
+       return (ret);
+}
+
+ssize_t fsi_pread_file(fsi_file_t *ffi, void *buf, size_t nbytes, uint64_t off)
+{
+       fsi_plugin_ops_t *ops;
+       ssize_t ret;
+ 
+       pthread_mutex_lock(&fsi_lock);
+       ops = ffi->ff_fsi->f_plugin->fp_ops;
+       ret = ops->fpo_pread(ffi, buf, nbytes, off);
+       pthread_mutex_unlock(&fsi_lock);
+
+       return (ret);
+}
diff --git a/tools/libfsimage/common/fsimage.h 
b/tools/libfsimage/common/fsimage.h
new file mode 100644
--- /dev/null
+++ b/tools/libfsimage/common/fsimage.h
@@ -0,0 +1,52 @@
+/*
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _FSIMAGE_H
+#define        _FSIMAGE_H
+
+#ifdef __cplusplus
+extern C {
+#endif
+
+#include <sys/types.h>
+#include <stdint.h>
+#include <unistd.h>
+
+typedef struct fsi fsi_t;
+typedef struct fsi_file fsi_file_t;
+
+fsi_t *fsi_open_fsimage(const char *, uint64_t);
+void fsi_close_fsimage(fsi_t *);
+
+int fsi_file_exists(fsi_t *, const char *);
+fsi_file_t *fsi_open_file(fsi_t *, const char *);
+int fsi_close_file(fsi_file_t *);
+
+ssize_t fsi_read_file(fsi_file_t *, void *, size_t);
+ssize_t fsi_pread_file(fsi_file_t *, void *, size_t, uint64_t);
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif /* _FSIMAGE_H */
diff --git a/tools/libfsimage/common/fsimage_grub.c 
b/tools/libfsimage/common/fsimage_grub.c
new file mode 100644
--- /dev/null
+++ b/tools/libfsimage/common/fsimage_grub.c
@@ -0,0 +1,277 @@
+/*
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef __sun__
+#define        _XOPEN_SOURCE 500
+#endif
+#include <stdlib.h>
+#include <strings.h>
+#include <errno.h>
+
+#include "fsimage_grub.h"
+#include "fsimage_priv.h"
+
+static char *disk_read_junk;
+
+typedef struct fsig_data {
+       char fd_buf[FSYS_BUFLEN];
+} fsig_data_t;
+
+typedef struct fsig_file_data {
+       char ffd_buf[FSYS_BUFLEN];
+       uint64_t ffd_curpos;
+       uint64_t ffd_filepos;
+       uint64_t ffd_filemax;
+       int ffd_int1;
+       int ffd_int2;
+       int ffd_errnum;
+} fsig_file_data_t;
+
+fsi_file_t *
+fsig_file_alloc(fsi_t *fsi)
+{
+       fsi_file_t *ffi;
+       fsig_file_data_t *data = malloc(sizeof (fsig_file_data_t));
+
+       if (data == NULL)
+               return (NULL);
+
+       bzero(data, sizeof (fsig_file_data_t));
+       bcopy(fsig_fs_buf(fsi), data->ffd_buf, FSYS_BUFLEN);
+
+       if ((ffi = fsip_file_alloc(fsi, data)) == NULL) {
+               free(data);
+               return (NULL);
+       }
+
+       return (ffi);
+}
+
+void *
+fsig_fs_buf(fsi_t *fsi)
+{
+       fsig_data_t *data = fsip_fs_data(fsi);
+       return ((void *)data->fd_buf);
+}
+
+void *
+fsig_file_buf(fsi_file_t *ffi)
+{
+       fsig_file_data_t *data = fsip_file_data(ffi);
+       return ((void *)data->ffd_buf);
+}
+
+uint64_t *
+fsig_filepos(fsi_file_t *ffi)
+{
+       fsig_file_data_t *data = fsip_file_data(ffi);
+       return (&data->ffd_filepos);
+}
+
+uint64_t *
+fsig_filemax(fsi_file_t *ffi)
+{
+       fsig_file_data_t *data = fsip_file_data(ffi);
+       return (&data->ffd_filemax);
+}
+
+int *
+fsig_int1(fsi_file_t *ffi)
+{
+       fsig_file_data_t *data = fsip_file_data(ffi);
+       return (&data->ffd_int1);
+}
+
+int *
+fsig_int2(fsi_file_t *ffi)
+{
+       fsig_file_data_t *data = fsip_file_data(ffi);
+       return (&data->ffd_int2);
+}
+
+int *
+fsig_errnum(fsi_file_t *ffi)
+{
+       fsig_file_data_t *data = fsip_file_data(ffi);
+       return (&data->ffd_errnum);
+}
+
+char **
+fsig_disk_read_junk(void)
+{
+       return (&disk_read_junk);
+}
+
+int
+fsig_devread(fsi_file_t *ffi, unsigned int sector, unsigned int offset,
+    unsigned int bufsize, char *buf)
+{
+       uint64_t off = ffi->ff_fsi->f_off + ((uint64_t)(sector * 512)) + offset;
+       ssize_t bytes_read = 0;
+
+       while (bufsize) {
+               ssize_t ret = pread(ffi->ff_fsi->f_fd, buf + bytes_read,
+                   bufsize, (off_t)off);
+               if (ret == -1)
+                       return (0);
+               if (ret == 0)
+                       return (0);
+
+               bytes_read += ret;
+               bufsize -= ret;
+       }
+
+       return (1);
+}
+
+int
+fsig_substring(const char *s1, const char *s2)
+{
+       while (*s1 == *s2) {
+               if (*s1 == '\0')
+                       return (0);
+               s1++;
+               s2++;
+       }
+
+       if (*s1 == '\0')
+               return (-1);
+
+       return (1);
+}
+
+static int
+fsig_mount(fsi_t *fsi, const char *path)
+{
+       fsig_plugin_ops_t *ops = fsi->f_plugin->fp_data;
+       fsi_file_t *ffi;
+       fsi->f_data = malloc(sizeof (fsig_data_t));
+
+       if (fsi->f_data == NULL)
+               return (-1);
+
+       if ((ffi = fsig_file_alloc(fsi)) == NULL) {
+               free(fsi->f_data);
+               fsi->f_data = NULL;
+               return (-1);
+       }
+
+       bzero(fsi->f_data, sizeof (fsig_data_t));
+
+       if (!ops->fpo_mount(ffi)) {
+               fsip_file_free(ffi);
+               free(fsi->f_data);
+               fsi->f_data = NULL;
+               return (-1);
+       }
+
+       bcopy(fsig_file_buf(ffi), fsig_fs_buf(fsi), FSYS_BUFLEN);
+       fsip_file_free(ffi);
+       return (0);
+}
+
+static int
+fsig_umount(fsi_t *fsi)
+{
+       fsip_fs_free(fsi);
+       return (0);
+}
+
+static fsi_file_t *
+fsig_open(fsi_t *fsi, const char *name)
+{
+       fsig_plugin_ops_t *ops = fsi->f_plugin->fp_data;
+       char *path = strdup(name);
+       fsi_file_t *ffi = NULL;
+
+       if (path == NULL || (ffi = fsig_file_alloc(fsi)) == NULL)
+               goto out;
+
+       if (ops->fpo_dir(ffi, path) == 0) {
+               fsip_file_free(ffi);
+               ffi = NULL;
+               errno = ENOENT;
+       }
+
+out:
+       free(path);
+       return (ffi);
+}
+
+static ssize_t
+fsig_pread(fsi_file_t *ffi, void *buf, size_t nbytes, uint64_t off)
+{
+       fsig_plugin_ops_t *ops = ffi->ff_fsi->f_plugin->fp_data;
+       fsig_file_data_t *data = fsip_file_data(ffi);
+
+       data->ffd_filepos = off;
+
+       if (data->ffd_filepos >= data->ffd_filemax)
+               return (0);
+
+       /* FIXME: check */
+       if (data->ffd_filepos + nbytes > data->ffd_filemax)
+               nbytes = data->ffd_filemax - data->ffd_filepos;
+
+       errnum = 0;
+       return (ops->fpo_read(ffi, buf, nbytes));
+}
+
+static ssize_t
+fsig_read(fsi_file_t *ffi, void *buf, size_t nbytes)
+{
+       fsig_file_data_t *data = fsip_file_data(ffi);
+       ssize_t ret;
+
+       ret = fsig_pread(ffi, buf, nbytes, data->ffd_curpos);
+       data->ffd_curpos = data->ffd_filepos;
+       return (ret);
+}
+
+static int
+fsig_close(fsi_file_t *ffi)
+{
+       fsip_file_free(ffi);
+       return (0);
+}
+
+static fsi_plugin_ops_t fsig_grub_ops = {
+       .fpo_version = FSIMAGE_PLUGIN_VERSION,
+       .fpo_mount = fsig_mount,
+       .fpo_umount = fsig_umount,
+       .fpo_open = fsig_open,
+       .fpo_read = fsig_read,
+       .fpo_pread = fsig_pread,
+       .fpo_close = fsig_close
+};
+
+fsi_plugin_ops_t *
+fsig_init(fsi_plugin_t *plugin, fsig_plugin_ops_t *ops)
+{
+       if (ops->fpo_version > FSIMAGE_PLUGIN_VERSION)
+               return (NULL);
+
+       plugin->fp_data = ops;
+
+       return (&fsig_grub_ops);
+}
diff --git a/tools/libfsimage/common/fsimage_grub.h 
b/tools/libfsimage/common/fsimage_grub.h
new file mode 100644
--- /dev/null
+++ b/tools/libfsimage/common/fsimage_grub.h
@@ -0,0 +1,92 @@
+/*
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _FSIMAGE_GRUB_H
+#define        _FSIMAGE_GRUB_H
+
+#ifdef __cplusplus
+extern C {
+#endif
+
+#include <sys/types.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#include "fsimage.h"
+#include "fsimage_plugin.h"
+
+typedef struct fsig_plugin_ops {
+       int fpo_version;
+       int (*fpo_mount)(fsi_file_t *);
+       int (*fpo_dir)(fsi_file_t *, char *);
+       int (*fpo_read)(fsi_file_t *, char *, int);
+} fsig_plugin_ops_t;
+
+#define        STAGE1_5
+#define FSYS_BUFLEN 0x8000
+#define        SECTOR_BITS 9
+#define        SECTOR_SIZE 0x200
+
+#define        FSYS_BUF (fsig_file_buf(ffi))
+#define        filepos (*fsig_filepos(ffi))
+#define        filemax (*fsig_filemax(ffi))
+#define        devread fsig_devread
+#define substring fsig_substring
+#define        errnum (*fsig_errnum(ffi))
+#define        disk_read_func (*fsig_disk_read_junk())
+#define        disk_read_hook (*fsig_disk_read_junk())
+#define        print_possibilities 0
+
+#define        grub_memset memset
+#define        grub_memmove memmove
+
+extern char **fsig_disk_read_junk(void);
+
+#define        ERR_FSYS_CORRUPT 1
+#define        ERR_SYMLINK_LOOP 1
+#define        ERR_FILELENGTH 1
+#define        ERR_BAD_FILETYPE 1
+#define        ERR_BAD_FILETYPE 1
+#define        ERR_FILE_NOT_FOUND 1
+
+fsi_plugin_ops_t *fsig_init(fsi_plugin_t *, fsig_plugin_ops_t *);
+
+int fsig_devread(fsi_file_t *, unsigned int, unsigned int, unsigned int, char 
*);
+int fsig_substring(const char *, const char *);
+
+void *fsig_fs_buf(fsi_t *);
+
+fsi_file_t *fsig_file_alloc(fsi_t *);
+void *fsig_file_buf(fsi_file_t *);
+uint64_t *fsig_filepos(fsi_file_t *);
+uint64_t *fsig_filemax(fsi_file_t *);
+int *fsig_int1(fsi_file_t *);
+int *fsig_int2(fsi_file_t *);
+int *fsig_errnum(fsi_file_t *);
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif /* _FSIMAGE_GRUB_H */
diff --git a/tools/libfsimage/common/fsimage_plugin.c 
b/tools/libfsimage/common/fsimage_plugin.c
new file mode 100644
--- /dev/null
+++ b/tools/libfsimage/common/fsimage_plugin.c
@@ -0,0 +1,214 @@
+/*
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <strings.h>
+#include <string.h>
+#include <dirent.h>
+#include <dlfcn.h>
+#include <errno.h>
+
+#include "fsimage_plugin.h"
+#include "fsimage_priv.h"
+
+static fsi_plugin_t *plugins;
+
+void
+fsip_fs_set_data(fsi_t *fsi, void *data)
+{
+       fsi->f_data = data;
+}
+
+void
+fsip_fs_free(fsi_t *fsi)
+{
+       free(fsi->f_data);
+       free(fsi);
+}
+
+fsi_file_t *
+fsip_file_alloc(fsi_t *fsi, void *data)
+{
+       fsi_file_t *ffi = malloc(sizeof (fsi_file_t));
+       if (ffi == NULL)
+               return (NULL);
+
+       bzero(ffi, sizeof (fsi_file_t));
+
+       ffi->ff_fsi = fsi;
+       ffi->ff_data = data;
+       return (ffi);
+}
+
+void
+fsip_file_free(fsi_file_t *ffi)
+{
+       free(ffi->ff_data);
+       free(ffi);
+}
+
+fsi_t *
+fsip_fs(fsi_file_t *ffi)
+{
+       return (ffi->ff_fsi);
+}
+
+uint64_t
+fsip_fs_offset(fsi_t *fsi)
+{
+       return (fsi->f_off);
+}
+
+void *
+fsip_fs_data(fsi_t *fsi)
+{
+       return (fsi->f_data);
+}
+
+void *
+fsip_file_data(fsi_file_t *ffi)
+{
+       return (ffi->ff_data);
+}
+
+static int init_plugin(const char *lib)
+{
+       fsi_plugin_init_t init;
+       fsi_plugin_t *fp = malloc(sizeof (fsi_plugin_t));
+
+       if (fp == NULL)
+               return (-1);
+
+       bzero(fp, sizeof (fsi_plugin_t));
+
+       if ((fp->fp_dlh = dlopen(lib, RTLD_LAZY | RTLD_LOCAL)) == NULL) {
+               free(fp);
+               return (0);
+       }
+
+       init = dlsym(fp->fp_dlh, "fsi_init_plugin");
+
+       if (init == NULL)
+               goto fail;
+
+       fp->fp_ops = init(FSIMAGE_PLUGIN_VERSION, fp, &fp->fp_name);
+       if (fp->fp_ops == NULL ||
+           fp->fp_ops->fpo_version > FSIMAGE_PLUGIN_VERSION)
+               goto fail;
+
+       fp->fp_next = plugins;
+       plugins = fp;
+
+       return (0);
+fail:
+       (void) dlclose(fp->fp_dlh);
+       free(fp);
+       return (-1);
+}
+
+static int load_plugins(void)
+{
+       const char *fsdir = getenv("FSIMAGE_FSDIR");
+       const char *isadir = "";
+       struct dirent *dp = NULL;
+       struct dirent *dpp;
+       DIR *dir = NULL;
+       char *tmp = NULL;
+       size_t name_max;
+       int err;
+       int ret = -1;
+
+#ifdef __sun__
+       if (fsdir == NULL)
+               fsdir = "/usr/lib/fs";
+
+       if (sizeof(void *) == 8)
+               isadir = "64/";
+#else
+       if (fsdir == NULL) {
+               if (sizeof(void *) == 8)
+                       fsdir = "/usr/lib64/fs";
+               else
+                       fsdir = "/usr/lib/fs";
+       }
+#endif
+
+       if ((name_max = pathconf(fsdir, _PC_NAME_MAX)) == -1)
+               goto fail;
+
+       if ((tmp = malloc(name_max + 1)) == NULL)
+               goto fail;
+
+       if ((dp = malloc(sizeof (struct dirent) + name_max + 1)) == NULL)
+               goto fail;
+
+       if ((dir = opendir(fsdir)) == NULL)
+               goto fail;
+
+       bzero(dp, sizeof (struct dirent) + name_max + 1);
+
+       while (readdir_r(dir, dp, &dpp) == 0 && dpp != NULL) {
+               if (strcmp(dpp->d_name, ".") == 0)
+                       continue;
+               if (strcmp(dpp->d_name, "..") == 0)
+                       continue;
+
+               (void) snprintf(tmp, name_max, "%s/%s/%sfsimage.so", fsdir,
+                   dpp->d_name, isadir);
+
+               if (init_plugin(tmp) != 0)
+                       goto fail;
+       }
+
+       ret = 0;
+
+fail:
+       err = errno;
+       if (dir != NULL)
+               (void) closedir(dir);
+       free(tmp);
+       free(dp);
+       errno = err;
+       return (ret);
+}
+
+int find_plugin(fsi_t *fsi, const char *path)
+{
+       fsi_plugin_t *fp;
+       int ret = 0;
+
+       if (plugins == NULL && (ret = load_plugins()) != 0)
+               goto out;
+
+       for (fp = plugins; fp != NULL; fp = fp->fp_next) {
+               fsi->f_plugin = fp;
+               if (fp->fp_ops->fpo_mount(fsi, path) == 0)
+                       goto out;
+       }
+
+       ret = -1;
+       errno = ENOTSUP;
+out:
+       return (ret);
+}
diff --git a/tools/libfsimage/common/fsimage_plugin.h 
b/tools/libfsimage/common/fsimage_plugin.h
new file mode 100644
--- /dev/null
+++ b/tools/libfsimage/common/fsimage_plugin.h
@@ -0,0 +1,65 @@
+/*
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _FSIMAGE_PLUGIN_H
+#define        _FSIMAGE_PLUGIN_H
+
+#ifdef __cplusplus
+extern C {
+#endif
+
+#include <sys/types.h>
+
+#include "fsimage.h"
+
+#define        FSIMAGE_PLUGIN_VERSION 1
+
+typedef struct fsi_plugin fsi_plugin_t;
+
+typedef struct fsi_plugin_ops {
+       int fpo_version;
+       int (*fpo_mount)(fsi_t *, const char *);
+       int (*fpo_umount)(fsi_t *);
+       fsi_file_t *(*fpo_open)(fsi_t *, const char *);
+       ssize_t (*fpo_read)(fsi_file_t *, void *, size_t);
+       ssize_t (*fpo_pread)(fsi_file_t *, void *, size_t, uint64_t);
+       int (*fpo_close)(fsi_file_t *);
+} fsi_plugin_ops_t;
+
+typedef fsi_plugin_ops_t *
+    (*fsi_plugin_init_t)(int, fsi_plugin_t *, const char **);
+
+void fsip_fs_set_data(fsi_t *, void *);
+void fsip_fs_free(fsi_t *);
+fsi_file_t *fsip_file_alloc(fsi_t *, void *);
+void fsip_file_free(fsi_file_t *);
+fsi_t * fsip_fs(fsi_file_t *ffi);
+uint64_t fsip_fs_offset(fsi_t *fsi);
+void *fsip_fs_data(fsi_t *);
+void *fsip_file_data(fsi_file_t *);
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif /* _FSIMAGE_PLUGIN_H */
diff --git a/tools/libfsimage/common/fsimage_priv.h 
b/tools/libfsimage/common/fsimage_priv.h
new file mode 100644
--- /dev/null
+++ b/tools/libfsimage/common/fsimage_priv.h
@@ -0,0 +1,62 @@
+/*
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _FSIMAGE_PRIV_H
+#define        _FSIMAGE_PRIV_H
+
+#ifdef __cplusplus
+extern C {
+#endif
+
+#include <sys/types.h>
+
+#include "fsimage.h"
+#include "fsimage_plugin.h"
+
+struct fsi_plugin {
+       const char *fp_name;
+       void *fp_dlh;
+       fsi_plugin_ops_t *fp_ops;
+       struct fsi_plugin *fp_next;
+       void *fp_data;
+};
+
+struct fsi {
+       int f_fd;
+       uint64_t f_off;
+       void *f_data;
+       fsi_plugin_t *f_plugin;
+};
+
+struct fsi_file {
+       fsi_t *ff_fsi;
+       void *ff_data;
+};
+
+int find_plugin(fsi_t *, const char *);
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif /* _FSIMAGE_PRIV_H */
diff --git a/tools/libfsimage/common/mapfile-GNU 
b/tools/libfsimage/common/mapfile-GNU
new file mode 100644
--- /dev/null
+++ b/tools/libfsimage/common/mapfile-GNU
@@ -0,0 +1,37 @@
+VERSION {
+       libfsimage.so.1.1 {
+               global:
+                       fsi_open_fsimage;
+                       fsi_close_fsimage;
+                       fsi_file_exists;
+                       fsi_open_file;
+                       fsi_close_file;
+                       fsi_read_file;
+                       fsi_pread_file;
+       
+                       fsip_fs_set_data;
+                       fsip_fs_free;
+                       fsip_file_alloc;
+                       fsip_file_free;
+                       fsip_fs;
+                       fsip_fs_offset;
+                       fsip_fs_data;
+                       fsip_file_data;
+       
+                       fsig_init;
+                       fsig_devread;
+                       fsig_substring;
+                       fsig_fs_buf;
+                       fsig_file_alloc;
+                       fsig_file_buf;
+                       fsig_filepos;
+                       fsig_filemax;
+                       fsig_int1;
+                       fsig_int2;
+                       fsig_errnum;
+                       fsig_disk_read_junk;
+       
+               local:
+                       *;
+       };
+}
diff --git a/tools/libfsimage/common/mapfile-SunOS 
b/tools/libfsimage/common/mapfile-SunOS
new file mode 100644
--- /dev/null
+++ b/tools/libfsimage/common/mapfile-SunOS
@@ -0,0 +1,35 @@
+libfsimage.so.1.1 {
+       global:
+               fsi_open_fsimage;
+               fsi_close_fsimage;
+               fsi_file_exists;
+               fsi_open_file;
+               fsi_close_file;
+               fsi_read_file;
+               fsi_pread_file;
+
+               fsip_fs_set_data;
+               fsip_fs_free;
+               fsip_file_alloc;
+               fsip_file_free;
+               fsip_fs;
+               fsip_fs_data;
+               fsip_fs_offset;
+               fsip_file_data;
+
+               fsig_init;
+               fsig_devread;
+               fsig_substring;
+               fsig_fs_buf;
+               fsig_file_alloc;
+               fsig_file_buf;
+               fsig_filepos;
+               fsig_filemax;
+               fsig_int1;
+               fsig_int2;
+               fsig_errnum;
+               fsig_disk_read_junk;
+
+       local:
+               *;
+};
diff --git a/tools/libfsimage/ext2fs-lib/Makefile 
b/tools/libfsimage/ext2fs-lib/Makefile
new file mode 100644
--- /dev/null
+++ b/tools/libfsimage/ext2fs-lib/Makefile
@@ -0,0 +1,15 @@
+XEN_ROOT = ../../..
+
+LIB_SRCS-y = ext2fs-lib.c
+
+FS = ext2fs-lib
+
+FS_LIBDEPS = -lext2fs
+
+.PHONY: all
+all: fs-all
+
+.PHONY: install
+install: fs-install
+
+include $(XEN_ROOT)/tools/libfsimage/Rules.mk
diff --git a/tools/libfsimage/ext2fs-lib/ext2fs-lib.c 
b/tools/libfsimage/ext2fs-lib/ext2fs-lib.c
new file mode 100644
--- /dev/null
+++ b/tools/libfsimage/ext2fs-lib/ext2fs-lib.c
@@ -0,0 +1,171 @@
+/*
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <fsimage_plugin.h>
+#include <ext2fs/ext2fs.h>
+#include <errno.h>
+
+static int
+ext2lib_mount(fsi_t *fsi, const char *name)
+{
+       int err;
+       char opts[30] = "";
+       ext2_filsys *fs;
+       uint64_t offset = fsip_fs_offset(fsi);
+
+       if (offset)
+               snprintf(opts, 29, "offset=%lld", offset);
+
+       fs = malloc(sizeof (*fs));
+       if (fs == NULL)
+               return (-1);
+
+       err = ext2fs_open2(name, opts, 0, 0, 0, unix_io_manager, fs);
+
+       if (err != 0) {
+               free(fs);
+               errno = EINVAL;
+               return (-1);
+       }
+
+       fsip_fs_set_data(fsi, fs);
+       return (0);
+}
+
+static int
+ext2lib_umount(fsi_t *fsi)
+{
+       ext2_filsys *fs = fsip_fs_data(fsi);
+       if (ext2fs_close(*fs) != 0) {
+               errno = EINVAL;
+               return (-1);
+       }
+       return (0);
+}
+
+fsi_file_t *
+ext2lib_open(fsi_t *fsi, const char *path)
+{
+       ext2_ino_t ino;
+       ext2_filsys *fs = fsip_fs_data(fsi);
+       ext2_file_t *f;
+       fsi_file_t *file;
+       int err;
+
+       err = ext2fs_namei_follow(*fs, EXT2_ROOT_INO, EXT2_ROOT_INO,
+           path, &ino);
+
+       if (err != 0) {
+               errno = ENOENT;
+               return (NULL);
+       }
+
+       f = malloc(sizeof (*f));
+       if (f == NULL)
+               return (NULL);
+
+       err = ext2fs_file_open(*fs, ino, 0, f);
+
+       if (err != 0) {
+               free(f);
+               errno = EINVAL;
+               return (NULL);
+       }
+
+       file = fsip_file_alloc(fsi, f);
+       if (file == NULL)
+               free(f);
+       return (file);
+}
+
+ssize_t
+ext2lib_read(fsi_file_t *file, void *buf, size_t nbytes)
+{
+       ext2_file_t *f = fsip_file_data(file);
+       unsigned int n;
+       int err;
+
+       err = ext2fs_file_read(*f, buf, nbytes, &n);
+       if (err != 0) {
+               errno = EINVAL;
+               return (-1);
+       }
+
+       return (n);
+}
+
+ssize_t
+ext2lib_pread(fsi_file_t *file, void *buf, size_t nbytes, uint64_t off)
+{
+       ext2_file_t *f = fsip_file_data(file);
+       uint64_t tmpoff;
+       unsigned int n;
+       int err;
+
+       if ((err = ext2fs_file_llseek(*f, 0, EXT2_SEEK_CUR, &tmpoff)) != 0) {
+               errno = EINVAL;
+               return (-1);
+       }
+
+       if ((err = ext2fs_file_llseek(*f, off, EXT2_SEEK_SET, NULL)) != 0) {
+               errno = EINVAL;
+               return (-1);
+       }
+
+       err = ext2fs_file_read(*f, buf, nbytes, &n);
+
+       ext2fs_file_llseek(*f, tmpoff, EXT2_SEEK_SET, NULL);
+
+       if (err != 0) {
+               errno = EINVAL;
+               return (-1);
+       }
+
+       return (n);
+}
+
+int
+ext2lib_close(fsi_file_t *file)
+{
+       ext2_file_t *f = fsip_file_data(file);
+       ext2fs_file_close(*f);
+       free(f);
+       return (0);
+}
+
+fsi_plugin_ops_t *
+fsi_init_plugin(int version, fsi_plugin_t *fp, const char **name)
+{
+       static fsi_plugin_ops_t ops = {
+               FSIMAGE_PLUGIN_VERSION,
+               .fpo_mount = ext2lib_mount,
+               .fpo_umount = ext2lib_umount,
+               .fpo_open = ext2lib_open,
+               .fpo_read = ext2lib_read,
+               .fpo_pread = ext2lib_pread,
+               .fpo_close = ext2lib_close
+       };
+
+       *name = "ext2fs-lib";
+       return (&ops);
+}
diff --git a/tools/libfsimage/ext2fs/Makefile b/tools/libfsimage/ext2fs/Makefile
new file mode 100644
--- /dev/null
+++ b/tools/libfsimage/ext2fs/Makefile
@@ -0,0 +1,13 @@
+XEN_ROOT = ../../..
+
+LIB_SRCS-y = fsys_ext2fs.c
+
+FS = ext2fs
+
+.PHONY: all
+all: fs-all
+
+.PHONY: install
+install: fs-install
+
+include $(XEN_ROOT)/tools/libfsimage/Rules.mk
diff --git a/tools/libfsimage/ext2fs/fsys_ext2fs.c 
b/tools/libfsimage/ext2fs/fsys_ext2fs.c
new file mode 100644
--- /dev/null
+++ b/tools/libfsimage/ext2fs/fsys_ext2fs.c
@@ -0,0 +1,804 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 1999, 2001, 2003  Free Software Foundation, Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <fsimage_grub.h>
+
+#define        mapblock1 (*fsig_int1(ffi))
+#define        mapblock2 (*fsig_int2(ffi))
+
+/* sizes are always in bytes, BLOCK values are always in DEV_BSIZE (sectors) */
+#define DEV_BSIZE 512
+
+/* include/linux/fs.h */
+#define BLOCK_SIZE 1024                /* initial block size for superblock 
read */
+/* made up, defaults to 1 but can be passed via mount_opts */
+#define WHICH_SUPER 1
+/* kind of from fs/ext2/super.c */
+#define SBLOCK (WHICH_SUPER * BLOCK_SIZE / DEV_BSIZE)  /* = 2 */
+
+/* include/asm-i386/types.h */
+typedef __signed__ char __s8;
+typedef unsigned char __u8;
+typedef __signed__ short __s16;
+typedef unsigned short __u16;
+typedef __signed__ int __s32;
+typedef unsigned int __u32;
+
+/*
+ * Constants relative to the data blocks, from ext2_fs.h
+ */
+#define EXT2_NDIR_BLOCKS                12
+#define EXT2_IND_BLOCK                  EXT2_NDIR_BLOCKS
+#define EXT2_DIND_BLOCK                 (EXT2_IND_BLOCK + 1)
+#define EXT2_TIND_BLOCK                 (EXT2_DIND_BLOCK + 1)
+#define EXT2_N_BLOCKS                   (EXT2_TIND_BLOCK + 1)
+
+/* include/linux/ext2_fs.h */
+struct ext2_super_block
+  {
+    __u32 s_inodes_count;      /* Inodes count */
+    __u32 s_blocks_count;      /* Blocks count */
+    __u32 s_r_blocks_count;    /* Reserved blocks count */
+    __u32 s_free_blocks_count; /* Free blocks count */
+    __u32 s_free_inodes_count; /* Free inodes count */
+    __u32 s_first_data_block;  /* First Data Block */
+    __u32 s_log_block_size;    /* Block size */
+    __s32 s_log_frag_size;     /* Fragment size */
+    __u32 s_blocks_per_group;  /* # Blocks per group */
+    __u32 s_frags_per_group;   /* # Fragments per group */
+    __u32 s_inodes_per_group;  /* # Inodes per group */
+    __u32 s_mtime;             /* Mount time */
+    __u32 s_wtime;             /* Write time */
+    __u16 s_mnt_count;         /* Mount count */
+    __s16 s_max_mnt_count;     /* Maximal mount count */
+    __u16 s_magic;             /* Magic signature */
+    __u16 s_state;             /* File system state */
+    __u16 s_errors;            /* Behaviour when detecting errors */
+    __u16 s_pad;
+    __u32 s_lastcheck;         /* time of last check */
+    __u32 s_checkinterval;     /* max. time between checks */
+    __u32 s_creator_os;                /* OS */
+    __u32 s_rev_level;         /* Revision level */
+    __u16 s_def_resuid;                /* Default uid for reserved blocks */
+    __u16 s_def_resgid;                /* Default gid for reserved blocks */
+    __u32 s_reserved[235];     /* Padding to the end of the block */
+  };
+
+struct ext2_group_desc
+  {
+    __u32 bg_block_bitmap;     /* Blocks bitmap block */
+    __u32 bg_inode_bitmap;     /* Inodes bitmap block */
+    __u32 bg_inode_table;      /* Inodes table block */
+    __u16 bg_free_blocks_count;        /* Free blocks count */
+    __u16 bg_free_inodes_count;        /* Free inodes count */
+    __u16 bg_used_dirs_count;  /* Directories count */
+    __u16 bg_pad;
+    __u32 bg_reserved[3];
+  };
+
+struct ext2_inode
+  {
+    __u16 i_mode;              /* File mode */
+    __u16 i_uid;               /* Owner Uid */
+    __u32 i_size;              /* 4: Size in bytes */
+    __u32 i_atime;             /* Access time */
+    __u32 i_ctime;             /* 12: Creation time */
+    __u32 i_mtime;             /* Modification time */
+    __u32 i_dtime;             /* 20: Deletion Time */
+    __u16 i_gid;               /* Group Id */
+    __u16 i_links_count;       /* 24: Links count */
+    __u32 i_blocks;            /* Blocks count */
+    __u32 i_flags;             /* 32: File flags */
+    union
+      {
+       struct
+         {
+           __u32 l_i_reserved1;
+         }
+       linux1;
+       struct
+         {
+           __u32 h_i_translator;
+         }
+       hurd1;
+       struct
+         {
+           __u32 m_i_reserved1;
+         }
+       masix1;
+      }
+    osd1;                      /* OS dependent 1 */
+    __u32 i_block[EXT2_N_BLOCKS];      /* 40: Pointers to blocks */
+    __u32 i_version;           /* File version (for NFS) */
+    __u32 i_file_acl;          /* File ACL */
+    __u32 i_dir_acl;           /* Directory ACL */
+    __u32 i_faddr;             /* Fragment address */
+    union
+      {
+       struct
+         {
+           __u8 l_i_frag;      /* Fragment number */
+           __u8 l_i_fsize;     /* Fragment size */
+           __u16 i_pad1;
+           __u32 l_i_reserved2[2];
+         }
+       linux2;
+       struct
+         {
+           __u8 h_i_frag;      /* Fragment number */
+           __u8 h_i_fsize;     /* Fragment size */
+           __u16 h_i_mode_high;
+           __u16 h_i_uid_high;
+           __u16 h_i_gid_high;
+           __u32 h_i_author;
+         }
+       hurd2;
+       struct
+         {
+           __u8 m_i_frag;      /* Fragment number */
+           __u8 m_i_fsize;     /* Fragment size */
+           __u16 m_pad1;
+           __u32 m_i_reserved2[2];
+         }
+       masix2;
+      }
+    osd2;                      /* OS dependent 2 */
+  };
+
+/* linux/limits.h */
+#define NAME_MAX         255   /* # chars in a file name */
+
+/* linux/posix_type.h */
+typedef long linux_off_t;
+
+/* linux/ext2fs.h */
+#define EXT2_NAME_LEN 255
+struct ext2_dir_entry
+  {
+    __u32 inode;               /* Inode number */
+    __u16 rec_len;             /* Directory entry length */
+    __u8 name_len;             /* Name length */
+    __u8 file_type;
+    char name[EXT2_NAME_LEN];  /* File name */
+  };
+
+/* linux/ext2fs.h */
+/*
+ * EXT2_DIR_PAD defines the directory entries boundaries
+ *
+ * NOTE: It must be a multiple of 4
+ */
+#define EXT2_DIR_PAD                    4
+#define EXT2_DIR_ROUND                  (EXT2_DIR_PAD - 1)
+#define EXT2_DIR_REC_LEN(name_len)      (((name_len) + 8 + EXT2_DIR_ROUND) & \
+                                         ~EXT2_DIR_ROUND)
+
+
+/* ext2/super.c */
+#define log2(n) ffz(~(n))
+
+#define EXT2_SUPER_MAGIC      0xEF53   /* include/linux/ext2_fs.h */
+#define EXT2_ROOT_INO              2   /* include/linux/ext2_fs.h */
+#define PATH_MAX                1024   /* include/linux/limits.h */
+#define MAX_LINK_COUNT             5   /* number of symbolic links to follow */
+
+/* made up, these are pointers into FSYS_BUF */
+/* read once, always stays there: */
+#define SUPERBLOCK \
+    ((struct ext2_super_block *)(FSYS_BUF))
+#define GROUP_DESC \
+    ((struct ext2_group_desc *) \
+     ((char *)SUPERBLOCK + sizeof(struct ext2_super_block)))
+#define INODE \
+    ((struct ext2_inode *)((caddr_t)GROUP_DESC + EXT2_BLOCK_SIZE(SUPERBLOCK)))
+#define DATABLOCK1 \
+    ((char *)((caddr_t)INODE + sizeof(struct ext2_inode)))
+#define DATABLOCK2 \
+    ((char *)((caddr_t)DATABLOCK1 + EXT2_BLOCK_SIZE(SUPERBLOCK)))
+
+/* linux/ext2_fs.h */
+#define EXT2_ADDR_PER_BLOCK(s)          (EXT2_BLOCK_SIZE(s) / sizeof (__u32))
+#define EXT2_ADDR_PER_BLOCK_BITS(s)            (log2(EXT2_ADDR_PER_BLOCK(s)))
+
+/* linux/ext2_fs.h */
+#define EXT2_BLOCK_SIZE_BITS(s)        ((s)->s_log_block_size + 10)
+/* kind of from ext2/super.c */
+#define EXT2_BLOCK_SIZE(s)     (1 << EXT2_BLOCK_SIZE_BITS(s))
+/* linux/ext2fs.h */
+#define EXT2_DESC_PER_BLOCK(s) \
+     (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_group_desc))
+/* linux/stat.h */
+#define S_IFMT  00170000
+#define S_IFLNK  0120000
+#define S_IFREG  0100000
+#define S_IFDIR  0040000
+#define S_ISLNK(m)     (((m) & S_IFMT) == S_IFLNK)
+#define S_ISREG(m)      (((m) & S_IFMT) == S_IFREG)
+#define S_ISDIR(m)      (((m) & S_IFMT) == S_IFDIR)
+
+/* include/asm-i386/bitops.h */
+/*
+ * ffz = Find First Zero in word. Undefined if no zero exists,
+ * so code should check against ~0UL first..
+ */
+#ifdef __amd64
+#define BSF "bsfq"
+#else
+#define BSF "bsfl"
+#endif
+static __inline__ unsigned long
+ffz (unsigned long word)
+{
+  __asm__ (BSF " %1,%0"
+:         "=r" (word)
+:         "r" (~word));
+  return word;
+}
+
+/* check filesystem types and read superblock into memory buffer */
+int
+ext2fs_mount (fsi_file_t *ffi)
+{
+  int retval = 1;
+
+  if (/*(((current_drive & 0x80) || (current_slice != 0))
+       && (current_slice != PC_SLICE_TYPE_EXT2FS)
+       && (current_slice != PC_SLICE_TYPE_LINUX_RAID)
+       && (! IS_PC_SLICE_TYPE_BSD_WITH_FS (current_slice, FS_EXT2FS))
+       && (! IS_PC_SLICE_TYPE_BSD_WITH_FS (current_slice, FS_OTHER)))
+      || part_length < (SBLOCK + (sizeof (struct ext2_super_block) / 
DEV_BSIZE))
+      || */ !devread (ffi, SBLOCK, 0, sizeof (struct ext2_super_block),
+                  (char *) SUPERBLOCK)
+      || SUPERBLOCK->s_magic != EXT2_SUPER_MAGIC)
+      retval = 0;
+
+  return retval;
+}
+
+/* Takes a file system block number and reads it into BUFFER. */
+static int
+ext2_rdfsb (fsi_file_t *ffi, int fsblock, char *buffer)
+{
+#ifdef E2DEBUG
+  printf ("fsblock %d buffer %d\n", fsblock, buffer);
+#endif /* E2DEBUG */
+  return devread (ffi, fsblock * (EXT2_BLOCK_SIZE (SUPERBLOCK) / DEV_BSIZE), 0,
+                 EXT2_BLOCK_SIZE (SUPERBLOCK), (char *) buffer);
+}
+
+/* from
+  ext2/inode.c:ext2_bmap()
+*/
+/* Maps LOGICAL_BLOCK (the file offset divided by the blocksize) into
+   a physical block (the location in the file system) via an inode. */
+static int
+ext2fs_block_map (fsi_file_t *ffi, int logical_block)
+{
+
+#ifdef E2DEBUG
+  unsigned char *i;
+  for (i = (unsigned char *) INODE;
+       i < ((unsigned char *) INODE + sizeof (struct ext2_inode));
+       i++)
+    {
+      printf ("%c", "0123456789abcdef"[*i >> 4]);
+      printf ("%c", "0123456789abcdef"[*i % 16]);
+      if (!((i + 1 - (unsigned char *) INODE) % 16))
+       {
+         printf ("\n");
+       }
+      else
+       {
+         printf (" ");
+       }
+    }
+  printf ("logical block %d\n", logical_block);
+#endif /* E2DEBUG */
+
+  /* if it is directly pointed to by the inode, return that physical addr */
+  if (logical_block < EXT2_NDIR_BLOCKS)
+    {
+#ifdef E2DEBUG
+      printf ("returning %d\n", (unsigned char *) 
(INODE->i_block[logical_block]));
+      printf ("returning %d\n", INODE->i_block[logical_block]);
+#endif /* E2DEBUG */
+      return INODE->i_block[logical_block];
+    }
+  /* else */
+  logical_block -= EXT2_NDIR_BLOCKS;
+  /* try the indirect block */
+  if (logical_block < EXT2_ADDR_PER_BLOCK (SUPERBLOCK))
+    {
+      if (mapblock1 != 1
+         && !ext2_rdfsb (ffi, INODE->i_block[EXT2_IND_BLOCK], DATABLOCK1))
+       {
+         errnum = ERR_FSYS_CORRUPT;
+         return -1;
+       }
+      mapblock1 = 1;
+      return ((__u32 *) DATABLOCK1)[logical_block];
+    }
+  /* else */
+  logical_block -= EXT2_ADDR_PER_BLOCK (SUPERBLOCK);
+  /* now try the double indirect block */
+  if (logical_block < (1 << (EXT2_ADDR_PER_BLOCK_BITS (SUPERBLOCK) * 2)))
+    {
+      int bnum;
+      if (mapblock1 != 2
+         && !ext2_rdfsb (ffi, INODE->i_block[EXT2_DIND_BLOCK], DATABLOCK1))
+       {
+         errnum = ERR_FSYS_CORRUPT;
+         return -1;
+       }
+      mapblock1 = 2;
+      if ((bnum = (((__u32 *) DATABLOCK1)
+                  [logical_block >> EXT2_ADDR_PER_BLOCK_BITS (SUPERBLOCK)]))
+         != mapblock2
+         && !ext2_rdfsb (ffi, bnum, DATABLOCK2))
+       {
+         errnum = ERR_FSYS_CORRUPT;
+         return -1;
+       }
+      mapblock2 = bnum;
+      return ((__u32 *) DATABLOCK2)
+       [logical_block & (EXT2_ADDR_PER_BLOCK (SUPERBLOCK) - 1)];
+    }
+  /* else */
+  mapblock2 = -1;
+  logical_block -= (1 << (EXT2_ADDR_PER_BLOCK_BITS (SUPERBLOCK) * 2));
+  if (mapblock1 != 3
+      && !ext2_rdfsb (ffi, INODE->i_block[EXT2_TIND_BLOCK], DATABLOCK1))
+    {
+      errnum = ERR_FSYS_CORRUPT;
+      return -1;
+    }
+  mapblock1 = 3;
+  if (!ext2_rdfsb (ffi, ((__u32 *) DATABLOCK1)
+                  [logical_block >> (EXT2_ADDR_PER_BLOCK_BITS (SUPERBLOCK)
+                                     * 2)],
+                  DATABLOCK2))
+    {
+      errnum = ERR_FSYS_CORRUPT;
+      return -1;
+    }
+  if (!ext2_rdfsb (ffi, ((__u32 *) DATABLOCK2)
+                  [(logical_block >> EXT2_ADDR_PER_BLOCK_BITS (SUPERBLOCK))
+                   & (EXT2_ADDR_PER_BLOCK (SUPERBLOCK) - 1)],
+                  DATABLOCK2))
+    {
+      errnum = ERR_FSYS_CORRUPT;
+      return -1;
+    }
+  return ((__u32 *) DATABLOCK2)
+    [logical_block & (EXT2_ADDR_PER_BLOCK (SUPERBLOCK) - 1)];
+}
+
+/* preconditions: all preconds of ext2fs_block_map */
+int
+ext2fs_read (fsi_file_t *ffi, char *buf, int len)
+{
+  int logical_block;
+  int offset;
+  int map;
+  int ret = 0;
+  int size = 0;
+
+#ifdef E2DEBUG
+  static char hexdigit[] = "0123456789abcdef";
+  unsigned char *i;
+  for (i = (unsigned char *) INODE;
+       i < ((unsigned char *) INODE + sizeof (struct ext2_inode));
+       i++)
+    {
+      printf ("%c", hexdigit[*i >> 4]);
+      printf ("%c", hexdigit[*i % 16]);
+      if (!((i + 1 - (unsigned char *) INODE) % 16))
+       {
+         printf ("\n");
+       }
+      else
+       {
+         printf (" ");
+       }
+    }
+#endif /* E2DEBUG */
+  while (len > 0)
+    {
+      /* find the (logical) block component of our location */
+      logical_block = filepos >> EXT2_BLOCK_SIZE_BITS (SUPERBLOCK);
+      offset = filepos & (EXT2_BLOCK_SIZE (SUPERBLOCK) - 1);
+      map = ext2fs_block_map (ffi, logical_block);
+#ifdef E2DEBUG
+      printf ("map=%d\n", map);
+#endif /* E2DEBUG */
+      if (map < 0)
+       break;
+
+      size = EXT2_BLOCK_SIZE (SUPERBLOCK);
+      size -= offset;
+      if (size > len)
+       size = len;
+
+      if (map == 0) {
+        memset ((char *) buf, 0, size);
+      } else {
+        disk_read_func = disk_read_hook;
+
+        devread (ffi, map * (EXT2_BLOCK_SIZE (SUPERBLOCK) / DEV_BSIZE),
+                offset, size, buf);
+
+        disk_read_func = NULL;
+      }
+
+      buf += size;
+      len -= size;
+      filepos += size;
+      ret += size;
+    }
+
+  if (errnum)
+    ret = 0;
+
+  return ret;
+}
+
+
+/* Based on:
+   def_blk_fops points to
+   blkdev_open, which calls (I think):
+   sys_open()
+   do_open()
+   open_namei()
+   dir_namei() which accesses current->fs->root
+     fs->root was set during original mount:
+     (something)... which calls (I think):
+     ext2_read_super()
+     iget()
+     __iget()
+     read_inode()
+     ext2_read_inode()
+       uses desc_per_block_bits, which is set in ext2_read_super()
+       also uses group descriptors loaded during ext2_read_super()
+   lookup()
+   ext2_lookup()
+   ext2_find_entry()
+   ext2_getblk()
+
+*/
+
+static inline
+int ext2_is_fast_symlink (fsi_file_t *ffi)
+{
+  int ea_blocks;
+  ea_blocks = INODE->i_file_acl ? EXT2_BLOCK_SIZE (SUPERBLOCK) / DEV_BSIZE : 0;
+  return INODE->i_blocks == ea_blocks;
+}
+
+/* preconditions: ext2fs_mount already executed, therefore supblk in buffer
+ *   known as SUPERBLOCK
+ * returns: 0 if error, nonzero iff we were able to find the file successfully
+ * postconditions: on a nonzero return, buffer known as INODE contains the
+ *   inode of the file we were trying to look up
+ * side effects: messes up GROUP_DESC buffer area
+ */
+int
+ext2fs_dir (fsi_file_t *ffi, char *dirname)
+{
+  int current_ino = EXT2_ROOT_INO;     /* start at the root */
+  int updir_ino = current_ino; /* the parent of the current directory */
+  int group_id;                        /* which group the inode is in */
+  int group_desc;              /* fs pointer to that group */
+  int desc;                    /* index within that group */
+  int ino_blk;                 /* fs pointer of the inode's information */
+  int str_chk = 0;             /* used to hold the results of a string compare 
*/
+  struct ext2_group_desc *gdp;
+  struct ext2_inode *raw_inode;        /* inode info corresponding to 
current_ino */
+
+  char linkbuf[PATH_MAX];      /* buffer for following symbolic links */
+  int link_count = 0;
+
+  char *rest;
+  char ch;                     /* temp char holder */
+
+  int off;                     /* offset within block of directory entry (off 
mod blocksize) */
+  int loc;                     /* location within a directory */
+  int blk;                     /* which data blk within dir entry (off div 
blocksize) */
+  long map;                    /* fs pointer of a particular block from dir 
entry */
+  struct ext2_dir_entry *dp;   /* pointer to directory entry */
+#ifdef E2DEBUG
+  unsigned char *i;
+#endif /* E2DEBUG */
+
+  /* loop invariants:
+     current_ino = inode to lookup
+     dirname = pointer to filename component we are cur looking up within
+     the directory known pointed to by current_ino (if any)
+   */
+
+  while (1)
+    {
+#ifdef E2DEBUG
+      printf ("inode %d\n", current_ino);
+      printf ("dirname=%s\n", dirname);
+#endif /* E2DEBUG */
+
+      /* look up an inode */
+      group_id = (current_ino - 1) / (SUPERBLOCK->s_inodes_per_group);
+      group_desc = group_id >> log2 (EXT2_DESC_PER_BLOCK (SUPERBLOCK));
+      desc = group_id & (EXT2_DESC_PER_BLOCK (SUPERBLOCK) - 1);
+#ifdef E2DEBUG
+      printf ("ipg=%d, dpb=%d\n", SUPERBLOCK->s_inodes_per_group,
+             EXT2_DESC_PER_BLOCK (SUPERBLOCK));
+      printf ("group_id=%d group_desc=%d desc=%d\n", group_id, group_desc, 
desc);
+#endif /* E2DEBUG */
+      if (!ext2_rdfsb (ffi, 
+                       (WHICH_SUPER + group_desc + 
SUPERBLOCK->s_first_data_block),
+                       (char *)GROUP_DESC))
+       {
+         return 0;
+       }
+      gdp = GROUP_DESC;
+      ino_blk = gdp[desc].bg_inode_table +
+       (((current_ino - 1) % (SUPERBLOCK->s_inodes_per_group))
+        >> log2 (EXT2_BLOCK_SIZE (SUPERBLOCK) / sizeof (struct ext2_inode)));
+#ifdef E2DEBUG
+      printf ("inode table fsblock=%d\n", ino_blk);
+#endif /* E2DEBUG */
+      if (!ext2_rdfsb (ffi, ino_blk, (char *)INODE))
+       {
+         return 0;
+       }
+
+      /* reset indirect blocks! */
+      mapblock2 = mapblock1 = -1;
+
+      raw_inode = INODE +
+       ((current_ino - 1)
+        & (EXT2_BLOCK_SIZE (SUPERBLOCK) / sizeof (struct ext2_inode) - 1));
+#ifdef E2DEBUG
+      printf ("ipb=%d, sizeof(inode)=%d\n",
+             (EXT2_BLOCK_SIZE (SUPERBLOCK) / sizeof (struct ext2_inode)),
+             sizeof (struct ext2_inode));
+      printf ("inode=%x, raw_inode=%x\n", INODE, raw_inode);
+      printf ("offset into inode table block=%d\n", (int) raw_inode - (int) 
INODE);
+      for (i = (unsigned char *) INODE; i <= (unsigned char *) raw_inode;
+          i++)
+       {
+         printf ("%c", "0123456789abcdef"[*i >> 4]);
+         printf ("%c", "0123456789abcdef"[*i % 16]);
+         if (!((i + 1 - (unsigned char *) INODE) % 16))
+           {
+             printf ("\n");
+           }
+         else
+           {
+             printf (" ");
+           }
+       }
+      printf ("first word=%x\n", *((int *) raw_inode));
+#endif /* E2DEBUG */
+
+      /* copy inode to fixed location */
+      memmove ((void *) INODE, (void *) raw_inode, sizeof (struct ext2_inode));
+
+#ifdef E2DEBUG
+      printf ("first word=%x\n", *((int *) INODE));
+#endif /* E2DEBUG */
+
+      /* If we've got a symbolic link, then chase it. */
+      if (S_ISLNK (INODE->i_mode))
+       {
+         int len;
+         if (++link_count > MAX_LINK_COUNT)
+           {
+             errnum = ERR_SYMLINK_LOOP;
+             return 0;
+           }
+
+         /* Find out how long our remaining name is. */
+         len = 0;
+         while (dirname[len] && !isspace (dirname[len]))
+           len++;
+
+         /* Get the symlink size. */
+         filemax = (INODE->i_size);
+         if (filemax + len > sizeof (linkbuf) - 2)
+           {
+             errnum = ERR_FILELENGTH;
+             return 0;
+           }
+
+         if (len)
+           {
+             /* Copy the remaining name to the end of the symlink data.
+                Note that DIRNAME and LINKBUF may overlap! */
+             memmove (linkbuf + filemax, dirname, len);
+           }
+         linkbuf[filemax + len] = '\0';
+
+         /* Read the symlink data. */
+         if (! ext2_is_fast_symlink (ffi))
+           {
+             /* Read the necessary blocks, and reset the file pointer. */
+             len = ext2fs_read (ffi, linkbuf, filemax);
+             filepos = 0;
+             if (!len)
+               return 0;
+           }
+         else
+           {
+             /* Copy the data directly from the inode. */
+             len = filemax;
+             memmove (linkbuf, (char *) INODE->i_block, len);
+           }
+
+#ifdef E2DEBUG
+         printf ("symlink=%s\n", linkbuf);
+#endif
+
+         dirname = linkbuf;
+         if (*dirname == '/')
+           {
+             /* It's an absolute link, so look it up in root. */
+             current_ino = EXT2_ROOT_INO;
+             updir_ino = current_ino;
+           }
+         else
+           {
+             /* Relative, so look it up in our parent directory. */
+             current_ino = updir_ino;
+           }
+
+         /* Try again using the new name. */
+         continue;
+       }
+
+      /* if end of filename, INODE points to the file's inode */
+      if (!*dirname || isspace (*dirname))
+       {
+         if (!S_ISREG (INODE->i_mode))
+           {
+             errnum = ERR_BAD_FILETYPE;
+             return 0;
+           }
+
+         filemax = (INODE->i_size);
+         return 1;
+       }
+
+      /* else we have to traverse a directory */
+      updir_ino = current_ino;
+
+      /* skip over slashes */
+      while (*dirname == '/')
+       dirname++;
+
+      /* if this isn't a directory of sufficient size to hold our file, abort 
*/
+      if (!(INODE->i_size) || !S_ISDIR (INODE->i_mode))
+       {
+         errnum = ERR_BAD_FILETYPE;
+         return 0;
+       }
+
+      /* skip to next slash or end of filename (space) */
+      for (rest = dirname; (ch = *rest) && !isspace (ch) && ch != '/';
+          rest++);
+
+      /* look through this directory and find the next filename component */
+      /* invariant: rest points to slash after the next filename component */
+      *rest = 0;
+      loc = 0;
+
+      do
+       {
+
+#ifdef E2DEBUG
+         printf ("dirname=%s, rest=%s, loc=%d\n", dirname, rest, loc);
+#endif /* E2DEBUG */
+
+         /* if our location/byte offset into the directory exceeds the size,
+            give up */
+         if (loc >= INODE->i_size)
+           {
+             if (print_possibilities < 0)
+               {
+# if 0
+                 putchar ('\n');
+# endif
+               }
+             else
+               {
+                 errnum = ERR_FILE_NOT_FOUND;
+                 *rest = ch;
+               }
+             return (print_possibilities < 0);
+           }
+
+         /* else, find the (logical) block component of our location */
+         blk = loc >> EXT2_BLOCK_SIZE_BITS (SUPERBLOCK);
+
+         /* we know which logical block of the directory entry we are looking
+            for, now we have to translate that to the physical (fs) block on
+            the disk */
+         map = ext2fs_block_map (ffi, blk);
+#ifdef E2DEBUG
+         printf ("fs block=%d\n", map);
+#endif /* E2DEBUG */
+         mapblock2 = -1;
+         if ((map < 0) || !ext2_rdfsb (ffi, map, DATABLOCK2))
+           {
+             errnum = ERR_FSYS_CORRUPT;
+             *rest = ch;
+             return 0;
+           }
+         off = loc & (EXT2_BLOCK_SIZE (SUPERBLOCK) - 1);
+         dp = (struct ext2_dir_entry *) (DATABLOCK2 + off);
+         /* advance loc prematurely to next on-disk directory entry  */
+         loc += dp->rec_len;
+
+         /* NOTE: ext2fs filenames are NOT null-terminated */
+
+#ifdef E2DEBUG
+         printf ("directory entry ino=%d\n", dp->inode);
+         if (dp->inode)
+           printf ("entry=%s\n", dp->name);
+#endif /* E2DEBUG */
+
+         if (dp->inode)
+           {
+             int saved_c = dp->name[dp->name_len];
+
+             dp->name[dp->name_len] = 0;
+             str_chk = substring (dirname, dp->name);
+
+# ifndef STAGE1_5
+             if (print_possibilities && ch != '/'
+                 && (!*dirname || str_chk <= 0))
+               {
+                 if (print_possibilities > 0)
+                   print_possibilities = -print_possibilities;
+                 print_a_completion (dp->name);
+               }
+# endif
+
+             dp->name[dp->name_len] = saved_c;
+           }
+
+       }
+      while (!dp->inode || (str_chk || (print_possibilities && ch != '/')));
+
+      current_ino = dp->inode;
+      *(dirname = rest) = ch;
+    }
+  /* never get here */
+}
+
+fsi_plugin_ops_t *
+fsi_init_plugin(int version, fsi_plugin_t *fp, const char **name)
+{
+       static fsig_plugin_ops_t ops = {
+               FSIMAGE_PLUGIN_VERSION,
+               .fpo_mount = ext2fs_mount,
+               .fpo_dir = ext2fs_dir,
+               .fpo_read = ext2fs_read
+       };
+
+       *name = "ext2fs";
+       return (fsig_init(fp, &ops));
+}
diff --git a/tools/libfsimage/reiserfs/Makefile 
b/tools/libfsimage/reiserfs/Makefile
new file mode 100644
--- /dev/null
+++ b/tools/libfsimage/reiserfs/Makefile
@@ -0,0 +1,13 @@
+XEN_ROOT = ../../..
+
+LIB_SRCS-y = fsys_reiserfs.c
+
+FS = reiserfs
+
+.PHONY: all
+all: fs-all
+
+.PHONY: install
+install: fs-install
+
+include $(XEN_ROOT)/tools/libfsimage/Rules.mk
diff --git a/tools/libfsimage/reiserfs/fsys_reiserfs.c 
b/tools/libfsimage/reiserfs/fsys_reiserfs.c
new file mode 100644
--- /dev/null
+++ b/tools/libfsimage/reiserfs/fsys_reiserfs.c
@@ -0,0 +1,1254 @@
+/* fsys_reiserfs.c - an implementation for the ReiserFS filesystem */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2000, 2001  Free Software Foundation, Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <fsimage_grub.h>
+
+#undef REISERDEBUG
+
+/* Some parts of this code (mainly the structures and defines) are
+ * from the original reiser fs code, as found in the linux kernel.
+ */
+
+/* include/asm-i386/types.h */
+typedef __signed__ char __s8;
+typedef unsigned char __u8;
+typedef __signed__ short __s16;
+typedef unsigned short __u16;
+typedef __signed__ int __s32;
+typedef unsigned int __u32;
+typedef unsigned long long __u64;
+
+/* linux/posix_type.h */
+typedef long linux_off_t;
+
+/* linux/little_endian.h */
+#define __cpu_to_le64(x) ((__u64) (x))
+#define __le64_to_cpu(x) ((__u64) (x))
+#define __cpu_to_le32(x) ((__u32) (x))
+#define __le32_to_cpu(x) ((__u32) (x))
+#define __cpu_to_le16(x) ((__u16) (x))
+#define __le16_to_cpu(x) ((__u16) (x))
+
+/* include/linux/reiser_fs.h */
+/* This is the new super block of a journaling reiserfs system */
+struct reiserfs_super_block
+{
+  __u32 s_block_count;                 /* blocks count         */
+  __u32 s_free_blocks;                  /* free blocks count    */
+  __u32 s_root_block;                  /* root block number    */
+  __u32 s_journal_block;               /* journal block number    */
+  __u32 s_journal_dev;                 /* journal device number  */
+  __u32 s_journal_size;                /* size of the journal on FS creation.  
used to make sure they don't overflow it */
+  __u32 s_journal_trans_max;            /* max number of blocks in a 
transaction.  */
+  __u32 s_journal_magic;                /* random value made on fs creation */
+  __u32 s_journal_max_batch;            /* max number of blocks to batch into 
a trans */
+  __u32 s_journal_max_commit_age;       /* in seconds, how old can an async 
commit be */
+  __u32 s_journal_max_trans_age;        /* in seconds, how old can a 
transaction be */
+  __u16 s_blocksize;                           /* block size           */
+  __u16 s_oid_maxsize;                 /* max size of object id array  */
+  __u16 s_oid_cursize;                 /* current size of object id array */
+  __u16 s_state;                               /* valid or error       */
+  char s_magic[16];                     /* reiserfs magic string indicates 
that file system is reiserfs */
+  __u16 s_tree_height;                  /* height of disk tree */
+  __u16 s_bmap_nr;                      /* amount of bitmap blocks needed to 
address each block of file system */
+  __u16 s_version;
+  char s_unused[128];                  /* zero filled by mkreiserfs */
+};
+
+#define REISERFS_MAX_SUPPORTED_VERSION 2
+#define REISERFS_SUPER_MAGIC_STRING "ReIsErFs"
+#define REISER2FS_SUPER_MAGIC_STRING "ReIsEr2Fs"
+#define REISER3FS_SUPER_MAGIC_STRING "ReIsEr3Fs"
+
+#define MAX_HEIGHT 7
+
+/* must be correct to keep the desc and commit structs at 4k */
+#define JOURNAL_TRANS_HALF 1018
+
+/* first block written in a commit.  */
+struct reiserfs_journal_desc {
+  __u32 j_trans_id;                    /* id of commit */
+  __u32 j_len;                         /* length of commit. len +1 is the 
commit block */
+  __u32 j_mount_id;                    /* mount id of this trans*/
+  __u32 j_realblock[JOURNAL_TRANS_HALF]; /* real locations for the first 
blocks */
+  char j_magic[12];
+};
+
+/* last block written in a commit */
+struct reiserfs_journal_commit {
+  __u32 j_trans_id;                    /* must match j_trans_id from the desc 
block */
+  __u32 j_len;                 /* ditto */
+  __u32 j_realblock[JOURNAL_TRANS_HALF]; /* real locations for the last blocks 
*/
+  char j_digest[16];                   /* md5 sum of all the blocks involved, 
including desc and commit. not used, kill it */
+};
+
+/* this header block gets written whenever a transaction is considered
+   fully flushed, and is more recent than the last fully flushed
+   transaction.  
+   fully flushed means all the log blocks and all the real blocks are
+   on disk, and this transaction does not need to be replayed.  
+*/
+struct reiserfs_journal_header {
+  /* id of last fully flushed transaction */
+  __u32 j_last_flush_trans_id;
+  /* offset in the log of where to start replay after a crash */
+  __u32 j_first_unflushed_offset;
+  /* mount id to detect very old transactions */
+  __u32 j_mount_id;
+};
+
+/* magic string to find desc blocks in the journal */
+#define JOURNAL_DESC_MAGIC "ReIsErLB" 
+
+
+/*
+ * directories use this key as well as old files
+ */
+struct offset_v1
+{
+  /*
+   * for regular files this is the offset to the first byte of the
+   * body, contained in the object-item, as measured from the start of
+   * the entire body of the object.
+   *
+   * for directory entries, k_offset consists of hash derived from
+   * hashing the name and using few bits (23 or more) of the resulting
+   * hash, and generation number that allows distinguishing names with
+   * hash collisions. If number of collisions overflows generation
+   * number, we return EEXIST.  High order bit is 0 always 
+   */
+  __u32 k_offset;
+  __u32 k_uniqueness;
+};
+
+struct offset_v2
+{
+  /*
+   * for regular files this is the offset to the first byte of the
+   * body, contained in the object-item, as measured from the start of
+   * the entire body of the object.
+   *
+   * for directory entries, k_offset consists of hash derived from
+   * hashing the name and using few bits (23 or more) of the resulting
+   * hash, and generation number that allows distinguishing names with
+   * hash collisions. If number of collisions overflows generation
+   * number, we return EEXIST.  High order bit is 0 always 
+   */
+  __u64 k_offset:60;
+  __u64 k_type: 4;
+};
+
+
+struct key
+{
+  /* packing locality: by default parent directory object id */
+  __u32 k_dir_id;
+  /* object identifier */
+  __u32 k_objectid;
+  /* the offset and node type (old and new form) */
+  union
+  {
+    struct offset_v1 v1;
+    struct offset_v2 v2;
+  }
+  u;
+};
+
+#define KEY_SIZE (sizeof (struct key))
+
+/* Header of a disk block.  More precisely, header of a formatted leaf
+   or internal node, and not the header of an unformatted node. */
+struct block_head
+{       
+  __u16 blk_level;        /* Level of a block in the tree. */
+  __u16 blk_nr_item;      /* Number of keys/items in a block. */
+  __u16 blk_free_space;   /* Block free space in bytes. */
+  struct key  blk_right_delim_key; /* Right delimiting key for this block 
(supported for leaf level nodes
+                                     only) */
+};
+#define BLKH_SIZE (sizeof (struct block_head))
+#define DISK_LEAF_NODE_LEVEL  1 /* Leaf node level.                       */
+
+struct item_head
+{
+  struct key ih_key;   /* Everything in the tree is found by searching for it 
based on its key.*/
+  
+  union
+  {
+    __u16 ih_free_space; /* The free space in the last unformatted node of an 
indirect item if this
+                           is an indirect item.  This equals 0xFFFF iff this 
is a direct item or
+                           stat data item. Note that the key, not this field, 
is used to determine
+                           the item type, and thus which field this union 
contains. */
+    __u16 ih_entry_count; /* Iff this is a directory item, this field equals 
the number of directory
+                            entries in the directory item. */
+  }
+  u;
+  __u16 ih_item_len;           /* total size of the item body                  
*/
+  __u16 ih_item_location;      /* an offset to the item body within the block  
*/
+  __u16 ih_version;           /* ITEM_VERSION_1 for all old items, 
+                                 ITEM_VERSION_2 for new ones. 
+                                 Highest bit is set by fsck
+                                  temporary, cleaned after all done */
+};
+/* size of item header     */
+#define IH_SIZE (sizeof (struct item_head))
+
+#define ITEM_VERSION_1 0
+#define ITEM_VERSION_2 1
+#define IH_KEY_OFFSET(ih) ((ih)->ih_version == ITEM_VERSION_1 \
+                          ? (ih)->ih_key.u.v1.k_offset \
+                          : (ih)->ih_key.u.v2.k_offset)
+
+#define IH_KEY_ISTYPE(ih, type) ((ih)->ih_version == ITEM_VERSION_1 \
+                                ? (ih)->ih_key.u.v1.k_uniqueness == V1_##type \
+                                : (ih)->ih_key.u.v2.k_type == V2_##type)
+
+struct disk_child
+{
+  unsigned long       dc_block_number;              /* Disk child's block 
number. */
+  unsigned short      dc_size;                     /* Disk child's used space. 
  */
+};
+
+#define DC_SIZE (sizeof (struct disk_child))
+
+/* Stat Data on disk.
+ *
+ * Note that reiserfs has two different forms of stat data.  Luckily
+ * the fields needed by grub are at the same position.
+ */
+struct stat_data
+{
+  __u16 sd_mode;       /* file type, permissions */
+  __u16 sd_notused1[3]; /* fields not needed by reiserfs */
+  __u32 sd_size;       /* file size */
+  __u32 sd_size_hi;    /* file size high 32 bits (since version 2) */
+};
+
+struct reiserfs_de_head
+{
+  __u32 deh_offset;  /* third component of the directory entry key */
+  __u32 deh_dir_id;  /* objectid of the parent directory of the
+                       object, that is referenced by directory entry */
+  __u32 deh_objectid;/* objectid of the object, that is referenced by
+                        directory entry */
+  __u16 deh_location;/* offset of name in the whole item */
+  __u16 deh_state;   /* whether 1) entry contains stat data (for
+                       future), and 2) whether entry is hidden
+                       (unlinked) */
+};
+
+#define DEH_SIZE (sizeof (struct reiserfs_de_head))
+
+#define DEH_Statdata (1 << 0)                  /* not used now */
+#define DEH_Visible  (1 << 2)
+
+#define SD_OFFSET  0
+#define SD_UNIQUENESS 0
+#define DOT_OFFSET 1
+#define DOT_DOT_OFFSET 2
+#define DIRENTRY_UNIQUENESS 500
+
+#define V1_TYPE_STAT_DATA 0x0
+#define V1_TYPE_DIRECT 0xffffffff
+#define V1_TYPE_INDIRECT 0xfffffffe
+#define V1_TYPE_DIRECTORY_MAX 0xfffffffd
+#define V2_TYPE_STAT_DATA 0
+#define V2_TYPE_INDIRECT 1
+#define V2_TYPE_DIRECT 2
+#define V2_TYPE_DIRENTRY 3 
+
+#define REISERFS_ROOT_OBJECTID 2
+#define REISERFS_ROOT_PARENT_OBJECTID 1
+#define REISERFS_DISK_OFFSET_IN_BYTES (64 * 1024)
+/* the spot for the super in versions 3.5 - 3.5.11 (inclusive) */
+#define REISERFS_OLD_DISK_OFFSET_IN_BYTES (8 * 1024)
+#define REISERFS_OLD_BLOCKSIZE 4096
+
+#define S_ISREG(mode) (((mode) & 0170000) == 0100000)
+#define S_ISDIR(mode) (((mode) & 0170000) == 0040000)
+#define S_ISLNK(mode) (((mode) & 0170000) == 0120000)
+
+#define PATH_MAX       1024    /* include/linux/limits.h */
+#define MAX_LINK_COUNT    5    /* number of symbolic links to follow */
+
+/* The size of the node cache */
+#define FSYSREISER_CACHE_SIZE 24*1024
+#define FSYSREISER_MIN_BLOCKSIZE SECTOR_SIZE
+#define FSYSREISER_MAX_BLOCKSIZE FSYSREISER_CACHE_SIZE / 3
+
+/* Info about currently opened file */
+struct fsys_reiser_fileinfo
+{
+  __u32 k_dir_id;
+  __u32 k_objectid;
+};
+
+/* In memory info about the currently mounted filesystem */
+struct fsys_reiser_info
+{
+  /* The last read item head */
+  struct item_head *current_ih;
+  /* The last read item */
+  char *current_item;
+  /* The information for the currently opened file */
+  struct fsys_reiser_fileinfo fileinfo;
+  /* The start of the journal */
+  __u32 journal_block;
+  /* The size of the journal */
+  __u32 journal_block_count;
+  /* The first valid descriptor block in journal
+     (relative to journal_block) */
+  __u32 journal_first_desc;
+
+  /* The ReiserFS version. */
+  __u16 version;
+  /* The current depth of the reiser tree. */
+  __u16 tree_depth;
+  /* SECTOR_SIZE << blocksize_shift == blocksize. */
+  __u8  blocksize_shift;
+  /* 1 << full_blocksize_shift == blocksize. */
+  __u8  fullblocksize_shift;
+  /* The reiserfs block size  (must be a power of 2) */
+  __u16 blocksize;
+  /* The number of cached tree nodes */
+  __u16 cached_slots;
+  /* The number of valid transactions in journal */
+  __u16 journal_transactions;
+  
+  unsigned int blocks[MAX_HEIGHT];
+  unsigned int next_key_nr[MAX_HEIGHT];
+};
+
+/* The cached s+tree blocks in FSYS_BUF,  see below
+ * for a more detailed description.
+ */
+#define ROOT     ((char *) FSYS_BUF)
+#define CACHE(i) (ROOT + ((i) << INFO->fullblocksize_shift))
+#define LEAF     CACHE (DISK_LEAF_NODE_LEVEL)
+
+#define BLOCKHEAD(cache) ((struct block_head *) cache)
+#define ITEMHEAD         ((struct item_head  *) ((char *) LEAF + BLKH_SIZE))
+#define KEY(cache)       ((struct key        *) ((char *) cache + BLKH_SIZE))
+#define DC(cache)        ((struct disk_child *) \
+                         ((char *) cache + BLKH_SIZE + KEY_SIZE * nr_item))
+/* The fsys_reiser_info block.
+ */
+#define INFO \
+    ((struct fsys_reiser_info *) ((char *) FSYS_BUF + FSYSREISER_CACHE_SIZE))
+/* 
+ * The journal cache.  For each transaction it contains the number of
+ * blocks followed by the real block numbers of this transaction.  
+ *
+ * If the block numbers of some transaction won't fit in this space,
+ * this list is stopped with a 0xffffffff marker and the remaining
+ * uncommitted transactions aren't cached.  
+ */
+#define JOURNAL_START    ((__u32 *) (INFO + 1))
+#define JOURNAL_END      ((__u32 *) (FSYS_BUF + FSYS_BUFLEN))
+
+#ifdef __amd64
+#define BSF "bsfq"
+#else
+#define BSF "bsfl"
+#endif
+static __inline__ unsigned long
+grub_log2 (unsigned long word)
+{
+  __asm__ (BSF " %1,%0"
+          : "=r" (word)
+          : "r" (word));
+  return word;
+}
+#define log2 grub_log2
+
+static __inline__ int
+is_power_of_two (unsigned long word)
+{
+  return (word & -word) == word;
+}
+
+static int 
+journal_read (fsi_file_t *ffi, int block, int len, char *buffer) 
+{
+  return devread (ffi, (INFO->journal_block + block) << INFO->blocksize_shift, 
+                 0, len, buffer);
+}
+
+/* Read a block from ReiserFS file system, taking the journal into
+ * account.  If the block nr is in the journal, the block from the
+ * journal taken.  
+ */
+static int
+block_read (fsi_file_t *ffi, int blockNr, int start, int len, char *buffer)
+{
+  int transactions = INFO->journal_transactions;
+  int desc_block = INFO->journal_first_desc;
+  int journal_mask = INFO->journal_block_count - 1;
+  int translatedNr = blockNr;
+  __u32 *journal_table = JOURNAL_START;
+  while (transactions-- > 0) 
+    {
+      int i = 0;
+      int j_len;
+      if (*journal_table != 0xffffffff)
+       {
+         /* Search for the blockNr in cached journal */
+         j_len = *journal_table++;
+         while (i++ < j_len)
+           {
+             if (*journal_table++ == blockNr)
+               {
+                 journal_table += j_len - i;
+                 goto found;
+               }
+           }
+       }
+      else
+       {
+         /* This is the end of cached journal marker.  The remaining
+          * transactions are still on disk.
+          */
+         struct reiserfs_journal_desc   desc;
+         struct reiserfs_journal_commit commit;
+
+         if (! journal_read (ffi, desc_block, sizeof (desc), (char *) &desc))
+           return 0;
+
+         j_len = desc.j_len;
+         while (i < j_len && i < JOURNAL_TRANS_HALF)
+           if (desc.j_realblock[i++] == blockNr)
+             goto found;
+         
+         if (j_len >= JOURNAL_TRANS_HALF)
+           {
+             int commit_block = (desc_block + 1 + j_len) & journal_mask;
+             if (! journal_read (ffi, commit_block, 
+                                 sizeof (commit), (char *) &commit))
+               return 0;
+             while (i < j_len)
+               if (commit.j_realblock[i++ - JOURNAL_TRANS_HALF] == blockNr)
+                 goto found;
+           }
+       }
+      goto not_found;
+      
+    found:
+      translatedNr = INFO->journal_block + ((desc_block + i) & journal_mask);
+#ifdef REISERDEBUG
+      printf ("block_read: block %d is mapped to journal block %d.\n", 
+             blockNr, translatedNr - INFO->journal_block);
+#endif
+      /* We must continue the search, as this block may be overwritten
+       * in later transactions.
+       */
+    not_found:
+      desc_block = (desc_block + 2 + j_len) & journal_mask;
+    }
+  return devread (ffi, translatedNr << INFO->blocksize_shift, start, len, 
buffer);
+}
+
+/* Init the journal data structure.  We try to cache as much as
+ * possible in the JOURNAL_START-JOURNAL_END space, but if it is full
+ * we can still read the rest from the disk on demand.
+ *
+ * The first number of valid transactions and the descriptor block of the
+ * first valid transaction are held in INFO.  The transactions are all 
+ * adjacent, but we must take care of the journal wrap around. 
+ */
+static int
+journal_init (fsi_file_t *ffi)
+{
+  unsigned int block_count = INFO->journal_block_count;
+  unsigned int desc_block;
+  unsigned int commit_block;
+  unsigned int next_trans_id;
+  struct reiserfs_journal_header header;
+  struct reiserfs_journal_desc   desc;
+  struct reiserfs_journal_commit commit;
+  __u32 *journal_table = JOURNAL_START;
+
+  journal_read (ffi, block_count, sizeof (header), (char *) &header);
+  desc_block = header.j_first_unflushed_offset;
+  if (desc_block >= block_count)
+    return 0;
+
+  INFO->journal_first_desc = desc_block;
+  next_trans_id = header.j_last_flush_trans_id + 1;
+
+#ifdef REISERDEBUG
+  printf ("journal_init: last flushed %d\n", 
+         header.j_last_flush_trans_id);
+#endif
+
+  while (1) 
+    {
+      journal_read (ffi, desc_block, sizeof (desc), (char *) &desc);
+      if (substring (JOURNAL_DESC_MAGIC, desc.j_magic)
+         || desc.j_trans_id != next_trans_id
+         || desc.j_mount_id != header.j_mount_id)
+       /* no more valid transactions */
+       break;
+      
+      commit_block = (desc_block + desc.j_len + 1) & (block_count - 1);
+      journal_read (ffi, commit_block, sizeof (commit), (char *) &commit);
+      if (desc.j_trans_id != commit.j_trans_id
+         || desc.j_len != commit.j_len)
+       /* no more valid transactions */
+       break;
+      
+#ifdef REISERDEBUG
+      printf ("Found valid transaction %d/%d at %d.\n", 
+             desc.j_trans_id, desc.j_mount_id, desc_block);
+#endif
+
+      next_trans_id++;
+      if (journal_table < JOURNAL_END)
+       {
+         if ((journal_table + 1 + desc.j_len) >= JOURNAL_END)
+           {
+             /* The table is almost full; mark the end of the cached
+              * journal.*/
+             *journal_table = 0xffffffff;
+             journal_table = JOURNAL_END;
+           }
+         else
+           {
+             int i;
+             /* Cache the length and the realblock numbers in the table.
+              * The block number of descriptor can easily be computed.
+              * and need not to be stored here.
+              */
+             *journal_table++ = desc.j_len;
+             for (i = 0; i < desc.j_len && i < JOURNAL_TRANS_HALF; i++)
+               {
+                 *journal_table++ = desc.j_realblock[i];
+#ifdef REISERDEBUG
+                 printf ("block %d is in journal %d.\n", 
+                         desc.j_realblock[i], desc_block);
+#endif
+               }
+             for (     ; i < desc.j_len; i++)
+               {
+                 *journal_table++ = commit.j_realblock[i-JOURNAL_TRANS_HALF];
+#ifdef REISERDEBUG
+                 printf ("block %d is in journal %d.\n", 
+                         commit.j_realblock[i-JOURNAL_TRANS_HALF], 
+                         desc_block);
+#endif
+               }
+           }
+       }
+      desc_block = (commit_block + 1) & (block_count - 1);
+    }
+#ifdef REISERDEBUG
+  printf ("Transaction %d/%d at %d isn't valid.\n", 
+         desc.j_trans_id, desc.j_mount_id, desc_block);
+#endif
+
+  INFO->journal_transactions
+    = next_trans_id - header.j_last_flush_trans_id - 1;
+  return errnum == 0;
+}
+
+/* check filesystem types and read superblock into memory buffer */
+int
+reiserfs_mount (fsi_file_t *ffi)
+{
+  struct reiserfs_super_block super;
+  int superblock = REISERFS_DISK_OFFSET_IN_BYTES >> SECTOR_BITS;
+
+  if (/*part_length < superblock + (sizeof (super) >> SECTOR_BITS)
+      || */ !devread (ffi, superblock, 0, sizeof (struct 
reiserfs_super_block), 
+               (char *) &super)
+      || (substring (REISER3FS_SUPER_MAGIC_STRING, super.s_magic) > 0
+         && substring (REISER2FS_SUPER_MAGIC_STRING, super.s_magic) > 0
+         && substring (REISERFS_SUPER_MAGIC_STRING, super.s_magic) > 0)
+      || (/* check that this is not a copy inside the journal log */
+         super.s_journal_block * super.s_blocksize
+         <= REISERFS_DISK_OFFSET_IN_BYTES))
+    {
+      /* Try old super block position */
+      superblock = REISERFS_OLD_DISK_OFFSET_IN_BYTES >> SECTOR_BITS;
+      if (/*part_length < superblock + (sizeof (super) >> SECTOR_BITS)
+       || */ ! devread (ffi, superblock, 0, sizeof (struct 
reiserfs_super_block), 
+                       (char *) &super))
+       return 0;
+
+      if (substring (REISER3FS_SUPER_MAGIC_STRING, super.s_magic) > 0
+         && substring (REISER2FS_SUPER_MAGIC_STRING, super.s_magic) > 0
+         && substring (REISERFS_SUPER_MAGIC_STRING, super.s_magic) > 0)
+       {
+         /* pre journaling super block ? */
+         if (substring (REISERFS_SUPER_MAGIC_STRING, 
+                        (char*) ((char *) &super + 20)) > 0)
+           return 0;
+         
+         super.s_blocksize = REISERFS_OLD_BLOCKSIZE;
+         super.s_journal_block = 0;
+         super.s_version = 0;
+       }
+    }
+
+  /* check the version number.  */
+  if (super.s_version > REISERFS_MAX_SUPPORTED_VERSION)
+    return 0;
+  
+  INFO->version = super.s_version;
+  INFO->blocksize = super.s_blocksize;
+  INFO->fullblocksize_shift = log2 (super.s_blocksize);
+  INFO->blocksize_shift = INFO->fullblocksize_shift - SECTOR_BITS;
+  INFO->cached_slots = 
+    (FSYSREISER_CACHE_SIZE >> INFO->fullblocksize_shift) - 1;
+
+#ifdef REISERDEBUG
+  printf ("reiserfs_mount: version=%d, blocksize=%d\n", 
+         INFO->version, INFO->blocksize);
+#endif /* REISERDEBUG */
+
+  /* Clear node cache. */
+  memset (INFO->blocks, 0, sizeof (INFO->blocks));
+
+  if (super.s_blocksize < FSYSREISER_MIN_BLOCKSIZE
+      || super.s_blocksize > FSYSREISER_MAX_BLOCKSIZE
+      || (SECTOR_SIZE << INFO->blocksize_shift) != super.s_blocksize)
+    return 0;
+
+  /* Initialize journal code.  If something fails we end with zero
+   * journal_transactions, so we don't access the journal at all.  
+   */
+  INFO->journal_transactions = 0;
+  if (super.s_journal_block != 0 && super.s_journal_dev == 0)
+    {
+      INFO->journal_block = super.s_journal_block;
+      INFO->journal_block_count = super.s_journal_size;
+      if (is_power_of_two (INFO->journal_block_count))
+       journal_init (ffi);
+
+      /* Read in super block again, maybe it is in the journal */
+      block_read (ffi, superblock >> INFO->blocksize_shift, 
+                 0, sizeof (struct reiserfs_super_block), (char *) &super);
+    }
+
+  if (! block_read (ffi, super.s_root_block, 0, INFO->blocksize, (char*) ROOT))
+    return 0;
+  
+  INFO->tree_depth = BLOCKHEAD (ROOT)->blk_level;
+  
+#ifdef REISERDEBUG
+  printf ("root read_in: block=%d, depth=%d\n", 
+         super.s_root_block, INFO->tree_depth);
+#endif /* REISERDEBUG */
+
+  if (INFO->tree_depth >= MAX_HEIGHT)
+    return 0;
+  if (INFO->tree_depth == DISK_LEAF_NODE_LEVEL)
+    {
+      /* There is only one node in the whole filesystem, 
+       * which is simultanously leaf and root */
+      memcpy (LEAF, ROOT, INFO->blocksize);
+    }
+  return 1;
+}
+
+/***************** TREE ACCESSING METHODS *****************************/
+
+/* I assume you are familiar with the ReiserFS tree, if not go to
+ * http://www.namesys.com/content_table.html
+ *
+ * My tree node cache is organized as following
+ *   0   ROOT node
+ *   1   LEAF node  (if the ROOT is also a LEAF it is copied here
+ *   2-n other nodes on current path from bottom to top.  
+ *       if there is not enough space in the cache, the top most are
+ *       omitted.
+ *
+ * I have only two methods to find a key in the tree:
+ *   search_stat(dir_id, objectid) searches for the stat entry (always
+ *       the first entry) of an object.
+ *   next_key() gets the next key in tree order.
+ *
+ * This means, that I can only sequential reads of files are
+ * efficient, but this really doesn't hurt for grub.  
+ */
+
+/* Read in the node at the current path and depth into the node cache.
+ * You must set INFO->blocks[depth] before.
+ */
+static char *
+read_tree_node (fsi_file_t *ffi, unsigned int blockNr, int depth)
+{
+  char* cache = CACHE(depth);
+  int num_cached = INFO->cached_slots;
+  if (depth < num_cached)
+    {
+      /* This is the cached part of the path.  Check if same block is
+       * needed.  
+       */
+      if (blockNr == INFO->blocks[depth])
+       return cache;
+    }
+  else
+    cache = CACHE(num_cached);
+
+#ifdef REISERDEBUG
+  printf ("  next read_in: block=%d (depth=%d)\n",
+         blockNr, depth);
+#endif /* REISERDEBUG */
+  if (! block_read (ffi, blockNr, 0, INFO->blocksize, cache))
+    return 0;
+  /* Make sure it has the right node level */
+  if (BLOCKHEAD (cache)->blk_level != depth)
+    {
+      errnum = ERR_FSYS_CORRUPT;
+      return 0;
+    }
+
+  INFO->blocks[depth] = blockNr;
+  return cache;
+}
+
+/* Get the next key, i.e. the key following the last retrieved key in
+ * tree order.  INFO->current_ih and 
+ * INFO->current_info are adapted accordingly.  */
+static int
+next_key (fsi_file_t *ffi)
+{
+  int depth;
+  struct item_head *ih = INFO->current_ih + 1;
+  char *cache;
+  
+#ifdef REISERDEBUG
+  printf ("next_key:\n  old ih: key %d:%d:%d:%d version:%d\n", 
+         INFO->current_ih->ih_key.k_dir_id, 
+         INFO->current_ih->ih_key.k_objectid, 
+         INFO->current_ih->ih_key.u.v1.k_offset,
+         INFO->current_ih->ih_key.u.v1.k_uniqueness,
+         INFO->current_ih->ih_version);
+#endif /* REISERDEBUG */
+  
+  if (ih == &ITEMHEAD[BLOCKHEAD (LEAF)->blk_nr_item])
+    {
+      depth = DISK_LEAF_NODE_LEVEL;
+      /* The last item, was the last in the leaf node.  
+       * Read in the next block 
+       */
+      do
+       {
+         if (depth == INFO->tree_depth)
+           {
+             /* There are no more keys at all.
+              * Return a dummy item with MAX_KEY */
+             ih = (struct item_head *) &BLOCKHEAD (LEAF)->blk_right_delim_key;
+             goto found;
+           }
+         depth++;
+#ifdef REISERDEBUG
+         printf ("  depth=%d, i=%d\n", depth, INFO->next_key_nr[depth]);
+#endif /* REISERDEBUG */
+       }
+      while (INFO->next_key_nr[depth] == 0);
+      
+      if (depth == INFO->tree_depth)
+       cache = ROOT;
+      else if (depth <= INFO->cached_slots)
+       cache = CACHE (depth);
+      else 
+       {
+         cache = read_tree_node (ffi, INFO->blocks[depth], depth);
+         if (! cache)
+           return 0;
+       }
+      
+      do
+       {
+         int nr_item = BLOCKHEAD (cache)->blk_nr_item;
+         int key_nr = INFO->next_key_nr[depth]++;
+#ifdef REISERDEBUG
+         printf ("  depth=%d, i=%d/%d\n", depth, key_nr, nr_item);
+#endif /* REISERDEBUG */
+         if (key_nr == nr_item)
+           /* This is the last item in this block, set the next_key_nr to 0 */
+           INFO->next_key_nr[depth] = 0;
+
+         cache = read_tree_node (ffi, DC (cache)[key_nr].dc_block_number, 
--depth);
+         if (! cache)
+           return 0;
+       }
+      while (depth > DISK_LEAF_NODE_LEVEL);
+      
+      ih = ITEMHEAD;
+    }
+ found:
+  INFO->current_ih   = ih;
+  INFO->current_item = &LEAF[ih->ih_item_location];
+#ifdef REISERDEBUG
+  printf ("  new ih: key %d:%d:%d:%d version:%d\n", 
+         INFO->current_ih->ih_key.k_dir_id, 
+         INFO->current_ih->ih_key.k_objectid, 
+         INFO->current_ih->ih_key.u.v1.k_offset,
+         INFO->current_ih->ih_key.u.v1.k_uniqueness,
+         INFO->current_ih->ih_version);
+#endif /* REISERDEBUG */
+  return 1;
+}
+
+/* preconditions: reiserfs_mount already executed, therefore 
+ *   INFO block is valid
+ * returns: 0 if error (errnum is set), 
+ *   nonzero iff we were able to find the key successfully.
+ * postconditions: on a nonzero return, the current_ih and 
+ *   current_item fields describe the key that equals the
+ *   searched key.  INFO->next_key contains the next key after
+ *   the searched key.
+ * side effects: messes around with the cache.
+ */
+static int
+search_stat (fsi_file_t *ffi, __u32 dir_id, __u32 objectid) 
+{
+  char *cache;
+  int depth;
+  int nr_item;
+  int i;
+  struct item_head *ih;
+#ifdef REISERDEBUG
+  printf ("search_stat:\n  key %d:%d:0:0\n", dir_id, objectid);
+#endif /* REISERDEBUG */
+  
+  depth = INFO->tree_depth;
+  cache = ROOT;
+  
+  while (depth > DISK_LEAF_NODE_LEVEL)
+    {
+      struct key *key;
+      nr_item = BLOCKHEAD (cache)->blk_nr_item;
+      
+      key = KEY (cache);
+      
+      for (i = 0; i < nr_item; i++) 
+       {
+         if (key->k_dir_id > dir_id
+             || (key->k_dir_id == dir_id 
+                 && (key->k_objectid > objectid
+                     || (key->k_objectid == objectid
+                         && (key->u.v1.k_offset
+                             | key->u.v1.k_uniqueness) > 0))))
+           break;
+         key++;
+       }
+      
+#ifdef REISERDEBUG
+      printf ("  depth=%d, i=%d/%d\n", depth, i, nr_item);
+#endif /* REISERDEBUG */
+      INFO->next_key_nr[depth] = (i == nr_item) ? 0 : i+1;
+      cache = read_tree_node (ffi, DC (cache)[i].dc_block_number, --depth);
+      if (! cache)
+       return 0;
+    }
+  
+  /* cache == LEAF */
+  nr_item = BLOCKHEAD (LEAF)->blk_nr_item;
+  ih = ITEMHEAD;
+  for (i = 0; i < nr_item; i++) 
+    {
+      if (ih->ih_key.k_dir_id == dir_id 
+         && ih->ih_key.k_objectid == objectid
+         && ih->ih_key.u.v1.k_offset == 0
+         && ih->ih_key.u.v1.k_uniqueness == 0)
+       {
+#ifdef REISERDEBUG
+         printf ("  depth=%d, i=%d/%d\n", depth, i, nr_item);
+#endif /* REISERDEBUG */
+         INFO->current_ih   = ih;
+         INFO->current_item = &LEAF[ih->ih_item_location];
+         return 1;
+       }
+      ih++;
+    }
+  errnum = ERR_FSYS_CORRUPT;
+  return 0;
+}
+
+int
+reiserfs_read (fsi_file_t *ffi, char *buf, int len)
+{
+  unsigned int blocksize;
+  unsigned int offset;
+  unsigned int to_read;
+  char *prev_buf = buf;
+  
+#ifdef REISERDEBUG
+  printf ("reiserfs_read: filepos=%d len=%d, offset=%x:%x\n",
+         filepos, len, (__u64) IH_KEY_OFFSET (INFO->current_ih) - 1);
+#endif /* REISERDEBUG */
+  
+  if (INFO->current_ih->ih_key.k_objectid != INFO->fileinfo.k_objectid
+      || IH_KEY_OFFSET (INFO->current_ih) > filepos + 1)
+    {
+      search_stat (ffi, INFO->fileinfo.k_dir_id, INFO->fileinfo.k_objectid);
+      goto get_next_key;
+    }
+  
+  while (! errnum)
+    {
+      if (INFO->current_ih->ih_key.k_objectid != INFO->fileinfo.k_objectid)
+       break;
+      
+      offset = filepos - IH_KEY_OFFSET (INFO->current_ih) + 1;
+      blocksize = INFO->current_ih->ih_item_len;
+      
+#ifdef REISERDEBUG
+      printf ("  loop: filepos=%d len=%d, offset=%d blocksize=%d\n",
+             filepos, len, offset, blocksize);
+#endif /* REISERDEBUG */
+      
+      if (IH_KEY_ISTYPE(INFO->current_ih, TYPE_DIRECT)
+         && offset < blocksize)
+       {
+#ifdef REISERDEBUG
+         printf ("direct_read: offset=%d, blocksize=%d\n",
+                 offset, blocksize);
+#endif /* REISERDEBUG */
+         to_read = blocksize - offset;
+         if (to_read > len)
+           to_read = len;
+         
+         if (disk_read_hook != NULL)
+           {
+             disk_read_func = disk_read_hook;
+             
+             block_read (ffi, INFO->blocks[DISK_LEAF_NODE_LEVEL],
+                         (INFO->current_item - LEAF + offset), to_read, buf);
+             
+             disk_read_func = NULL;
+           }
+         else
+           memcpy (buf, INFO->current_item + offset, to_read);
+         goto update_buf_len;
+       }
+      else if (IH_KEY_ISTYPE(INFO->current_ih, TYPE_INDIRECT))
+       {
+         blocksize = (blocksize >> 2) << INFO->fullblocksize_shift;
+#ifdef REISERDEBUG
+         printf ("indirect_read: offset=%d, blocksize=%d\n",
+                 offset, blocksize);
+#endif /* REISERDEBUG */
+         
+         while (offset < blocksize)
+           {
+             __u32 blocknr = ((__u32 *) INFO->current_item)
+               [offset >> INFO->fullblocksize_shift];
+             int blk_offset = offset & (INFO->blocksize-1);
+             
+             to_read = INFO->blocksize - blk_offset;
+             if (to_read > len)
+               to_read = len;
+             
+             disk_read_func = disk_read_hook;
+             
+             /* Journal is only for meta data.  Data blocks can be read
+              * directly without using block_read
+              */
+             devread (ffi, blocknr << INFO->blocksize_shift,
+                      blk_offset, to_read, buf);
+             
+             disk_read_func = NULL;
+           update_buf_len:
+             len -= to_read;
+             buf += to_read;
+             offset += to_read;
+             filepos += to_read;
+             if (len == 0)
+               goto done;
+           }
+       }
+    get_next_key:
+      next_key (ffi);
+    }
+ done:
+  return errnum ? 0 : buf - prev_buf;
+}
+
+
+/* preconditions: reiserfs_mount already executed, therefore 
+ *   INFO block is valid
+ * returns: 0 if error, nonzero iff we were able to find the file successfully
+ * postconditions: on a nonzero return, INFO->fileinfo contains the info
+ *   of the file we were trying to look up, filepos is 0 and filemax is 
+ *   the size of the file.
+ */
+int
+reiserfs_dir (fsi_file_t *ffi, char *dirname)
+{
+  struct reiserfs_de_head *de_head;
+  char *rest, ch;
+  __u32 dir_id, objectid, parent_dir_id = 0, parent_objectid = 0;
+#ifndef STAGE1_5
+  int do_possibilities = 0;
+#endif /* ! STAGE1_5 */
+  char linkbuf[PATH_MAX];      /* buffer for following symbolic links */
+  int link_count = 0;
+  int mode;
+
+  dir_id = REISERFS_ROOT_PARENT_OBJECTID;
+  objectid = REISERFS_ROOT_OBJECTID;
+  
+  while (1)
+    {
+#ifdef REISERDEBUG
+      printf ("dirname=%s\n", dirname);
+#endif /* REISERDEBUG */
+      
+      /* Search for the stat info first. */
+      if (! search_stat (ffi, dir_id, objectid))
+       return 0;
+      
+#ifdef REISERDEBUG
+      printf ("sd_mode=%x sd_size=%d\n", 
+             ((struct stat_data *) INFO->current_item)->sd_mode,
+             ((struct stat_data *) INFO->current_item)->sd_size);
+#endif /* REISERDEBUG */
+      
+      mode = ((struct stat_data *) INFO->current_item)->sd_mode;
+
+      /* If we've got a symbolic link, then chase it. */
+      if (S_ISLNK (mode))
+       {
+         int len;
+         if (++link_count > MAX_LINK_COUNT)
+           {
+             errnum = ERR_SYMLINK_LOOP;
+             return 0;
+           }
+
+         /* Get the symlink size. */
+         filemax = ((struct stat_data *) INFO->current_item)->sd_size;
+
+         /* Find out how long our remaining name is. */
+         len = 0;
+         while (dirname[len] && !isspace (dirname[len]))
+           len++;
+
+         if (filemax + len > sizeof (linkbuf) - 1)
+           {
+             errnum = ERR_FILELENGTH;
+             return 0;
+           }
+         
+         /* Copy the remaining name to the end of the symlink data.
+            Note that DIRNAME and LINKBUF may overlap! */
+         grub_memmove (linkbuf + filemax, dirname, len+1);
+
+         INFO->fileinfo.k_dir_id = dir_id;
+         INFO->fileinfo.k_objectid = objectid;
+         filepos = 0;
+         if (! next_key (ffi)
+             || reiserfs_read (ffi, linkbuf, filemax) != filemax)
+           {
+             if (! errnum)
+               errnum = ERR_FSYS_CORRUPT;
+             return 0;
+           }
+
+#ifdef REISERDEBUG
+         printf ("symlink=%s\n", linkbuf);
+#endif /* REISERDEBUG */
+
+         dirname = linkbuf;
+         if (*dirname == '/')
+           {
+             /* It's an absolute link, so look it up in root. */
+             dir_id = REISERFS_ROOT_PARENT_OBJECTID;
+             objectid = REISERFS_ROOT_OBJECTID;
+           }
+         else
+           {
+             /* Relative, so look it up in our parent directory. */
+             dir_id   = parent_dir_id;
+             objectid = parent_objectid;
+           }
+
+         /* Now lookup the new name. */
+         continue;
+       }
+
+      /* if we have a real file (and we're not just printing possibilities),
+        then this is where we want to exit */
+      
+      if (! *dirname || isspace (*dirname))
+       {
+         if (! S_ISREG (mode))
+           {
+             errnum = ERR_BAD_FILETYPE;
+             return 0;
+           }
+         
+         filepos = 0;
+         filemax = ((struct stat_data *) INFO->current_item)->sd_size;
+         
+         /* If this is a new stat data and size is > 4GB set filemax to 
+          * maximum
+          */
+         if (INFO->current_ih->ih_version == ITEM_VERSION_2
+             && ((struct stat_data *) INFO->current_item)->sd_size_hi > 0)
+           filemax = 0xffffffff;
+         
+         INFO->fileinfo.k_dir_id = dir_id;
+         INFO->fileinfo.k_objectid = objectid;
+         return next_key (ffi);
+       }
+      
+      /* continue with the file/directory name interpretation */
+      while (*dirname == '/')
+       dirname++;
+      if (! S_ISDIR (mode))
+       {
+         errnum = ERR_BAD_FILETYPE;
+         return 0;
+       }
+      for (rest = dirname; (ch = *rest) && ! isspace (ch) && ch != '/'; 
rest++);
+      *rest = 0;
+      
+# ifndef STAGE1_5
+      if (print_possibilities && ch != '/')
+       do_possibilities = 1;
+# endif /* ! STAGE1_5 */
+      
+      while (1)
+       {
+         char *name_end;
+         int num_entries;
+         
+         if (! next_key (ffi))
+           return 0;
+#ifdef REISERDEBUG
+         printf ("ih: key %d:%d:%d:%d version:%d\n", 
+                 INFO->current_ih->ih_key.k_dir_id, 
+                 INFO->current_ih->ih_key.k_objectid, 
+                 INFO->current_ih->ih_key.u.v1.k_offset,
+                 INFO->current_ih->ih_key.u.v1.k_uniqueness,
+                 INFO->current_ih->ih_version);
+#endif /* REISERDEBUG */
+         
+         if (INFO->current_ih->ih_key.k_objectid != objectid)
+           break;
+         
+         name_end = INFO->current_item + INFO->current_ih->ih_item_len;
+         de_head = (struct reiserfs_de_head *) INFO->current_item;
+         num_entries = INFO->current_ih->u.ih_entry_count;
+         while (num_entries > 0)
+           {
+             char *filename = INFO->current_item + de_head->deh_location;
+             char  tmp = *name_end;
+             if ((de_head->deh_state & DEH_Visible))
+               {
+                 int cmp;
+                 /* Directory names in ReiserFS are not null
+                  * terminated.  We write a temporary 0 behind it.
+                  * NOTE: that this may overwrite the first block in
+                  * the tree cache.  That doesn't hurt as long as we
+                  * don't call next_key () in between.  
+                  */
+                 *name_end = 0;
+                 cmp = substring (dirname, filename);
+                 *name_end = tmp;
+# ifndef STAGE1_5
+                 if (do_possibilities)
+                   {
+                     if (cmp <= 0)
+                       {
+                         if (print_possibilities > 0)
+                           print_possibilities = -print_possibilities;
+                         *name_end = 0;
+                         print_a_completion (filename);
+                         *name_end = tmp;
+                       }
+                   }
+                 else
+# endif /* ! STAGE1_5 */
+                   if (cmp == 0)
+                     goto found;
+               }
+             /* The beginning of this name marks the end of the next name.
+              */
+             name_end = filename;
+             de_head++;
+             num_entries--;
+           }
+       }
+      
+# ifndef STAGE1_5
+      if (print_possibilities < 0)
+       return 1;
+# endif /* ! STAGE1_5 */
+      
+      errnum = ERR_FILE_NOT_FOUND;
+      *rest = ch;
+      return 0;
+      
+    found:
+      
+      *rest = ch;
+      dirname = rest;
+
+      parent_dir_id = dir_id;
+      parent_objectid = objectid;
+      dir_id = de_head->deh_dir_id;
+      objectid = de_head->deh_objectid;
+    }
+}
+
+int
+reiserfs_embed (fsi_file_t *ffi, int *start_sector, int needed_sectors)
+{
+  struct reiserfs_super_block super;
+  int num_sectors;
+  
+  if (! devread (ffi, REISERFS_DISK_OFFSET_IN_BYTES >> SECTOR_BITS, 0, 
+                sizeof (struct reiserfs_super_block), (char *) &super))
+    return 0;
+  
+  *start_sector = 1; /* reserve first sector for stage1 */
+  if ((substring (REISERFS_SUPER_MAGIC_STRING, super.s_magic) <= 0
+       || substring (REISER2FS_SUPER_MAGIC_STRING, super.s_magic) <= 0
+       || substring (REISER3FS_SUPER_MAGIC_STRING, super.s_magic) <= 0)
+      && (/* check that this is not a super block copy inside
+          * the journal log */
+         super.s_journal_block * super.s_blocksize 
+         > REISERFS_DISK_OFFSET_IN_BYTES))
+    num_sectors = (REISERFS_DISK_OFFSET_IN_BYTES >> SECTOR_BITS) - 1;
+  else
+    num_sectors = (REISERFS_OLD_DISK_OFFSET_IN_BYTES >> SECTOR_BITS) - 1;
+  
+  return (needed_sectors <= num_sectors);
+}
+
+fsi_plugin_ops_t *
+fsi_init_plugin(int version, fsi_plugin_t *fp, const char **name)
+{
+       static fsig_plugin_ops_t ops = {
+               FSIMAGE_PLUGIN_VERSION,
+               .fpo_mount = reiserfs_mount,
+               .fpo_dir = reiserfs_dir,
+               .fpo_read = reiserfs_read
+       };
+
+       *name = "reiserfs";
+       return (fsig_init(fp, &ops));
+}
diff --git a/tools/libfsimage/ufs/Makefile b/tools/libfsimage/ufs/Makefile
new file mode 100644
--- /dev/null
+++ b/tools/libfsimage/ufs/Makefile
@@ -0,0 +1,13 @@
+XEN_ROOT = ../../..
+
+LIB_SRCS-y = fsys_ufs.c
+
+FS = ufs
+
+.PHONY: all
+all: fs-all
+
+.PHONY: install
+install: fs-install
+
+include $(XEN_ROOT)/tools/libfsimage/Rules.mk
diff --git a/tools/libfsimage/ufs/fsys_ufs.c b/tools/libfsimage/ufs/fsys_ufs.c
new file mode 100644
--- /dev/null
+++ b/tools/libfsimage/ufs/fsys_ufs.c
@@ -0,0 +1,276 @@
+/*  
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2006 Free Software Foundation, Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/*
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* From Solaris usr/src/stand/lib/fs/ufs/ufsops.c */
+
+#include <fsimage_grub.h>
+
+#include "ufs.h"
+
+/* These are the pools of buffers, etc. */
+
+#define SUPERBLOCK ((struct fs *)(FSYS_BUF + 0x2000))
+#define        INODE ((struct icommon *)(FSYS_BUF + 0x1000))
+#define DIRENT (FSYS_BUF + 0x4000)
+#define INDIRBLK1 ((grub_daddr32_t *)(FSYS_BUF + 0x4000)) /* 2+ indir blk */
+#define        INDIRBLK0 ((grub_daddr32_t *)(FSYS_BUF+ 0x6000))  /* 1st 
indirect blk */
+
+#define        indirblk0 (*fsig_int1(ffi))
+#define        indirblk1 (*fsig_int2(ffi))
+
+static int openi(fsi_file_t *, grub_ino_t);
+static grub_ino_t dlook(fsi_file_t *, grub_ino_t, char *);
+static grub_daddr32_t sbmap(fsi_file_t *, grub_daddr32_t);
+
+/* read superblock and check fs magic */
+int
+ufs_mount(fsi_file_t *ffi)
+{
+       if (/*! IS_PC_SLICE_TYPE_SOLARIS(current_slice) || */
+           !devread(ffi, UFS_SBLOCK, 0, UFS_SBSIZE, (char *)SUPERBLOCK) ||
+           SUPERBLOCK->fs_magic != UFS_MAGIC)
+               return 0;
+
+       return 1;
+}
+
+
+/*
+ * searching for a file, if successful, inode will be loaded in INODE
+ * The entry point should really be named ufs_open(char *pathname).
+ * For now, keep it consistent with the rest of fsys modules.
+ */
+int
+ufs_dir(fsi_file_t *ffi, char *dirname)
+{
+       grub_ino_t inode = ROOTINO;     /* start from root */
+       char *fname, ch;
+
+       indirblk0 = indirblk1 = 0;
+
+       /* skip leading slashes */
+       while (*dirname == '/')
+               dirname++;
+
+       while (inode && *dirname && !isspace(*dirname)) {
+               if (!openi(ffi, inode))
+                       return 0;
+
+               /* parse for next path component */
+               fname = dirname;
+               while (*dirname && !isspace(*dirname) && *dirname != '/')
+                       dirname++;
+               ch = *dirname;
+               *dirname = 0;   /* ensure null termination */
+
+               inode = dlook(ffi, inode, fname);
+               *dirname = ch;
+               while (*dirname == '/')
+                       dirname++;
+       }
+
+       /* return 1 only if inode exists and is a regular file */
+       if  (! openi(ffi, inode))
+               return (0);
+       filepos = 0;
+       filemax = INODE->ic_sizelo;
+       return (inode && ((INODE->ic_smode & IFMT) == IFREG));
+}
+
+/*
+ * This is the high-level read function.
+ */
+int
+ufs_read(fsi_file_t *ffi, char *buf, int len)
+{
+       int off, size, ret = 0, ok;
+       grub_daddr32_t lblk, dblk;
+
+       while (len) {
+               off = blkoff(SUPERBLOCK, filepos);
+               lblk = lblkno(SUPERBLOCK, filepos);
+               size = SUPERBLOCK->fs_bsize;
+               size -= off;
+               if (size > len)
+                       size = len;
+
+               if ((dblk = sbmap(ffi, lblk)) <= 0) {
+                       /* we are in a file hole, just zero the buf */
+                       grub_memset(buf, 0, size);
+               } else {
+                       disk_read_func = disk_read_hook;
+                       ok = devread(ffi, fsbtodb(SUPERBLOCK, dblk),
+                               off, size, buf);
+                       disk_read_func = 0;
+                       if (!ok)
+                               return 0;
+               }
+               buf += size;
+               len -= size;
+               filepos += size;
+               ret += size;
+       }
+
+       return (ret);
+}
+
+int
+ufs_embed (int *start_sector, int needed_sectors)
+{
+       if (needed_sectors > 14)
+               return 0;
+
+       *start_sector = 2;
+       return 1;
+}
+
+/* read inode and place content in INODE */
+static int
+openi(fsi_file_t *ffi, grub_ino_t inode)
+{
+       grub_daddr32_t dblk;
+       int off;
+
+       /* get block and byte offset into the block */
+       dblk = fsbtodb(SUPERBLOCK, itod(SUPERBLOCK, inode));
+       off = itoo(SUPERBLOCK, inode) * sizeof (struct icommon);
+
+       return (devread(ffi, dblk, off, sizeof (struct icommon), (char 
*)INODE));
+}
+
+/*
+ * Performs fileblock mapping. Convert file block no. to disk block no.
+ * Returns 0 when block doesn't exist and <0 when block isn't initialized
+ * (i.e belongs to a hole in the file).
+ */
+grub_daddr32_t
+sbmap(fsi_file_t *ffi, grub_daddr32_t bn)
+{
+       int level, bound, i, index;
+       grub_daddr32_t nb, blkno;
+       grub_daddr32_t *db = INODE->ic_db;
+
+       /* blocks 0..UFS_NDADDR are direct blocks */
+       if (bn < UFS_NDADDR) {
+               return db[bn];
+       }
+
+       /* determine how many levels of indirection. */
+       level = 0;
+       bn -= UFS_NDADDR;
+       bound = UFS_NINDIR(SUPERBLOCK);
+       while (bn >= bound) {
+               level++;
+               bn -= bound;
+               bound *= UFS_NINDIR(SUPERBLOCK);
+       }
+       if (level >= UFS_NIADDR)        /* bn too big */
+               return ((grub_daddr32_t)0);
+
+       /* fetch the first indirect block */
+       nb = INODE->ic_ib[level];
+       if (nb == 0) {
+               return ((grub_daddr32_t)0);
+       }
+       if (indirblk0 != nb) {
+               indirblk0 = 0;
+               blkno = fsbtodb(SUPERBLOCK, nb);
+               if (!devread(ffi, blkno, 0, SUPERBLOCK->fs_bsize,
+                   (char *)INDIRBLK0))
+                       return (0);
+               indirblk0 = nb;
+       }
+       bound /= UFS_NINDIR(SUPERBLOCK);
+       index = (bn / bound) % UFS_NINDIR(SUPERBLOCK);
+       nb = INDIRBLK0[index];
+
+       /* fetch through the indirect blocks */
+       for (i = 1; i <= level; i++) {
+               if (indirblk1 != nb) {
+                       blkno = fsbtodb(SUPERBLOCK, nb);
+                       if (!devread(ffi, blkno, 0, SUPERBLOCK->fs_bsize,
+                           (char *)INDIRBLK1))
+                               return (0);
+                       indirblk1 = nb;
+               }
+               bound /= UFS_NINDIR(SUPERBLOCK);
+               index = (bn / bound) % UFS_NINDIR(SUPERBLOCK);
+               nb = INDIRBLK1[index];
+               if (nb == 0)
+                       return ((grub_daddr32_t)0);
+       }
+
+       return (nb);
+}
+
+/* search directory content for name, return inode number */
+static grub_ino_t
+dlook(fsi_file_t *ffi, grub_ino_t dir_ino, char *name)
+{
+       int loc, off;
+       grub_daddr32_t lbn, dbn, dblk;
+       struct direct *dp;
+
+       if ((INODE->ic_smode & IFMT) != IFDIR)
+               return 0;
+
+       loc = 0;
+       while (loc < INODE->ic_sizelo) {
+               /* offset into block */
+               off = blkoff(SUPERBLOCK, loc);
+               if (off == 0) {         /* need to read in a new block */
+                       /* get logical block number */
+                       lbn = lblkno(SUPERBLOCK, loc);
+                       /* resolve indrect blocks */
+                       dbn = sbmap(ffi, lbn);
+                       if (dbn == 0)
+                               return (0);
+
+                       dblk = fsbtodb(SUPERBLOCK, dbn);
+                       if (!devread(ffi, dblk, 0, SUPERBLOCK->fs_bsize,
+                           (char *)DIRENT)) {
+                               return 0;
+                       }
+               }
+
+               dp = (struct direct *)(DIRENT + off);
+               if (dp->d_ino && substring(name, dp->d_name) == 0)
+                       return (dp->d_ino);
+               loc += dp->d_reclen;
+       }
+       return (0);
+}
+
+fsi_plugin_ops_t *
+fsi_init_plugin(int version, fsi_plugin_t *fp, const char **name)
+{
+       static fsig_plugin_ops_t ops = {
+               FSIMAGE_PLUGIN_VERSION,
+               .fpo_mount = ufs_mount,
+               .fpo_dir = ufs_dir,
+               .fpo_read = ufs_read
+       };
+
+       *name = "ufs";
+       return (fsig_init(fp, &ops));
+}
diff --git a/tools/libfsimage/ufs/ufs.h b/tools/libfsimage/ufs/ufs.h
new file mode 100644
--- /dev/null
+++ b/tools/libfsimage/ufs/ufs.h
@@ -0,0 +1,228 @@
+/*
+ * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _GRUB_UFS_H
+#define _GRUB_UFS_H_
+
+/* ufs specific constants */
+#define UFS_SBLOCK     16
+#define UFS_SBSIZE     8192
+#define        UFS_MAGIC       0x011954
+#define        ROOTINO         2       /* i number of all roots */
+#define UFS_NDADDR     12      /* direct blocks */
+#define        UFS_NIADDR      3       /* indirect blocks */
+#define        MAXMNTLEN       512
+#define        MAXCSBUFS       32
+#define        MAXNAMELEN      256
+
+/* file types */
+#define        IFMT            0xf000
+#define        IFREG           0x8000
+#define        IFDIR           0x4000
+
+typedef unsigned char  grub_uchar_t;
+typedef        unsigned short  grub_ushort_t;
+typedef        unsigned short  grub_o_mode_t;
+typedef        unsigned short  grub_o_uid_t;
+typedef        unsigned short  grub_o_gid_t;
+typedef        uint32_t        grub_ino_t;
+typedef        int32_t         grub_int32_t;
+typedef        int32_t         grub_uid_t;
+typedef        int32_t         grub_gid_t;
+typedef uint32_t       grub_uint32_t;
+typedef uint32_t       grub_daddr32_t;
+typedef        uint32_t        grub_time32_t;
+typedef struct { int val[2]; } grub_quad_t;
+
+struct timeval32 {
+       grub_time32_t   tv_sec;
+       grub_int32_t    tv_usec;
+};
+
+/*
+ * Per cylinder group information; summarized in blocks allocated
+ * from first cylinder group data blocks.  These blocks have to be
+ * read in from fs_csaddr (size fs_cssize) in addition to the
+ * super block.
+ *
+ * N.B. sizeof (struct csum) must be a power of two in order for
+ * the ``fs_cs'' macro to work (see below).
+ */
+struct csum {
+       grub_int32_t    cs_ndir;        /* number of directories */
+       grub_int32_t    cs_nbfree;      /* number of free blocks */
+       grub_int32_t    cs_nifree;      /* number of free inodes */
+       grub_int32_t    cs_nffree;      /* number of free frags */
+};
+
+/* Ufs super block */
+struct fs {
+       grub_uint32_t   fs_link;        /* linked list of file systems */
+       grub_uint32_t   fs_rolled;      /* logging only: fs fully rolled */
+       grub_daddr32_t  fs_sblkno;      /* addr of super-block in filesys */
+       grub_daddr32_t  fs_cblkno;      /* offset of cyl-block in filesys */
+       grub_daddr32_t  fs_iblkno;      /* offset of inode-blocks in filesys */
+       grub_daddr32_t  fs_dblkno;      /* offset of first data after cg */
+       grub_int32_t    fs_cgoffset;    /* cylinder group offset in cylinder */
+       grub_int32_t    fs_cgmask;      /* used to calc mod fs_ntrak */
+       grub_time32_t   fs_time;        /* last time written */
+       grub_int32_t    fs_size;        /* number of blocks in fs */
+       grub_int32_t    fs_dsize;       /* number of data blocks in fs */
+       grub_int32_t    fs_ncg;         /* number of cylinder groups */
+       grub_int32_t    fs_bsize;       /* size of basic blocks in fs */
+       grub_int32_t    fs_fsize;       /* size of frag blocks in fs */
+       grub_int32_t    fs_frag;        /* number of frags in a block in fs */
+       /* these are configuration parameters */
+       grub_int32_t    fs_minfree;     /* minimum percentage of free blocks */
+       grub_int32_t    fs_rotdelay;    /* num of ms for optimal next block */
+       grub_int32_t    fs_rps;         /* disk revolutions per second */
+       /* these fields can be computed from the others */
+       grub_int32_t    fs_bmask;       /* ``blkoff'' calc of blk offsets */
+       grub_int32_t    fs_fmask;       /* ``fragoff'' calc of frag offsets */
+       grub_int32_t    fs_bshift;      /* ``lblkno'' calc of logical blkno */
+       grub_int32_t    fs_fshift;      /* ``numfrags'' calc number of frags */
+       /* these are configuration parameters */
+       grub_int32_t    fs_maxcontig;   /* max number of contiguous blks */
+       grub_int32_t    fs_maxbpg;      /* max number of blks per cyl group */
+       /* these fields can be computed from the others */
+       grub_int32_t    fs_fragshift;   /* block to frag shift */
+       grub_int32_t    fs_fsbtodb;     /* fsbtodb and dbtofsb shift constant */
+       grub_int32_t    fs_sbsize;      /* actual size of super block */
+       grub_int32_t    fs_csmask;      /* csum block offset */
+       grub_int32_t    fs_csshift;     /* csum block number */
+       grub_int32_t    fs_nindir;      /* value of NINDIR */
+       grub_int32_t    fs_inopb;       /* value of INOPB */
+       grub_int32_t    fs_nspf;        /* value of NSPF */
+       /* yet another configuration parameter */
+       grub_int32_t    fs_optim;       /* optimization preference, see below */
+       /* these fields are derived from the hardware */
+       /* USL SVR4 compatibility */
+       /*
+        *      * USL SVR4 compatibility
+        *
+        * There was a significant divergence here between Solaris and
+        * SVR4 for x86.        By swapping these two members in the superblock,
+        * we get read-only compatibility of SVR4 filesystems.  Otherwise
+        * there would be no compatibility.     This change was introduced
+        * during bootstrapping of Solaris on x86.      By making this ifdef'ed
+        * on byte order, we provide ongoing compatibility across all
+        * platforms with the same byte order, the highest compatibility
+        * that can be achieved.
+        */
+       grub_int32_t    fs_state;       /* file system state time stamp */
+       grub_int32_t    fs_si;          /* summary info state - lufs only */
+       grub_int32_t    fs_trackskew;   /* sector 0 skew, per track */
+       /* unique id for this filesystem (currently unused and unmaintained) */
+       /* In 4.3 Tahoe this space is used by fs_headswitch and fs_trkseek */
+       /* Neither of those fields is used in the Tahoe code right now but */
+       /* there could be problems if they are. */
+       grub_int32_t    fs_id[2];       /* file system id */
+       /* sizes determined by number of cylinder groups and their sizes */
+       grub_daddr32_t  fs_csaddr;      /* blk addr of cyl grp summary area */
+       grub_int32_t    fs_cssize;      /* size of cyl grp summary area */
+       grub_int32_t    fs_cgsize;      /* cylinder group size */
+       /* these fields are derived from the hardware */
+       grub_int32_t    fs_ntrak;       /* tracks per cylinder */
+       grub_int32_t    fs_nsect;       /* sectors per track */
+       grub_int32_t    fs_spc;         /* sectors per cylinder */
+       /* this comes from the disk driver partitioning */
+       grub_int32_t    fs_ncyl;        /* cylinders in file system */
+       /* these fields can be computed from the others */
+       grub_int32_t    fs_cpg;         /* cylinders per group */
+       grub_int32_t    fs_ipg;         /* inodes per group */
+       grub_int32_t    fs_fpg;         /* blocks per group * fs_frag */
+       /* this data must be re-computed after crashes */
+       struct csum     fs_cstotal;     /* cylinder summary information */
+       /* these fields are cleared at mount time */
+       char            fs_fmod;        /* super block modified flag */
+       char            fs_clean;       /* file system state flag */
+       char            fs_ronly;       /* mounted read-only flag */
+       char            fs_flags;       /* largefiles flag, etc. */
+       char            fs_fsmnt[MAXMNTLEN];    /* name mounted on */
+       /* these fields retain the current block allocation info */
+       grub_int32_t    fs_cgrotor;     /* last cg searched */
+       /*
+        * The following used to be fs_csp[MAXCSBUFS]. It was not
+        * used anywhere except in old utilities.  We removed this
+        * in 5.6 and expect fs_u.fs_csp to be used instead.
+        * We no longer limit fs_cssize based on MAXCSBUFS.
+        */
+       union { /* fs_cs (csum) info */
+               grub_uint32_t   fs_csp_pad[MAXCSBUFS];
+               struct csum     *fs_csp;
+       } fs_u;
+       grub_int32_t    fs_cpc;         /* cyl per cycle in postbl */
+       short           fs_opostbl[16][8];  /* old rotation block list head */
+       grub_int32_t    fs_sparecon[51];    /* reserved for future constants */
+       grub_int32_t    fs_version;     /* minor version of MTB ufs */
+       grub_int32_t    fs_logbno;      /* block # of embedded log */
+       grub_int32_t    fs_reclaim;     /* reclaim open, deleted files */
+       grub_int32_t    fs_sparecon2;   /* reserved for future constant */
+       /* USL SVR4 compatibility */
+       grub_int32_t    fs_npsect;      /* # sectors/track including spares */
+       grub_quad_t     fs_qbmask;      /* ~fs_bmask - for use with quad size */
+       grub_quad_t     fs_qfmask;      /* ~fs_fmask - for use with quad size */
+       grub_int32_t    fs_postblformat; /* fmt of positional layout tables */
+       grub_int32_t    fs_nrpos;       /* number of rotaional positions */
+       grub_int32_t    fs_postbloff;   /* (short) rotation block list head */
+       grub_int32_t    fs_rotbloff;    /* (grub_uchar_t) blocks for each */
+                                       /* rotation */
+       grub_int32_t    fs_magic;       /* magic number */
+       grub_uchar_t    fs_space[1];    /* list of blocks for each rotation */
+       /* actually longer */
+};
+
+struct icommon {
+       grub_o_mode_t   ic_smode;       /* 0: mode and type of file */
+       short           ic_nlink;       /* 2: number of links to file */
+       grub_o_uid_t    ic_suid;        /* 4: owner's user id */
+       grub_o_gid_t    ic_sgid;        /* 6: owner's group id */
+       grub_uint32_t   ic_sizelo;      /* 8: number of bytes in file */
+       grub_uint32_t   ic_sizehi;      /* 12: number of bytes in file */
+       struct timeval32 ic_atime;      /* 16: time last accessed */
+       struct timeval32 ic_mtime;      /* 24: time last modified */
+       struct timeval32 ic_ctime;      /* 32: last time inode changed */
+       grub_daddr32_t  ic_db[UFS_NDADDR];      /* 40: disk block addresses */
+       grub_daddr32_t  ic_ib[UFS_NIADDR];      /* 88: indirect blocks */
+       grub_int32_t    ic_flags;       /* 100: cflags */
+       grub_int32_t    ic_blocks;      /* 104: 512 byte blocks actually held */
+       grub_int32_t    ic_gen;         /* 108: generation number */
+       grub_int32_t    ic_shadow;      /* 112: shadow inode */
+       grub_uid_t      ic_uid;         /* 116: long EFT version of uid */
+       grub_gid_t      ic_gid;         /* 120: long EFT version of gid */
+       grub_uint32_t   ic_oeftflag;    /* 124: extended attr directory ino, */
+                                       /*      0 = none */
+};
+
+struct direct {
+       grub_ino_t      d_ino;
+       grub_ushort_t   d_reclen;
+       grub_ushort_t   d_namelen;
+       char            d_name[MAXNAMELEN + 1];
+};
+
+/* inode macros */
+#define INOPB(fs)       ((fs)->fs_inopb)
+#define itoo(fs, x)    ((x) % (grub_uint32_t)INOPB(fs))
+#define        itog(fs, x)     ((x) / (grub_uint32_t)(fs)->fs_ipg)
+#define itod(fs, x)    ((grub_daddr32_t)(cgimin(fs, itog(fs, x)) + \
+  (blkstofrags((fs), \
+  ((x) % (grub_uint32_t)(fs)->fs_ipg / (grub_uint32_t)INOPB(fs))))))
+
+/* block conversion macros */
+#define        UFS_NINDIR(fs)  ((fs)->fs_nindir)       /* # of indirects */
+#define blkoff(fs, loc)        ((int)((loc & ~(fs)->fs_bmask)))
+#define lblkno(fs, loc) ((grub_int32_t)((loc) >> (fs)->fs_bshift))
+/* frag to blk */
+#define fsbtodb(fs, b) (((grub_daddr32_t)(b)) << (fs)->fs_fsbtodb)
+#define blkstofrags(fs, b) ((b) << (fs)->fs_fragshift)
+
+/* cynlinder group macros */
+#define cgbase(fs, c)  ((grub_daddr32_t)((fs)->fs_fpg * (c)))
+#define        cgimin(fs, c)   (cgstart(fs, c) + (fs)->fs_iblkno) /* inode 
block */
+#define cgstart(fs, c) \
+  (cgbase(fs, c) + (fs)->fs_cgoffset * ((c) & ~((fs)->fs_cgmask)))
+
+#endif /* !_GRUB_UFS_H */

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.