--- pvfs2/configure.in	2007-06-09 20:36:57.000000000 +0000
+++ pvfs2-fuse/configure.in	2007-06-13 20:14:30.000000000 +0000
@@ -191,6 +191,38 @@
 [test_for_karma]
 )
 
+dnl a function to check if we have the required libraries for the
+dnl FUSE interface
+test_for_fuse()
+{
+  AC_CHECK_PROG(HAVE_PKGCONFIG, pkg-config, yes, no)
+  if test "x$HAVE_PKGCONFIG" = "xyes" ; then
+     AC_MSG_CHECKING([for FUSE library])
+     if `pkg-config --exists fuse` ; then
+        AC_MSG_RESULT(yes)
+        FUSE_LDFLAGS=`pkg-config --libs fuse`
+        FUSE_CFLAGS=`pkg-config --cflags fuse``
+
+        AC_SUBST(FUSE_LDFLAGS)
+        AC_SUBST(FUSE_CFLAGS)
+        BUILD_FUSE="1"
+        AC_SUBST(BUILD_FUSE)
+     else
+        AC_MSG_RESULT(no)
+     fi
+  fi
+}
+
+dnl optionally disable building the FUSE interface
+AC_ARG_ENABLE(fuse,
+[  --disable-fuse         Disables optional FUSE interface.  (Enabled by default)],
+[ if test "x$enableval" = "xyes" ; then
+      test_for_fuse
+   fi
+],
+[test_for_fuse]
+)
+
 dnl shared or static client library (see --enable-shared below)
 AC_ARG_ENABLE(static,
 [  --disable-static        Do not build static client library],
@@ -1122,6 +1154,7 @@
 src/apps/admin/module.mk
 src/apps/admin/pvfs2-config
 src/apps/karma/module.mk
+src/apps/fuse/module.mk
 src/apps/vis/module.mk
 src/apps/kernel/linux/module.mk
 src/io/trove/module.mk
@@ -1175,6 +1208,12 @@
    AC_MSG_RESULT([PVFS2 configured to build karma gui               :  no])
 fi
 
+if test "x$BUILD_FUSE" = "x1" ; then
+   AC_MSG_RESULT([PVFS2 configured to build FUSE interface          : yes])
+else
+   AC_MSG_RESULT([PVFS2 configured to build FUSE interface          :  no])
+fi
+
 if test "x$BUILD_EPOLL" = "x1" ; then
    AC_MSG_RESULT([PVFS2 configured to use epoll                     : yes])
 else
--- pvfs2/configure	2007-06-09 20:37:37.000000000 +0000
+++ pvfs2-fuse/configure	2007-06-13 20:14:29.000000000 +0000
@@ -309,7 +309,7 @@
 # include <unistd.h>
 #endif"
 
-ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS PVFS2_VERSION build build_cpu build_vendor build_os host host_cpu host_vendor host_os CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT CPP EGREP INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA HAVE_PERL HAVE_FIND HAVE_BISON HAVE_FLEX BUILD_CC LIBCFLAGS THREAD_LIB BUILD_SERVER MMAP_RA_CACHE TRUSTED_CONNECTIONS HAVE_PKGCONFIG GTKLIBS GTKCFLAGS BUILD_KARMA build_static REDHAT_RELEASE NPTL_WORKAROUND MISC_TROVE_FLAGS LINUX_KERNEL_SRC LINUX24_KERNEL_SRC LINUX24_KERNEL_MINOR_VER BUILD_ABSOLUTE_TOP SRC_RELATIVE_TOP SRC_ABSOLUTE_TOP ENABLE_COVERAGE QUIET_COMPILE BUILD_EPOLL build_shared INTELC GNUC DB_CFLAGS DB_LIB NEEDS_LIBRT TARGET_OS_DARWIN TARGET_OS_LINUX GM_HOME BUILD_GM MX_HOME BUILD_MX BUILD_IB IB_INCDIR IB_LIBDIR BUILD_OPENIB OPENIB_INCDIR OPENIB_LIBDIR SERVER_LDFLAGS BUILD_VIS VISCFLAGS VISLIBS LIBOBJS LTLIBOBJS'
+ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS PVFS2_VERSION build build_cpu build_vendor build_os host host_cpu host_vendor host_os CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT CPP EGREP INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA HAVE_PERL HAVE_FIND HAVE_BISON HAVE_FLEX BUILD_CC LIBCFLAGS THREAD_LIB BUILD_SERVER MMAP_RA_CACHE TRUSTED_CONNECTIONS HAVE_PKGCONFIG GTKLIBS GTKCFLAGS BUILD_KARMA FUSE_LDFLAGS FUSE_CFLAGS BUILD_FUSE build_static REDHAT_RELEASE NPTL_WORKAROUND MISC_TROVE_FLAGS LINUX_KERNEL_SRC LINUX24_KERNEL_SRC LINUX24_KERNEL_MINOR_VER BUILD_ABSOLUTE_TOP SRC_RELATIVE_TOP SRC_ABSOLUTE_TOP ENABLE_COVERAGE QUIET_COMPILE BUILD_EPOLL build_shared INTELC GNUC DB_CFLAGS DB_LIB NEEDS_LIBRT TARGET_OS_DARWIN TARGET_OS_LINUX GM_HOME BUILD_GM MX_HOME BUILD_MX BUILD_IB IB_INCDIR IB_LIBDIR BUILD_OPENIB OPENIB_INCDIR OPENIB_LIBDIR SERVER_LDFLAGS BUILD_VIS VISCFLAGS VISLIBS LIBOBJS LTLIBOBJS'
 ac_subst_files=''
 
 # Initialize some variables set by options.
@@ -853,6 +853,7 @@
   --enable-trusted-connections  Enable connects only from trusted hosts/ports
                                 (experimental, off by default)
   --disable-karma         Disables optional gui.  (Enabled by default)
+  --disable-fuse          Disables FUSE interface.  (Enabled by default)
   --disable-static        Do not build static client library
   --enable-redhat24       Enable workaround for RedHat 2.4 kernel
   --enable-nptl-workaround Enable workaround for buggy NPTL/Pthread libraries
@@ -6402,6 +6403,76 @@
 
 fi;
 
+test_for_fuse()
+{
+  # Extract the first word of "pkg-config", so it can be a program name with args.
+set dummy pkg-config; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_HAVE_PKGCONFIG+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$HAVE_PKGCONFIG"; then
+  ac_cv_prog_HAVE_PKGCONFIG="$HAVE_PKGCONFIG" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_HAVE_PKGCONFIG="yes"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+
+  test -z "$ac_cv_prog_HAVE_PKGCONFIG" && ac_cv_prog_HAVE_PKGCONFIG="no"
+fi
+fi
+HAVE_PKGCONFIG=$ac_cv_prog_HAVE_PKGCONFIG
+if test -n "$HAVE_PKGCONFIG"; then
+  echo "$as_me:$LINENO: result: $HAVE_PKGCONFIG" >&5
+echo "${ECHO_T}$HAVE_PKGCONFIG" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+  if test "x$HAVE_PKGCONFIG" = "xyes" ; then
+     echo "$as_me:$LINENO: checking for FUSE library" >&5
+echo $ECHO_N "checking for FUSE library... $ECHO_C" >&6
+     if `pkg-config --exists fuse` ; then
+        echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+        FUSE_LDFLAGS=`pkg-config --libs fuse`
+        FUSE_CFLAGS=`pkg-config --cflags fuse`
+
+
+
+        BUILD_FUSE="1"
+
+     else
+        echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+     fi
+  fi
+}
+
+# Check whether --enable-fuse or --disable-fuse was given.
+if test "${enable_fuse+set}" = set; then
+  enableval="$enable_fuse"
+   if test "x$enableval" = "xyes" ; then
+      test_for_fuse
+   fi
+
+else
+  test_for_fuse
+
+fi;
+
 # Check whether --enable-static or --disable-static was given.
 if test "${enable_static+set}" = set; then
   enableval="$enable_static"
@@ -16712,7 +16783,7 @@
        install -d $d;
 done
 
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                  ac_config_files="$ac_config_files Makefile module.mk src/apps/admin/module.mk src/apps/admin/pvfs2-config src/apps/karma/module.mk src/apps/vis/module.mk src/apps/kernel/linux/module.mk src/io/trove/module.mk src/io/trove/trove-handle-mgmt/module.mk src/io/trove/trove-dbpf/module.mk src/common/misc/module.mk src/common/quickhash/module.mk src/common/quicklist/module.mk src/common/dotconf/module.mk src/common/id-generator/module.mk src/common/gossip/module.mk src/common/gen-locks/module.mk src/common/llist/module.mk src/common/statecomp/module.mk src/io/bmi/module.mk src/io/bmi/bmi_tcp/module.mk src/io/bmi/bmi_gm/module.mk src/io/bmi/bmi_mx/module.mk src/io/bmi/bmi_ib/module.mk src/io/description/module.mk src/io/flow/module.mk src/io/flow/flowproto-bmi-trove/module.mk src/io/flow/flowproto-template/module.mk src/io/flow/flowproto-dump-offsets/module.mk src/io/flow/flowproto-bmi-cache/module.mk src/io/buffer/module.mk src/io/job/module.mk src/io/dev/module.mk src/proto/module.mk src/server/module.mk src/server/request-scheduler/module.mk src/client/sysint/module.mk src/kernel/linux-2.6/Makefile src/kernel/linux-2.4/Makefile doc/module.mk doc/coding/module.mk doc/design/module.mk doc/random/module.mk examples/pvfs2-server.rc doc/doxygen/pvfs2-doxygen.conf"
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                  ac_config_files="$ac_config_files Makefile module.mk src/apps/admin/module.mk src/apps/admin/pvfs2-config src/apps/karma/module.mk src/apps/fuse/module.mk src/apps/vis/module.mk src/apps/kernel/linux/module.mk src/io/trove/module.mk src/io/trove/trove-handle-mgmt/module.mk src/io/trove/trove-dbpf/module.mk src/common/misc/module.mk src/common/quickhash/module.mk src/common/quicklist/module.mk src/common/dotconf/module.mk src/common/id-generator/module.mk src/common/gossip/module.mk src/common/gen-locks/module.mk src/common/llist/module.mk src/common/statecomp/module.mk src/io/bmi/module.mk src/io/bmi/bmi_tcp/module.mk src/io/bmi/bmi_gm/module.mk src/io/bmi/bmi_mx/module.mk src/io/bmi/bmi_ib/module.mk src/io/description/module.mk src/io/flow/module.mk src/io/flow/flowproto-bmi-trove/module.mk src/io/flow/flowproto-template/module.mk src/io/flow/flowproto-dump-offsets/module.mk src/io/flow/flowproto-bmi-cache/module.mk src/io/buffer/module.mk src/io/job/module.mk src/io/dev/module.mk src/proto/module.mk src/server/module.mk src/server/request-scheduler/module.mk src/client/sysint/module.mk src/kernel/linux-2.6/Makefile src/kernel/linux-2.4/Makefile doc/module.mk doc/coding/module.mk doc/design/module.mk doc/random/module.mk examples/pvfs2-server.rc doc/doxygen/pvfs2-doxygen.conf"
 cat >confcache <<\_ACEOF
 # This file is a shell script that caches the results of configure
 # tests run on this system so they can be shared between configure
@@ -17243,6 +17314,7 @@
   "src/apps/admin/module.mk" ) CONFIG_FILES="$CONFIG_FILES src/apps/admin/module.mk" ;;
   "src/apps/admin/pvfs2-config" ) CONFIG_FILES="$CONFIG_FILES src/apps/admin/pvfs2-config" ;;
   "src/apps/karma/module.mk" ) CONFIG_FILES="$CONFIG_FILES src/apps/karma/module.mk" ;;
+  "src/apps/fuse/module.mk" ) CONFIG_FILES="$CONFIG_FILES src/apps/fuse/module.mk" ;;
   "src/apps/vis/module.mk" ) CONFIG_FILES="$CONFIG_FILES src/apps/vis/module.mk" ;;
   "src/apps/kernel/linux/module.mk" ) CONFIG_FILES="$CONFIG_FILES src/apps/kernel/linux/module.mk" ;;
   "src/io/trove/module.mk" ) CONFIG_FILES="$CONFIG_FILES src/io/trove/module.mk" ;;
@@ -17403,6 +17475,9 @@
 s,@GTKLIBS@,$GTKLIBS,;t t
 s,@GTKCFLAGS@,$GTKCFLAGS,;t t
 s,@BUILD_KARMA@,$BUILD_KARMA,;t t
+s,@FUSE_LDFLAGS@,$FUSE_LDFLAGS,;t t
+s,@FUSE_CFLAGS@,$FUSE_CFLAGS,;t t
+s,@BUILD_FUSE@,$BUILD_FUSE,;t t
 s,@build_static@,$build_static,;t t
 s,@REDHAT_RELEASE@,$REDHAT_RELEASE,;t t
 s,@NPTL_WORKAROUND@,$NPTL_WORKAROUND,;t t
@@ -17948,6 +18023,14 @@
 echo "${ECHO_T}PVFS2 configured to build karma gui               :  no" >&6
 fi
 
+if test "x$BUILD_FUSE" = "x1" ; then
+   echo "$as_me:$LINENO: result: PVFS2 configured to build FUSE interface          : yes" >&5
+echo "${ECHO_T}PVFS2 configured to build FUSE interface          : yes" >&6
+else
+   echo "$as_me:$LINENO: result: PVFS2 configured to build FUSE interface          :  no" >&5
+echo "${ECHO_T}PVFS2 configured to build FUSE interface          :  no" >&6
+fi
+
 if test "x$BUILD_EPOLL" = "x1" ; then
    echo "$as_me:$LINENO: result: PVFS2 configured to use epoll                     : yes" >&5
 echo "${ECHO_T}PVFS2 configured to use epoll                     : yes" >&6
--- pvfs2/Makefile.in	2007-05-28 22:40:55.000000000 +0000
+++ pvfs2-fuse/Makefile.in	2007-06-13 20:14:28.000000000 +0000
@@ -69,6 +69,7 @@
 BUILD_OPENIB = @BUILD_OPENIB@
 BUILD_VIS = @BUILD_VIS@
 BUILD_KARMA = @BUILD_KARMA@
+BUILD_FUSE = @BUILD_FUSE@
 BUILD_EPOLL = @BUILD_EPOLL@
 BUILD_SERVER = @BUILD_SERVER@
 NEEDS_LIBRT = @NEEDS_LIBRT@
@@ -383,6 +384,8 @@
 VISMISCSRC :=
 # KARMASRC is source for the karma gui
 KARMASRC :=
+# FUSESRC is source for the FUSE interface daemon
+FUSESRC :=
 # userland helper programs for kernel drivers
 KERNAPPSRC :=
 #
@@ -498,6 +501,10 @@
 KARMAOBJS := $(patsubst %.c,%.o, $(filter %.c,$(KARMASRC)))
 KARMADEPENDS := $(patsubst %.c,%.d, $(filter %.c,$(KARMASRC)))
 
+# FUSEOBJS, FUSEDEPENDS for the FUSE interface
+FUSEOBJS := $(patsubst %.c,%.o, $(filter %.c,$(FUSESRC)))
+FUSEDEPENDS := $(patsubst %.c,%.d, $(filter %.c,$(FUSESRC)))
+
 # state machine generation tool, built for the build machine, not the
 # host machine, in the case of cross-compilation
 STATECOMPOBJS := $(patsubst %.c,%.o,$(STATECOMPSRC))
@@ -520,13 +527,13 @@
 #   doesn't matter at all.
 DEPENDS := $(sort $(LIBDEPENDS) $(SERVERDEPENDS) $(MISCDEPENDS) \
     $(ADMINDEPENDS) $(ADMINDEPENDS_SERVER) $(KERNAPPDEPENDS) $(VISDEPENDS) \
-    $(VISMISCDEPENDS) $(KARMADEPENDS) $(STATECOMPDEPS))
+    $(VISMISCDEPENDS) $(KARMADEPENDS) $(FUSEDEPENDS) $(STATECOMPDEPS))
 
 ####################################################################
 # Rules and dependencies
 
 # default rule builds server, library, and applications
-all:: $(SERVER) $(KARMA) $(LIBRARIES) $(LIBRARIES_THREADED) admintools $(VISS) $(KARMA)
+all:: $(SERVER) $(KARMA) $(LIBRARIES) $(LIBRARIES_THREADED) admintools $(VISS) $(KARMA) $(FUSE)
 
 # target for building admin tools
 admintools: $(ADMINTOOLS) $(ADMINTOOLS_SERVER)
@@ -622,6 +629,11 @@
 	$(Q) "  LD		$@"
 	$(E)$(LD) -o $@ $(LDFLAGS) $(KARMAOBJS) $(LIBS) $(call modldflags,$<)
 
+# rule for building karma gui and its objects
+$(FUSE): $(FUSEOBJS) $(LIBRARIES)
+	$(Q) "  LD		$@"
+	$(E)$(LD) -o $@ $(LDFLAGS) $(FUSEOBJS) $(LIBS) $(call modldflags,$<)
+
 # rule for building vis executables from object files
 $(VISS): %: %.o $(VISMISCOBJS) $(LIBRARIES)
 	$(Q) "  LD		$@"
--- pvfs2/src/common/misc/pint-util.c	2007-03-20 18:32:30.000000000 +0000
+++ pvfs2-fuse/src/common/misc/pint-util.c	2007-06-04 17:41:36.000000000 +0000
@@ -34,7 +34,6 @@
 static long check_group_pw_buffer_size = 0;
 static char* check_group_gr_buffer = NULL;
 static long check_group_gr_buffer_size = 0;
-static int PINT_check_group(uid_t uid, gid_t gid);
 
 void PINT_time_mark(PINT_time_marker *out_marker)
 {
@@ -463,7 +462,7 @@
  * returns 0 on success, -PVFS_ENOENT if not a member, other PVFS error codes
  * on system failure
  */
-static int PINT_check_group(uid_t uid, gid_t gid)
+int PINT_check_group(uid_t uid, gid_t gid)
 {
     struct passwd pwd;
     struct passwd* pwd_p = NULL;
@@ -494,6 +493,10 @@
         /* newish posix systems can tell us what the max buffer size is */
         check_group_gr_buffer_size = sysconf(_SC_GETGR_R_SIZE_MAX);
         check_group_pw_buffer_size = sysconf(_SC_GETPW_R_SIZE_MAX);
+	if ( check_group_gr_buffer_size == -1 )
+	    check_group_gr_buffer_size = 1024;
+	if ( check_group_pw_buffer_size == -1 )
+	    check_group_pw_buffer_size = 1024;
 #else
         /* fall back for older systems */
         check_group_pw_buffer_size = 1024;
--- pvfs2/src/common/misc/pint-util.h	2006-09-13 19:09:35.000000000 +0000
+++ pvfs2-fuse/src/common/misc/pint-util.h	2007-05-30 02:29:05.000000000 +0000
@@ -147,6 +147,8 @@
 int PINT_util_digest_md5(const void *input_message, size_t input_length,
 		char **output, size_t *output_length);
 
+int PINT_check_group(uid_t uid, gid_t gid);
+
 #endif /* __PINT_UTIL_H */
 
 /*
--- pvfs2/src/common/misc/pvfs2-util.c	2007-03-20 20:01:36.000000000 +0000
+++ pvfs2-fuse/src/common/misc/pvfs2-util.c	2007-04-24 20:03:12.000000000 +0000
@@ -370,7 +370,8 @@
     i = 0;
     while ((tmp_ent = PINT_fstab_next_entry(mnt_fp)))
     {
-        if (strcmp(PINT_FSTAB_TYPE(tmp_ent), "pvfs2") == 0)
+	const char *type = PINT_FSTAB_TYPE(tmp_ent);
+        if ( type && strcmp(type, "pvfs2") == 0)
         {
             struct PVFS_sys_mntent *me = &current_tab->mntent_array[i];
             char *cp;
--- pvfs2/src/apps/fuse/module.mk.in	1970-01-01 00:00:00.000000000 +0000
+++ pvfs2-fuse/src/apps/fuse/module.mk.in	2007-06-13 20:18:55.000000000 +0000
@@ -0,0 +1,13 @@
+ifdef BUILD_FUSE
+
+DIR := src/apps/fuse
+
+FUSESRC += \
+    $(DIR)/pvfs2fuse.c
+
+FUSE := $(DIR)/pvfs2fuse
+
+MODCFLAGS_$(DIR) := @FUSE_CFLAGS@
+MODLDFLAGS_$(DIR) := @FUSE_LDFLAGS@
+
+endif  # BUILD_FUSE
--- pvfs2/src/apps/fuse/pvfs2fuse.c	1970-01-01 00:00:00.000000000 +0000
+++ pvfs2-fuse/src/apps/fuse/pvfs2fuse.c	2007-06-19 20:17:44.000000000 +0000
@@ -0,0 +1,1206 @@
+/*
+ *   PVFS FUSE interface
+ *
+ *
+ *   (C) 2001 Clemson University and The University of Chicago
+ *
+ *   (C) 2007 University of Connecticut. All rights reserved.
+ *
+ *   Author: John A. Chandy
+ *   $Date: $
+ *   $Revision: $
+ *
+ */
+
+/* char *pvfs2fuse_version = "$Id$"; */
+char *pvfs2fuse_version = "0.01";
+
+#define FUSE_USE_VERSION 26
+
+#include <fuse.h>
+#include <fuse_opt.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <utime.h>
+#include <unistd.h>
+
+#include "pvfs2.h"
+#include "pint-dev-shared.h"
+#include "pint-util.h"
+#include "str-utils.h"
+
+typedef struct {
+    PVFS_object_ref	ref;
+    PVFS_credentials	creds;
+} pvfs_fuse_handle_t;
+
+struct pvfs2fuse {
+    char	*fs_spec;
+    char	*mntpoint;
+    PVFS_fs_id	fs_id;
+    struct PVFS_sys_mntent mntent;
+};
+
+static struct pvfs2fuse pvfs2fuse;
+
+
+#if __LP64__
+#define SET_FUSE_HANDLE( fi, pfh ) \
+	fi->fh = (uint64_t)pfh
+#define GET_FUSE_HANDLE( fi ) \
+	(pvfs_fuse_handle_t *)fi->fh
+#else
+#define SET_FUSE_HANDLE( fi, pfh ) \
+	*((pvfs_fuse_handle_t **)(&fi->fh)) = pfh
+#define GET_FUSE_HANDLE( fi ) \
+	*((pvfs_fuse_handle_t **)(&fi->fh))
+#endif
+
+static void pvfs_fuse_gen_credentials(
+    PVFS_credentials *credentials)
+{
+    credentials->uid = fuse_get_context()->uid;
+    credentials->gid = fuse_get_context()->gid;
+}
+
+static int lookup( const char *path, pvfs_fuse_handle_t *pfh, 
+		   int32_t follow_link )
+{
+    PVFS_sysresp_lookup lk_response;
+    int			ret;
+
+    /* we don't have to do a PVFS_util_resolve
+     * because FUSE resolves the path for us
+     */
+
+    pvfs_fuse_gen_credentials(&pfh->creds);
+
+    memset(&lk_response, 0, sizeof(lk_response));
+    ret = PVFS_sys_lookup(pvfs2fuse.fs_id, 
+			  (char *)path,
+			  &pfh->creds, 
+			  &lk_response, 
+			  follow_link);
+    if ( ret < 0 ) {
+        return ret;
+    }
+
+    pfh->ref.handle = lk_response.ref.handle;
+    pfh->ref.fs_id  = pvfs2fuse.fs_id;
+
+    return 0;
+}
+
+static int pvfs_fuse_getattr_pfhp(pvfs_fuse_handle_t *pfhp, struct stat *stbuf)
+{
+    PVFS_sysresp_getattr getattr_response;
+    PVFS_sys_attr*	attrs;
+    int			ret;
+    int			perm_mode = 0;
+
+    memset(&getattr_response,0, sizeof(PVFS_sysresp_getattr));
+
+    ret = PVFS_sys_getattr(pfhp->ref, 
+                          PVFS_ATTR_SYS_ALL_NOHINT,
+                          (PVFS_credentials *) &pfhp->creds, 
+                          &getattr_response);
+    if ( ret < 0 )
+        return PVFS_ERROR_TO_ERRNO( ret );
+   
+    memset(stbuf, 0, sizeof(struct stat));
+
+    /* Code copied from kernel/linux-2.x/pvfs2-utils.c */
+
+    /*
+      arbitrarily set the inode block size; FIXME: we need to
+      resolve the difference between the reported inode blocksize
+      and the PAGE_CACHE_SIZE, since our block count will always
+      be wrong.
+
+      For now, we're setting the block count to be the proper
+      number assuming the block size is 512 bytes, and the size is
+      rounded up to the nearest 4K.  This is apparently required
+      to get proper size reports from the 'du' shell utility.
+
+    */
+
+    attrs = &getattr_response.attr;
+   
+    if (attrs->objtype == PVFS_TYPE_METAFILE)
+    {
+        if (attrs->mask & PVFS_ATTR_SYS_SIZE)
+	{
+	    size_t inode_size = attrs->size;
+	    size_t rounded_up_size = (inode_size + (4096 - (inode_size % 4096)));
+
+	    stbuf->st_size = inode_size;
+	    stbuf->st_blocks = (unsigned long)(rounded_up_size / 512);
+	}
+    }
+    else if ((attrs->objtype == PVFS_TYPE_SYMLINK) &&
+	     (attrs->link_target != NULL))
+    {
+        stbuf->st_size = strlen(attrs->link_target);
+    }
+    else
+    {
+      /* what should this be??? */
+	unsigned long PAGE_CACHE_SIZE = 4096;
+        stbuf->st_blocks = (unsigned long)(PAGE_CACHE_SIZE / 512);
+	stbuf->st_size = PAGE_CACHE_SIZE;
+    }
+
+    stbuf->st_uid = attrs->owner;
+    stbuf->st_gid = attrs->group;
+
+    stbuf->st_atime = (time_t)attrs->atime;
+    stbuf->st_mtime = (time_t)attrs->mtime;
+    stbuf->st_ctime = (time_t)attrs->ctime;
+
+    stbuf->st_mode = 0;
+    if (attrs->perms & PVFS_O_EXECUTE)
+        perm_mode |= S_IXOTH;
+    if (attrs->perms & PVFS_O_WRITE)
+        perm_mode |= S_IWOTH;
+    if (attrs->perms & PVFS_O_READ)
+        perm_mode |= S_IROTH;
+
+    if (attrs->perms & PVFS_G_EXECUTE)
+        perm_mode |= S_IXGRP;
+    if (attrs->perms & PVFS_G_WRITE)
+        perm_mode |= S_IWGRP;
+    if (attrs->perms & PVFS_G_READ)
+        perm_mode |= S_IRGRP;
+
+    if (attrs->perms & PVFS_U_EXECUTE)
+        perm_mode |= S_IXUSR;
+    if (attrs->perms & PVFS_U_WRITE)
+        perm_mode |= S_IWUSR;
+    if (attrs->perms & PVFS_U_READ)
+        perm_mode |= S_IRUSR;
+
+    if (attrs->perms & PVFS_G_SGID)
+      perm_mode |= S_ISGID;
+
+    /* Should we honor the suid bit of the file? */
+    /* Should we check the file system suid flag */
+    if ( /* get_suid_flag(inode) == 1 && */ (attrs->perms & PVFS_U_SUID))
+        perm_mode |= S_ISUID;
+
+    stbuf->st_mode |= perm_mode;
+
+    /* special case: mark the root inode as sticky */
+    if (pfhp->ref.handle == 0)
+    {
+        stbuf->st_mode |= S_ISVTX;
+    }
+
+    switch (attrs->objtype)
+    {
+        case PVFS_TYPE_METAFILE:
+	    stbuf->st_mode |= S_IFREG;
+	    break;
+        case PVFS_TYPE_DIRECTORY:
+	    stbuf->st_mode |= S_IFDIR;
+	    /* NOTE: we have no good way to keep nlink consistent for 
+	     * directories across clients; keep constant at 1.  Why 1?  If
+	     * we go with 2, then find(1) gets confused and won't work
+	     * properly withouth the -noleaf option */
+	    stbuf->st_nlink = 1;
+	    break;
+        case PVFS_TYPE_SYMLINK:
+	    stbuf->st_mode |= S_IFLNK;
+	    break;
+        default:
+	    break;
+    }
+
+    stbuf->st_dev = pfhp->ref.fs_id;
+    stbuf->st_ino = pfhp->ref.handle;
+
+    stbuf->st_rdev = 0;
+    stbuf->st_blksize = 4096;
+
+    PVFS_util_release_sys_attr(attrs);
+    
+    return 0;
+}
+
+static int pvfs_fuse_getattr(const char *path, struct stat *stbuf)
+{
+    int			ret;
+    pvfs_fuse_handle_t	pfh;
+
+    ret = lookup( path, &pfh, PVFS2_LOOKUP_LINK_NO_FOLLOW );
+    if ( ret < 0 )
+        return PVFS_ERROR_TO_ERRNO( ret );
+   
+    return pvfs_fuse_getattr_pfhp( &pfh, stbuf );
+}
+
+static int pvfs_fuse_fgetattr(const char *path, struct stat *stbuf,
+			      struct fuse_file_info *fi)
+{
+    return pvfs_fuse_getattr_pfhp( GET_FUSE_HANDLE( fi ), stbuf );
+}
+
+static int pvfs_fuse_readlink(const char *path, char *buf, size_t size)
+{
+    PVFS_sysresp_getattr getattr_response;
+    int			ret;
+    size_t		len;
+    pvfs_fuse_handle_t	pfh;
+
+    ret = lookup( path, &pfh, PVFS2_LOOKUP_LINK_NO_FOLLOW );
+    if ( ret < 0 )
+        return PVFS_ERROR_TO_ERRNO( ret );
+   
+    ret = PVFS_sys_getattr(pfh.ref, 
+			   PVFS_ATTR_SYS_ALL_NOHINT,
+			   (PVFS_credentials *) &pfh.creds, 
+			   &getattr_response);
+    if ( ret < 0 )
+        return PVFS_ERROR_TO_ERRNO( ret );
+
+    if (getattr_response.attr.objtype != PVFS_TYPE_SYMLINK)
+        return -EINVAL;
+
+    len = strlen( getattr_response.attr.link_target );
+    if ( len < (size-1) )
+        size = len;
+
+    bcopy( getattr_response.attr.link_target, buf, size );
+
+    buf[len] = '\0';
+
+    return 0;
+}
+
+static int pvfs_fuse_mkdir(const char *path, mode_t mode)
+{
+    int rc;
+    int num_segs;
+    PVFS_sys_attr attr;
+    char parent[PVFS_NAME_MAX];
+    char dirname[PVFS_SEGMENT_MAX];
+    pvfs_fuse_handle_t	parent_pfh;
+
+    PVFS_sysresp_mkdir resp_mkdir;
+
+    /* Translate path into pvfs2 relative path */
+    rc = PINT_get_base_dir((char *)path, parent, PVFS_NAME_MAX);
+    num_segs = PINT_string_count_segments((char *)path);
+    rc = PINT_get_path_element((char *)path, num_segs - 1,
+			       dirname, PVFS_SEGMENT_MAX);
+
+    if (rc)
+    {
+	return PVFS_ERROR_TO_ERRNO( rc );
+    }
+
+    lookup( parent, &parent_pfh, PVFS2_LOOKUP_LINK_FOLLOW );
+
+    /* Set attributes */
+    memset(&attr, 0, sizeof(PVFS_sys_attr));
+    attr.owner = parent_pfh.creds.uid;
+    attr.group = parent_pfh.creds.gid;
+    attr.perms = mode;
+    attr.mask = PVFS_ATTR_SYS_ALL_SETABLE;
+
+    rc = PVFS_sys_mkdir(dirname,
+			parent_pfh.ref,
+			attr,
+			&parent_pfh.creds,
+			&resp_mkdir);
+    if (rc)
+    {
+        return PVFS_ERROR_TO_ERRNO( rc );
+    }
+
+    return 0;
+}
+
+static int pvfs_fuse_remove( const char *path )
+{
+    int rc;
+    int num_segs;
+    char parent[PVFS_NAME_MAX];
+    char filename[PVFS_SEGMENT_MAX];
+    pvfs_fuse_handle_t	parent_pfh;
+
+    /* Translate path into pvfs2 relative path */
+    rc = PINT_get_base_dir((char *)path, parent, PVFS_NAME_MAX);
+    num_segs = PINT_string_count_segments((char *)path);
+    rc = PINT_get_path_element((char *)path, num_segs - 1,
+			       filename, PVFS_SEGMENT_MAX);
+
+    if (rc)
+    {
+	return PVFS_ERROR_TO_ERRNO( rc );
+    }
+
+    lookup( parent, &parent_pfh, PVFS2_LOOKUP_LINK_FOLLOW );
+
+    rc = PVFS_sys_remove(filename, parent_pfh.ref, &parent_pfh.creds);
+    if (rc)
+    {
+        return PVFS_ERROR_TO_ERRNO( rc );
+    }
+
+    return 0;
+}
+
+static int pvfs_fuse_unlink(const char *path)
+{
+    return pvfs_fuse_remove(path);
+}
+
+static int pvfs_fuse_rmdir(const char *path)
+{
+    return pvfs_fuse_remove(path);
+}
+
+static int pvfs_fuse_symlink(const char *from, const char *to)
+{
+    int                  ret                        = 0;
+    PVFS_sys_attr        attr;
+    PVFS_sysresp_lookup  resp_lookup;
+    PVFS_object_ref      parent_ref;
+    PVFS_sysresp_symlink resp_sym;
+    PVFS_credentials    credentials;
+    pvfs_fuse_handle_t	dir_pfh;
+    char *tofile, *todir, *cp;
+
+    pvfs_fuse_gen_credentials(&credentials);
+
+    /* Initialize any variables */
+    memset(&attr,        0, sizeof(attr));
+    memset(&resp_lookup, 0, sizeof(resp_lookup));
+    memset(&parent_ref,  0, sizeof(parent_ref));
+    memset(&resp_sym,    0, sizeof(resp_sym));
+
+    /* Set the attributes for the new directory */
+    attr.owner = credentials.uid;
+    attr.group = credentials.gid;
+    attr.perms = 0777;              
+    attr.mask = (PVFS_ATTR_SYS_ALL_SETABLE);
+
+    todir = strdup( to );
+    if ( todir == NULL )
+	return -ENOMEM;
+
+    /* find the last / to get the parent directory */
+    cp = rindex( todir,  '/' );
+    if ( cp == NULL )
+    {
+	free( todir );
+	return -ENOTDIR;
+    }
+    tofile = strdup( cp+1 );
+    if ( cp == todir )
+    {
+	/* we're creating a link at the root, so keep the slash */
+	*(cp+1) = '\0';
+    }
+    else
+    {
+	*cp = '\0';
+    }
+
+    ret = lookup( todir, &dir_pfh, PVFS2_LOOKUP_LINK_FOLLOW );
+    if(ret < 0)
+    {
+        free( tofile );
+        free( todir );
+        PVFS_perror("lookup", ret);
+        return(-1);
+    }
+
+    ret = PVFS_sys_symlink(tofile, 
+                           dir_pfh.ref, 
+                           (char *) from,
+                           attr, 
+                           &credentials, 
+                           &resp_sym);
+
+    if (ret < 0)
+    {
+        PVFS_perror("PVFS_sys_symlink", ret);
+        return(ret);
+    }
+    else
+    {
+	ret = 0;
+    }
+    
+    free( tofile );
+    free( todir );
+    return(ret);
+}
+
+static int pvfs_fuse_rename(const char *from, const char *to)
+{
+    int rc;
+    int num_segs;
+    char fromdir[PVFS_NAME_MAX], todir[PVFS_NAME_MAX];
+    char fromname[PVFS_SEGMENT_MAX], toname[PVFS_SEGMENT_MAX];
+    pvfs_fuse_handle_t	todir_pfh, fromdir_pfh;
+
+    /* Translate path into pvfs2 relative path */
+    rc = PINT_get_base_dir((char *)from, fromdir, PVFS_NAME_MAX);
+    num_segs = PINT_string_count_segments((char *)from);
+    rc = PINT_get_path_element((char *)from, num_segs - 1,
+			       fromname, PVFS_SEGMENT_MAX);
+
+    if (rc)
+	return PVFS_ERROR_TO_ERRNO( rc );
+
+    rc = lookup( fromdir, &fromdir_pfh, PVFS2_LOOKUP_LINK_FOLLOW );
+    if (rc < 0)
+	return PVFS_ERROR_TO_ERRNO( rc );
+
+    /* Translate path into pvfs2 relative path */
+    rc = PINT_get_base_dir((char *)to, todir, PVFS_NAME_MAX);
+    num_segs = PINT_string_count_segments((char *)to);
+    rc = PINT_get_path_element((char *)to, num_segs - 1,
+			       toname, PVFS_SEGMENT_MAX);
+
+    if (rc)
+	return PVFS_ERROR_TO_ERRNO( rc );
+
+    lookup( todir, &todir_pfh, PVFS2_LOOKUP_LINK_FOLLOW );
+    if (rc < 0)
+	return PVFS_ERROR_TO_ERRNO( rc );
+
+    rc = PVFS_sys_rename(fromname,
+			 fromdir_pfh.ref,
+			 toname,
+			 todir_pfh.ref,
+			 &todir_pfh.creds);
+    if (rc)
+        return PVFS_ERROR_TO_ERRNO( rc );
+
+    return 0;
+}
+
+static int pvfs_fuse_chmod(const char *path, mode_t mode)
+{
+    int			ret;
+    PVFS_sys_attr	new_attr;
+ 
+    pvfs_fuse_handle_t	pfh;
+
+    ret = lookup( path, &pfh, PVFS2_LOOKUP_LINK_FOLLOW );
+    if ( ret < 0 )
+        return PVFS_ERROR_TO_ERRNO( ret );
+   
+    new_attr.perms = mode;
+    new_attr.mask = PVFS_ATTR_SYS_PERM;
+ 
+    ret = PVFS_sys_setattr(pfh.ref,new_attr,&pfh.creds);
+    if (ret < 0) 
+        return PVFS_ERROR_TO_ERRNO( ret );
+
+    return 0;
+}
+
+static int pvfs_fuse_chown(const char *path, uid_t uid, gid_t gid)
+{
+    int			ret;
+    PVFS_sys_attr	new_attr;
+ 
+    pvfs_fuse_handle_t	pfh;
+
+    ret = lookup( path, &pfh, PVFS2_LOOKUP_LINK_FOLLOW );
+    if ( ret < 0 )
+        return PVFS_ERROR_TO_ERRNO( ret );
+   
+    new_attr.owner = uid;
+    new_attr.group = gid;
+    new_attr.mask = PVFS_ATTR_SYS_UID | PVFS_ATTR_SYS_GID;
+ 
+    ret = PVFS_sys_setattr(pfh.ref,new_attr,&pfh.creds);
+    if (ret < 0) 
+        return PVFS_ERROR_TO_ERRNO( ret );
+
+    return 0;
+}
+
+static int pvfs_fuse_truncate(const char *path, off_t size)
+{
+    int			ret;
+    pvfs_fuse_handle_t	pfh;
+
+    ret = lookup( path, &pfh, PVFS2_LOOKUP_LINK_FOLLOW );
+    if ( ret < 0 )
+        return PVFS_ERROR_TO_ERRNO( ret );
+   
+    ret = PVFS_sys_truncate(pfh.ref,size,&pfh.creds);
+    if (ret < 0) 
+        return PVFS_ERROR_TO_ERRNO( ret );
+
+    return 0;
+}
+
+static int pvfs_fuse_utime(const char *path, struct utimbuf *timbuf)
+{
+    int			ret;
+    PVFS_sys_attr	new_attr;
+ 
+    pvfs_fuse_handle_t	pfh;
+
+    ret = lookup( path, &pfh, PVFS2_LOOKUP_LINK_FOLLOW );
+    if ( ret < 0 )
+        return PVFS_ERROR_TO_ERRNO( ret );
+   
+    new_attr.atime = (PVFS_time)timbuf->actime;
+    new_attr.mtime = (PVFS_time)timbuf->modtime;
+    new_attr.mask = PVFS_ATTR_SYS_ATIME | PVFS_ATTR_SYS_MTIME;
+ 
+    ret = PVFS_sys_setattr(pfh.ref,new_attr,&pfh.creds);
+    if (ret < 0) 
+        return PVFS_ERROR_TO_ERRNO( ret );
+
+    return 0;
+}
+
+static int pvfs_fuse_open(const char *path, struct fuse_file_info *fi)
+{
+    pvfs_fuse_handle_t *pfhp;
+    int			ret;
+
+    pfhp = (pvfs_fuse_handle_t *)malloc( sizeof( pvfs_fuse_handle_t ) );
+    if (pfhp == NULL)
+    {
+        return -ENOMEM;
+    }
+
+    ret = lookup( path, pfhp, PVFS2_LOOKUP_LINK_FOLLOW );
+    if ( ret < 0 ) {
+      free( pfhp );
+      return PVFS_ERROR_TO_ERRNO( ret );
+    }
+
+    SET_FUSE_HANDLE( fi, pfhp );
+
+    return 0;
+}
+
+static int pvfs_fuse_read(const char *path, char *buf, size_t size, off_t offset,
+                    struct fuse_file_info *fi)
+{
+    PVFS_Request	mem_req, file_req;
+    PVFS_sysresp_io	resp_io;
+    int			ret;
+    pvfs_fuse_handle_t	*pfh = GET_FUSE_HANDLE( fi );
+  
+    file_req = PVFS_BYTE;
+    ret = PVFS_Request_contiguous(size, PVFS_BYTE, &mem_req);
+    if (ret < 0)
+        return PVFS_ERROR_TO_ERRNO( ret );
+
+    ret = PVFS_sys_read(pfh->ref, file_req, offset, buf,
+			mem_req, &pfh->creds, &resp_io);
+    if (ret == 0) 
+    {
+        PVFS_Request_free(&mem_req);
+	return(resp_io.total_completed);
+    }
+    else
+	return PVFS_ERROR_TO_ERRNO( ret );
+}
+
+static int pvfs_fuse_write(const char *path, const char *buf, size_t size,
+                     off_t offset, struct fuse_file_info *fi)
+{
+    PVFS_Request	mem_req, file_req;
+    PVFS_sysresp_io	resp_io;
+    int			ret;
+    pvfs_fuse_handle_t	*pfh = GET_FUSE_HANDLE( fi );
+  
+    file_req = PVFS_BYTE;
+    ret = PVFS_Request_contiguous(size, PVFS_BYTE, &mem_req);
+    if (ret < 0)
+        return PVFS_ERROR_TO_ERRNO( ret );
+
+    ret = PVFS_sys_write(pfh->ref, file_req, offset, (char*)buf,
+			 mem_req, &pfh->creds, &resp_io);
+    if (ret == 0) 
+    {
+        PVFS_Request_free(&mem_req);
+	return(resp_io.total_completed);
+    }
+    else
+	return PVFS_ERROR_TO_ERRNO( ret );
+}
+
+static int pvfs_fuse_statfs(const char *path, struct statvfs *stbuf)
+{
+    int			ret;
+    PVFS_credentials	creds;
+    PVFS_sysresp_statfs resp_statfs;
+
+    pvfs_fuse_gen_credentials(&creds);
+
+    /* gather normal statfs statistics from system interface */
+
+    ret = PVFS_sys_statfs(pvfs2fuse.fs_id, &creds, &resp_statfs);
+    if (ret < 0)
+        return PVFS_ERROR_TO_ERRNO( ret );
+
+    memcpy(&stbuf->f_fsid, &resp_statfs.statfs_buf.fs_id, 
+	   sizeof(resp_statfs.statfs_buf.fs_id));
+
+    /* is this bsize right? */
+
+    stbuf->f_bsize = PVFS2_BUFMAP_DEFAULT_DESC_SIZE;
+    stbuf->f_frsize = PVFS2_BUFMAP_DEFAULT_DESC_SIZE;
+    stbuf->f_namemax = PVFS_NAME_MAX;
+
+    stbuf->f_blocks = resp_statfs.statfs_buf.bytes_total / stbuf->f_bsize;
+    stbuf->f_bfree = resp_statfs.statfs_buf.bytes_available / stbuf->f_bsize;
+    stbuf->f_bavail = resp_statfs.statfs_buf.bytes_available / stbuf->f_bsize;
+    stbuf->f_files = resp_statfs.statfs_buf.handles_total_count;
+    stbuf->f_ffree = resp_statfs.statfs_buf.handles_available_count;
+    stbuf->f_favail = resp_statfs.statfs_buf.handles_available_count;
+
+    stbuf->f_flag = 0;
+
+    return 0;
+}
+
+static int pvfs_fuse_release(const char *path, struct fuse_file_info *fi)
+{
+    pvfs_fuse_handle_t *pfh = GET_FUSE_HANDLE( fi );
+  
+    if ( pfh != NULL ) {
+      free( pfh );
+      SET_FUSE_HANDLE( fi, NULL );
+    }
+
+    return 0;
+}
+
+static int pvfs_fuse_fsync(const char *path, int isdatasync,
+                     struct fuse_file_info *fi)
+{
+    /* Just a stub.  This method is optional and can safely be left
+       unimplemented */
+
+    (void) path;
+    (void) isdatasync;
+    (void) fi;
+    return 0;
+}
+
+#define MAX_NUM_DIRENTS    32
+
+static int pvfs_fuse_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
+                       off_t offset, struct fuse_file_info *fi)
+{
+    int			ret;
+    PVFS_ds_position	token;
+    pvfs_fuse_handle_t	pfh;
+    int			pvfs_dirent_incount;
+    PVFS_sysresp_readdir rd_response;
+
+    ret = lookup( path, &pfh, PVFS2_LOOKUP_LINK_FOLLOW );
+    if ( ret < 0 )
+        return PVFS_ERROR_TO_ERRNO( ret );
+
+    pvfs_dirent_incount = MAX_NUM_DIRENTS;
+    token = 0;
+    do
+    {
+	char *cur_file = NULL;
+	int i;
+
+        memset(&rd_response, 0, sizeof(PVFS_sysresp_readdir));
+        ret = PVFS_sys_readdir(
+                pfh.ref, (!token ? PVFS_READDIR_START : token),
+                pvfs_dirent_incount, &pfh.creds, &rd_response);
+        if(ret < 0)
+	    return PVFS_ERROR_TO_ERRNO( ret );
+
+        for(i = 0; i < rd_response.pvfs_dirent_outcount; i++)
+        {
+            cur_file = rd_response.dirent_array[i].d_name;
+
+	    if (filler(buf, cur_file, NULL, 0))
+		break;
+        }
+        token += rd_response.pvfs_dirent_outcount;
+
+        if (rd_response.pvfs_dirent_outcount)
+        {
+            free(rd_response.dirent_array);
+            rd_response.dirent_array = NULL;
+        }
+
+    } while(rd_response.pvfs_dirent_outcount == pvfs_dirent_incount);
+
+return 0;
+}
+
+static int pvfs_fuse_access(const char *path, int mask)
+{
+    PVFS_sysresp_getattr getattr_response;
+    PVFS_sys_attr*	attrs;
+    int			ret;
+    pvfs_fuse_handle_t	pfh;
+    int			in_group_flag = 0;
+
+    ret = lookup( path, &pfh, PVFS2_LOOKUP_LINK_FOLLOW );
+    if ( ret < 0 )
+        return PVFS_ERROR_TO_ERRNO( ret );
+
+    /* give root permission, no matter what */
+    if ( pfh.creds.uid == 0 )
+	return 0;
+
+    /* if checking for file existence, return 0 */
+    if ( mask == F_OK )
+	return 0;
+
+    ret = PVFS_sys_getattr(pfh.ref, 
+                          PVFS_ATTR_SYS_ALL_NOHINT,
+                          (PVFS_credentials *) &pfh.creds, 
+                          &getattr_response);
+    if ( ret < 0 )
+        return PVFS_ERROR_TO_ERRNO( ret );
+
+    attrs = &getattr_response.attr;
+
+    /* basic code is copied from PINT_check_mode() */
+
+    /* see if uid matches object owner */
+    if ( attrs->owner == pfh.creds.uid )
+    {
+        /* see if object user permissions match access type */
+        if( (mask & R_OK) && (attrs->perms & PVFS_U_READ))
+        {
+            return(0);
+        }
+        if( (mask & W_OK) && (attrs->perms & PVFS_U_WRITE))
+        {
+            return(0);
+        }
+        if( (mask & X_OK) && (attrs->perms & PVFS_U_EXECUTE))
+        {
+            return(0);
+        }
+    }
+
+    /* see if other bits allow access */
+    if( (mask & R_OK) && (attrs->perms & PVFS_O_READ))
+    {
+        return(0);
+    }
+    if( (mask & W_OK) && (attrs->perms & PVFS_O_WRITE))
+    {
+        return(0);
+    }
+    if( (mask & X_OK) && (attrs->perms & PVFS_O_EXECUTE))
+    {
+        return(0);
+    }
+
+    /* see if gid matches object group */
+    if(attrs->group == pfh.creds.gid)
+    {
+        /* default group match */
+        in_group_flag = 1;
+    }
+    else
+    {
+        /* no default group match, check supplementary groups */
+        ret = PINT_check_group(pfh.creds.uid, attrs->group);
+        if(ret == 0)
+        {
+            in_group_flag = 1;
+        }
+        else
+        {
+            if(ret != -PVFS_ENOENT)
+            {
+                /* system error; not just failed match */
+                return(ret);
+            }
+        }
+    }
+
+    if(in_group_flag)
+    {
+        /* see if object group permissions match access type */
+        if( (mask & R_OK) && (attrs->perms & PVFS_G_READ))
+        {
+            return(0);
+        }
+        if( (mask & W_OK) && (attrs->perms & PVFS_G_WRITE))
+        {
+            return(0);
+        }
+        if( (mask & X_OK) && (attrs->perms & PVFS_G_EXECUTE))
+        {
+            return(0);
+        }
+    }
+  
+    /* default case: access denied */
+    return -EACCES;
+}
+
+static int pvfs_fuse_create(const char *path, mode_t mode,
+			    struct fuse_file_info *fi)
+{
+    int rc;
+    int num_segs;
+    PVFS_sys_attr attr;
+    char directory[PVFS_NAME_MAX];
+    char filename[PVFS_SEGMENT_MAX];
+    pvfs_fuse_handle_t	dir_pfh, *pfhp;
+
+    PVFS_sysresp_create resp_create;
+
+    /* Translate path into pvfs2 relative path */
+    rc = PINT_get_base_dir((char *)path, directory, PVFS_NAME_MAX);
+    num_segs = PINT_string_count_segments((char *)path);
+    rc = PINT_get_path_element((char *)path, num_segs - 1,
+			       filename, PVFS_SEGMENT_MAX);
+
+    if (rc)
+    {
+	return PVFS_ERROR_TO_ERRNO( rc );
+    }
+
+    rc = lookup( directory, &dir_pfh, PVFS2_LOOKUP_LINK_FOLLOW );
+    if ( rc < 0 )
+        return PVFS_ERROR_TO_ERRNO( rc );
+
+    /* Set attributes */
+    memset(&attr, 0, sizeof(PVFS_sys_attr));
+    attr.owner = dir_pfh.creds.uid;
+    attr.group = dir_pfh.creds.gid;
+    attr.perms = mode;
+    attr.atime = time(NULL);
+    attr.mtime = attr.atime;
+    attr.mask = PVFS_ATTR_SYS_ALL_SETABLE;
+    attr.dfile_count = 0;
+
+    rc = PVFS_sys_create(filename,
+			 dir_pfh.ref,
+			 attr,
+			 &dir_pfh.creds,
+			 NULL,
+			 &resp_create);
+    if (rc)
+    {
+      /* FIXME
+       * the PVFS2 server code returns a ENOENT instead of an EACCES
+       * because it does a ACL lookup for the system.posix_acl_access
+       * which returns a ENOENT from the TROVE DBPF and that error is
+       * just passed up in prelude_check_acls (server/prelude.c).  I'm
+       * not sure that's the right thing to do.
+       */
+        if ( rc == -PVFS_ENOENT ) 
+	{
+	    return -EACCES;
+	}
+        return PVFS_ERROR_TO_ERRNO( rc );
+    }
+
+    pfhp = (pvfs_fuse_handle_t *)malloc( sizeof( pvfs_fuse_handle_t ) );
+    if (pfhp == NULL)
+    {
+        return -ENOMEM;
+    }
+
+    pfhp->ref = resp_create.ref;
+    pfhp->creds = dir_pfh.creds;
+
+    SET_FUSE_HANDLE( fi, pfhp );
+
+    return 0;
+}
+
+static struct fuse_operations pvfs_fuse_oper = {
+    .getattr	= pvfs_fuse_getattr,
+    .fgetattr	= pvfs_fuse_fgetattr,
+    .readlink	= pvfs_fuse_readlink,
+    .mkdir	= pvfs_fuse_mkdir,
+    .unlink	= pvfs_fuse_unlink,
+    .rmdir	= pvfs_fuse_rmdir,
+    .symlink	= pvfs_fuse_symlink,
+    .rename	= pvfs_fuse_rename,
+    /* .link	= pvfs_fuse_link, */ /* hard links not supported on PVFS */
+    .chmod	= pvfs_fuse_chmod,
+    .chown	= pvfs_fuse_chown,
+    .truncate	= pvfs_fuse_truncate,
+    .utime	= pvfs_fuse_utime,
+    .open	= pvfs_fuse_open,
+    .read	= pvfs_fuse_read,
+    .write	= pvfs_fuse_write,
+    .statfs	= pvfs_fuse_statfs,
+/*  .flush	= pvfs_fuse_flush, */
+    .release	= pvfs_fuse_release,
+    .fsync	= pvfs_fuse_fsync,
+    .readdir	= pvfs_fuse_readdir,
+    .access	= pvfs_fuse_access,
+    .create	= pvfs_fuse_create,
+};
+
+enum {
+    KEY_HELP,
+    KEY_VERSION,
+};
+
+#define PVFS2FUSE_OPT(t, p, v) { t, offsetof(struct pvfs2fuse, p), v }
+
+static struct fuse_opt pvfs2fuse_opts[] = {
+    PVFS2FUSE_OPT("fs_spec=%s",     fs_spec, 0),
+
+    FUSE_OPT_KEY("-V",             KEY_VERSION),
+    FUSE_OPT_KEY("--version",      KEY_VERSION),
+    FUSE_OPT_KEY("-h",             KEY_HELP),
+    FUSE_OPT_KEY("--help",         KEY_HELP),
+    FUSE_OPT_END
+};
+
+static void usage(const char *progname)
+{
+    fprintf(stderr,
+"usage: %s mountpoint [options]\n"
+"\n"
+"general options:\n"
+"    -o opt,[opt...]        mount options\n"
+"    -h   --help            print help\n"
+"    -V   --version         print version\n"
+"\n"
+"PVFS2FUSE options:\n"
+"    -o fs_spec=FS_SPEC     PVFS2 fs_spec URI (eg. tcp://localhost:3334/pvfs2-fs)\n"
+"\n", progname);
+}
+
+static int pvfs_fuse_main(struct fuse_args *args)
+{
+#if FUSE_VERSION >= 26
+    return fuse_main(args->argc, args->argv, &pvfs_fuse_oper, NULL);
+#else
+    return fuse_main(args->argc, args->argv, &pvfs_fuse_oper);
+#endif
+}
+
+static int pvfs2fuse_opt_proc(void *data, const char *arg, int key,
+				struct fuse_args *outargs)
+{
+    (void) data;
+
+    switch (key) {
+    case FUSE_OPT_KEY_OPT:
+        return 1;
+
+    case FUSE_OPT_KEY_NONOPT:
+        if (!pvfs2fuse.mntpoint) {
+            pvfs2fuse.mntpoint = strdup(arg);
+        }
+        return 1;
+
+    case KEY_HELP:
+        usage(outargs->argv[0]);
+	/* for now don't show the FUSE arguments
+        fuse_opt_add_arg(outargs, "-ho");
+        pvfs_fuse_main(outargs); */
+        exit(1);
+
+    case KEY_VERSION:
+        fprintf(stderr, "PVFS2FUSE version %s (PVFS2 %s) (%s, %s)\n",
+                pvfs2fuse_version, PVFS2_VERSION, __DATE__, __TIME__);
+#if FUSE_VERSION >= 25
+        fuse_opt_add_arg(outargs, "--version");
+        pvfs_fuse_main(outargs);
+#endif
+        exit(0);
+
+    default:
+        fprintf(stderr, "internal error\n");
+        abort();
+    }
+}
+
+int main(int argc, char *argv[])
+{
+    int ret;
+    struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
+
+    umask(0);
+
+    if (fuse_opt_parse(&args, &pvfs2fuse, pvfs2fuse_opts,
+		       pvfs2fuse_opt_proc) == -1 )
+	exit(1);
+
+    if (pvfs2fuse.fs_spec == NULL)
+    {
+	ret = PVFS_util_init_defaults();
+	if(ret < 0)
+	{
+	    PVFS_perror("PVFS_util_init_defaults", ret);
+	    return(-1);
+	}
+
+	ret = PVFS_util_get_default_fsid(&pvfs2fuse.fs_id);
+	if( ret < 0 )
+	{
+	    PVFS_perror("No default PVFS2 filesystem found", ret);
+	    return(-1);
+	}
+
+	PVFS_util_get_mntent_copy( pvfs2fuse.fs_id, &pvfs2fuse.mntent );
+    }
+    else
+    {
+	struct PVFS_sys_mntent *me = &pvfs2fuse.mntent;
+	char *cp;
+	int cur_server;
+
+	/* the following is copied from PVFS_util_init_defaults()
+	   in fuse/lib/pvfs2-util.c */
+
+	/* initialize pvfs system interface */
+	ret = PVFS_sys_initialize(GOSSIP_NO_DEBUG);
+	if (ret < 0)
+	{
+	    return(ret);
+	}
+
+	/* the following is copied from PVFS_util_parse_pvfstab()
+	   in fuse/lib/pvfs2-util.c */
+	memset( me, 0, sizeof(pvfs2fuse.mntent) );
+
+	/* Enable integrity checks by default */
+	me->integrity_check = 1;
+	/* comma-separated list of ways to contact a config server */
+	me->num_pvfs_config_servers = 1;
+
+	for (cp=pvfs2fuse.fs_spec; *cp; cp++)
+	    if (*cp == ',')
+		++me->num_pvfs_config_servers;
+
+	/* allocate room for our copies of the strings */
+	me->pvfs_config_servers =
+	    malloc(me->num_pvfs_config_servers *
+		   sizeof(*me->pvfs_config_servers));
+	if (!me->pvfs_config_servers)
+	    exit(-1);
+	memset(me->pvfs_config_servers, 0,
+	       me->num_pvfs_config_servers * sizeof(*me->pvfs_config_servers));
+
+	me->mnt_dir = strdup(pvfs2fuse.mntpoint);
+	me->mnt_opts = NULL;
+
+	cp = pvfs2fuse.fs_spec;
+	cur_server = 0;
+	for (;;) {
+	    char *tok;
+	    int slashcount;
+	    char *slash;
+	    char *last_slash;
+
+	    tok = strsep(&cp, ",");
+	    if (!tok) break;
+
+	    slash = tok;
+	    slashcount = 0;
+	    while ((slash = index(slash, '/')))
+            {
+		slash++;
+		slashcount++;
+	    }
+	    if (slashcount != 3)
+            {
+		fprintf(stderr,"Error: invalid FS spec: %s\n",
+			pvfs2fuse.fs_spec);
+		exit(-1);
+	    }
+
+	    /* find a reference point in the string */
+	    last_slash = rindex(tok, '/');
+	    *last_slash = '\0';
+
+	    /* config server and fs name are a special case, take one 
+	     * string and split it in half on "/" delimiter
+	     */
+	    me->pvfs_config_servers[cur_server] = strdup(tok);
+	    if (!me->pvfs_config_servers[cur_server])
+		exit(-1);
+
+	    ++last_slash;
+
+	    if (cur_server == 0) {
+		me->pvfs_fs_name = strdup(last_slash);
+		if (!me->pvfs_fs_name)
+		    exit(-1);
+	    } else {
+		if (strcmp(last_slash, me->pvfs_fs_name) != 0) {
+		    fprintf(stderr,
+                          "Error: different fs names in server addresses: %s\n",
+                          pvfs2fuse.fs_spec);
+		    exit(-1);
+		}
+	    }
+	    ++cur_server;
+	}
+	
+	/* flowproto, encoding, and default_num_dfiles
+	   should be set as a command line option */
+	me->flowproto = FLOWPROTO_DEFAULT;
+	me->encoding = ENCODING_DEFAULT;
+
+	ret = PVFS_sys_fs_add(me);
+	if( ret < 0 )
+	{
+	    PVFS_perror("Could not add mnt entry", ret);
+	    return(-1);
+	}
+	pvfs2fuse.fs_id = me->fs_id;
+    }
+
+    /* Should we allow all the FUSE options?  Maybe we should
+     * pass only some of the FUSE options to fuse_main.  For now,
+     * force the direct_io and allow_other options.  Also turn off
+     * multithreaded operation since it doesnt work with PVFS.
+     */
+
+    fuse_opt_insert_arg( &args, 1, "-odirect_io" );
+    if ( getuid() == 0 )
+	fuse_opt_insert_arg( &args, 1, "-oallow_other" );
+    fuse_opt_insert_arg( &args, 1, "-s" );
+    
+    {
+	/* set the fsname and volname */
+	char name[200];
+	char *config = pvfs2fuse.mntent.the_pvfs_config_server;
+
+	if ( !config )
+	    config = pvfs2fuse.mntent.pvfs_config_servers[0];
+
+	snprintf( name, 200, "-ofsname=pvfs2fuse#%s", config );
+	fuse_opt_insert_arg( &args, 1, name );
+#if (__FreeBSD__ >= 10)
+	snprintf( name, 200, "-ovolname=%s", pvfs2fuse.mntent.pvfs_fs_name );
+	fuse_opt_insert_arg( &args, 1, name );
+#endif
+    }
+    
+#if (__FreeBSD__ >= 10)
+    {
+	/* MacFUSE has a bug where cached attributes
+	 * arent invalidated on direct_io writes
+	 */
+	fuse_opt_insert_arg( &args, 1, "-oattr_timeout=0" );
+    }
+#endif
+
+    return pvfs_fuse_main(&args);
+}
