# 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
|