Changes from raven at themaw.net to support NFSv3 for automounted
authorChristos Zoulas <christos@zoulas.com>
Sun, 20 Jul 2014 09:55:12 +0000 (05:55 -0400)
committerChristos Zoulas <christos@zoulas.com>
Sun, 20 Jul 2014 09:55:12 +0000 (05:55 -0400)
toplevel filesystems presented to the list in May. A few bug fixes
and integration changes by me. The code now works well enough to
mount the filesystem with NFSv3 and automount children but readdir
does not work yet (so no listing of automounted filesystems). The
new code is not enabled by default. To enable use auto_nfs_version = 3
in your configuration file.

20 files changed:
amd/amd.h
amd/amfs_error.c
amd/amfs_generic.c
amd/autil.c
amd/conf.c
amd/map.c
amd/nfs_prot_svc.c
amd/nfs_start.c
amd/nfs_subr.c
amd/ops_TEMPLATE.c
amd/readdir.c
amd/restart.c
conf/nfs_prot/nfs_prot_netbsd1_4.h
conf/transp/transp_sockets.c
conf/transp/transp_tli.c
hlfsd/hlfsd.c
include/am_utils.h
include/am_xdr_func.h
libamu/mount_fs.c
libamu/xdr_func.c

index 883a67a66d770b0f691e5610896860085e18e4d7..b9bdcf52a67550f7f02648fc9f994d88c4fe0030 100644 (file)
--- a/amd/amd.h
+++ b/amd/amd.h
@@ -242,13 +242,17 @@ typedef int (*vmount_fs) (am_node *, mntfs *);
 typedef int (*vumount_fs) (am_node *, mntfs *);
 typedef am_node *(*vlookup_child) (am_node *, char *, int *, int);
 typedef am_node *(*vmount_child) (am_node *, int *);
-typedef int (*vreaddir) (am_node *, nfscookie, nfsdirlist *, nfsentry *, u_int);
+typedef int (*vreaddir) (am_node *, voidp, voidp, voidp, u_int);
 typedef am_node *(*vreadlink) (am_node *, int *);
 typedef void (*vmounted) (mntfs *);
 typedef void (*vumounted) (mntfs *);
 typedef fserver *(*vffserver) (mntfs *);
 typedef wchan_t (*vget_wchan) (mntfs *);
 
+/*
+ * NFS progran dispatcher
+ */
+typedef void (*dispatcher_t)(struct svc_req *rqstp, SVCXPRT *transp);
 
 
 /*
@@ -472,6 +476,8 @@ struct am_stats {
   int s_readdir;               /* Count of readdirs */
   int s_readlink;              /* Count of readlinks */
   int s_statfs;                        /* Count of statfs */
+  int s_fsinfo;                        /* Count of fsinfo */
+  int s_pathconf;              /* Count of pathconf */
 };
 
 /*
@@ -662,6 +668,7 @@ extern char hostd[SIZEOF_HOSTD]; /* Host+domain */
  * Global variables.
  */
 extern SVCXPRT *current_transp; /* For nfs_quick_reply() */
+extern dispatcher_t nfs_dispatcher;
 extern char *conf_tag;
 #define SIZEOF_UID_STR 12
 #define SIZEOF_GID_STR 12
@@ -819,7 +826,7 @@ extern am_ops amfs_root_ops;        /* Root file system */
  */
 extern am_node *amfs_generic_lookup_child(am_node *mp, char *fname, int *error_return, int op);
 extern am_node *amfs_generic_mount_child(am_node *ap, int *error_return);
-extern int amfs_generic_readdir(am_node *mp, nfscookie cookie, nfsdirlist *dp, nfsentry *ep, u_int count);
+extern int amfs_generic_readdir(am_node *mp, voidp cookie, voidp dp, voidp ep, u_int count);
 extern int amfs_generic_umount(am_node *mp, mntfs *mf);
 extern void amfs_generic_mounted(mntfs *mf);
 extern char *amfs_generic_match(am_opts *fo);
@@ -855,7 +862,8 @@ extern am_ops amfs_direct_ops;      /* Direct Automount file system (this too) */
 extern am_ops amfs_error_ops;  /* Error file system */
 extern am_node *amfs_error_lookup_child(am_node *mp, char *fname, int *error_return, int op);
 extern am_node *amfs_error_mount_child(am_node *ap, int *error_return);
-extern int amfs_error_readdir(am_node *mp, nfscookie cookie, nfsdirlist *dp, nfsentry *ep, u_int count);
+extern int amfs_error_readdir(am_node *mp, voidp cookie, voidp dp, voidp ep, u_int count);
+
 #endif /* HAVE_AMU_FS_ERROR */
 
 /*
index 8e015ed94ad2c572a1daed0b2470572878bba2b1..58a623102c1e06c5e42b042c8ba255d4120e7687 100644 (file)
@@ -141,7 +141,7 @@ amfs_error_mount_child(am_node *ap, int *error_return)
  * If we do then just give an error.
  */
 int
-amfs_error_readdir(am_node *mp, nfscookie cookie, nfsdirlist *dp, nfsentry *ep, u_int count)
+amfs_error_readdir(am_node *mp, voidp cookie, voidp dp, voidp ep, u_int count)
 {
   return ESTALE;
 }
index 1ba3c8b5f00100da3060447712d7d367d6d889f5..25d734bbde0094f211a3b9184d6cdb28d1dd0a70 100644 (file)
@@ -1120,7 +1120,7 @@ amfs_generic_mount_child(am_node *new_mp, int *error_return)
 
   /*
    * Code for quick reply.  If current_transp is set, then it's the
-   * transp that's been passed down from nfs_program_2() or from
+   * transp that's been passed down from nfs_dispatcher() or from
    * autofs_program_[123]().
    * If new_mp->am_transp is not already set, set it by copying in
    * current_transp.  Once am_transp is set, nfs_quick_reply() and
index 7320188375f2d166c6bce1a1426f4f13312440e1..cc073e89f57dc88e0915135950e6392dce93d8e0 100644 (file)
@@ -451,8 +451,9 @@ amfs_mount(am_node *mp, mntfs *mf, char *opts)
   mntent_t mnt;
   MTYPE_TYPE type;
   int forced_unmount = 0;      /* are we using forced unmounts? */
+  u_long nfs_version = get_nfs_dispatcher_version(nfs_dispatcher);
 
-  memset((voidp) &mnt, 0, sizeof(mnt));
+  memset(&mnt, 0, sizeof(mnt));
   mnt.mnt_dir = dir;
   mnt.mnt_fsname = pid_fsname;
   mnt.mnt_opts = opts;
@@ -543,7 +544,7 @@ again:
     /*
      * Create sockaddr to point to the local machine.
      */
-    memset((voidp) &sin, 0, sizeof(sin));
+    memset(&sin, 0, sizeof(sin));
     /* as per POSIX, sin_len need not be set (used internally by kernel) */
     sin.sin_family = AF_INET;
     sin.sin_addr = myipaddr;
@@ -564,7 +565,7 @@ again:
                     genflags,
                     nfsncp,
                     NULL,      /* remote host IP addr is set below */
-                    NFS_VERSION,       /* version 2 */
+                    nfs_version,
                     "udp",
                     &anh,
                     fs_hostname,
@@ -585,7 +586,7 @@ again:
                     genflags,
                     NULL,
                     &sin,
-                    NFS_VERSION,       /* version 2 */
+                    nfs_version,
                     "udp",
                     &anh,
                     fs_hostname,
index 8cf65577d371a7173391fe56d73c88d8feb12a36..57e1b9ddbd02adf87be6b659cb254d014534f7f3 100644 (file)
@@ -73,6 +73,7 @@ struct _func_map {
 static int gopt_arch(const char *val);
 static int gopt_auto_attrcache(const char *val);
 static int gopt_auto_dir(const char *val);
+static int gopt_auto_nfs_version(const char *val);
 static int gopt_autofs_use_lofs(const char *val);
 static int gopt_browsable_dirs(const char *val);
 static int gopt_cache_duration(const char *val);
@@ -158,6 +159,7 @@ static struct _func_map glob_functable[] = {
   {"arch",                     gopt_arch},
   {"auto_attrcache",           gopt_auto_attrcache},
   {"auto_dir",                 gopt_auto_dir},
+  {"auto_nfs_version",         gopt_auto_nfs_version},
   {"autofs_use_lofs",          gopt_autofs_use_lofs},
   {"browsable_dirs",           gopt_browsable_dirs},
   {"cache_duration",           gopt_cache_duration},
@@ -393,6 +395,19 @@ gopt_auto_dir(const char *val)
   return 0;
 }
 
+static int
+gopt_auto_nfs_version(const char *val)
+{
+  if (strcmp(val, "2") == 0)
+    nfs_dispatcher = nfs_program_2;
+  else if (strcmp(val, "3") == 0)
+    nfs_dispatcher = nfs_program_3;
+  else {
+    fprintf(stderr, "conf: bad auto nfs version : \"%s\"\n", val);
+    return 1;
+  }
+  return 0;
+}
 
 static int
 gopt_autofs_use_lofs(const char *val)
index 00e42c64e0af649b65e557f7fbb4ac5b7addb7a9..d924d703c08739cac05a5f4fa2b5cb167b020dda 100644 (file)
--- a/amd/map.c
+++ b/amd/map.c
@@ -548,7 +548,10 @@ get_root_nfs_fh(char *dir)
   static am_nfs_fh nfh;
   am_node *mp = get_root_ap(dir);
   if (mp) {
-    mp_to_fh(mp, &nfh);
+    if (nfs_dispatcher == nfs_program_2)
+      mp_to_fh(mp, &nfh);
+    else
+      mp_to_fh3(mp, &nfh);
     return &nfh;
   }
 
index b3366b6dd3d16e8c47b4cf53ea76a0729d0331fb..cbde17274aeab70c1af94b93c1911180dfb75ce6 100644 (file)
@@ -65,6 +65,7 @@ extern nfsstatfsres *nfsproc_statfs_2_svc(am_nfs_fh *, struct svc_req *);
 
 /* global variables */
 SVCXPRT *current_transp;
+dispatcher_t nfs_dispatcher = nfs_program_2;
 
 /* typedefs */
 typedef char *(*nfssvcproc_t)(voidp, struct svc_req *);
@@ -295,3 +296,193 @@ nfs_program_2(struct svc_req *rqstp, SVCXPRT *transp)
     going_down(1);
   }
 }
+
+void
+nfs_program_3(struct svc_req *rqstp, register SVCXPRT *transp)
+{
+  union {
+    am_GETATTR3args am_nfs3_getattr_3_arg;
+    am_SETATTR3args am_nfs3_setattr_3_arg;
+    am_LOOKUP3args am_nfs3_lookup_3_arg;
+    am_ACCESS3args am_nfs3_access_3_arg;
+    am_READLINK3args am_nfs3_readlink_3_arg;
+    am_READ3args am_nfs3_read_3_arg;
+    am_WRITE3args am_nfs3_write_3_arg;
+    am_CREATE3args am_nfs3_create_3_arg;
+    am_MKDIR3args am_nfs3_mkdir_3_arg;
+    am_SYMLINK3args am_nfs3_symlink_3_arg;
+    am_MKNOD3args am_nfs3_mknod_3_arg;
+    am_REMOVE3args am_nfs3_remove_3_arg;
+    am_RMDIR3args am_nfs3_rmdir_3_arg;
+    am_RENAME3args am_nfs3_rename_3_arg;
+    am_LINK3args am_nfs3_link_3_arg;
+    am_READDIR3args am_nfs3_readdir_3_arg;
+    am_READDIRPLUS3args am_nfs3_readdirplus_3_arg;
+    am_FSSTAT3args am_nfs3_fsstat_3_arg;
+    am_FSINFO3args am_nfs3_fsinfo_3_arg;
+    am_PATHCONF3args am_nfs3_pathconf_3_arg;
+    am_COMMIT3args am_nfs3_commit_3_arg;
+  } argument;
+  char *result;
+  xdrproc_t _xdr_argument, _xdr_result;
+  nfssvcproc_t local;
+
+  switch (rqstp->rq_proc) {
+  case AM_NFS3_NULL:
+    _xdr_argument = (xdrproc_t) xdr_void;
+    _xdr_result = (xdrproc_t) xdr_void;
+    local = (nfssvcproc_t) am_nfs3_null_3_svc;
+    break;
+
+  case AM_NFS3_GETATTR:
+    _xdr_argument = (xdrproc_t) xdr_am_GETATTR3args;
+    _xdr_result = (xdrproc_t) xdr_am_GETATTR3res;
+    local = (nfssvcproc_t) (char *(*)(char *, struct svc_req *)) am_nfs3_getattr_3_svc;
+    break;
+
+  case AM_NFS3_SETATTR:
+    _xdr_argument = (xdrproc_t) xdr_am_SETATTR3args;
+    _xdr_result = (xdrproc_t) xdr_am_SETATTR3res;
+    local = (nfssvcproc_t) (char *(*)(char *, struct svc_req *)) am_nfs3_setattr_3_svc;
+    break;
+
+  case AM_NFS3_LOOKUP:
+    _xdr_argument = (xdrproc_t) xdr_am_LOOKUP3args;
+    _xdr_result = (xdrproc_t) xdr_am_LOOKUP3res;
+    local = (nfssvcproc_t) (char *(*)(char *, struct svc_req *)) am_nfs3_lookup_3_svc;
+    break;
+
+  case AM_NFS3_ACCESS:
+    _xdr_argument = (xdrproc_t) xdr_am_ACCESS3args;
+    _xdr_result = (xdrproc_t) xdr_am_ACCESS3res;
+    local = (nfssvcproc_t) (char *(*)(char *, struct svc_req *)) am_nfs3_access_3_svc;
+    break;
+
+  case AM_NFS3_READLINK:
+    _xdr_argument = (xdrproc_t) xdr_am_READLINK3args;
+    _xdr_result = (xdrproc_t) xdr_am_READLINK3res;
+    local = (nfssvcproc_t) (char *(*)(char *, struct svc_req *)) am_nfs3_readlink_3_svc;
+    break;
+
+  case AM_NFS3_READ:
+    _xdr_argument = (xdrproc_t) xdr_am_READ3args;
+    _xdr_result = (xdrproc_t) xdr_am_READ3res;
+    local = (nfssvcproc_t) (char *(*)(char *, struct svc_req *)) am_nfs3_read_3_svc;
+    break;
+
+  case AM_NFS3_WRITE:
+    _xdr_argument = (xdrproc_t) xdr_am_WRITE3args;
+    _xdr_result = (xdrproc_t) xdr_am_WRITE3res;
+    local = (nfssvcproc_t) (char *(*)(char *, struct svc_req *)) am_nfs3_write_3_svc;
+    break;
+
+  case AM_NFS3_CREATE:
+    _xdr_argument = (xdrproc_t) xdr_am_CREATE3args;
+    _xdr_result = (xdrproc_t) xdr_am_CREATE3res;
+    local = (nfssvcproc_t) (char *(*)(char *, struct svc_req *)) am_nfs3_create_3_svc;
+    break;
+
+  case AM_NFS3_MKDIR:
+    _xdr_argument = (xdrproc_t) xdr_am_MKDIR3args;
+    _xdr_result = (xdrproc_t) xdr_am_MKDIR3res;
+    local = (nfssvcproc_t) (char *(*)(char *, struct svc_req *)) am_nfs3_mkdir_3_svc;
+    break;
+
+  case AM_NFS3_SYMLINK:
+    _xdr_argument = (xdrproc_t) xdr_am_SYMLINK3args;
+    _xdr_result = (xdrproc_t) xdr_am_SYMLINK3res;
+    local = (nfssvcproc_t) (char *(*)(char *, struct svc_req *)) am_nfs3_symlink_3_svc;
+    break;
+
+  case AM_NFS3_MKNOD:
+    _xdr_argument = (xdrproc_t) xdr_am_MKNOD3args;
+    _xdr_result = (xdrproc_t) xdr_am_MKNOD3res;
+    local = (nfssvcproc_t) (char *(*)(char *, struct svc_req *)) am_nfs3_mknod_3_svc;
+    break;
+
+  case AM_NFS3_REMOVE:
+    _xdr_argument = (xdrproc_t) xdr_am_REMOVE3args;
+    _xdr_result = (xdrproc_t) xdr_am_REMOVE3res;
+    local = (nfssvcproc_t) (char *(*)(char *, struct svc_req *)) am_nfs3_remove_3_svc;
+    break;
+
+  case AM_NFS3_RMDIR:
+    _xdr_argument = (xdrproc_t) xdr_am_RMDIR3args;
+    _xdr_result = (xdrproc_t) xdr_am_RMDIR3res;
+    local = (nfssvcproc_t) (char *(*)(char *, struct svc_req *)) am_nfs3_rmdir_3_svc;
+    break;
+
+  case AM_NFS3_RENAME:
+    _xdr_argument = (xdrproc_t) xdr_am_RENAME3args;
+    _xdr_result = (xdrproc_t) xdr_am_RENAME3res;
+    local = (nfssvcproc_t) (char *(*)(char *, struct svc_req *)) am_nfs3_rename_3_svc;
+    break;
+
+  case AM_NFS3_LINK:
+    _xdr_argument = (xdrproc_t) xdr_am_LINK3args;
+    _xdr_result = (xdrproc_t) xdr_am_LINK3res;
+    local = (nfssvcproc_t) (char *(*)(char *, struct svc_req *)) am_nfs3_link_3_svc;
+    break;
+
+  case AM_NFS3_READDIR:
+    _xdr_argument = (xdrproc_t) xdr_am_READDIR3args;
+    _xdr_result = (xdrproc_t) xdr_am_READDIR3res;
+    local = (nfssvcproc_t) (char *(*)(char *, struct svc_req *)) am_nfs3_readdir_3_svc;
+    break;
+
+  case AM_NFS3_READDIRPLUS:
+    _xdr_argument = (xdrproc_t) xdr_am_READDIRPLUS3args;
+    _xdr_result = (xdrproc_t) xdr_am_READDIRPLUS3res;
+    local = (nfssvcproc_t) (char *(*)(char *, struct svc_req *)) am_nfs3_readdirplus_3_svc;
+    break;
+
+  case AM_NFS3_FSSTAT:
+    _xdr_argument = (xdrproc_t) xdr_am_FSSTAT3args;
+    _xdr_result = (xdrproc_t) xdr_am_FSSTAT3res;
+    local = (nfssvcproc_t) (char *(*)(char *, struct svc_req *)) am_nfs3_fsstat_3_svc;
+    break;
+
+  case AM_NFS3_FSINFO:
+    _xdr_argument = (xdrproc_t) xdr_am_FSINFO3args;
+    _xdr_result = (xdrproc_t) xdr_am_FSINFO3res;
+    local = (nfssvcproc_t) (char *(*)(char *, struct svc_req *)) am_nfs3_fsinfo_3_svc;
+    break;
+
+  case AM_NFS3_PATHCONF:
+    _xdr_argument = (xdrproc_t) xdr_am_PATHCONF3args;
+    _xdr_result = (xdrproc_t) xdr_am_PATHCONF3res;
+    local = (nfssvcproc_t) (char *(*)(char *, struct svc_req *)) am_nfs3_pathconf_3_svc;
+    break;
+
+  case AM_NFS3_COMMIT:
+    _xdr_argument = (xdrproc_t) xdr_am_COMMIT3args;
+    _xdr_result = (xdrproc_t) xdr_am_COMMIT3res;
+    local = (nfssvcproc_t) (char *(*)(char *, struct svc_req *)) am_nfs3_commit_3_svc;
+    break;
+
+  default:
+    svcerr_noproc (transp);
+    return;
+  }
+
+  memset ((char *)&argument, 0, sizeof (argument));
+
+  if (!svc_getargs(transp, (xdrproc_t) _xdr_argument, (caddr_t) &argument)) {
+    plog(XLOG_ERROR,
+        "NFS xdr decode failed for %d %d %d",
+        (int) rqstp->rq_prog, (int) rqstp->rq_vers, (int) rqstp->rq_proc);
+    svcerr_decode(transp);
+    return;
+  }
+
+  result = (*local) (&argument, rqstp);
+  if (result != NULL && !svc_sendreply(transp, (xdrproc_t) _xdr_result, result)) {
+    svcerr_systemerr (transp);
+  }
+
+  if (!svc_freeargs (transp, (xdrproc_t) _xdr_argument, (caddr_t) &argument)) {
+    plog(XLOG_FATAL, "unable to free rpc arguments in nfs_program_3");
+    going_down(1);
+  }
+  return;
+}
index 87db6bcfdfb72bb4a5ec22720ee030d12374ad1c..b6c544ddf178db7d4e6878d45fac22852fa5b6c0 100644 (file)
@@ -360,7 +360,8 @@ mount_automounter(int ppid)
    * already created the service during restart_automounter_nodes().
    */
   if (nfs_port == 0) {
-    ret = create_nfs_service(&soNFS, &nfs_port, &nfsxprt, nfs_program_2);
+    ret = create_nfs_service(&soNFS, &nfs_port, &nfsxprt, nfs_dispatcher,
+       get_nfs_dispatcher_version(nfs_dispatcher));
     if (ret != 0)
       return ret;
   }
index 4c7157e760e423da6bb32aa78c84e8d78f8cb0f9..bee0f5b224bffe943672fb939a93ae1547bb4261 100644 (file)
@@ -74,6 +74,17 @@ struct am_fh {
   } u;
 };
 
+struct am_fh3 {
+  u_int fhh_gen;                               /* generation number */
+  union {
+    struct {
+      int fhh_type;                            /* old or new am_fh */
+      pid_t fhh_pid;                           /* process id */
+      int fhh_id;                              /* map id */
+    } s;
+    char fhh_path[AM_FHSIZE3-sizeof(u_int)];   /* path to am_node */
+  } u;
+};
 
 /* forward declarations */
 /* converting am-filehandles to mount-points */
@@ -621,57 +632,17 @@ out:
   *out_bavail = bavail;
 }
 
-
-/*
- * Convert from file handle to automount node.
- */
 static am_node *
-fh_to_mp3(am_nfs_fh *fhp, int *rp, int vop)
+validate_ap(am_node *node, int *rp, u_int fhh_gen)
 {
-  struct am_fh *fp = (struct am_fh *) fhp;
-  am_node *ap = NULL;
-
-  if (fp->u.s.fhh_type != 0) {
-    /* New filehandle type */
-    int len = sizeof(*fhp) - sizeof(fp->fhh_gen);
-    char *path = xmalloc(len+1);
-    /*
-     * Because fhp is treated as a filehandle we use memcpy
-     * instead of xstrlcpy.
-     */
-    memcpy(path, (char *) fp->u.fhh_path, len);
-    path[len] = '\0';
-    /* dlog("fh_to_mp3: new filehandle: %s", path); */
-
-    ap = path_to_exported_ap(path);
-    XFREE(path);
-  } else {
-    /* dlog("fh_to_mp3: old filehandle: %d", fp->u.s.fhh_id); */
-    /*
-     * Check process id matches
-     * If it doesn't then it is probably
-     * from an old kernel-cached filehandle
-     * which is now out of date.
-     */
-    if (fp->u.s.fhh_pid != get_server_pid()) {
-      dlog("fh_to_mp3: wrong pid %ld != my pid %ld",
-          (long) fp->u.s.fhh_pid, get_server_pid());
-      goto drop;
-    }
-
-    /*
-     * Get hold of the supposed mount node
-     */
-    ap = get_exported_ap(fp->u.s.fhh_id);
-  }
-
+  am_node *ap = node;
   /*
    * Check the generation number in the node
    * matches the one from the kernel.  If not
    * then the old node has been timed out and
    * a new one allocated.
    */
-  if (ap != NULL && ap->am_gen != fp->fhh_gen)
+  if (node != NULL && node->am_gen != fhh_gen)
     ap = NULL;
 
   /*
@@ -690,7 +661,7 @@ fh_to_mp3(am_nfs_fh *fhp, int *rp, int vop)
     int error;
     am_node *orig_ap = ap;
 
-    dlog("fh_to_mp3: %s (%s) is hung: lookup alternative file server",
+    dlog("%s: %s (%s) is hung: lookup alternative file server", __func__,
         orig_ap->am_path, orig_ap->am_al->al_mnt->mf_info);
 
     /*
@@ -769,6 +740,51 @@ drop:
   return ap;
 }
 
+/*
+ * Convert from file handle to automount node.
+ */
+static am_node *
+fh_to_mp3(am_nfs_fh *fhp, int *rp, int vop)
+{
+  struct am_fh *fp = (struct am_fh *) fhp;
+  am_node *ap = NULL;
+
+  if (fp->u.s.fhh_type != 0) {
+    /* New filehandle type */
+    int len = sizeof(*fhp) - sizeof(fp->fhh_gen);
+    char *path = xmalloc(len+1);
+    /*
+     * Because fhp is treated as a filehandle we use memcpy
+     * instead of xstrlcpy.
+     */
+    memcpy(path, (char *) fp->u.fhh_path, len);
+    path[len] = '\0';
+    dlog("%s: new filehandle: %s", __func__, path);
+
+    ap = path_to_exported_ap(path);
+    XFREE(path);
+  } else {
+    dlog("%s: old filehandle: %d", __func__, fp->u.s.fhh_id);
+    /*
+     * Check process id matches
+     * If it doesn't then it is probably
+     * from an old kernel-cached filehandle
+     * which is now out of date.
+     */
+    if (fp->u.s.fhh_pid != get_server_pid()) {
+      dlog("%s: wrong pid %ld != my pid %ld", __func__,
+          (long) fp->u.s.fhh_pid, get_server_pid());
+      goto done;
+    }
+
+    /*
+     * Get hold of the supposed mount node
+     */
+    ap = get_exported_ap(fp->u.s.fhh_id);
+  }
+done:
+  return validate_ap(ap, rp, fp->fhh_gen);
+}
 
 static am_node *
 fh_to_mp(am_nfs_fh *fhp)
@@ -778,6 +794,56 @@ fh_to_mp(am_nfs_fh *fhp)
   return fh_to_mp3(fhp, &dummy, VLOOK_CREATE);
 }
 
+static am_node *
+fh3_to_mp3(am_nfs_fh3 *fhp, int *rp, int vop)
+{
+  struct am_fh3 *fp = (struct am_fh3 *) fhp->am_fh3_data;
+  am_node *ap = NULL;
+
+  if (fp->u.s.fhh_type != 0) {
+    /* New filehandle type */
+    int len = sizeof(*fp) - sizeof(fp->fhh_gen);
+    char *path = xmalloc(len+1);
+    /*
+     * Because fhp is treated as a filehandle we use memcpy
+     * instead of xstrlcpy.
+     */
+    memcpy(path, (char *) fp->u.fhh_path, len);
+    path[len] = '\0';
+    dlog("%s: new filehandle: %s", __func__, path);
+
+    ap = path_to_exported_ap(path);
+    XFREE(path);
+  } else {
+    dlog("%s: old filehandle: %d", __func__, fp->u.s.fhh_id);
+    /*
+     * Check process id matches
+     * If it doesn't then it is probably
+     * from an old kernel-cached filehandle
+     * which is now out of date.
+     */
+    if (fp->u.s.fhh_pid != get_server_pid()) {
+      dlog("%s: wrong pid %ld != my pid %ld", __func__,
+          (long) fp->u.s.fhh_pid, get_server_pid());
+      goto done;
+    }
+
+    /*
+     * Get hold of the supposed mount node
+     */
+    ap = get_exported_ap(fp->u.s.fhh_id);
+  }
+done:
+  return validate_ap(ap, rp, fp->fhh_gen);
+}
+
+static am_node *
+fh3_to_mp(am_nfs_fh3 *fhp)
+{
+  int dummy;
+
+  return fh3_to_mp3(fhp, &dummy, VLOOK_CREATE);
+}
 
 /*
  * Convert from automount node to file handle.
@@ -823,3 +889,971 @@ mp_to_fh(am_node *mp, am_nfs_fh *fhp)
     /* dlog("mp_to_fh: old filehandle: %d", fp->u.s.fhh_id); */
   }
 }
+void
+mp_to_fh3(am_node *mp, am_nfs_fh3 *fhp)
+{
+  u_int pathlen;
+  struct am_fh3 *fp = (struct am_fh3 *) fhp->am_fh3_data;
+
+  memset((char *) fhp, 0, sizeof(am_nfs_fh3));
+  fhp->am_fh3_length = AM_FHSIZE3;
+
+  /* Store the generation number */
+  fp->fhh_gen = mp->am_gen;
+
+  pathlen = strlen(mp->am_path);
+  if (pathlen <= sizeof(*fp) - sizeof(fp->fhh_gen)) {
+    /* dlog("mp_to_fh: new filehandle: %s", mp->am_path); */
+
+    /*
+     * Because fhp is treated as a filehandle we use memcpy instead of
+     * xstrlcpy.
+     */
+    memcpy(fp->u.fhh_path, mp->am_path, pathlen); /* making a filehandle */
+  } else {
+    /*
+     * Take the process id
+     */
+    fp->u.s.fhh_pid = get_server_pid();
+
+    /*
+     * ... the map number
+     */
+    fp->u.s.fhh_id = mp->am_mapno;
+
+    /*
+     * ... and the generation number (previously stored)
+     * to make a "unique" triple that will never
+     * be reallocated except across reboots (which doesn't matter)
+     * or if we are unlucky enough to be given the same
+     * pid as a previous amd (very unlikely).
+     */
+    /* dlog("mp_to_fh: old filehandle: %d", fp->u.s.fhh_id); */
+  }
+}
+
+#ifdef HAVE_FS_NFS3
+static am_ftype3 ftype_to_ftype3(nfsftype ftype)
+{
+  if (ftype == NFFIFO)
+    return AM_NF3FIFO;
+  else
+    return ftype;
+}
+
+static void nfstime_to_am_nfstime3(nfstime *time, am_nfstime3 *time3)
+{
+  time3->seconds = time->seconds;
+  time3->nseconds = time->useconds * 1000;
+}
+
+static void rdev_to_am_specdata3(u_int rdev, am_specdata3 *rdev3)
+{
+  /* No device node here */
+  rdev3->specdata1 = (u_int) -1;
+  rdev3->specdata2 = (u_int) -1;
+}
+
+static void fattr_to_fattr3(nfsfattr *fattr, am_fattr3 *fattr3)
+{
+  fattr3->type = ftype_to_ftype3(fattr->na_type);
+  fattr3->mode = (am_mode3) fattr->na_mode;
+  fattr3->nlink = fattr->na_nlink;
+  fattr3->uid = (am_uid3) fattr->na_uid;
+  fattr3->gid = (am_uid3) fattr->na_gid;
+  fattr3->size = (am_size3) fattr->na_size;
+  fattr3->used = (am_size3) fattr->na_size;
+  rdev_to_am_specdata3(fattr->na_rdev, &fattr3->rdev);
+  fattr3->fsid = (uint64) fattr->na_fsid;
+  fattr3->fileid = (uint64) fattr->na_fileid;
+  nfstime_to_am_nfstime3(&fattr->na_atime, &fattr3->atime);
+  nfstime_to_am_nfstime3(&fattr->na_mtime, &fattr3->mtime);
+  nfstime_to_am_nfstime3(&fattr->na_ctime, &fattr3->ctime);
+}
+
+static void fattr_to_wcc_attr(nfsfattr *fattr, am_wcc_attr *wcc_attr)
+{
+  wcc_attr->size = (am_size3) fattr->na_size;
+  nfstime_to_am_nfstime3(&fattr->na_mtime, &wcc_attr->mtime);
+  nfstime_to_am_nfstime3(&fattr->na_ctime, &wcc_attr->ctime);
+}
+
+static am_nfsstat3 return_estale_or_rofs(am_nfs_fh3 *fh,
+                                         am_pre_op_attr *pre_op,
+                                         am_post_op_attr *post_op)
+{
+  am_node *mp;
+
+  mp = fh3_to_mp(fh);
+  if (!mp) {
+    pre_op->attributes_follow = 0;
+    post_op->attributes_follow = 0;
+    return  nfs_error(ESTALE);
+  } else {
+    am_fattr3 *fattr3 = &post_op->am_post_op_attr_u.attributes;
+    am_wcc_attr *wcc_attr = &pre_op->am_pre_op_attr_u.attributes;
+    nfsfattr *fattr = &mp->am_fattr;
+    pre_op->attributes_follow = 1;
+    fattr_to_wcc_attr(fattr, wcc_attr);
+    post_op->attributes_follow = 1;
+    fattr_to_fattr3(fattr, fattr3);
+    return nfs_error(EROFS);
+  }
+}
+
+static am_nfsstat3 unlink3_or_rmdir3(am_diropargs3 *argp,
+                                     am_wcc_data *wcc_data, int unlinkp)
+{
+  static am_nfsstat3 res;
+  am_nfs_fh3 *dir = &argp->dir;
+  am_filename3 name = argp->name;
+  am_pre_op_attr *pre_op_dir = &wcc_data->before;
+  am_post_op_attr *post_op_dir = &wcc_data->after;
+  nfsfattr *fattr;
+  am_wcc_attr *wcc_attr;
+  am_node *mp, *ap;
+  int retry;
+
+  post_op_dir->attributes_follow = 0;
+
+  mp = fh3_to_mp3(dir, &retry, VLOOK_DELETE);
+  if (!mp) {
+    pre_op_dir->attributes_follow = 0;
+    if (retry < 0) {
+      amd_stats.d_drops++;
+      return 0;
+    }
+    res = nfs_error(retry);
+    goto out;
+  }
+
+  pre_op_dir->attributes_follow = 1;
+  fattr = &mp->am_fattr;
+  wcc_attr = &pre_op_dir->am_pre_op_attr_u.attributes;
+  fattr_to_wcc_attr(fattr, wcc_attr);
+
+  if (mp->am_fattr.na_type != NFDIR) {
+    res = nfs_error(ENOTDIR);
+    goto out;
+  }
+
+  if (amuDebug(D_TRACE))
+    plog(XLOG_DEBUG, "\tremove(%s, %s)", mp->am_path, name);
+
+  ap = mp->am_al->al_mnt->mf_ops->lookup_child(mp, name, &retry, VLOOK_DELETE);
+  if (!ap) {
+    /*
+     * Ignore retries...
+     */
+    if (retry < 0)
+      retry = 0;
+    /*
+     * Usual NFS workaround...
+     */
+    else if (retry == ENOENT)
+      retry = 0;
+    res = nfs_error(retry);
+  } else {
+    forcibly_timeout_mp(mp);
+    res = AM_NFS3_OK;
+  }
+
+out:
+  return res;
+}
+
+voidp
+am_nfs3_null_3_svc(voidp argp, struct svc_req *rqstp)
+{
+  static char * result;
+
+  return (voidp) &result;
+}
+
+am_GETATTR3res *
+am_nfs3_getattr_3_svc(am_GETATTR3args *argp, struct svc_req *rqstp)
+{
+  static am_GETATTR3res  result;
+  am_nfs_fh3 *fh = (am_nfs_fh3 *) &argp->object;
+  am_fattr3 *fattr3;
+  nfsfattr *fattr;
+  am_node *mp;
+  int retry = 0;
+  time_t now = clocktime(NULL);
+
+  if (amuDebug(D_TRACE))
+    plog(XLOG_DEBUG, "getattr_3:");
+
+  mp = fh3_to_mp3(fh, &retry, VLOOK_CREATE);
+  if (!mp) {
+    if (amuDebug(D_TRACE))
+      plog(XLOG_DEBUG, "\tretry=%d", retry);
+
+    if (retry < 0) {
+      amd_stats.d_drops++;
+      return 0;
+    }
+    result.status = nfs_error(retry);
+    return &result;
+  }
+
+  fattr = &mp->am_fattr;
+  fattr3 = (am_fattr3 *) &result.res_u.ok.obj_attributes;
+  fattr_to_fattr3(fattr, fattr3);
+
+  result.status = AM_NFS3_OK;
+
+  if (amuDebug(D_TRACE))
+    plog(XLOG_DEBUG, "\tstat(%s), size = %lu, mtime=%d.%d",
+        mp->am_path,
+        (am_size3) fattr3->size,
+        (u_int) fattr3->mtime.seconds,
+        (u_int) fattr3->mtime.nseconds);
+
+  /* Delay unmount of what was looked up */
+  if (mp->am_timeo_w < 4 * gopt.am_timeo_w)
+    mp->am_timeo_w += gopt.am_timeo_w;
+  mp->am_ttl = now + mp->am_timeo_w;
+
+  mp->am_stats.s_getattr++;
+
+  return &result;
+}
+
+am_SETATTR3res *
+am_nfs3_setattr_3_svc(am_SETATTR3args *argp, struct svc_req *rqstp)
+{
+  static am_SETATTR3res  result;
+  am_nfs_fh3 *fh = (am_nfs_fh3 *) &argp->object;
+  am_pre_op_attr *pre_op_obj = &result.res_u.fail.obj_wcc.before;
+  am_post_op_attr *post_op_obj = &result.res_u.fail.obj_wcc.after;
+
+  if (amuDebug(D_TRACE))
+    plog(XLOG_DEBUG, "setattr_3:");
+
+  result.status = return_estale_or_rofs(fh, pre_op_obj, post_op_obj);
+
+  return &result;
+}
+
+am_LOOKUP3res *
+am_nfs3_lookup_3_svc(am_LOOKUP3args *argp, struct svc_req *rqstp)
+{
+  static am_LOOKUP3res  result;
+  am_nfs_fh3 *dir = &argp->what.dir;
+  am_post_op_attr *post_op_dir;
+  am_post_op_attr *post_op_obj;
+  am_node *mp;
+  int retry;
+  uid_t uid;
+  gid_t gid;
+
+  if (amuDebug(D_TRACE))
+    plog(XLOG_DEBUG, "lookup_3:");
+
+  /* finally, find the effective uid/gid from RPC request */
+  if (getcreds(rqstp, &uid, &gid, nfsxprt) < 0)
+    plog(XLOG_ERROR, "cannot get uid/gid from RPC credentials");
+  xsnprintf(opt_uid, sizeof(uid_str), "%d", (int) uid);
+  xsnprintf(opt_gid, sizeof(gid_str), "%d", (int) gid);
+
+  mp = fh3_to_mp3(dir, &retry, VLOOK_CREATE);
+  if (!mp) {
+    post_op_dir = &result.res_u.fail.dir_attributes;
+    post_op_dir->attributes_follow = 0;
+    if (retry < 0) {
+      amd_stats.d_drops++;
+      return 0;
+    }
+    result.status = nfs_error(retry);
+  } else {
+    post_op_dir = &result.res_u.ok.dir_attributes;
+    post_op_obj = &result.res_u.ok.obj_attributes;
+    am_filename3 name;
+    am_fattr3 *fattr3;
+    nfsfattr *fattr;
+    am_node *ap;
+    int error;
+
+    /* dir attributes */
+    post_op_dir->attributes_follow = 1;
+    fattr = &mp->am_fattr;
+    fattr3 = &post_op_dir->am_post_op_attr_u.attributes;
+    fattr_to_fattr3(fattr, fattr3);
+
+    post_op_obj->attributes_follow = 0;
+
+    name = argp->what.name;
+
+    if (amuDebug(D_TRACE))
+      plog(XLOG_DEBUG, "\tlookup_3(%s, %s)", mp->am_path, name);
+
+    ap = mp->am_al->al_mnt->mf_ops->lookup_child(mp, name, &error, VLOOK_CREATE);
+    if (ap && error < 0)
+      ap = mp->am_al->al_mnt->mf_ops->mount_child(ap, &error);
+    if (ap == 0) {
+      if (error < 0) {
+       amd_stats.d_drops++;
+       return 0;
+      }
+      result.status = nfs_error(error);
+    } else {
+      /*
+       * XXX: EXPERIMENTAL! Delay unmount of what was looked up.  This
+       * should reduce the chance for race condition between unmounting an
+       * entry synchronously, and re-mounting it asynchronously.
+       */
+      if (ap->am_ttl < mp->am_ttl)
+        ap->am_ttl = mp->am_ttl;
+
+      mp_to_fh3(ap, &result.res_u.ok.object);
+
+      /* mount attributes */
+      post_op_obj->attributes_follow = 1;
+      fattr = &ap->am_fattr;
+      fattr3 = &post_op_obj->am_post_op_attr_u.attributes;
+      fattr_to_fattr3(fattr, fattr3);
+
+      result.status = AM_NFS3_OK;
+    }
+    mp->am_stats.s_lookup++;
+  }
+  return &result;
+}
+
+am_ACCESS3res *
+am_nfs3_access_3_svc(am_ACCESS3args *argp, struct svc_req *rqstp)
+{
+  static am_ACCESS3res  result;
+
+  am_nfs_fh3 *obj = &argp->object;
+  u_int accessbits = argp->access;
+  u_int accessmask = AM_ACCESS3_LOOKUP;
+  am_post_op_attr *post_op_obj;
+  am_node *mp;
+
+  if (amuDebug(D_TRACE))
+    plog(XLOG_DEBUG, "access_3:");
+
+  mp = fh3_to_mp(obj);
+  if (!mp) {
+    post_op_obj = &result.res_u.fail.obj_attributes;
+    post_op_obj->attributes_follow = 0;
+    result.status = nfs_error(ENOENT);
+  } else {
+    nfsfattr *fattr = &mp->am_fattr;
+    am_fattr3 *fattr3;
+    post_op_obj = &result.res_u.ok.obj_attributes;
+    fattr3 = &post_op_obj->am_post_op_attr_u.attributes;
+    post_op_obj->attributes_follow = 1;
+    fattr_to_fattr3(fattr, fattr3);
+
+    result.res_u.ok.access = accessbits & accessmask;
+
+    result.status = AM_NFS3_OK;
+  }
+
+  return &result;
+}
+
+am_READLINK3res *
+am_nfs3_readlink_3_svc(am_READLINK3args *argp, struct svc_req *rqstp)
+{
+  static am_READLINK3res  result;
+
+  am_nfs_fh3 *symlink = (am_nfs_fh3 *) &argp->symlink;
+  am_post_op_attr *post_op_sym;
+  am_node *mp;
+  int retry = 0;
+
+  if (amuDebug(D_TRACE))
+    plog(XLOG_DEBUG, "readlink_3:");
+
+  mp = fh3_to_mp3(symlink, &retry, VLOOK_CREATE);
+  if (!mp) {
+  readlink_retry:
+    if (retry < 0) {
+      amd_stats.d_drops++;
+      return 0;
+    }
+    post_op_sym = &result.res_u.fail.symlink_attributes;
+    post_op_sym->attributes_follow = 0;
+    result.status = nfs_error(retry);
+  } else {
+    nfsfattr *fattr;
+    am_fattr3 *fattr3;
+    char *ln;
+
+    ln = do_readlink(mp, &retry);
+    if (!ln)
+      goto readlink_retry;
+
+    if (amuDebug(D_TRACE) && ln)
+      plog(XLOG_DEBUG, "\treadlink_3(%s) = %s", mp->am_path, ln);
+
+    result.res_u.ok.data = ln;
+
+    post_op_sym = &result.res_u.ok.symlink_attributes;
+    post_op_sym->attributes_follow = 1;
+    fattr = &mp->am_fattr;
+    fattr3 = &post_op_sym->am_post_op_attr_u.attributes;
+    fattr_to_fattr3(fattr, fattr3);
+
+    mp->am_stats.s_readlink++;
+    result.status = AM_NFS3_OK;
+  }
+
+  return &result;
+}
+
+am_READ3res *
+am_nfs3_read_3_svc(am_READ3args *argp, struct svc_req *rqstp)
+{
+  static am_READ3res  result;
+
+  am_nfs_fh3 *file = (am_nfs_fh3 *) &argp->file;
+  am_post_op_attr *post_op_file;
+  am_node *mp;
+
+  if (amuDebug(D_TRACE))
+    plog(XLOG_DEBUG, "read_3:");
+
+  post_op_file = &result.res_u.fail.file_attributes;
+  result.status = nfs_error(EACCES);
+
+  mp = fh3_to_mp(file);
+  if (!mp)
+    post_op_file->attributes_follow = 0;
+  else {
+    nfsfattr *fattr = &mp->am_fattr;
+    am_fattr3 *fattr3 = &post_op_file->am_post_op_attr_u.attributes;
+    post_op_file->attributes_follow = 1;
+    fattr_to_fattr3(fattr, fattr3);
+  }
+
+  return &result;
+}
+
+am_WRITE3res *
+am_nfs3_write_3_svc(am_WRITE3args *argp, struct svc_req *rqstp)
+{
+  static am_WRITE3res  result;
+
+  am_nfs_fh3 *file = (am_nfs_fh3 *) &argp->file;
+  am_pre_op_attr *pre_op_file = &result.res_u.fail.file_wcc.before;
+  am_post_op_attr *post_op_file = &result.res_u.fail.file_wcc.after;
+
+  if (amuDebug(D_TRACE))
+    plog(XLOG_DEBUG, "write_3:");
+
+  result.status = return_estale_or_rofs(file, pre_op_file, post_op_file);
+
+  return &result;
+}
+
+am_CREATE3res *
+am_nfs3_create_3_svc(am_CREATE3args *argp, struct svc_req *rqstp)
+{
+  static am_CREATE3res  result;
+
+  am_nfs_fh3 *dir = (am_nfs_fh3 *) &argp->where.dir;
+  am_pre_op_attr *pre_op_dir = &result.res_u.fail.dir_wcc.before;
+  am_post_op_attr *post_op_dir = &result.res_u.fail.dir_wcc.after;
+
+  if (amuDebug(D_TRACE))
+    plog(XLOG_DEBUG, "create_3:");
+
+  result.status = return_estale_or_rofs(dir, pre_op_dir, post_op_dir);
+
+  return &result;
+}
+
+am_MKDIR3res *
+am_nfs3_mkdir_3_svc(am_MKDIR3args *argp, struct svc_req *rqstp)
+{
+  static am_MKDIR3res  result;
+
+  am_nfs_fh3 *dir = (am_nfs_fh3 *) &argp->where.dir;
+  am_pre_op_attr *pre_op_dir = &result.res_u.fail.dir_wcc.before;
+  am_post_op_attr *post_op_dir = &result.res_u.fail.dir_wcc.after;
+
+  if (amuDebug(D_TRACE))
+    plog(XLOG_DEBUG, "mkdir_3:");
+
+  result.status = return_estale_or_rofs(dir, pre_op_dir, post_op_dir);
+
+  return &result;
+}
+
+am_SYMLINK3res *
+am_nfs3_symlink_3_svc(am_SYMLINK3args *argp, struct svc_req *rqstp)
+{
+  static am_SYMLINK3res  result;
+
+  am_nfs_fh3 *dir = (am_nfs_fh3 *) &argp->where.dir;
+  am_pre_op_attr *pre_op_dir = &result.res_u.fail.dir_wcc.before;
+  am_post_op_attr *post_op_dir = &result.res_u.fail.dir_wcc.after;
+
+  if (amuDebug(D_TRACE))
+    plog(XLOG_DEBUG, "symlink_3:");
+
+  result.status = return_estale_or_rofs(dir, pre_op_dir, post_op_dir);
+
+  return &result;
+}
+
+am_MKNOD3res *
+am_nfs3_mknod_3_svc(am_MKNOD3args *argp, struct svc_req *rqstp)
+{
+  static am_MKNOD3res  result;
+
+  am_nfs_fh3 *dir = (am_nfs_fh3 *) &argp->where.dir;
+  am_pre_op_attr *pre_op_dir = &result.res_u.fail.dir_wcc.before;
+  am_post_op_attr *post_op_dir =  &result.res_u.fail.dir_wcc.after;
+
+  if (amuDebug(D_TRACE))
+    plog(XLOG_DEBUG, "mknod_3:");
+
+  result.status = return_estale_or_rofs(dir, pre_op_dir, post_op_dir);
+  return &result;
+}
+
+am_REMOVE3res *
+am_nfs3_remove_3_svc(am_REMOVE3args *argp, struct svc_req *rqstp)
+{
+  static am_REMOVE3res  result;
+
+  am_diropargs3 *obj = &argp->object;
+  am_wcc_data dir_wcc;
+
+  if (amuDebug(D_TRACE))
+    plog(XLOG_DEBUG, "remove_3:");
+
+  result.status = unlink3_or_rmdir3(obj, &dir_wcc, TRUE);
+
+  result.res_u.ok.dir_wcc = dir_wcc;
+  return &result;
+}
+
+am_RMDIR3res *
+am_nfs3_rmdir_3_svc(am_RMDIR3args *argp, struct svc_req *rqstp)
+{
+  static am_RMDIR3res  result;
+
+  am_diropargs3 *obj = &argp->object;
+  am_wcc_data dir_wcc;
+
+  if (amuDebug(D_TRACE))
+    plog(XLOG_DEBUG, "rmdir_3:");
+
+  result.status = unlink3_or_rmdir3(obj, &dir_wcc, TRUE);
+
+  result.res_u.ok.dir_wcc = dir_wcc;
+  return &result;
+}
+
+am_RENAME3res *
+am_nfs3_rename_3_svc(am_RENAME3args *argp, struct svc_req *rqstp)
+{
+  static am_RENAME3res  result;
+
+  am_nfs_fh3 *fromdir = (am_nfs_fh3 *) &argp->from.dir;
+  am_nfs_fh3 *todir = (am_nfs_fh3 *) &argp->to.dir;
+  am_filename3 name = argp->to.name;
+  am_node *to_mp, *from_mp;
+
+  if (amuDebug(D_TRACE))
+    plog(XLOG_DEBUG, "rename_3:");
+
+  if (!(from_mp = fh3_to_mp(fromdir)) || !(to_mp = fh3_to_mp(todir)))
+    result.status = nfs_error(ESTALE);
+  /*
+   * If the kernel is doing clever things with referenced files
+   * then let it pretend...
+   */
+  else {
+    am_wcc_attr *wcc_attr;
+    am_fattr3 *fattr3;
+    am_wcc_data *to_wcc_data, *from_wcc_data;
+    am_pre_op_attr *pre_op_to, *pre_op_from;
+    am_post_op_attr *post_op_to, *post_op_from;
+    nfsfattr *fattr;
+
+    to_wcc_data = &result.res_u.ok.todir_wcc;
+
+    pre_op_to = &to_wcc_data->before;
+    post_op_to = &to_wcc_data->after;
+
+    pre_op_to->attributes_follow = 1;
+    fattr = &to_mp->am_fattr;
+    wcc_attr = &pre_op_to->am_pre_op_attr_u.attributes;
+    fattr_to_wcc_attr(fattr, wcc_attr);
+    post_op_to->attributes_follow = 1;
+    fattr3 = &post_op_to->am_post_op_attr_u.attributes;
+    fattr_to_fattr3(fattr, fattr3);
+
+    from_wcc_data = &result.res_u.ok.fromdir_wcc;
+
+    pre_op_from = &from_wcc_data->before;
+    post_op_from = &from_wcc_data->after;
+
+    pre_op_from->attributes_follow = 1;
+    fattr = &from_mp->am_fattr;
+    wcc_attr = &pre_op_from->am_pre_op_attr_u.attributes;
+    fattr_to_wcc_attr(fattr, wcc_attr);
+    post_op_from->attributes_follow = 1;
+    fattr3 = &post_op_from->am_post_op_attr_u.attributes;
+    fattr_to_fattr3(fattr, fattr3);
+
+    if (NSTREQ(name, ".nfs", 4))
+      result.status = AM_NFS3_OK;
+    /*
+     * otherwise a failure
+     */
+    else
+      result.status = nfs_error(EROFS);
+  }
+
+  return &result;
+}
+
+am_LINK3res *
+am_nfs3_link_3_svc(am_LINK3args *argp, struct svc_req *rqstp)
+{
+  static am_LINK3res  result;
+
+  am_nfs_fh3 *file = (am_nfs_fh3 *) &argp->file;
+  am_nfs_fh3 *dir = (am_nfs_fh3 *) &argp->link.dir;
+  am_post_op_attr *post_op_file;
+  am_pre_op_attr *pre_op_dir;
+  am_post_op_attr *post_op_dir;
+  am_node *mp_file, *mp_dir;
+
+  if (amuDebug(D_TRACE))
+    plog(XLOG_DEBUG, "link_3:");
+
+  post_op_file = &result.res_u.fail.file_attributes;
+  post_op_file->attributes_follow = 0;
+
+  mp_file = fh3_to_mp(file);
+  if (mp_file) {
+    nfsfattr *fattr = &mp_file->am_fattr;
+    am_fattr3 *fattr3 = &post_op_file->am_post_op_attr_u.attributes;
+    fattr_to_fattr3(fattr, fattr3);
+  }
+
+  pre_op_dir = &result.res_u.fail.linkdir_wcc.before;
+  pre_op_dir->attributes_follow = 0;
+  post_op_dir = &result.res_u.fail.linkdir_wcc.after;
+  post_op_dir->attributes_follow = 0;
+
+  mp_dir = fh3_to_mp(dir);
+  if (mp_dir) {
+    nfsfattr *fattr = &mp_dir->am_fattr;
+    am_fattr3 *fattr3 = &post_op_dir->am_post_op_attr_u.attributes;
+    am_wcc_attr *wcc_attr = &pre_op_dir->am_pre_op_attr_u.attributes;
+
+    pre_op_dir->attributes_follow = 1;
+    fattr_to_wcc_attr(fattr, wcc_attr);
+    post_op_dir->attributes_follow = 1;
+    fattr_to_fattr3(fattr, fattr3);
+  }
+
+  if (!mp_file || !mp_dir)
+    result.status = nfs_error(ESTALE);
+  else
+    result.status = nfs_error(EROFS);
+
+  return &result;
+}
+
+am_READDIR3res *
+am_nfs3_readdir_3_svc(am_READDIR3args *argp, struct svc_req *rqstp)
+{
+  static am_READDIR3res  result;
+  static am_entry3 entries[MAX_READDIR_ENTRIES];
+  am_nfs_fh3 *dir = (am_nfs_fh3 *) &argp->dir;
+  am_cookie3 cookie = argp->cookie;
+  am_cookieverf3 cookieverf;
+  am_count3 count = argp->count;
+  am_post_op_attr *post_op_dir;
+  am_node *mp;
+  int retry;
+
+  if (amuDebug(D_TRACE))
+    plog(XLOG_DEBUG, "readdir_3:");
+
+  memcpy(&cookieverf, &argp->cookieverf, sizeof(am_cookieverf3));
+
+  mp = fh3_to_mp3(dir, &retry, VLOOK_CREATE);
+  if (mp == NULL) {
+    if (retry < 0) {
+      amd_stats.d_drops++;
+      return 0;
+    }
+    post_op_dir = &result.res_u.fail.dir_attributes;
+    post_op_dir->attributes_follow = 0;
+    result.status = nfs_error(retry);
+  } else {
+    am_dirlist3 *list = &result.res_u.ok.reply;
+    am_nfsstat3 status;
+
+    if (amuDebug(D_TRACE))
+      plog(XLOG_DEBUG, "\treaddir_3(%s)", mp->am_path);
+
+    status = mp->am_al->al_mnt->mf_ops->readdir(mp,
+                                       (voidp)&cookie, list, entries, count);
+    if (status == 0) {
+      post_op_dir = &result.res_u.ok.dir_attributes;
+      nfsfattr *fattr;
+      am_fattr3 *fattr3;
+
+      fattr = &mp->am_fattr;
+      fattr3 = &post_op_dir->am_post_op_attr_u.attributes;
+      post_op_dir->attributes_follow = 1;
+      fattr_to_fattr3(fattr, fattr3);
+      result.status = AM_NFS3_OK;
+    } else {
+      post_op_dir = &result.res_u.fail.dir_attributes;
+      post_op_dir->attributes_follow = 0;
+      result.status = nfs_error(status);
+    }
+
+    mp->am_stats.s_readdir++;
+  }
+
+  return &result;
+}
+
+am_READDIRPLUS3res *
+am_nfs3_readdirplus_3_svc(am_READDIRPLUS3args *argp, struct svc_req *rqstp)
+{
+  static am_READDIRPLUS3res  result;
+  am_nfs_fh3 *dir = (am_nfs_fh3 *) &argp->dir;
+  am_post_op_attr *post_op_dir;
+  nfsfattr *fattr;
+  am_fattr3 *fattr3;
+  am_node *mp;
+  int retry;
+
+  mp = fh3_to_mp3(dir, &retry, VLOOK_CREATE);
+  if (mp == NULL) {
+    if (retry < 0) {
+      amd_stats.d_drops++;
+      return 0;
+    }
+    post_op_dir = &result.res_u.fail.dir_attributes;
+    post_op_dir->attributes_follow = 0;
+    result.status = nfs_error(retry);
+  } else {
+      post_op_dir = &result.res_u.ok.dir_attributes;
+      fattr = &mp->am_fattr;
+      fattr3 = &post_op_dir->am_post_op_attr_u.attributes;
+      post_op_dir->attributes_follow = 1;
+      fattr_to_fattr3(fattr, fattr3);
+      result.status = AM_NFS3ERR_NOTSUPP;
+  }
+
+  return &result;
+}
+
+am_FSSTAT3res *
+am_nfs3_fsstat_3_svc(am_FSSTAT3args *argp, struct svc_req *rqstp)
+{
+  static am_FSSTAT3res  result;
+
+  am_nfs_fh3 *fsroot = (am_nfs_fh3 *) &argp->fsroot;
+  am_post_op_attr *post_op_fsroot;
+  am_node *mp;
+  int retry;
+  if (amuDebug(D_TRACE))
+    plog(XLOG_DEBUG, "fsstat_3:");
+
+  mp = fh3_to_mp3(fsroot, &retry, VLOOK_CREATE);
+  if (!mp) {
+    if (retry < 0) {
+      amd_stats.d_drops++;
+      return 0;
+    }
+    post_op_fsroot = &result.res_u.fail.obj_attributes;
+    post_op_fsroot->attributes_follow = 0;
+    result.status = nfs_error(retry);
+  } else {
+    am_FSSTAT3resok *ok = &result.res_u.ok;
+    u_int blocks, bfree, bavail;
+    nfsfattr *fattr;
+    am_fattr3 *fattr3;
+    mntent_t mnt;
+
+    if (amuDebug(D_TRACE))
+      plog(XLOG_DEBUG, "\tfsstat_3(%s)", mp->am_path);
+
+    fattr = &mp->am_fattr;
+    post_op_fsroot = &ok->obj_attributes;
+    post_op_fsroot->attributes_follow = 1;
+    fattr3 = &post_op_fsroot->am_post_op_attr_u.attributes;
+    fattr_to_fattr3(fattr, fattr3);
+
+    /*
+     * just return faked up file system information
+     */
+    ok->tbytes = 1024;
+    ok->invarsec = 0;
+
+    /* check if map is browsable and show_statfs_entries=yes  */
+    if ((gopt.flags & CFM_SHOW_STATFS_ENTRIES) &&
+       mp->am_al->al_mnt && mp->am_al->al_mnt->mf_mopts) {
+      mnt.mnt_opts = mp->am_al->al_mnt->mf_mopts;
+      if (amu_hasmntopt(&mnt, "browsable")) {
+       count_map_entries(mp, &blocks, &bfree, &bavail);
+      }
+      ok->fbytes = bfree;
+      ok->abytes = bavail;
+      ok->ffiles = bfree;
+      ok->afiles = bavail;
+      ok->tfiles = blocks;
+    } else {
+      ok->fbytes = 0;
+      ok->abytes = 0;
+      ok->ffiles = 0;
+      ok->afiles = 0;
+      ok->tfiles = 0; /* set to 1 if you don't want empty automounts */
+    }
+
+    result.status = AM_NFS3_OK;
+    mp->am_stats.s_statfs++;
+  }
+
+  return &result;
+}
+
+#define FSF3_HOMOGENEOUS 0x0008
+
+am_FSINFO3res *
+am_nfs3_fsinfo_3_svc(am_FSINFO3args *argp, struct svc_req *rqstp)
+{
+  static am_FSINFO3res  result;
+
+  am_nfs_fh3 *fsroot = (am_nfs_fh3 *) &argp->fsroot;
+  am_post_op_attr *post_op_fsroot;
+  am_node *mp;
+  int retry;
+
+  if (amuDebug(D_TRACE))
+    plog(XLOG_DEBUG, "fsinfo_3:");
+
+  mp = fh3_to_mp3(fsroot, &retry, VLOOK_CREATE);
+  if (!mp) {
+    if (retry < 0) {
+      amd_stats.d_drops++;
+      return 0;
+    }
+    post_op_fsroot = &result.res_u.fail.obj_attributes;
+    post_op_fsroot->attributes_follow = 0;
+    result.status = nfs_error(retry);
+  } else {
+    am_FSINFO3resok *ok = &result.res_u.ok;
+    nfsfattr *fattr;
+    am_fattr3 *fattr3;
+
+    if (amuDebug(D_TRACE))
+      plog(XLOG_DEBUG, "\tfsinfo_3(%s)", mp->am_path);
+
+    fattr = &mp->am_fattr;
+    post_op_fsroot = &ok->obj_attributes;
+    post_op_fsroot->attributes_follow = 1;
+    fattr3 = &post_op_fsroot->am_post_op_attr_u.attributes;
+    fattr_to_fattr3(fattr, fattr3);
+
+    /*
+     * just return faked up file system information
+     */
+    ok->rtmax = 0;
+    ok->rtpref = 0;
+    ok->rtmult = 0;
+    ok->wtmax = 0;
+    ok->wtpref = 0;
+    ok->wtmult = 0;
+    ok->dtpref = 1024;
+    ok->maxfilesize = 0;
+    ok->time_delta.seconds = 1;
+    ok->time_delta.nseconds = 0;
+    ok->properties = FSF3_HOMOGENEOUS;
+
+    result.status = AM_NFS3_OK;
+    mp->am_stats.s_fsinfo++;
+  }
+
+  return &result;
+}
+
+am_PATHCONF3res *
+am_nfs3_pathconf_3_svc(am_PATHCONF3args *argp, struct svc_req *rqstp)
+{
+  static am_PATHCONF3res  result;
+
+  am_nfs_fh3 *obj = (am_nfs_fh3 *) &argp->object;
+  am_post_op_attr *post_op_obj;
+  am_node *mp;
+  int retry;
+
+  if (amuDebug(D_TRACE))
+    plog(XLOG_DEBUG, "pathconf_3:");
+
+  mp = fh3_to_mp3(obj, &retry, VLOOK_CREATE);
+  if (!mp) {
+    if (retry < 0) {
+      amd_stats.d_drops++;
+      return 0;
+    }
+    post_op_obj = &result.res_u.fail.obj_attributes;
+    post_op_obj->attributes_follow = 0;
+    result.status = nfs_error(retry);
+  } else {
+    am_PATHCONF3resok *ok = &result.res_u.ok;
+    nfsfattr *fattr;
+    am_fattr3 *fattr3;
+
+    if (amuDebug(D_TRACE))
+      plog(XLOG_DEBUG, "\tpathconf_3(%s)", mp->am_path);
+
+    fattr = &mp->am_fattr;
+    post_op_obj = &ok->obj_attributes;
+    post_op_obj->attributes_follow = 1;
+    fattr3 = &post_op_obj->am_post_op_attr_u.attributes;
+    fattr_to_fattr3(fattr, fattr3);
+
+    ok->linkmax = 0;
+    ok->name_max = NAME_MAX;
+    ok->no_trunc = 1;
+    ok->chown_restricted = 1;
+    ok->case_insensitive = 0;
+    ok->case_preserving = 1;
+
+    result.status = AM_NFS3_OK;
+    mp->am_stats.s_pathconf++;
+  }
+
+  return &result;
+}
+
+am_COMMIT3res *
+am_nfs3_commit_3_svc(am_COMMIT3args *argp, struct svc_req *rqstp)
+{
+  static am_COMMIT3res  result;
+
+  am_nfs_fh3 *file = (am_nfs_fh3 *) &argp->file;
+  am_pre_op_attr *pre_op_file = &result.res_u.fail.file_wcc.before;
+  am_post_op_attr *post_op_file = &result.res_u.fail.file_wcc.after;
+
+  if (amuDebug(D_TRACE))
+    plog(XLOG_DEBUG, "commit_3:");
+
+  result.status = return_estale_or_rofs(file, pre_op_file, post_op_file);
+
+  return &result;
+}
+#endif /* HAVE_FS_NFS3 */
index 07573378f9bcbee8e450f4b88509bf7616668f57..b873c8ece27101ad8487741eef69d395bdbdbbb9 100644 (file)
@@ -60,7 +60,7 @@ static int foofs_init(mntfs *mf);
 static int foofs_mount(am_node *mp, mntfs *mf);
 static int foofs_umount(am_node *mp, mntfs *mf);
 static am_node *foofs_lookuppn(am_node *mp, char *fname, int *error_return, int op);
-static int foofs_readdir(am_node *mp, nfscookie cookie, nfsdirlist *dp, nfsentry *ep, u_int count);
+static int foofs_readdir(am_node *mp, void cookie, voidp dp, voidp ep, u_int count);
 static am_node *foofs_readlink(am_node *mp, int *error_return);
 static void foofs_mounted(am_node *am, mntfs *mf);
 static void foofs_umounted(am_node *mp, mntfs *mf);
@@ -216,7 +216,7 @@ foofs_lookuppn(am_node *mp, char *fname, int *error_return, int op)
  * If OK, fills in ep with chain of directory entries.
  */
 static int
-foofs_readdir(am_node *mp, nfscookie cookie, nfsdirlist *dp, nfsentry *ep, u_int count)
+foofs_readdir(am_node *mp, void cookie, voidp dp, voidp ep, u_int count)
 {
   int error = 0;
 
index 758f6146bf6170db1af926053640dabda28d077d..aa9ae6b84841f09196d0959b6a7f82f328c8caf1 100644 (file)
@@ -221,7 +221,7 @@ amfs_readdir_browsable(am_node *mp, nfscookie cookie, nfsdirlist *dp, nfsentry *
      * to be returned in a single packet.  If it isn't (which would be
      * fairly unbelievable) then tough.
      */
-    dlog("amfs_readdir_browsable: default search");
+    dlog("%s: default search", __func__);
     /*
      * Check for enough room.  This is extremely approximate but is more
      * than enough space.  Really need 2 times:
@@ -309,10 +309,10 @@ amfs_readdir_browsable(am_node *mp, nfscookie cookie, nfsdirlist *dp, nfsentry *
     return 0;
   } /* end of "if (gen == 0)" statement */
 
-  dlog("amfs_readdir_browsable: real child");
+  dlog("%s: real child", __func__);
 
   if (gen == DOT_DOT_COOKIE) {
-    dlog("amfs_readdir_browsable: End of readdir in %s", mp->am_path);
+    dlog("%s: End of readdir in %s", __func__, mp->am_path);
     dp->dl_eof = TRUE;
     dp->dl_entries = NULL;
     return 0;
@@ -361,29 +361,14 @@ amfs_readdir_browsable(am_node *mp, nfscookie cookie, nfsdirlist *dp, nfsentry *
   return 0;
 }
 
-
-/*
- * This readdir function which call a special version of it that allows
- * browsing if browsable_dirs=yes was set on the map.
- */
-int
-amfs_generic_readdir(am_node *mp, nfscookie cookie, nfsdirlist *dp, nfsentry *ep, u_int count)
+static int
+amfs_readdir(am_node *mp, nfscookie cookie, nfsdirlist *dp, nfsentry *ep, u_int count)
 {
   u_int gen = *(u_int *) cookie;
   am_node *xp;
-  mntent_t mnt;
 
   dp->dl_eof = FALSE;          /* assume readdir not done */
 
-  /* check if map is browsable */
-  if (mp->am_al->al_mnt && mp->am_al->al_mnt->mf_mopts) {
-    mnt.mnt_opts = mp->am_al->al_mnt->mf_mopts;
-    if (amu_hasmntopt(&mnt, "fullybrowsable"))
-      return amfs_readdir_browsable(mp, cookie, dp, ep, count, TRUE);
-    if (amu_hasmntopt(&mnt, "browsable"))
-      return amfs_readdir_browsable(mp, cookie, dp, ep, count, FALSE);
-  }
-
   /* when gen is 0, we start reading from the beginning of the directory */
   if (gen == 0) {
     /*
@@ -394,7 +379,7 @@ amfs_generic_readdir(am_node *mp, nfscookie cookie, nfsdirlist *dp, nfsentry *ep
      * to be returned in a single packet.  If it isn't (which would be
      * fairly unbelievable) then tough.
      */
-    dlog("amfs_generic_readdir: default search");
+    dlog("%s: default search", __func__);
     /*
      * Check for enough room.  This is extremely approximate but is more
      * than enough space.  Really need 2 times:
@@ -440,10 +425,10 @@ amfs_generic_readdir(am_node *mp, nfscookie cookie, nfsdirlist *dp, nfsentry *ep
     }
     return 0;
   }
-  dlog("amfs_generic_readdir: real child");
+  dlog("%s: real child", __func__);
 
   if (gen == DOT_DOT_COOKIE) {
-    dlog("amfs_generic_readdir: End of readdir in %s", mp->am_path);
+    dlog("%s: End of readdir in %s", __func__, mp->am_path);
     dp->dl_eof = TRUE;
     dp->dl_entries = NULL;
     if (amuDebug(D_READDIR))
@@ -504,3 +489,456 @@ amfs_generic_readdir(am_node *mp, nfscookie cookie, nfsdirlist *dp, nfsentry *ep
   }
   return ESTALE;
 }
+
+/*
+ * Search a chain for an entry with some name.
+ */
+static int
+key_already_in_chain3(char *keyname, const am_entry3 *chain)
+{
+  const am_entry3 *tmpchain = chain;
+
+  while (tmpchain) {
+    if (keyname && tmpchain->name && STREQ(keyname, tmpchain->name))
+        return 1;
+    tmpchain = tmpchain->nextentry;
+  }
+
+  return 0;
+}
+
+/*
+ * Create a chain of entries which are not linked.
+ */
+static am_entry3 *
+make_entry_chain3(am_node *mp, const am_entry3 *current_chain, int fully_browsable)
+{
+  static uint64 last_cookie = (uint64) 2;      /* monotonically increasing */
+  static am_entry3 chain[MAX_CHAIN];
+  static int max_entries = MAX_CHAIN;
+  char *key;
+  int num_entries = 0, i;
+  u_int preflen = 0;
+  am_entry3 *retval = (am_entry3 *) NULL;
+  mntfs *mf;
+  mnt_map *mmp;
+
+  if (!mp) {
+    plog(XLOG_DEBUG, "make_entry_chain3: mp is (NULL)");
+    return retval;
+  }
+  mf = mp->am_al->al_mnt;
+  if (!mf) {
+    plog(XLOG_DEBUG, "make_entry_chain3: mp->am_al->al_mnt is (NULL)");
+    return retval;
+  }
+  mmp = (mnt_map *) mf->mf_private;
+  if (!mmp) {
+    plog(XLOG_DEBUG, "make_entry_chain3: mp->am_al->al_mnt->mf_private is (NULL)");
+    return retval;
+  }
+
+  if (mp->am_pref)
+    preflen = strlen(mp->am_pref);
+
+  /* iterate over keys */
+  for (i = 0; i < NKVHASH; i++) {
+    kv *k;
+    for (k = mmp->kvhash[i]; k ; k = k->next) {
+
+      /*
+       * Skip unwanted entries which are either not real entries or
+       * very difficult to interpret (wildcards...)  This test needs
+       * lots of improvement.  Any takers?
+       */
+      key = k->key;
+      if (!key)
+       continue;
+
+      /* Skip '/defaults' */
+      if (STREQ(key, "/defaults"))
+       continue;
+
+      /* Skip '*' */
+      if (!fully_browsable && strchr(key, '*'))
+       continue;
+
+      /*
+       * If the map has a prefix-string then check if the key starts with
+       * this string, and if it does, skip over this prefix.  If it has a
+       * prefix and it doesn't match the start of the key, skip it.
+       */
+      if (preflen) {
+       if (preflen > strlen(key))
+         continue;
+       if (!NSTREQ(key, mp->am_pref, preflen))
+         continue;
+       key += preflen;
+      }
+
+      /* no more '/' are allowed, unless browsable_dirs=full was used */
+      if (!fully_browsable && strchr(key, '/'))
+       continue;
+
+      /* no duplicates allowed */
+      if (key_already_in_chain3(key, current_chain))
+       continue;
+
+      /* fill in a cell and link the entry */
+      if (num_entries >= max_entries) {
+       /* out of space */
+       plog(XLOG_DEBUG, "make_entry_chain3: no more space in chain");
+       if (num_entries > 0) {
+         chain[num_entries - 1].nextentry = NULL;
+         retval = &chain[0];
+       }
+       return retval;
+      }
+
+      /* we have space.  put entry in next cell */
+      ++last_cookie;
+      chain[num_entries].fileid = last_cookie;
+      chain[num_entries].cookie = last_cookie;
+      chain[num_entries].name = key;
+      if (num_entries < max_entries - 1) {     /* link to next one */
+       chain[num_entries].nextentry = &chain[num_entries + 1];
+      }
+      ++num_entries;
+    } /* end of "while (k)" */
+  } /* end of "for (i ... NKVHASH ..." */
+
+  /* terminate chain */
+  if (num_entries > 0) {
+    chain[num_entries - 1].nextentry = NULL;
+    retval = &chain[0];
+  }
+
+  return retval;
+}
+
+/* This one is called only if map is browsable */
+static int
+amfs_readdir3_browsable(am_node *mp, am_cookie3 cookie,
+                       am_dirlist3 *dp, am_entry3 *ep, u_int count,
+                       int fully_browsable)
+{
+  uint64 gen = *(uint64 *) cookie;
+  int chain_length, i;
+  static am_entry3 *te, *te_next;
+  static int j;
+
+  dp->eof = FALSE;             /* assume readdir not done */
+
+  if (amuDebug(D_READDIR))
+    plog(XLOG_DEBUG, "amfs_readdir3_browsable gen=%lu, count=%d", gen, count);
+
+  if (gen == 0) {
+    /*
+     * In the default instance (which is used to start a search) we return
+     * "." and "..".
+     *
+     * This assumes that the count is big enough to allow both "." and ".."
+     * to be returned in a single packet.  If it isn't (which would be
+     * fairly unbelievable) then tough.
+     */
+    dlog("%s: default search", __func__);
+    /*
+     * Check for enough room.  This is extremely approximate but should
+     * be enough space.  Really need 2 times:
+     *      (8byte fileid
+     *      8byte cookie
+     *      8byte name pointer
+     *      8byte next entry addres) = sizeof(*ep)
+     *      2byte name + 1byte terminator
+     * plus the dirlist structure */
+    if (count < ((2 * ((sizeof(*ep) + sizeof("..") + 1))) + sizeof(*dp)));
+      return EINVAL;
+
+    /*
+     * compute # of entries to send in this chain.
+     * heuristics: 128 bytes per entry.
+     * This is too much probably, but it seems to work better because
+     * of the re-entrant nature of nfs_readdir, and esp. on systems
+     * like OpenBSD 2.2.
+     */
+    chain_length = count / 128;
+
+    /* reset static state counters */
+    te = te_next = NULL;
+
+    dp->entries = ep;
+
+    /* construct "." */
+    ep[0].fileid = mp->am_gen;
+    ep[0].name = ".";
+    ep[0].nextentry = &ep[1];
+    ep[0].cookie = 0;
+
+    /* construct ".." */
+    if (mp->am_parent)
+      ep[1].fileid = mp->am_parent->am_gen;
+    else
+      ep[1].fileid = mp->am_gen;
+
+    ep[1].name = "..";
+    ep[1].nextentry = NULL;
+    ep[1].cookie = dotdotcookie;
+
+    /*
+     * If map is browsable, call a function make_entry_chain() to construct
+     * a linked list of unmounted keys, and return it.  Then link the chain
+     * to the regular list.  Get the chain only once, but return
+     * chunks of it each time.
+     */
+    te = make_entry_chain3(mp, dp->entries, fully_browsable);
+    if (!te)
+      return 0;
+    if (amuDebug(D_READDIR)) {
+      am_entry3 *ne;
+      for (j = 0, ne = te; ne; ne = ne->ne_nextentry)
+       plog(XLOG_DEBUG, "gen1 key %4d \"%s\"", j++, ne->ne_name);
+    }
+
+    /* return only "chain_length" entries */
+    te_next = te;
+    for (i=1; i<chain_length; ++i) {
+      te_next = te_next->nextentry;
+      if (!te_next)
+       break;
+    }
+    if (te_next) {
+      am_entry3 *te_saved = te_next->nextentry;
+      te_next->nextentry = NULL; /* terminate "te" chain */
+      te_next = te_saved;       /* save rest of "te" for next iteration */
+      dp->eof = FALSE;          /* tell readdir there's more */
+    } else {
+      dp->eof = TRUE;           /* tell readdir that's it */
+    }
+    ep[1].nextentry = te;       /* append this chunk of "te" chain */
+    if (amuDebug(D_READDIR)) {
+      am_entry3 *ne;
+      for (j = 0, ne = te; ne; ne = ne->ne_nextentry)
+       plog(XLOG_DEBUG, "gen2 key %4d \"%s\"", j++, ne->name);
+      for (j = 0, ne = ep; ne; ne = ne->ne_nextentry) {
+       plog(XLOG_DEBUG, "gen2+ key %4d \"%s\" fi=%lu ck=%lu",
+            j++, ne->name, ne->fileid, ne->cookie);
+      }
+      plog(XLOG_DEBUG, "EOF is %d", dp->eof);
+    }
+    return 0;
+  } /* end of "if (gen == 0)" statement */
+
+  dlog("%s: real child", __func__);
+
+  if (gen == DOT_DOT_COOKIE) {
+    dlog("%s: End of readdir in %s", __func__, mp->am_path);
+    dp->eof = TRUE;
+    dp->entries = NULL;
+    return 0;
+  }
+
+  /*
+   * If browsable directories, then continue serving readdir() with another
+   * chunk of entries, starting from where we left off (when gen was equal
+   * to 0).  Once again, assume last chunk served to readdir.
+   */
+  dp->eof = TRUE;
+  dp->entries = ep;
+
+  te = te_next;                        /* reset 'te' from last saved te_next */
+  if (!te) {                   /* another indicator of end of readdir */
+    dp->entries = NULL;
+    return 0;
+  }
+  /*
+   * compute # of entries to send in this chain.
+   * heuristics: 128 bytes per entry.
+   */
+  chain_length = count / 128;
+
+  /* return only "chain_length" entries */
+  for (i = 1; i < chain_length; ++i) {
+    te_next = te_next->nextentry;
+    if (!te_next)
+      break;
+  }
+  if (te_next) {
+    am_entry3 *te_saved = te_next->nextentry;
+    te_next->nextentry = NULL; /* terminate "te" chain */
+    te_next = te_saved;                /* save rest of "te" for next iteration */
+    dp->eof = FALSE;           /* tell readdir there's more */
+  }
+  ep = te;                     /* send next chunk of "te" chain */
+  dp->entries = ep;
+  if (amuDebug(D_READDIR)) {
+    am_entry3 *ne;
+    plog(XLOG_DEBUG,
+        "entries=%p, te_next=%p, eof=%d", dp->entries, te_next, dp->eof);
+    for (ne = te; ne; ne = ne->nextentry)
+      plog(XLOG_DEBUG, "gen3 key %4d \"%s\"", j++, ne->name);
+  }
+  return 0;
+}
+
+static int
+amfs_readdir3(am_node *mp, am_cookie3 cookie,
+             am_dirlist3 *dp, am_entry3 *ep, u_int count)
+{
+  uint64 gen = *(uint64 *) cookie;
+  am_node *xp;
+
+  if (amuDebug(D_READDIR))
+    plog(XLOG_DEBUG, "amfs_readdir3 gen=%lu, count=%d", gen, count);
+
+  dp->eof = FALSE;             /* assume readdir not done */
+
+  /* when gen is 0, we start reading from the beginning of the directory */
+  if (gen == 0) {
+    /*
+     * In the default instance (which is used to start a search) we return
+     * "." and "..".
+     *
+     * This assumes that the count is big enough to allow both "." and ".."
+     * to be returned in a single packet.  If it isn't (which would be
+     * fairly unbelievable) then tough.
+     */
+    dlog("%s: default search", __func__);
+    /*
+     * Check for enough room.  This is extremely approximate but should
+     * be enough space.  Really need 2 times:
+     *      (8byte fileid
+     *      8byte cookie
+     *      8byte name pointer
+     *      8byte next entry addres) = sizeof(*ep)
+     *      2byte name + 1byte terminator
+     * plus the dirlist structure */
+    if (count < ((2 * ((sizeof(*ep) + sizeof("..") + 1))) + sizeof(*dp)));
+      return EINVAL;
+
+    xp = next_nonerror_node(mp->am_child);
+    dp->entries = ep;
+
+    /* construct "." */
+    ep[0].fileid = mp->am_gen;
+    ep[0].name = ".";
+    ep[0].cookie = 0;
+    ep[0].nextentry = &ep[1];
+
+    /* construct ".." */
+    if (mp->am_parent)
+      ep[1].fileid = mp->am_parent->am_gen;
+    else
+      ep[1].fileid = mp->am_gen;
+    ep[1].name = "..";
+    ep[1].nextentry = NULL;
+    ep[1].cookie = (xp ? xp->am_gen : dotdotcookie);
+
+    if (!xp)
+      dp->eof = TRUE;  /* by default assume readdir done */
+
+    if (amuDebug(D_READDIR)) {
+      am_entry3 *ne;
+      int j;
+      for (j = 0, ne = ep; ne; ne = ne->nextentry) {
+       plog(XLOG_DEBUG, "gen1 key %4d \"%s\" fi=%lu ck=%lu",
+            j++, ne->name, ne->fileid, ne->cookie);
+      }
+    }
+    return 0;
+  }
+  dlog("%s: real child", __func__);
+
+  if (gen == (uint64) DOT_DOT_COOKIE) {
+    dlog("%s: End of readdir in %s", __func__, mp->am_path);
+    dp->eof = TRUE;
+    dp->entries = NULL;
+    if (amuDebug(D_READDIR))
+      plog(XLOG_DEBUG, "end of readdir eof=TRUE, dl_entries=0\n");
+    return 0;
+  }
+
+  /* non-browsable directories code */
+  xp = mp->am_child;
+  while (xp && xp->am_gen != gen)
+    xp = xp->am_osib;
+
+  if (xp) {
+    int nbytes = count / 2;    /* conservative */
+    int todo = MAX_READDIR_ENTRIES;
+
+    dp->entries = ep;
+    do {
+      am_node *xp_next = next_nonerror_node(xp->am_osib);
+
+      if (xp_next) {
+        ep->cookie = xp_next->am_gen;
+      } else {
+       ep->cookie = (uint64) dotdotcookie;
+       dp->eof = TRUE;
+      }
+
+      ep->fileid = xp->am_gen;
+      ep->name = xp->am_name;
+      nbytes -= sizeof(*ep) + 1;
+      if (xp->am_name)
+       nbytes -= strlen(xp->am_name);
+
+      xp = xp_next;
+
+      if (nbytes > 0 && !dp->dl_eof && todo > 1) {
+       ep->nextentry = ep + 1;
+       ep++;
+       --todo;
+      } else {
+       todo = 0;
+      }
+    } while (todo > 0);
+
+    ep->nextentry = NULL;
+
+    if (amuDebug(D_READDIR)) {
+      am_entry3 *ne;
+      int j;
+      for (j = 0, ne = ep; ne; ne = ne->nextentry) {
+       plog(XLOG_DEBUG, "gen2 key %4d \"%s\" fi=%lu ck=%lu",
+            j++, ne->name, ne->fileid, ne->cookie);
+      }
+    }
+    return 0;
+  }
+  return ESTALE;
+}
+
+/*
+ * This readdir function which call a special version of it that allows
+ * browsing if browsable_dirs=yes was set on the map.
+ */
+int
+amfs_generic_readdir(am_node *mp, voidp cookie, voidp dp, voidp ep, u_int count)
+{
+  int browsable, full;
+
+  /* check if map is browsable */
+  browsable = 0;
+  if (mp->am_al->al_mnt && mp->am_al->al_mnt->mf_mopts) {
+    mntent_t mnt;
+    mnt.mnt_opts = mp->am_al->al_mnt->mf_mopts;
+    if (amu_hasmntopt(&mnt, "fullybrowsable"))
+      browsable = 2;
+    else if (amu_hasmntopt(&mnt, "browsable"))
+      browsable = 1;
+  }
+  full = (browsable == 2);
+
+  if (nfs_dispatcher == nfs_program_2) {
+    if (browsable)
+      return amfs_readdir_browsable(mp, cookie, dp, ep, count, full);
+    else
+      return amfs_readdir(mp, cookie, dp, ep, count);
+  } else {
+    if (browsable)
+      return amfs_readdir3_browsable(mp, (am_cookie3) cookie, dp, ep, count, full);
+    else
+      return amfs_readdir3(mp, (am_cookie3) cookie, dp, ep, count);
+  }
+}
index ede5679ae091f5adb54d8dde15436967584778c4..de38bcfb2741b9281e247516d35533516dec89d3 100644 (file)
@@ -256,7 +256,8 @@ restart_automounter_nodes(void)
       if (old_ports[i] == 0) {
        int soNFS;
        SVCXPRT *nfsxprt;
-       if (create_nfs_service(&soNFS, &port, &nfsxprt, nfs_program_2) != 0) {
+       if (create_nfs_service(&soNFS, &port, &nfsxprt, nfs_dispatcher,
+           get_nfs_dispatcher_version(nfs_dispatcher)) != 0) {
          plog(XLOG_WARNING, "Can't bind to port %u", port);
          goto give_up;
        }
index 3bee9fc6d91db1983a6eb4158a617ffe41fee71b..c52c75e2cf9bce1ded6455bdb82b8be42cf428f0 100644 (file)
@@ -103,6 +103,7 @@ typedef int (*ypall_callback_fxn_t)(int, char *, int, char *, int, char *);
 #define na_mode                mode
 #define na_mtime       mtime
 #define na_nlink       nlink
+#define na_rdev                rdev
 #define na_size                size
 #define na_uid         uid
 #define na_type                type
index 8664a468859cd22720241bb52d78437674d0cbf0..b3ad5fc5cbd3795ff2a2dace4589a4795c51b895 100644 (file)
@@ -244,9 +244,8 @@ amu_svc_register(SVCXPRT *xprt, u_long prognum, u_long versnum,
  * Create the nfs service for amd
  */
 int
-create_nfs_service(int *soNFSp, u_short *nfs_portp, SVCXPRT **nfs_xprtp, void (*dispatch_fxn)(struct svc_req *rqstp, SVCXPRT *transp))
+create_nfs_service(int *soNFSp, u_short *nfs_portp, SVCXPRT **nfs_xprtp, void (*dispatch_fxn)(struct svc_req *rqstp, SVCXPRT *transp), u_long nfs_version)
 {
-
   *soNFSp = socket(AF_INET, SOCK_DGRAM, 0);
 
   if (*soNFSp < 0 || bind_resv_port(*soNFSp, nfs_portp) < 0) {
@@ -266,9 +265,9 @@ create_nfs_service(int *soNFSp, u_short *nfs_portp, SVCXPRT **nfs_xprtp, void (*
     close(*soNFSp);
     return 1;
   }
-  if (!svc_register(*nfs_xprtp, NFS_PROGRAM, NFS_VERSION, dispatch_fxn, 0)) {
-    plog(XLOG_FATAL, "unable to register (%ld, %ld, 0)",
-        (u_long) NFS_PROGRAM, (u_long) NFS_VERSION);
+  if (!svc_register(*nfs_xprtp, NFS_PROGRAM, nfs_version, dispatch_fxn, 0)) {
+    plog(XLOG_FATAL, "unable to register (%lu, %lu, 0)",
+        (u_long) NFS_PROGRAM, nfs_version);
     svc_destroy(*nfs_xprtp);
     close(*soNFSp);
     return 3;
index 8ec32d748ddd5586987ae1796a319f5332ce3560..d26a511bfe40621735f0b36d722d765582de2c78 100644 (file)
@@ -418,7 +418,7 @@ bind_nfs_port(int unused_so, u_short *nfs_portp)
  * return 0 (TRUE) if OK, 1 (FALSE) if failed.
  */
 int
-create_nfs_service(int *soNFSp, u_short *nfs_portp, SVCXPRT **nfs_xprtp, void (*dispatch_fxn)(struct svc_req *rqstp, SVCXPRT *transp))
+create_nfs_service(int *soNFSp, u_short *nfs_portp, SVCXPRT **nfs_xprtp, void (*dispatch_fxn)(struct svc_req *rqstp, SVCXPRT *transp), u_long nfs_version)
 {
   char *nettype = "ticlts";
 
@@ -450,7 +450,7 @@ create_nfs_service(int *soNFSp, u_short *nfs_portp, SVCXPRT **nfs_xprtp, void (*
     svc_destroy(*nfs_xprtp);
     return 1;
   }
-  if (svc_reg(*nfs_xprtp, NFS_PROGRAM, NFS_VERSION, dispatch_fxn, NULL) != 1) {
+  if (svc_reg(*nfs_xprtp, NFS_PROGRAM, nfs_version, dispatch_fxn, NULL) != 1) {
     plog(XLOG_ERROR, "could not register amd NFS service");
     svc_destroy(*nfs_xprtp);
     return 1;
index 6800e77e2f4cd15ba3f71cb1fff74f3d0520eb28..686bb63db23944b751ebfd336436602bfe8b1ef1 100644 (file)
@@ -416,11 +416,8 @@ main(int argc, char *argv[])
   /*
    * Register hlfsd as an nfs service with the portmapper.
    */
-#ifdef HAVE_TRANSPORT_TYPE_TLI
-  ret = create_nfs_service(&soNFS, &nfs_port, &nfsxprt, nfs_program_2);
-#else /* not HAVE_TRANSPORT_TYPE_TLI */
-  ret = create_nfs_service(&soNFS, &nfs_port, &nfsxprt, nfs_program_2);
-#endif /* not HAVE_TRANSPORT_TYPE_TLI */
+  ret = create_nfs_service(&soNFS, &nfs_port, &nfsxprt, nfs_program_2,
+    NFS_VERSION);
   if (ret != 0)
     fatal("cannot create NFS service");
 
index 4b245e5a295a657b3cbab80448870bdaa0fa90f7..0de881ad8c8529c01f5933886ec24ad5d2393d82 100644 (file)
@@ -302,6 +302,9 @@ extern int make_rpc_packet(char *, int, u_long, struct rpc_msg *, voidp, XDRPROC
 extern int mkdirs(char *, int);
 extern int mount_fs(mntent_t *, int, caddr_t, int, MTYPE_TYPE, u_long, const char *, const char *, int);
 extern void nfs_program_2(struct svc_req *rqstp, SVCXPRT *transp);
+extern void nfs_program_3(struct svc_req *rqstp, SVCXPRT *transp);
+#define get_nfs_dispatcher_version(a) \
+    ((a) == nfs_program_2 ? NFS_VERSION : NFS_VERSION3)
 extern int pickup_rpc_reply(voidp, int, voidp, XDRPROC_T_TYPE);
 extern int switch_option(char *);
 extern int switch_to_logfile(char *logfile, int orig_umask, int truncate_log);
@@ -374,7 +377,7 @@ extern int syslogging;
 extern void compute_nfs_args(void *nap, mntent_t *mntp, int genflags, struct netconfig *nfsncp, struct sockaddr_in *ip_addr, u_long nfs_version, char *nfs_proto, am_nfs_handle_t *fhp, char *host_name, char *fs_name);
 extern void destroy_nfs_args(void *nap, u_long nfs_version);
 extern int create_amq_service(int *udp_soAMQp, SVCXPRT **udp_amqpp, struct netconfig **udp_amqncpp, int *tcp_soAMQp, SVCXPRT **tcp_amqpp, struct netconfig **tcp_amqncpp, u_short preferred_amq_port);
-extern int create_nfs_service(int *soNFSp, u_short *nfs_portp, SVCXPRT **nfs_xprtp, void (*dispatch_fxn)(struct svc_req *rqstp, SVCXPRT *transp));
+extern int create_nfs_service(int *soNFSp, u_short *nfs_portp, SVCXPRT **nfs_xprtp, void (*dispatch_fxn)(struct svc_req *rqstp, SVCXPRT *transp), u_long nfs_version);
 extern int amu_svc_register(SVCXPRT *, u_long, u_long, void (*)(struct svc_req *, SVCXPRT *), u_long, struct netconfig *);
 
 #ifdef HAVE_TRANSPORT_TYPE_TLI
index 1803c02db93c38c1a4fb815b6165ec98e2222b40..3b6063025ddc5069e01e9391311f6ad93d5d8825 100644 (file)
 
 #ifdef HAVE_FS_NFS3
 
+#define AM_MOUNTVERS3 ((unsigned long)(3))
+
 #define AM_FHSIZE3 64          /* size in bytes of a file handle (v3) */
-#define        AM_MOUNTVERS3 ((unsigned long)(3))
+#define AM_NFS3_WRITEVERFSIZE 8
+#define AM_NFS3_CREATEVERFSIZE 8
+#define AM_NFS3_COOKIEVERFSIZE 8
+#define AM_ACCESS3_READ 0x0001
+#define AM_ACCESS3_LOOKUP 0x0002
+#define AM_ACCESS3_MODIFY 0x0004
+#define AM_ACCESS3_EXTEND 0x0008
+#define AM_ACCESS3_DELETE 0x0010
+#define AM_ACCESS3_EXECUTE 0x0020
+#define AM_FSF3_LINK 0x0001
+#define AM_FSF3_SYMLINK 0x0002
+#define AM_FSF3_HOMOGENEOUS 0x0008
+#define AM_FSF3_CANSETTIME 0x0010
+
+typedef char am_cookieverf3[AM_NFS3_COOKIEVERFSIZE];
+
+typedef u_quad_t uint64;
+
+typedef uint64 am_cookie3;
 
 /* NFSv3 handle */
 struct am_nfs_fh3 {
@@ -127,37 +147,830 @@ struct am_diropargs3 {
 };
 typedef struct am_diropargs3 am_diropargs3;
 
+enum am_ftype3 {
+  AM_NF3REG = 1,
+  AM_NF3DIR = 2,
+  AM_NF3BLK = 3,
+  AM_NF3CHR = 4,
+  AM_NF3LNK = 5,
+  AM_NF3SOCK = 6,
+  AM_NF3FIFO = 7,
+};
+typedef enum am_ftype3 am_ftype3;
+
+typedef u_int am_mode3;
+
+typedef u_int am_uid3;
+
+typedef u_int am_gid3;
+
+typedef uint64 am_size3;
+
+typedef uint64 am_fileid3;
+
+struct am_specdata3 {
+  u_int specdata1;
+  u_int specdata2;
+};
+typedef struct am_specdata3 am_specdata3;
+
+struct am_nfstime3 {
+  u_int seconds;
+  u_int nseconds;
+};
+typedef struct am_nfstime3 am_nfstime3;
+
+struct am_fattr3 {
+  am_ftype3 type;
+  am_mode3 mode;
+  u_int nlink;
+  am_uid3 uid;
+  am_gid3 gid;
+  am_size3 size;
+  am_size3 used;
+  am_specdata3 rdev;
+  uint64 fsid;
+  am_fileid3 fileid;
+  am_nfstime3 atime;
+  am_nfstime3 mtime;
+  am_nfstime3 ctime;
+};
+typedef struct am_fattr3 am_fattr3;
+
+struct am_post_op_attr {
+  bool_t attributes_follow;
+  union {
+    am_fattr3 attributes;
+  } am_post_op_attr_u;
+};
+typedef struct am_post_op_attr am_post_op_attr;
+
+enum am_stable_how {
+  AM_UNSTABLE = 0,
+  AM_DATA_SYNC = 1,
+  AM_FILE_SYNC = 2,
+};
+typedef enum am_stable_how am_stable_how;
+
+typedef uint64 am_offset3;
+
+typedef u_int am_count3;
+
+struct am_wcc_attr {
+  am_size3 size;
+  am_nfstime3 mtime;
+  am_nfstime3 ctime;
+};
+typedef struct am_wcc_attr am_wcc_attr;
+
+struct am_pre_op_attr {
+  bool_t attributes_follow;
+  union {
+    am_wcc_attr attributes;
+  } am_pre_op_attr_u;
+};
+typedef struct am_pre_op_attr am_pre_op_attr;
+
+struct am_wcc_data {
+  am_pre_op_attr before;
+  am_post_op_attr after;
+};
+typedef struct am_wcc_data am_wcc_data;
+
+struct am_WRITE3args {
+  am_nfs_fh3 file;
+  am_offset3 offset;
+  am_count3 count;
+  am_stable_how stable;
+  struct {
+    u_int data_len;
+    char *data_val;
+  } data;
+};
+typedef struct am_WRITE3args am_WRITE3args;
+
+typedef char am_writeverf3[AM_NFS3_WRITEVERFSIZE];
+
+struct am_WRITE3resok {
+  am_wcc_data file_wcc;
+  am_count3 count;
+  am_stable_how committed;
+  am_writeverf3 verf;
+};
+typedef struct am_WRITE3resok am_WRITE3resok;
+
+struct am_WRITE3resfail {
+  am_wcc_data file_wcc;
+};
+typedef struct am_WRITE3resfail am_WRITE3resfail;
+
+struct am_WRITE3res {
+  am_nfsstat3 status;
+  union {
+    am_WRITE3resok ok;
+    am_WRITE3resfail fail;
+  } res_u;
+};
+typedef struct am_WRITE3res am_WRITE3res;
+
 struct am_LOOKUP3args {
-       am_diropargs3 what;
+  am_diropargs3 what;
 };
 typedef struct am_LOOKUP3args am_LOOKUP3args;
 
 struct am_LOOKUP3resok {
-       am_nfs_fh3 object;
-#if 0
-       post_op_attr obj_attributes;
-       post_op_attr dir_attributes;
-#endif /* 0 */
+  am_nfs_fh3 object;
+  am_post_op_attr obj_attributes;
+  am_post_op_attr dir_attributes;
 };
 typedef struct am_LOOKUP3resok am_LOOKUP3resok;
 
 struct am_LOOKUP3resfail {
-#if 0
-       post_op_attr dir_attributes;
-#else /* !0 */
-       char dummy;             /* cannot have an empty declaration */
-#endif /* !0 */
+  am_post_op_attr dir_attributes;
 };
 typedef struct am_LOOKUP3resfail am_LOOKUP3resfail;
 
 struct am_LOOKUP3res {
-       am_nfsstat3 status;
-       union {
-               am_LOOKUP3resok ok;
-               am_LOOKUP3resfail fail;
-       } res_u;
+  am_nfsstat3 status;
+  union {
+    am_LOOKUP3resok ok;
+    am_LOOKUP3resfail fail;
+  } res_u;
 };
 typedef struct am_LOOKUP3res am_LOOKUP3res;
+
+struct am_COMMIT3args {
+  am_nfs_fh3 file;
+  am_offset3 offset;
+  am_count3 count;
+};
+typedef struct am_COMMIT3args am_COMMIT3args;
+
+struct am_COMMIT3resok {
+  am_wcc_data file_wcc;
+  am_writeverf3 verf;
+};
+typedef struct am_COMMIT3resok am_COMMIT3resok;
+
+struct am_COMMIT3resfail {
+  am_wcc_data file_wcc;
+};
+typedef struct am_COMMIT3resfail am_COMMIT3resfail;
+
+struct am_COMMIT3res {
+  am_nfsstat3 status;
+  union {
+    am_COMMIT3resok ok;
+    am_COMMIT3resfail fail;
+  } res_u;
+};
+typedef struct am_COMMIT3res am_COMMIT3res;
+
+struct am_ACCESS3args {
+  am_nfs_fh3 object;
+  u_int access;
+};
+typedef struct am_ACCESS3args am_ACCESS3args;
+
+struct am_ACCESS3resok {
+  am_post_op_attr obj_attributes;
+  u_int access;
+};
+typedef struct am_ACCESS3resok am_ACCESS3resok;
+
+struct am_ACCESS3resfail {
+  am_post_op_attr obj_attributes;
+};
+typedef struct am_ACCESS3resfail am_ACCESS3resfail;
+
+struct am_ACCESS3res {
+  am_nfsstat3 status;
+  union {
+    am_ACCESS3resok ok;
+    am_ACCESS3resfail fail;
+  } res_u;
+};
+typedef struct am_ACCESS3res am_ACCESS3res;
+
+struct am_GETATTR3args {
+  am_nfs_fh3 object;
+};
+typedef struct am_GETATTR3args am_GETATTR3args;
+
+struct am_GETATTR3resok {
+  am_fattr3 obj_attributes;
+};
+typedef struct am_GETATTR3resok am_GETATTR3resok;
+
+struct am_GETATTR3res {
+  am_nfsstat3 status;
+  union {
+    am_GETATTR3resok ok;
+  } res_u;
+};
+typedef struct am_GETATTR3res am_GETATTR3res;
+
+enum am_time_how {
+  AM_DONT_CHANGE = 0,
+  AM_SET_TO_SERVER_TIME = 1,
+  AM_SET_TO_CLIENT_TIME = 2,
+};
+typedef enum am_time_how am_time_how;
+
+struct am_set_mode3 {
+  bool_t set_it;
+  union {
+    am_mode3 mode;
+  } am_set_mode3_u;
+};
+typedef struct am_set_mode3 am_set_mode3;
+
+struct am_set_uid3 {
+  bool_t set_it;
+  union {
+    am_uid3 uid;
+  } am_set_uid3_u;
+};
+typedef struct am_set_uid3 am_set_uid3;
+
+struct am_set_gid3 {
+  bool_t set_it;
+  union {
+    am_gid3 gid;
+  } am_set_gid3_u;
+};
+typedef struct am_set_gid3 am_set_gid3;
+
+struct am_set_size3 {
+  bool_t set_it;
+  union {
+    am_size3 size;
+  } am_set_size3_u;
+};
+typedef struct am_set_size3 am_set_size3;
+
+struct am_set_atime {
+  am_time_how set_it;
+  union {
+    am_nfstime3 atime;
+  } am_set_atime_u;
+};
+typedef struct am_set_atime am_set_atime;
+
+struct am_set_mtime {
+  am_time_how set_it;
+  union {
+    am_nfstime3 mtime;
+  } am_set_mtime_u;
+};
+typedef struct am_set_mtime am_set_mtime;
+
+struct am_sattr3 {
+  am_set_mode3 mode;
+  am_set_uid3 uid;
+  am_set_gid3 gid;
+  am_set_size3 size;
+  am_set_atime atime;
+  am_set_mtime mtime;
+};
+typedef struct am_sattr3 am_sattr3;
+
+enum am_createmode3 {
+  AM_UNCHECKED = 0,
+  AM_GUARDED = 1,
+  AM_EXCLUSIVE = 2,
+};
+typedef enum am_createmode3 am_createmode3;
+
+typedef char am_createverf3[AM_NFS3_CREATEVERFSIZE];
+
+struct am_createhow3 {
+  am_createmode3 mode;
+  union {
+    am_sattr3 obj_attributes;
+    am_sattr3 g_obj_attributes;
+    am_createverf3 verf;
+  } am_createhow3_u;
+};
+typedef struct am_createhow3 am_createhow3;
+
+struct am_CREATE3args {
+  am_diropargs3 where;
+  am_createhow3 how;
+};
+typedef struct am_CREATE3args am_CREATE3args;
+
+struct am_post_op_fh3 {
+  bool_t handle_follows;
+  union {
+    am_nfs_fh3 handle;
+  } am_post_op_fh3_u;
+};
+typedef struct am_post_op_fh3 am_post_op_fh3;
+
+struct am_CREATE3resok {
+  am_post_op_fh3 obj;
+  am_post_op_attr obj_attributes;
+  am_wcc_data dir_wcc;
+};
+typedef struct am_CREATE3resok am_CREATE3resok;
+
+struct am_CREATE3resfail {
+  am_wcc_data dir_wcc;
+};
+typedef struct am_CREATE3resfail am_CREATE3resfail;
+
+struct am_CREATE3res {
+  am_nfsstat3 status;
+  union {
+    am_CREATE3resok ok;
+    am_CREATE3resfail fail;
+  } res_u;
+};
+typedef struct am_CREATE3res am_CREATE3res;
+
+struct am_REMOVE3args {
+  am_diropargs3 object;
+};
+typedef struct am_REMOVE3args am_REMOVE3args;
+
+struct am_REMOVE3resok {
+  am_wcc_data dir_wcc;
+};
+typedef struct am_REMOVE3resok am_REMOVE3resok;
+
+struct am_REMOVE3resfail {
+  am_wcc_data dir_wcc;
+};
+typedef struct am_REMOVE3resfail am_REMOVE3resfail;
+
+struct am_REMOVE3res {
+  am_nfsstat3 status;
+  union {
+    am_REMOVE3resok ok;
+    am_REMOVE3resfail fail;
+  } res_u;
+};
+typedef struct am_REMOVE3res am_REMOVE3res;
+
+struct am_READ3args {
+  am_nfs_fh3 file;
+  am_offset3 offset;
+  am_count3 count;
+};
+typedef struct am_READ3args am_READ3args;
+
+struct am_READ3resok {
+  am_post_op_attr file_attributes;
+  am_count3 count;
+  bool_t eof;
+  struct {
+    u_int data_len;
+    char *data_val;
+  } data;
+};
+typedef struct am_READ3resok am_READ3resok;
+
+struct am_READ3resfail {
+  am_post_op_attr file_attributes;
+};
+typedef struct am_READ3resfail am_READ3resfail;
+
+struct am_READ3res {
+  am_nfsstat3 status;
+  union {
+    am_READ3resok ok;
+    am_READ3resfail fail;
+  } res_u;
+};
+typedef struct am_READ3res am_READ3res;
+
+struct am_FSINFO3args {
+  am_nfs_fh3 fsroot;
+};
+typedef struct am_FSINFO3args am_FSINFO3args;
+
+struct am_FSINFO3resok {
+  am_post_op_attr obj_attributes;
+  u_int rtmax;
+  u_int rtpref;
+  u_int rtmult;
+  u_int wtmax;
+  u_int wtpref;
+  u_int wtmult;
+  u_int dtpref;
+  am_size3 maxfilesize;
+  am_nfstime3 time_delta;
+  u_int properties;
+};
+typedef struct am_FSINFO3resok am_FSINFO3resok;
+
+struct am_FSINFO3resfail {
+  am_post_op_attr obj_attributes;
+};
+typedef struct am_FSINFO3resfail am_FSINFO3resfail;
+
+struct am_FSINFO3res {
+  am_nfsstat3 status;
+  union {
+    am_FSINFO3resok ok;
+    am_FSINFO3resfail fail;
+  } res_u;
+};
+typedef struct am_FSINFO3res am_FSINFO3res;
+
+struct am_FSSTAT3args {
+  am_nfs_fh3 fsroot;
+};
+typedef struct am_FSSTAT3args am_FSSTAT3args;
+
+struct am_FSSTAT3resok {
+  am_post_op_attr obj_attributes;
+  am_size3 tbytes;
+  am_size3 fbytes;
+  am_size3 abytes;
+  am_size3 tfiles;
+  am_size3 ffiles;
+  am_size3 afiles;
+  u_int invarsec;
+};
+typedef struct am_FSSTAT3resok am_FSSTAT3resok;
+
+struct am_FSSTAT3resfail {
+  am_post_op_attr obj_attributes;
+};
+typedef struct am_FSSTAT3resfail am_FSSTAT3resfail;
+
+struct am_FSSTAT3res {
+  am_nfsstat3 status;
+  union {
+    am_FSSTAT3resok ok;
+    am_FSSTAT3resfail fail;
+  } res_u;
+};
+typedef struct am_FSSTAT3res am_FSSTAT3res;
+
+struct am_PATHCONF3args {
+  am_nfs_fh3 object;
+};
+typedef struct am_PATHCONF3args am_PATHCONF3args;
+
+struct am_PATHCONF3resok {
+  am_post_op_attr obj_attributes;
+  u_int linkmax;
+  u_int name_max;
+  bool_t no_trunc;
+  bool_t chown_restricted;
+  bool_t case_insensitive;
+  bool_t case_preserving;
+};
+typedef struct am_PATHCONF3resok am_PATHCONF3resok;
+
+struct am_PATHCONF3resfail {
+  am_post_op_attr obj_attributes;
+};
+typedef struct am_PATHCONF3resfail am_PATHCONF3resfail;
+
+struct am_PATHCONF3res {
+  am_nfsstat3 status;
+  union {
+    am_PATHCONF3resok ok;
+    am_PATHCONF3resfail fail;
+  } res_u;
+};
+typedef struct am_PATHCONF3res am_PATHCONF3res;
+
+typedef char *am_nfspath3;
+
+struct am_symlinkdata3 {
+  am_sattr3 symlink_attributes;
+  am_nfspath3 symlink_data;
+};
+typedef struct am_symlinkdata3 am_symlinkdata3;
+
+struct am_SYMLINK3args {
+  am_diropargs3 where;
+  am_symlinkdata3 symlink;
+};
+typedef struct am_SYMLINK3args am_SYMLINK3args;
+
+struct am_SYMLINK3resok {
+  am_post_op_fh3 obj;
+  am_post_op_attr obj_attributes;
+  am_wcc_data dir_wcc;
+};
+typedef struct am_SYMLINK3resok am_SYMLINK3resok;
+
+struct am_SYMLINK3resfail {
+  am_wcc_data dir_wcc;
+};
+typedef struct am_SYMLINK3resfail am_SYMLINK3resfail;
+
+struct am_SYMLINK3res {
+  am_nfsstat3 status;
+  union {
+    am_SYMLINK3resok ok;
+    am_SYMLINK3resfail fail;
+  } res_u;
+};
+typedef struct am_SYMLINK3res am_SYMLINK3res;
+
+struct am_READLINK3args {
+  am_nfs_fh3 symlink;
+};
+typedef struct am_READLINK3args am_READLINK3args;
+
+struct am_READLINK3resok {
+  am_post_op_attr symlink_attributes;
+  am_nfspath3 data;
+};
+typedef struct am_READLINK3resok am_READLINK3resok;
+
+struct am_READLINK3resfail {
+  am_post_op_attr symlink_attributes;
+};
+typedef struct am_READLINK3resfail am_READLINK3resfail;
+
+struct am_READLINK3res {
+  am_nfsstat3 status;
+  union {
+    am_READLINK3resok ok;
+    am_READLINK3resfail fail;
+  } res_u;
+};
+typedef struct am_READLINK3res am_READLINK3res;
+
+struct am_devicedata3 {
+  am_sattr3 dev_attributes;
+  am_specdata3 spec;
+};
+typedef struct am_devicedata3 am_devicedata3;
+
+struct am_mknoddata3 {
+  am_ftype3 type;
+  union {
+    am_devicedata3 chr_device;
+    am_devicedata3 blk_device;
+    am_sattr3 sock_attributes;
+    am_sattr3 pipe_attributes;
+  } am_mknoddata3_u;
+};
+typedef struct am_mknoddata3 am_mknoddata3;
+
+struct am_MKNOD3args {
+  am_diropargs3 where;
+  am_mknoddata3 what;
+};
+typedef struct am_MKNOD3args am_MKNOD3args;
+
+struct am_MKNOD3resok {
+  am_post_op_fh3 obj;
+  am_post_op_attr obj_attributes;
+  am_wcc_data dir_wcc;
+};
+typedef struct am_MKNOD3resok am_MKNOD3resok;
+
+struct am_MKNOD3resfail {
+  am_wcc_data dir_wcc;
+};
+typedef struct am_MKNOD3resfail am_MKNOD3resfail;
+
+struct am_MKNOD3res {
+  am_nfsstat3 status;
+  union {
+    am_MKNOD3resok ok;
+    am_MKNOD3resfail fail;
+  } res_u;
+};
+typedef struct am_MKNOD3res am_MKNOD3res;
+
+struct am_MKDIR3args {
+  am_diropargs3 where;
+  am_sattr3 attributes;
+};
+typedef struct am_MKDIR3args am_MKDIR3args;
+
+struct am_MKDIR3resok {
+  am_post_op_fh3 obj;
+  am_post_op_attr obj_attributes;
+  am_wcc_data dir_wcc;
+};
+typedef struct am_MKDIR3resok am_MKDIR3resok;
+
+struct am_MKDIR3resfail {
+  am_wcc_data dir_wcc;
+};
+typedef struct am_MKDIR3resfail am_MKDIR3resfail;
+
+struct am_MKDIR3res {
+  am_nfsstat3 status;
+  union {
+    am_MKDIR3resok ok;
+    am_MKDIR3resfail fail;
+  } res_u;
+};
+typedef struct am_MKDIR3res am_MKDIR3res;
+
+struct am_RMDIR3args {
+  am_diropargs3 object;
+};
+typedef struct am_RMDIR3args am_RMDIR3args;
+
+struct am_RMDIR3resok {
+  am_wcc_data dir_wcc;
+};
+typedef struct am_RMDIR3resok am_RMDIR3resok;
+
+struct am_RMDIR3resfail {
+  am_wcc_data dir_wcc;
+};
+typedef struct am_RMDIR3resfail am_RMDIR3resfail;
+
+struct am_RMDIR3res {
+  am_nfsstat3 status;
+  union {
+    am_RMDIR3resok ok;
+    am_RMDIR3resfail fail;
+  } res_u;
+};
+typedef struct am_RMDIR3res am_RMDIR3res;
+
+struct am_RENAME3args {
+  am_diropargs3 from;
+  am_diropargs3 to;
+};
+typedef struct am_RENAME3args am_RENAME3args;
+
+struct am_RENAME3resok {
+  am_wcc_data fromdir_wcc;
+  am_wcc_data todir_wcc;
+};
+typedef struct am_RENAME3resok am_RENAME3resok;
+
+struct am_RENAME3resfail {
+  am_wcc_data fromdir_wcc;
+  am_wcc_data todir_wcc;
+};
+typedef struct am_RENAME3resfail am_RENAME3resfail;
+
+struct am_RENAME3res {
+  am_nfsstat3 status;
+  union {
+    am_RENAME3resok ok;
+    am_RENAME3resfail fail;
+  } res_u;
+};
+typedef struct am_RENAME3res am_RENAME3res;
+
+struct am_READDIRPLUS3args {
+  am_nfs_fh3 dir;
+  am_cookie3 cookie;
+  am_cookieverf3 cookieverf;
+  am_count3 dircount;
+  am_count3 maxcount;
+};
+typedef struct am_READDIRPLUS3args am_READDIRPLUS3args;
+
+struct am_entryplus3 {
+  am_fileid3 fileid;
+  am_filename3 name;
+  am_cookie3 cookie;
+  am_post_op_attr name_attributes;
+  am_post_op_fh3 name_handle;
+  struct am_entryplus3 *nextentry;
+};
+typedef struct am_entryplus3 am_entryplus3;
+
+struct am_dirlistplus3 {
+  am_entryplus3 *entries;
+  bool_t eof;
+};
+typedef struct am_dirlistplus3 am_dirlistplus3;
+
+struct am_READDIRPLUS3resok {
+  am_post_op_attr dir_attributes;
+  am_cookieverf3 cookieverf;
+  am_dirlistplus3 reply;
+};
+typedef struct am_READDIRPLUS3resok am_READDIRPLUS3resok;
+
+struct am_READDIRPLUS3resfail {
+  am_post_op_attr dir_attributes;
+};
+typedef struct am_READDIRPLUS3resfail am_READDIRPLUS3resfail;
+
+struct am_READDIRPLUS3res {
+  am_nfsstat3 status;
+  union {
+    am_READDIRPLUS3resok ok;
+    am_READDIRPLUS3resfail fail;
+  } res_u;
+};
+typedef struct am_READDIRPLUS3res am_READDIRPLUS3res;
+
+struct am_READDIR3args {
+  am_nfs_fh3 dir;
+  am_cookie3 cookie;
+  am_cookieverf3 cookieverf;
+  am_count3 count;
+};
+typedef struct am_READDIR3args am_READDIR3args;
+
+struct am_entry3 {
+  am_fileid3 fileid;
+  am_filename3 name;
+  am_cookie3 cookie;
+  struct am_entry3 *nextentry;
+};
+typedef struct am_entry3 am_entry3;
+
+struct am_dirlist3 {
+  am_entry3 *entries;
+  bool_t eof;
+};
+typedef struct am_dirlist3 am_dirlist3;
+
+struct am_READDIR3resok {
+  am_post_op_attr dir_attributes;
+  am_cookieverf3 cookieverf;
+  am_dirlist3 reply;
+};
+typedef struct am_READDIR3resok am_READDIR3resok;
+
+struct am_READDIR3resfail {
+  am_post_op_attr dir_attributes;
+};
+typedef struct am_READDIR3resfail am_READDIR3resfail;
+
+struct am_READDIR3res {
+  am_nfsstat3 status;
+  union {
+    am_READDIR3resok ok;
+    am_READDIR3resfail fail;
+  } res_u;
+};
+typedef struct am_READDIR3res am_READDIR3res;
+
+struct am_LINK3args {
+  am_nfs_fh3 file;
+  am_diropargs3 link;
+};
+typedef struct am_LINK3args am_LINK3args;
+
+struct am_LINK3resok {
+  am_post_op_attr file_attributes;
+  am_wcc_data linkdir_wcc;
+};
+typedef struct am_LINK3resok am_LINK3resok;
+
+struct am_LINK3resfail {
+  am_post_op_attr file_attributes;
+  am_wcc_data linkdir_wcc;
+};
+typedef struct am_LINK3resfail am_LINK3resfail;
+
+struct am_LINK3res {
+  am_nfsstat3 status;
+  union {
+    am_LINK3resok ok;
+    am_LINK3resfail fail;
+  } res_u;
+};
+typedef struct am_LINK3res am_LINK3res;
+
+struct am_sattrguard3 {
+  bool_t check;
+  union {
+    am_nfstime3 obj_ctime;
+  } am_sattrguard3_u;
+};
+typedef struct am_sattrguard3 am_sattrguard3;
+
+struct am_SETATTR3args {
+  am_nfs_fh3 object;
+  am_sattr3 new_attributes;
+  am_sattrguard3 guard;
+};
+typedef struct am_SETATTR3args am_SETATTR3args;
+
+struct am_SETATTR3resok {
+  am_wcc_data obj_wcc;
+};
+typedef struct am_SETATTR3resok am_SETATTR3resok;
+
+struct am_SETATTR3resfail {
+  am_wcc_data obj_wcc;
+};
+typedef struct am_SETATTR3resfail am_SETATTR3resfail;
+
+struct am_SETATTR3res {
+  am_nfsstat3 status;
+  union {
+    am_SETATTR3resok ok;
+    am_SETATTR3resfail fail;
+  } res_u;
+};
+typedef struct am_SETATTR3res am_SETATTR3res;
 #endif /* HAVE_FS_NFS3 */
 
 /*
@@ -306,6 +1119,74 @@ bool_t xdr_writeargs(XDR *xdrs, nfswriteargs *objp);
  * NFS3 XDR FUNCTIONS:
  */
 #ifdef HAVE_FS_NFS3
+#define AM_NFS3_NULL 0
+void * am_nfs3_null_3(void *, CLIENT *);
+void * am_nfs3_null_3_svc(void *, struct svc_req *);
+#define AM_NFS3_GETATTR 1
+am_GETATTR3res * am_nfs3_getattr_3(am_GETATTR3args *, CLIENT *);
+am_GETATTR3res * am_nfs3_getattr_3_svc(am_GETATTR3args *, struct svc_req *);
+#define AM_NFS3_SETATTR 2
+am_SETATTR3res * am_nfs3_setattr_3(am_SETATTR3args *, CLIENT *);
+am_SETATTR3res * am_nfs3_setattr_3_svc(am_SETATTR3args *, struct svc_req *);
+#define AM_NFS3_LOOKUP 3
+am_LOOKUP3res * am_nfs3_lookup_3(am_LOOKUP3args *, CLIENT *);
+am_LOOKUP3res * am_nfs3_lookup_3_svc(am_LOOKUP3args *, struct svc_req *);
+#define AM_NFS3_ACCESS 4
+am_ACCESS3res * am_nfs3_access_3(am_ACCESS3args *, CLIENT *);
+am_ACCESS3res * am_nfs3_access_3_svc(am_ACCESS3args *, struct svc_req *);
+#define AM_NFS3_READLINK 5
+am_READLINK3res * am_nfs3_readlink_3(am_READLINK3args *, CLIENT *);
+am_READLINK3res * am_nfs3_readlink_3_svc(am_READLINK3args *, struct svc_req *);
+#define AM_NFS3_READ 6
+am_READ3res * am_nfs3_read_3(am_READ3args *, CLIENT *);
+am_READ3res * am_nfs3_read_3_svc(am_READ3args *, struct svc_req *);
+#define AM_NFS3_WRITE 7
+am_WRITE3res * am_nfs3_write_3(am_WRITE3args *, CLIENT *);
+am_WRITE3res * am_nfs3_write_3_svc(am_WRITE3args *, struct svc_req *);
+#define AM_NFS3_CREATE 8
+am_CREATE3res * am_nfs3_create_3(am_CREATE3args *, CLIENT *);
+am_CREATE3res * am_nfs3_create_3_svc(am_CREATE3args *, struct svc_req *);
+#define AM_NFS3_MKDIR 9
+am_MKDIR3res * am_nfs3_mkdir_3(am_MKDIR3args *, CLIENT *);
+am_MKDIR3res * am_nfs3_mkdir_3_svc(am_MKDIR3args *, struct svc_req *);
+#define AM_NFS3_SYMLINK 10
+am_SYMLINK3res * am_nfs3_symlink_3(am_SYMLINK3args *, CLIENT *);
+am_SYMLINK3res * am_nfs3_symlink_3_svc(am_SYMLINK3args *, struct svc_req *);
+#define AM_NFS3_MKNOD 11
+am_MKNOD3res * am_nfs3_mknod_3(am_MKNOD3args *, CLIENT *);
+am_MKNOD3res * am_nfs3_mknod_3_svc(am_MKNOD3args *, struct svc_req *);
+#define AM_NFS3_REMOVE 12
+am_REMOVE3res * am_nfs3_remove_3(am_REMOVE3args *, CLIENT *);
+am_REMOVE3res * am_nfs3_remove_3_svc(am_REMOVE3args *, struct svc_req *);
+#define AM_NFS3_RMDIR 13
+am_RMDIR3res * am_nfs3_rmdir_3(am_RMDIR3args *, CLIENT *);
+am_RMDIR3res * am_nfs3_rmdir_3_svc(am_RMDIR3args *, struct svc_req *);
+#define AM_NFS3_RENAME 14
+am_RENAME3res * am_nfs3_rename_3(am_RENAME3args *, CLIENT *);
+am_RENAME3res * am_nfs3_rename_3_svc(am_RENAME3args *, struct svc_req *);
+#define AM_NFS3_LINK 15
+am_LINK3res * am_nfs3_link_3(am_LINK3args *, CLIENT *);
+am_LINK3res * am_nfs3_link_3_svc(am_LINK3args *, struct svc_req *);
+#define AM_NFS3_READDIR 16
+am_READDIR3res * am_nfs3_readdir_3(am_READDIR3args *, CLIENT *);
+am_READDIR3res * am_nfs3_readdir_3_svc(am_READDIR3args *, struct svc_req *);
+#define AM_NFS3_READDIRPLUS 17
+am_READDIRPLUS3res * am_nfs3_readdirplus_3(am_READDIRPLUS3args *, CLIENT *);
+am_READDIRPLUS3res * am_nfs3_readdirplus_3_svc(am_READDIRPLUS3args *, struct svc_req *);
+#define AM_NFS3_FSSTAT 18
+am_FSSTAT3res * am_nfs3_fsstat_3(am_FSSTAT3args *, CLIENT *);
+am_FSSTAT3res * am_nfs3_fsstat_3_svc(am_FSSTAT3args *, struct svc_req *);
+#define AM_NFS3_FSINFO 19
+am_FSINFO3res * am_nfs3_fsinfo_3(am_FSINFO3args *, CLIENT *);
+am_FSINFO3res * am_nfs3_fsinfo_3_svc(am_FSINFO3args *, struct svc_req *);
+#define AM_NFS3_PATHCONF 20
+am_PATHCONF3res * am_nfs3_pathconf_3(am_PATHCONF3args *, CLIENT *);
+am_PATHCONF3res * am_nfs3_pathconf_3_svc(am_PATHCONF3args *, struct svc_req *);
+#define AM_NFS3_COMMIT 21
+am_COMMIT3res * am_nfs3_commit_3(am_COMMIT3args *, CLIENT *);
+am_COMMIT3res * am_nfs3_commit_3_svc(am_COMMIT3args *, struct svc_req *);
+int nfs_program_3_freeresult (SVCXPRT *, xdrproc_t, caddr_t);
+
 bool_t xdr_am_fhandle3(XDR *xdrs, am_fhandle3 *objp);
 bool_t xdr_am_mountstat3(XDR *xdrs, am_mountstat3 *objp);
 bool_t xdr_am_mountres3_ok(XDR *xdrs, am_mountres3_ok *objp);
@@ -318,6 +1199,134 @@ bool_t xdr_am_LOOKUP3resfail(XDR *xdrs, am_LOOKUP3resfail *objp);
 bool_t xdr_am_LOOKUP3resok(XDR *xdrs, am_LOOKUP3resok *objp);
 bool_t xdr_am_nfsstat3(XDR *xdrs, am_nfsstat3 *objp);
 bool_t xdr_am_nfs_fh3(XDR *xdrs, am_nfs_fh3 *objp);
+bool_t xdr_am_cookieverf3 (XDR *, am_cookieverf3);
+bool_t xdr_uint64 (XDR *, uint64*);
+bool_t xdr_am_cookie3 (XDR *, am_cookie3*);
+bool_t xdr_am_nfs_fh3 (XDR *, am_nfs_fh3*);
+bool_t xdr_am_nfsstat3 (XDR *, am_nfsstat3*);
+bool_t xdr_am_filename3 (XDR *, am_filename3*);
+bool_t xdr_am_diropargs3 (XDR *, am_diropargs3*);
+bool_t xdr_am_ftype3 (XDR *, am_ftype3*);
+bool_t xdr_am_mode3 (XDR *, am_mode3*);
+bool_t xdr_am_uid3 (XDR *, am_uid3*);
+bool_t xdr_am_gid3 (XDR *, am_gid3*);
+bool_t xdr_am_size3 (XDR *, am_size3*);
+bool_t xdr_am_fileid3 (XDR *, am_fileid3*);
+bool_t xdr_am_specdata3 (XDR *, am_specdata3*);
+bool_t xdr_am_nfstime3 (XDR *, am_nfstime3*);
+bool_t xdr_am_fattr3 (XDR *, am_fattr3*);
+bool_t xdr_am_post_op_attr (XDR *, am_post_op_attr*);
+bool_t xdr_am_stable_how (XDR *, am_stable_how*);
+bool_t xdr_am_offset3 (XDR *, am_offset3*);
+bool_t xdr_am_count3 (XDR *, am_count3*);
+bool_t xdr_am_wcc_attr (XDR *, am_wcc_attr*);
+bool_t xdr_am_pre_op_attr (XDR *, am_pre_op_attr*);
+bool_t xdr_am_wcc_data (XDR *, am_wcc_data*);
+bool_t xdr_am_WRITE3args (XDR *, am_WRITE3args*);
+bool_t xdr_am_writeverf3 (XDR *, am_writeverf3);
+bool_t xdr_am_WRITE3resok (XDR *, am_WRITE3resok*);
+bool_t xdr_am_WRITE3resfail (XDR *, am_WRITE3resfail*);
+bool_t xdr_am_WRITE3res (XDR *, am_WRITE3res*);
+bool_t xdr_am_LOOKUP3args (XDR *, am_LOOKUP3args*);
+bool_t xdr_am_LOOKUP3resok (XDR *, am_LOOKUP3resok*);
+bool_t xdr_am_LOOKUP3resfail (XDR *, am_LOOKUP3resfail*);
+bool_t xdr_am_LOOKUP3res (XDR *, am_LOOKUP3res*);
+bool_t xdr_am_COMMIT3args (XDR *, am_COMMIT3args*);
+bool_t xdr_am_COMMIT3resok (XDR *, am_COMMIT3resok*);
+bool_t xdr_am_COMMIT3resfail (XDR *, am_COMMIT3resfail*);
+bool_t xdr_am_COMMIT3res (XDR *, am_COMMIT3res*);
+bool_t xdr_am_ACCESS3args (XDR *, am_ACCESS3args*);
+bool_t xdr_am_ACCESS3resok (XDR *, am_ACCESS3resok*);
+bool_t xdr_am_ACCESS3resfail (XDR *, am_ACCESS3resfail*);
+bool_t xdr_am_ACCESS3res (XDR *, am_ACCESS3res*);
+bool_t xdr_am_GETATTR3args (XDR *, am_GETATTR3args*);
+bool_t xdr_am_GETATTR3resok (XDR *, am_GETATTR3resok*);
+bool_t xdr_am_GETATTR3res (XDR *, am_GETATTR3res*);
+bool_t xdr_am_time_how (XDR *, am_time_how*);
+bool_t xdr_am_set_mode3 (XDR *, am_set_mode3*);
+bool_t xdr_am_set_uid3 (XDR *, am_set_uid3*);
+bool_t xdr_am_set_gid3 (XDR *, am_set_gid3*);
+bool_t xdr_am_set_size3 (XDR *, am_set_size3*);
+bool_t xdr_am_set_atime (XDR *, am_set_atime*);
+bool_t xdr_am_set_mtime (XDR *, am_set_mtime*);
+bool_t xdr_am_sattr3 (XDR *, am_sattr3*);
+bool_t xdr_am_createmode3 (XDR *, am_createmode3*);
+bool_t xdr_am_createverf3 (XDR *, am_createverf3);
+bool_t xdr_am_createhow3 (XDR *, am_createhow3*);
+bool_t xdr_am_CREATE3args (XDR *, am_CREATE3args*);
+bool_t xdr_am_post_op_fh3 (XDR *, am_post_op_fh3*);
+bool_t xdr_am_CREATE3resok (XDR *, am_CREATE3resok*);
+bool_t xdr_am_CREATE3resfail (XDR *, am_CREATE3resfail*);
+bool_t xdr_am_CREATE3res (XDR *, am_CREATE3res*);
+bool_t xdr_am_REMOVE3args (XDR *, am_REMOVE3args*);
+bool_t xdr_am_REMOVE3resok (XDR *, am_REMOVE3resok*);
+bool_t xdr_am_REMOVE3resfail (XDR *, am_REMOVE3resfail*);
+bool_t xdr_am_REMOVE3res (XDR *, am_REMOVE3res*);
+bool_t xdr_am_READ3args (XDR *, am_READ3args*);
+bool_t xdr_am_READ3resok (XDR *, am_READ3resok*);
+bool_t xdr_am_READ3resfail (XDR *, am_READ3resfail*);
+bool_t xdr_am_READ3res (XDR *, am_READ3res*);
+bool_t xdr_am_FSINFO3args (XDR *, am_FSINFO3args*);
+bool_t xdr_am_FSINFO3resok (XDR *, am_FSINFO3resok*);
+bool_t xdr_am_FSINFO3resfail (XDR *, am_FSINFO3resfail*);
+bool_t xdr_am_FSINFO3res (XDR *, am_FSINFO3res*);
+bool_t xdr_am_FSSTAT3args (XDR *, am_FSSTAT3args*);
+bool_t xdr_am_FSSTAT3resok (XDR *, am_FSSTAT3resok*);
+bool_t xdr_am_FSSTAT3resfail (XDR *, am_FSSTAT3resfail*);
+bool_t xdr_am_FSSTAT3res (XDR *, am_FSSTAT3res*);
+bool_t xdr_am_PATHCONF3args (XDR *, am_PATHCONF3args*);
+bool_t xdr_am_PATHCONF3resok (XDR *, am_PATHCONF3resok*);
+bool_t xdr_am_PATHCONF3resfail (XDR *, am_PATHCONF3resfail*);
+bool_t xdr_am_PATHCONF3res (XDR *, am_PATHCONF3res*);
+bool_t xdr_am_nfspath3 (XDR *, am_nfspath3*);
+bool_t xdr_am_symlinkdata3 (XDR *, am_symlinkdata3*);
+bool_t xdr_am_SYMLINK3args (XDR *, am_SYMLINK3args*);
+bool_t xdr_am_SYMLINK3resok (XDR *, am_SYMLINK3resok*);
+bool_t xdr_am_SYMLINK3resfail (XDR *, am_SYMLINK3resfail*);
+bool_t xdr_am_SYMLINK3res (XDR *, am_SYMLINK3res*);
+bool_t xdr_am_READLINK3args (XDR *, am_READLINK3args*);
+bool_t xdr_am_READLINK3resok (XDR *, am_READLINK3resok*);
+bool_t xdr_am_READLINK3resfail (XDR *, am_READLINK3resfail*);
+bool_t xdr_am_READLINK3res (XDR *, am_READLINK3res*);
+bool_t xdr_am_devicedata3 (XDR *, am_devicedata3*);
+bool_t xdr_am_mknoddata3 (XDR *, am_mknoddata3*);
+bool_t xdr_am_MKNOD3args (XDR *, am_MKNOD3args*);
+bool_t xdr_am_MKNOD3resok (XDR *, am_MKNOD3resok*);
+bool_t xdr_am_MKNOD3resfail (XDR *, am_MKNOD3resfail*);
+bool_t xdr_am_MKNOD3res (XDR *, am_MKNOD3res*);
+bool_t xdr_am_MKDIR3args (XDR *, am_MKDIR3args*);
+bool_t xdr_am_MKDIR3resok (XDR *, am_MKDIR3resok*);
+bool_t xdr_am_MKDIR3resfail (XDR *, am_MKDIR3resfail*);
+bool_t xdr_am_MKDIR3res (XDR *, am_MKDIR3res*);
+bool_t xdr_am_RMDIR3args (XDR *, am_RMDIR3args*);
+bool_t xdr_am_RMDIR3resok (XDR *, am_RMDIR3resok*);
+bool_t xdr_am_RMDIR3resfail (XDR *, am_RMDIR3resfail*);
+bool_t xdr_am_RMDIR3res (XDR *, am_RMDIR3res*);
+bool_t xdr_am_RENAME3args (XDR *, am_RENAME3args*);
+bool_t xdr_am_RENAME3resok (XDR *, am_RENAME3resok*);
+bool_t xdr_am_RENAME3resfail (XDR *, am_RENAME3resfail*);
+bool_t xdr_am_RENAME3res (XDR *, am_RENAME3res*);
+bool_t xdr_am_READDIRPLUS3args (XDR *, am_READDIRPLUS3args*);
+bool_t xdr_am_entryplus3 (XDR *, am_entryplus3*);
+bool_t xdr_am_dirlistplus3 (XDR *, am_dirlistplus3*);
+bool_t xdr_am_READDIRPLUS3resok (XDR *, am_READDIRPLUS3resok*);
+bool_t xdr_am_READDIRPLUS3resfail (XDR *, am_READDIRPLUS3resfail*);
+bool_t xdr_am_READDIRPLUS3res (XDR *, am_READDIRPLUS3res*);
+bool_t xdr_am_READDIR3args (XDR *, am_READDIR3args*);
+bool_t xdr_am_entry3 (XDR *, am_entry3*);
+bool_t xdr_am_dirlist3 (XDR *, am_dirlist3*);
+bool_t xdr_am_READDIR3resok (XDR *, am_READDIR3resok*);
+bool_t xdr_am_READDIR3resfail (XDR *, am_READDIR3resfail*);
+bool_t xdr_am_READDIR3res (XDR *, am_READDIR3res*);
+bool_t xdr_am_LINK3args (XDR *, am_LINK3args*);
+bool_t xdr_am_LINK3resok (XDR *, am_LINK3resok*);
+bool_t xdr_am_LINK3resfail (XDR *, am_LINK3resfail*);
+bool_t xdr_am_LINK3res (XDR *, am_LINK3res*);
+bool_t xdr_am_sattrguard3 (XDR *, am_sattrguard3*);
+bool_t xdr_am_SETATTR3args (XDR *, am_SETATTR3args*);
+bool_t xdr_am_SETATTR3resok (XDR *, am_SETATTR3resok*);
+bool_t xdr_am_SETATTR3resfail (XDR *, am_SETATTR3resfail*);
+bool_t xdr_am_SETATTR3res (XDR *, am_SETATTR3res*);
 #endif /* HAVE_FS_NFS3 */
 
 #endif /* not _AM_XDR_FUNC_H */
index 09d1cd9e322b6bb6072711b150793a6380c0e9f2..40ab33c37a3566a884f286a60c8adca1e6c68941 100644 (file)
@@ -681,18 +681,27 @@ static char *
 get_hex_string(u_int len, const char *fhdata)
 {
   u_int i;
-  static char buf[128];                /* better not go over it! */
+  static u_int xlen;
+  static char *buf;
+  static u_short *arr;
   char str[16];
-  short int arr[64];
 
-  if (!fhdata)
+  if (!fhdata || len == 0 || len > 10240)
     return NULL;
+  i = xlen * 4 + 1;
+  if (xlen < i) {
+    buf = xrealloc(buf, i);
+    arr = xrealloc(arr, len * sizeof(*arr));
+    xlen = i;
+  }
+       
   buf[0] = '\0';
-  memset(&arr[0], 0, (64 * sizeof(short int)));
-  memcpy(&arr[0], &fhdata[0], len);
-  for (i=0; i<len/sizeof(unsigned short int); i++) {
+  memset(arr, 0, len * sizeof(*arr));
+  memcpy(arr, fhdata, len);
+  len /= sizeof(*arr);
+  for (i = 0; i < len; i++) {
     xsnprintf(str, sizeof(str), "%04x", ntohs(arr[i]));
-    xstrlcat(buf, str, sizeof(buf));
+    xstrlcat(buf, str, xlen);
   }
   return buf;
 }
index 3f876bcea3f45e71a29c465dcb9c94c6c1133555..0135d559a0bbdf3eaa694950406f1d01b4aad7e6 100644 (file)
@@ -947,7 +947,6 @@ xdr_am_mountres3_ok(XDR *xdrs, am_mountres3_ok *objp)
   return (TRUE);
 }
 
-
 bool_t
 xdr_am_mountres3(XDR *xdrs, am_mountres3 *objp)
 {
@@ -964,6 +963,64 @@ xdr_am_mountres3(XDR *xdrs, am_mountres3 *objp)
   return (TRUE);
 }
 
+bool_t
+xdr_am_cookieverf3(XDR *xdrs, am_cookieverf3 objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_cookieverf3:");
+
+  if (!xdr_opaque(xdrs, objp, AM_NFS3_COOKIEVERFSIZE))
+    return FALSE;
+  return TRUE;
+}
+
+bool_t
+xdr_uint64(XDR *xdrs, uint64 *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_uint64:");
+
+  if (!xdr_u_int64_t(xdrs, objp))
+    return FALSE;
+  return TRUE;
+}
+
+bool_t
+xdr_am_cookie3(XDR *xdrs, am_cookie3 *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_cookie3:");
+
+  if (!xdr_uint64(xdrs, objp))
+    return FALSE;
+  return TRUE;
+}
+
+bool_t
+xdr_am_nfs_fh3(XDR *xdrs, am_nfs_fh3 *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_nfs_fh3:");
+
+  if (!xdr_u_int(xdrs, &objp->am_fh3_length))
+    return (FALSE);
+  if (objp->am_fh3_length > AM_FHSIZE3)
+    return (FALSE);
+  if (!xdr_opaque(xdrs, objp->am_fh3_data, objp->am_fh3_length))
+    return (FALSE);
+  return (TRUE);
+}
+
+bool_t
+xdr_am_nfsstat3(XDR *xdrs, am_nfsstat3 *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_nfsstat3:");
+
+  if (!xdr_enum(xdrs, (enum_t *)objp))
+    return (FALSE);
+  return (TRUE);
+}
 
 bool_t
 xdr_am_diropargs3(XDR *xdrs, am_diropargs3 *objp)
@@ -978,7 +1035,6 @@ xdr_am_diropargs3(XDR *xdrs, am_diropargs3 *objp)
   return (TRUE);
 }
 
-
 bool_t
 xdr_am_filename3(XDR *xdrs, am_filename3 *objp)
 {
@@ -990,6 +1046,315 @@ xdr_am_filename3(XDR *xdrs, am_filename3 *objp)
   return (TRUE);
 }
 
+bool_t
+xdr_am_ftype3(XDR *xdrs, am_ftype3 *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_ftype3:");
+
+  if (!xdr_enum(xdrs, (enum_t *) objp))
+    return FALSE;
+  return TRUE;
+}
+
+bool_t
+xdr_am_mode3(XDR *xdrs, am_mode3 *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_mode3:");
+
+  if (!xdr_u_int(xdrs, objp))
+    return FALSE;
+  return TRUE;
+}
+
+bool_t
+xdr_am_uid3(XDR *xdrs, am_uid3 *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_uid3:");
+
+  if (!xdr_u_int(xdrs, objp))
+    return FALSE;
+  return TRUE;
+}
+
+bool_t
+xdr_am_gid3(XDR *xdrs, am_gid3 *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_gid3:");
+
+  if (!xdr_u_int(xdrs, objp))
+    return FALSE;
+  return TRUE;
+}
+
+bool_t
+xdr_am_size3(XDR *xdrs, am_size3 *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_size3:");
+
+  if (!xdr_uint64(xdrs, objp))
+    return FALSE;
+  return TRUE;
+}
+
+bool_t
+xdr_am_fileid3(XDR *xdrs, am_fileid3 *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_fileid3:");
+
+  if (!xdr_uint64(xdrs, objp))
+    return FALSE;
+  return TRUE;
+}
+
+bool_t
+xdr_am_specdata3(XDR *xdrs, am_specdata3 *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_specdata3:");
+
+  if (!xdr_u_int(xdrs, &objp->specdata1))
+    return FALSE;
+  if (!xdr_u_int(xdrs, &objp->specdata2))
+    return FALSE;
+  return TRUE;
+}
+
+bool_t
+xdr_am_nfstime3(XDR *xdrs, am_nfstime3 *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_nfstime3:");
+
+  if (!xdr_u_int(xdrs, &objp->seconds))
+    return FALSE;
+  if (!xdr_u_int(xdrs, &objp->nseconds))
+    return FALSE;
+  return TRUE;
+}
+
+bool_t
+xdr_am_fattr3(XDR *xdrs, am_fattr3 *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_fattr3:");
+
+  if (!xdr_am_ftype3(xdrs, &objp->type))
+    return FALSE;
+  if (!xdr_am_mode3(xdrs, &objp->mode))
+    return FALSE;
+  if (!xdr_u_int(xdrs, &objp->nlink))
+    return FALSE;
+  if (!xdr_am_uid3(xdrs, &objp->uid))
+    return FALSE;
+  if (!xdr_am_gid3(xdrs, &objp->gid))
+    return FALSE;
+  if (!xdr_am_size3(xdrs, &objp->size))
+    return FALSE;
+  if (!xdr_am_size3(xdrs, &objp->used))
+    return FALSE;
+  if (!xdr_am_specdata3(xdrs, &objp->rdev))
+    return FALSE;
+  if (!xdr_uint64(xdrs, &objp->fsid))
+    return FALSE;
+  if (!xdr_am_fileid3(xdrs, &objp->fileid))
+    return FALSE;
+  if (!xdr_am_nfstime3(xdrs, &objp->atime))
+    return FALSE;
+  if (!xdr_am_nfstime3(xdrs, &objp->mtime))
+    return FALSE;
+  if (!xdr_am_nfstime3(xdrs, &objp->ctime))
+    return FALSE;
+  return TRUE;
+}
+
+bool_t
+xdr_am_post_op_attr(XDR *xdrs, am_post_op_attr *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_post_op_attr:");
+
+  if (!xdr_bool(xdrs, &objp->attributes_follow))
+    return FALSE;
+  switch (objp->attributes_follow) {
+  case TRUE:
+    if (!xdr_am_fattr3(xdrs, &objp->am_post_op_attr_u.attributes))
+      return FALSE;
+    break;
+  case FALSE:
+    break;
+  default:
+    return FALSE;
+  }
+  return TRUE;
+}
+
+bool_t
+xdr_am_stable_how(XDR *xdrs, am_stable_how *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_stable_how:");
+
+  if (!xdr_enum(xdrs, (enum_t *) objp))
+    return FALSE;
+  return TRUE;
+}
+
+bool_t
+xdr_am_offset3(XDR *xdrs, am_offset3 *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_offset3:");
+
+  if (!xdr_uint64(xdrs, objp))
+    return FALSE;
+  return TRUE;
+}
+
+bool_t
+xdr_am_count3(XDR *xdrs, am_count3 *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_count3:");
+
+  if (!xdr_u_int(xdrs, objp))
+    return FALSE;
+  return TRUE;
+}
+
+bool_t
+xdr_am_wcc_attr(XDR *xdrs, am_wcc_attr *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_wcc_attr:");
+
+  if (!xdr_am_size3(xdrs, &objp->size))
+    return FALSE;
+  if (!xdr_am_nfstime3(xdrs, &objp->mtime))
+    return FALSE;
+  if (!xdr_am_nfstime3(xdrs, &objp->ctime))
+    return FALSE;
+  return TRUE;
+}
+
+bool_t
+xdr_am_pre_op_attr(XDR *xdrs, am_pre_op_attr *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, ":xdr_am_pre_op_attr");
+
+  if (!xdr_bool(xdrs, &objp->attributes_follow))
+    return FALSE;
+  switch (objp->attributes_follow) {
+  case TRUE:
+    if (!xdr_am_wcc_attr(xdrs, &objp->am_pre_op_attr_u.attributes))
+      return FALSE;
+    break;
+  case FALSE:
+    break;
+  default:
+    return FALSE;
+  }
+  return TRUE;
+}
+
+bool_t
+xdr_am_wcc_data(XDR *xdrs, am_wcc_data *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_wcc_data:");
+
+  if (!xdr_am_pre_op_attr(xdrs, &objp->before))
+    return FALSE;
+  if (!xdr_am_post_op_attr(xdrs, &objp->after))
+    return FALSE;
+  return TRUE;
+}
+
+bool_t
+xdr_am_WRITE3args(XDR *xdrs, am_WRITE3args *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_WRITE3args:");
+
+  if (!xdr_am_nfs_fh3(xdrs, &objp->file))
+    return FALSE;
+  if (!xdr_am_offset3(xdrs, &objp->offset))
+    return FALSE;
+  if (!xdr_am_count3(xdrs, &objp->count))
+    return FALSE;
+  if (!xdr_am_stable_how(xdrs, &objp->stable))
+    return FALSE;
+  if (!xdr_bytes(xdrs, (char **)&objp->data.data_val,
+                (u_int *) &objp->data.data_len, ~0))
+    return FALSE;
+  return TRUE;
+}
+
+bool_t
+xdr_am_writeverf3(XDR *xdrs, am_writeverf3 objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_writeverf3:");
+
+  if (!xdr_opaque(xdrs, objp, AM_NFS3_WRITEVERFSIZE))
+    return FALSE;
+  return TRUE;
+}
+
+bool_t
+xdr_am_WRITE3resok(XDR *xdrs, am_WRITE3resok *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_WRITE3resok:");
+
+  if (!xdr_am_wcc_data(xdrs, &objp->file_wcc))
+    return FALSE;
+  if (!xdr_am_count3(xdrs, &objp->count))
+    return FALSE;
+  if (!xdr_am_stable_how(xdrs, &objp->committed))
+    return FALSE;
+  if (!xdr_am_writeverf3(xdrs, objp->verf))
+    return FALSE;
+  return TRUE;
+}
+
+bool_t
+xdr_am_WRITE3resfail(XDR *xdrs, am_WRITE3resfail *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_WRITE3resfail:");
+
+  if (!xdr_am_wcc_data(xdrs, &objp->file_wcc))
+    return FALSE;
+  return TRUE;
+}
+
+bool_t
+xdr_am_WRITE3res(XDR *xdrs, am_WRITE3res *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_WRITE3res:");
+
+  if (!xdr_am_nfsstat3(xdrs, &objp->status))
+    return FALSE;
+  switch (objp->status) {
+  case AM_NFS3_OK:
+    if (!xdr_am_WRITE3resok(xdrs, &objp->res_u.ok))
+      return FALSE;
+    break;
+  default:
+    if (!xdr_am_WRITE3resfail(xdrs, &objp->res_u.fail))
+      return FALSE;
+    break;
+  }
+  return TRUE;
+}
 
 bool_t
 xdr_am_LOOKUP3args(XDR *xdrs, am_LOOKUP3args *objp)
@@ -1002,7 +1367,6 @@ xdr_am_LOOKUP3args(XDR *xdrs, am_LOOKUP3args *objp)
   return (TRUE);
 }
 
-
 bool_t
 xdr_am_LOOKUP3res(XDR *xdrs, am_LOOKUP3res *objp)
 {
@@ -1024,25 +1388,17 @@ xdr_am_LOOKUP3res(XDR *xdrs, am_LOOKUP3res *objp)
   return (TRUE);
 }
 
-
 bool_t
 xdr_am_LOOKUP3resfail(XDR *xdrs, am_LOOKUP3resfail *objp)
 {
   if (amuDebug(D_XDRTRACE))
     plog(XLOG_DEBUG, "xdr_am_LOOKUP3resfail:");
 
-  /*
-   * Don't xdr post_op_attr: amd doesn't need them, but they require many
-   * additional xdr functions.
-   */
-#if 0
-  if (!xdr_post_op_attr(xdrs, &objp->dir_attributes))
+  if (!xdr_am_post_op_attr(xdrs, &objp->dir_attributes))
     return (FALSE);
-#endif /* 0 */
   return (TRUE);
 }
 
-
 bool_t
 xdr_am_LOOKUP3resok(XDR *xdrs, am_LOOKUP3resok *objp)
 {
@@ -1051,44 +1407,1656 @@ xdr_am_LOOKUP3resok(XDR *xdrs, am_LOOKUP3resok *objp)
 
   if (!xdr_am_nfs_fh3(xdrs, &objp->object))
     return (FALSE);
-  /*
-   * Don't xdr post_op_attr: amd doesn't need them, but they require many
-   * additional xdr functions.
-   */
-#if 0
-  if (!xdr_post_op_attr(xdrs, &objp->obj_attributes))
+  if (!xdr_am_post_op_attr(xdrs, &objp->obj_attributes))
     return (FALSE);
-  if (!xdr_post_op_attr(xdrs, &objp->dir_attributes))
+  if (!xdr_am_post_op_attr(xdrs, &objp->dir_attributes))
     return (FALSE);
-#endif /* 0 */
   return (TRUE);
 }
 
+bool_t
+xdr_am_COMMIT3args(XDR *xdrs, am_COMMIT3args *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_COMMIT3args:");
+
+  if (!xdr_am_nfs_fh3(xdrs, &objp->file))
+    return FALSE;
+  if (!xdr_am_offset3(xdrs, &objp->offset))
+    return FALSE;
+  if (!xdr_am_count3(xdrs, &objp->count))
+    return FALSE;
+  return TRUE;
+}
 
 bool_t
-xdr_am_nfs_fh3(XDR *xdrs, am_nfs_fh3 *objp)
+xdr_am_COMMIT3resok(XDR *xdrs, am_COMMIT3resok *objp)
 {
   if (amuDebug(D_XDRTRACE))
-    plog(XLOG_DEBUG, "xdr_am_nfs_fh3:");
+    plog(XLOG_DEBUG, "xdr_am_COMMIT3resok:");
 
-  if (!xdr_u_int(xdrs, &objp->am_fh3_length))
-    return (FALSE);
-  if (objp->am_fh3_length > AM_FHSIZE3)
-    return (FALSE);
-  if (!xdr_opaque(xdrs, objp->am_fh3_data, objp->am_fh3_length))
-    return (FALSE);
-  return (TRUE);
+  if (!xdr_am_wcc_data(xdrs, &objp->file_wcc))
+    return FALSE;
+  if (!xdr_am_writeverf3(xdrs, objp->verf))
+    return FALSE;
+  return TRUE;
 }
 
+bool_t
+xdr_am_COMMIT3resfail(XDR *xdrs, am_COMMIT3resfail *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_COMMIT3resfail:");
+
+  if (!xdr_am_wcc_data(xdrs, &objp->file_wcc))
+    return FALSE;
+  return TRUE;
+}
 
 bool_t
-xdr_am_nfsstat3(XDR *xdrs, am_nfsstat3 *objp)
+xdr_am_COMMIT3res(XDR *xdrs, am_COMMIT3res *objp)
 {
   if (amuDebug(D_XDRTRACE))
-    plog(XLOG_DEBUG, "xdr_am_nfsstat3:");
+    plog(XLOG_DEBUG, "xdr_am_COMMIT3res:");
 
-  if (!xdr_enum(xdrs, (enum_t *)objp))
-    return (FALSE);
-  return (TRUE);
+  if (!xdr_am_nfsstat3(xdrs, &objp->status))
+    return FALSE;
+  switch (objp->status) {
+  case AM_NFS3_OK:
+    if (!xdr_am_COMMIT3resok(xdrs, &objp->res_u.ok))
+      return FALSE;
+    break;
+  default:
+    if (!xdr_am_COMMIT3resfail(xdrs, &objp->res_u.fail))
+      return FALSE;
+    break;
+  }
+  return TRUE;
+}
+
+bool_t
+xdr_am_ACCESS3args(XDR *xdrs, am_ACCESS3args *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_ACCESS3args:");
+
+  if (!xdr_am_nfs_fh3(xdrs, &objp->object))
+    return FALSE;
+  if (!xdr_u_int(xdrs, &objp->access))
+    return FALSE;
+  return TRUE;
+}
+
+bool_t
+xdr_am_ACCESS3resok(XDR *xdrs, am_ACCESS3resok *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_ACCESS3resok:");
+
+  if (!xdr_am_post_op_attr(xdrs, &objp->obj_attributes))
+    return FALSE;
+  if (!xdr_u_int(xdrs, &objp->access))
+    return FALSE;
+  return TRUE;
+}
+
+bool_t
+xdr_am_ACCESS3resfail(XDR *xdrs, am_ACCESS3resfail *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_ACCESS3resfail:");
+
+  if (!xdr_am_post_op_attr(xdrs, &objp->obj_attributes))
+    return FALSE;
+  return TRUE;
+}
+
+bool_t
+xdr_am_ACCESS3res(XDR *xdrs, am_ACCESS3res *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_ACCESS3res:");
+
+  if (!xdr_am_nfsstat3(xdrs, &objp->status))
+    return FALSE;
+  switch (objp->status) {
+  case AM_NFS3_OK:
+    if (!xdr_am_ACCESS3resok(xdrs, &objp->res_u.ok))
+      return FALSE;
+    break;
+  default:
+    if (!xdr_am_ACCESS3resfail(xdrs, &objp->res_u.fail))
+      return FALSE;
+    break;
+  }
+  return TRUE;
+}
+
+bool_t
+xdr_am_GETATTR3args(XDR *xdrs, am_GETATTR3args *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_GETATTR3args:");
+
+  if (!xdr_am_nfs_fh3(xdrs, &objp->object))
+    return FALSE;
+  return TRUE;
+}
+
+bool_t
+xdr_am_GETATTR3resok(XDR *xdrs, am_GETATTR3resok *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_GETATTR3resok:");
+
+  if (!xdr_am_fattr3(xdrs, &objp->obj_attributes))
+    return FALSE;
+  return TRUE;
+}
+
+bool_t
+xdr_am_GETATTR3res(XDR *xdrs, am_GETATTR3res *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_GETATTR3res:");
+
+  if (!xdr_am_nfsstat3(xdrs, &objp->status))
+    return FALSE;
+  switch (objp->status) {
+  case AM_NFS3_OK:
+    if (!xdr_am_GETATTR3resok(xdrs, &objp->res_u.ok))
+      return FALSE;
+    break;
+  default:
+    break;
+  }
+  return TRUE;
+}
+
+bool_t
+xdr_am_time_how(XDR *xdrs, am_time_how *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_time_how:");
+
+  if (!xdr_enum(xdrs, (enum_t *) objp))
+    return FALSE;
+  return TRUE;
+}
+
+bool_t
+xdr_am_set_mode3(XDR *xdrs, am_set_mode3 *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_set_mode3:");
+
+  if (!xdr_bool(xdrs, &objp->set_it))
+    return FALSE;
+  switch (objp->set_it) {
+  case TRUE:
+    if (!xdr_am_mode3(xdrs, &objp->am_set_mode3_u.mode))
+      return FALSE;
+    break;
+  default:
+    break;
+  }
+  return TRUE;
+}
+
+bool_t
+xdr_am_set_uid3(XDR *xdrs, am_set_uid3 *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_set_uid3:");
+
+  if (!xdr_bool(xdrs, &objp->set_it))
+    return FALSE;
+  switch (objp->set_it) {
+  case TRUE:
+    if (!xdr_am_uid3(xdrs, &objp->am_set_uid3_u.uid))
+      return FALSE;
+    break;
+  default:
+    break;
+  }
+  return TRUE;
+}
+
+bool_t
+xdr_am_set_gid3(XDR *xdrs, am_set_gid3 *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_set_gid3:");
+
+  if (!xdr_bool(xdrs, &objp->set_it))
+    return FALSE;
+  switch (objp->set_it) {
+  case TRUE:
+    if (!xdr_am_gid3(xdrs, &objp->am_set_gid3_u.gid))
+      return FALSE;
+    break;
+  default:
+    break;
+  }
+  return TRUE;
+}
+
+bool_t
+xdr_am_set_size3(XDR *xdrs, am_set_size3 *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_set_size3:");
+
+  if (!xdr_bool(xdrs, &objp->set_it))
+    return FALSE;
+  switch (objp->set_it) {
+  case TRUE:
+    if (!xdr_am_size3(xdrs, &objp->am_set_size3_u.size))
+      return FALSE;
+    break;
+  default:
+    break;
+  }
+  return TRUE;
+}
+
+bool_t
+xdr_am_set_atime(XDR *xdrs, am_set_atime *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_set_atime:");
+
+  if (!xdr_am_time_how(xdrs, &objp->set_it))
+    return FALSE;
+  switch (objp->set_it) {
+  case AM_SET_TO_CLIENT_TIME:
+    if (!xdr_am_nfstime3(xdrs, &objp->am_set_atime_u.atime))
+      return FALSE;
+    break;
+  default:
+    break;
+  }
+  return TRUE;
+}
+
+bool_t
+xdr_am_set_mtime(XDR *xdrs, am_set_mtime *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_set_mtime:");
+
+  if (!xdr_am_time_how(xdrs, &objp->set_it))
+    return FALSE;
+  switch (objp->set_it) {
+  case AM_SET_TO_CLIENT_TIME:
+    if (!xdr_am_nfstime3(xdrs, &objp->am_set_mtime_u.mtime))
+      return FALSE;
+    break;
+  default:
+    break;
+  }
+  return TRUE;
+}
+
+bool_t
+xdr_am_sattr3(XDR *xdrs, am_sattr3 *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_sattr3:");
+
+  if (!xdr_am_set_mode3(xdrs, &objp->mode))
+    return FALSE;
+  if (!xdr_am_set_uid3(xdrs, &objp->uid))
+    return FALSE;
+  if (!xdr_am_set_gid3(xdrs, &objp->gid))
+    return FALSE;
+  if (!xdr_am_set_size3(xdrs, &objp->size))
+     return FALSE;
+  if (!xdr_am_set_atime(xdrs, &objp->atime))
+    return FALSE;
+  if (!xdr_am_set_mtime(xdrs, &objp->mtime))
+    return FALSE;
+  return TRUE;
+}
+
+bool_t
+xdr_am_createmode3(XDR *xdrs, am_createmode3 *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_createmode3:");
+
+  if (!xdr_enum(xdrs, (enum_t *) objp))
+    return FALSE;
+  return TRUE;
+}
+
+bool_t
+xdr_am_createverf3(XDR *xdrs, am_createverf3 objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_createverf3:");
+
+  if (!xdr_opaque(xdrs, objp, AM_NFS3_CREATEVERFSIZE))
+    return FALSE;
+  return TRUE;
+}
+
+bool_t
+xdr_am_createhow3(XDR *xdrs, am_createhow3 *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_createhow3:");
+
+   if (!xdr_am_createmode3(xdrs, &objp->mode))
+     return FALSE;
+  switch (objp->mode) {
+  case AM_UNCHECKED:
+    if (!xdr_am_sattr3(xdrs, &objp->am_createhow3_u.obj_attributes))
+      return FALSE;
+    break;
+  case AM_GUARDED:
+    if (!xdr_am_sattr3(xdrs, &objp->am_createhow3_u.g_obj_attributes))
+      return FALSE;
+    break;
+  case AM_EXCLUSIVE:
+    if (!xdr_am_createverf3(xdrs, objp->am_createhow3_u.verf))
+      return FALSE;
+    break;
+  default:
+    return FALSE;
+  }
+  return TRUE;
+}
+
+bool_t
+xdr_am_CREATE3args(XDR *xdrs, am_CREATE3args *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_CREATE3args:");
+
+  if (!xdr_am_diropargs3(xdrs, &objp->where))
+    return FALSE;
+  if (!xdr_am_createhow3(xdrs, &objp->how))
+    return FALSE;
+  return TRUE;
+}
+
+bool_t
+xdr_am_post_op_fh3(XDR *xdrs, am_post_op_fh3 *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_post_op_fh3:");
+
+  if (!xdr_bool(xdrs, &objp->handle_follows))
+    return FALSE;
+  switch (objp->handle_follows) {
+  case TRUE:
+    if (!xdr_am_nfs_fh3(xdrs, &objp->am_post_op_fh3_u.handle))
+      return FALSE;
+    break;
+  case FALSE:
+    break;
+  default:
+    return FALSE;
+  }
+  return TRUE;
+}
+
+bool_t
+xdr_am_CREATE3resok(XDR *xdrs, am_CREATE3resok *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_CREATE3resok:");
+
+  if (!xdr_am_post_op_fh3(xdrs, &objp->obj))
+    return FALSE;
+  if (!xdr_am_post_op_attr(xdrs, &objp->obj_attributes))
+    return FALSE;
+  if (!xdr_am_wcc_data(xdrs, &objp->dir_wcc))
+    return FALSE;
+  return TRUE;
+}
+
+bool_t
+xdr_am_CREATE3resfail(XDR *xdrs, am_CREATE3resfail *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_CREATE3resfail:");
+
+  if (!xdr_am_wcc_data(xdrs, &objp->dir_wcc))
+    return FALSE;
+  return TRUE;
+}
+
+bool_t
+xdr_am_CREATE3res(XDR *xdrs, am_CREATE3res *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_CREATE3res:");
+
+  if (!xdr_am_nfsstat3(xdrs, &objp->status))
+    return FALSE;
+  switch (objp->status) {
+  case AM_NFS3_OK:
+    if (!xdr_am_CREATE3resok(xdrs, &objp->res_u.ok))
+      return FALSE;
+    break;
+  default:
+    if (!xdr_am_CREATE3resfail(xdrs, &objp->res_u.fail))
+      return FALSE;
+    break;
+  }
+  return TRUE;
+}
+
+bool_t
+xdr_am_REMOVE3args(XDR *xdrs, am_REMOVE3args *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_REMOVE3args:");
+
+  if (!xdr_am_diropargs3(xdrs, &objp->object))
+    return FALSE;
+  return TRUE;
+}
+
+bool_t
+xdr_am_REMOVE3resok(XDR *xdrs, am_REMOVE3resok *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_REMOVE3resok:");
+
+  if (!xdr_am_wcc_data(xdrs, &objp->dir_wcc))
+    return FALSE;
+  return TRUE;
+}
+
+bool_t
+xdr_am_REMOVE3resfail(XDR *xdrs, am_REMOVE3resfail *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_REMOVE3resfail:");
+
+  if (!xdr_am_wcc_data(xdrs, &objp->dir_wcc))
+    return FALSE;
+  return TRUE;
+}
+
+bool_t
+xdr_am_REMOVE3res(XDR *xdrs, am_REMOVE3res *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_REMOVE3res:");
+
+  if (!xdr_am_nfsstat3(xdrs, &objp->status))
+    return FALSE;
+  switch (objp->status) {
+  case AM_NFS3_OK:
+    if (!xdr_am_REMOVE3resok(xdrs, &objp->res_u.ok))
+      return FALSE;
+    break;
+  default:
+    if (!xdr_am_REMOVE3resfail(xdrs, &objp->res_u.fail))
+      return FALSE;
+    break;
+  }
+  return TRUE;
+}
+
+bool_t
+xdr_am_READ3args(XDR *xdrs, am_READ3args *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_READ3args:");
+
+  if (!xdr_am_nfs_fh3(xdrs, &objp->file))
+    return FALSE;
+  if (!xdr_am_offset3(xdrs, &objp->offset))
+    return FALSE;
+  if (!xdr_am_count3(xdrs, &objp->count))
+    return FALSE;
+  return TRUE;
+}
+
+bool_t
+xdr_am_READ3resok(XDR *xdrs, am_READ3resok *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_READ3resok:");
+
+  if (!xdr_am_post_op_attr(xdrs, &objp->file_attributes))
+    return FALSE;
+  if (!xdr_am_count3(xdrs, &objp->count))
+    return FALSE;
+  if (!xdr_bool(xdrs, &objp->eof))
+    return FALSE;
+  if (!xdr_bytes(xdrs, (char **)&objp->data.data_val, (u_int *) &objp->data.data_len, ~0))
+    return FALSE;
+  return TRUE;
+}
+
+bool_t
+xdr_am_READ3resfail(XDR *xdrs, am_READ3resfail *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_READ3resfail:");
+
+  if (!xdr_am_post_op_attr(xdrs, &objp->file_attributes))
+    return FALSE;
+  return TRUE;
+}
+
+bool_t
+xdr_am_READ3res(XDR *xdrs, am_READ3res *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_READ3res:");
+
+  if (!xdr_am_nfsstat3(xdrs, &objp->status))
+    return FALSE;
+  switch (objp->status) {
+  case AM_NFS3_OK:
+    if (!xdr_am_READ3resok(xdrs, &objp->res_u.ok))
+      return FALSE;
+    break;
+  default:
+    if (!xdr_am_READ3resfail(xdrs, &objp->res_u.fail))
+      return FALSE;
+    break;
+  }
+  return TRUE;
+}
+
+bool_t
+xdr_am_FSINFO3args(XDR *xdrs, am_FSINFO3args *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_FSINFO3args:");
+
+  if (!xdr_am_nfs_fh3(xdrs, &objp->fsroot))
+    return FALSE;
+  return TRUE;
+}
+
+bool_t
+xdr_am_FSINFO3resok(XDR *xdrs, am_FSINFO3resok *objp)
+{
+  register int32_t *buf;
+
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_FSINFO3resok:");
+
+  if (xdrs->x_op == XDR_ENCODE) {
+    if (!xdr_am_post_op_attr(xdrs, &objp->obj_attributes))
+      return FALSE;
+    buf = XDR_INLINE(xdrs, 7 * BYTES_PER_XDR_UNIT);
+    if (buf == NULL) {
+      if (!xdr_u_int(xdrs, &objp->rtmax))
+        return FALSE;
+      if (!xdr_u_int(xdrs, &objp->rtpref))
+        return FALSE;
+      if (!xdr_u_int(xdrs, &objp->rtmult))
+        return FALSE;
+      if (!xdr_u_int(xdrs, &objp->wtmax))
+        return FALSE;
+      if (!xdr_u_int(xdrs, &objp->wtpref))
+        return FALSE;
+      if (!xdr_u_int(xdrs, &objp->wtmult))
+        return FALSE;
+      if (!xdr_u_int(xdrs, &objp->dtpref))
+        return FALSE;
+    } else {
+      IXDR_PUT_U_LONG(buf, objp->rtmax);
+      IXDR_PUT_U_LONG(buf, objp->rtpref);
+      IXDR_PUT_U_LONG(buf, objp->rtmult);
+      IXDR_PUT_U_LONG(buf, objp->wtmax);
+      IXDR_PUT_U_LONG(buf, objp->wtpref);
+      IXDR_PUT_U_LONG(buf, objp->wtmult);
+      IXDR_PUT_U_LONG(buf, objp->dtpref);
+    }
+    if (!xdr_am_size3(xdrs, &objp->maxfilesize))
+      return FALSE;
+    if (!xdr_am_nfstime3(xdrs, &objp->time_delta))
+      return FALSE;
+    if (!xdr_u_int(xdrs, &objp->properties))
+      return FALSE;
+    return TRUE;
+  } else if (xdrs->x_op == XDR_DECODE) {
+    if (!xdr_am_post_op_attr(xdrs, &objp->obj_attributes))
+      return FALSE;
+    buf = XDR_INLINE(xdrs, 7 * BYTES_PER_XDR_UNIT);
+    if (buf == NULL) {
+      if (!xdr_u_int (xdrs, &objp->rtmax))
+        return FALSE;
+      if (!xdr_u_int (xdrs, &objp->rtpref))
+        return FALSE;
+      if (!xdr_u_int (xdrs, &objp->rtmult))
+        return FALSE;
+      if (!xdr_u_int (xdrs, &objp->wtmax))
+        return FALSE;
+      if (!xdr_u_int(xdrs, &objp->wtpref))
+        return FALSE;
+      if (!xdr_u_int(xdrs, &objp->wtmult))
+        return FALSE;
+      if (!xdr_u_int(xdrs, &objp->dtpref))
+        return FALSE;
+    } else {
+      objp->rtmax = IXDR_GET_U_LONG(buf);
+      objp->rtpref = IXDR_GET_U_LONG(buf);
+      objp->rtmult = IXDR_GET_U_LONG(buf);
+      objp->wtmax = IXDR_GET_U_LONG(buf);
+      objp->wtpref = IXDR_GET_U_LONG(buf);
+      objp->wtmult = IXDR_GET_U_LONG(buf);
+      objp->dtpref = IXDR_GET_U_LONG(buf);
+    }
+    if (!xdr_am_size3(xdrs, &objp->maxfilesize))
+      return FALSE;
+    if (!xdr_am_nfstime3(xdrs, &objp->time_delta))
+      return FALSE;
+    if (!xdr_u_int(xdrs, &objp->properties))
+      return FALSE;
+    return TRUE;
+  }
+
+  if (!xdr_am_post_op_attr(xdrs, &objp->obj_attributes))
+    return FALSE;
+  if (!xdr_u_int(xdrs, &objp->rtmax))
+    return FALSE;
+  if (!xdr_u_int(xdrs, &objp->rtpref))
+    return FALSE;
+  if (!xdr_u_int(xdrs, &objp->rtmult))
+    return FALSE;
+  if (!xdr_u_int(xdrs, &objp->wtmax))
+    return FALSE;
+  if (!xdr_u_int(xdrs, &objp->wtpref))
+    return FALSE;
+  if (!xdr_u_int(xdrs, &objp->wtmult))
+    return FALSE;
+  if (!xdr_u_int(xdrs, &objp->dtpref))
+   return FALSE;
+  if (!xdr_am_size3(xdrs, &objp->maxfilesize))
+    return FALSE;
+  if (!xdr_am_nfstime3(xdrs, &objp->time_delta))
+    return FALSE;
+  if (!xdr_u_int(xdrs, &objp->properties))
+    return FALSE;
+  return TRUE;
+}
+
+bool_t
+xdr_am_FSINFO3resfail(XDR *xdrs, am_FSINFO3resfail *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_FSINFO3resfail:");
+
+  if (!xdr_am_post_op_attr(xdrs, &objp->obj_attributes))
+    return FALSE;
+  return TRUE;
+}
+
+bool_t
+xdr_am_FSINFO3res(XDR *xdrs, am_FSINFO3res *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_FSINFO3res:");
+
+  if (!xdr_am_nfsstat3(xdrs, &objp->status))
+    return FALSE;
+  switch (objp->status) {
+  case AM_NFS3_OK:
+    if (!xdr_am_FSINFO3resok(xdrs, &objp->res_u.ok))
+      return FALSE;
+    break;
+  default:
+    if (!xdr_am_FSINFO3resfail(xdrs, &objp->res_u.fail))
+      return FALSE;
+    break;
+  }
+  return TRUE;
+}
+
+bool_t
+xdr_am_FSSTAT3args(XDR *xdrs, am_FSSTAT3args *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_FSSTAT3args:");
+
+  if (!xdr_am_nfs_fh3(xdrs, &objp->fsroot))
+    return FALSE;
+  return TRUE;
+}
+
+bool_t
+xdr_am_FSSTAT3resok(XDR *xdrs, am_FSSTAT3resok *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_FSSTAT3resok:");
+
+  if (!xdr_am_post_op_attr(xdrs, &objp->obj_attributes))
+    return FALSE;
+  if (!xdr_am_size3(xdrs, &objp->tbytes))
+    return FALSE;
+  if (!xdr_am_size3(xdrs, &objp->fbytes))
+    return FALSE;
+  if (!xdr_am_size3(xdrs, &objp->abytes))
+    return FALSE;
+  if (!xdr_am_size3(xdrs, &objp->tfiles))
+    return FALSE;
+  if (!xdr_am_size3(xdrs, &objp->ffiles))
+    return FALSE;
+  if (!xdr_am_size3(xdrs, &objp->afiles))
+    return FALSE;
+  if (!xdr_u_int(xdrs, &objp->invarsec))
+    return FALSE;
+  return TRUE;
+}
+
+bool_t
+xdr_am_FSSTAT3resfail(XDR *xdrs, am_FSSTAT3resfail *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_FSSTAT3resfail:");
+
+  if (!xdr_am_post_op_attr(xdrs, &objp->obj_attributes))
+    return FALSE;
+  return TRUE;
+}
+
+bool_t
+xdr_am_FSSTAT3res(XDR *xdrs, am_FSSTAT3res *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_FSSTAT3res:");
+
+  if (!xdr_am_nfsstat3(xdrs, &objp->status))
+    return FALSE;
+  switch (objp->status) {
+  case AM_NFS3_OK:
+    if (!xdr_am_FSSTAT3resok(xdrs, &objp->res_u.ok))
+      return FALSE;
+    break;
+  default:
+    if (!xdr_am_FSSTAT3resfail(xdrs, &objp->res_u.fail))
+      return FALSE;
+    break;
+  }
+  return TRUE;
+}
+
+bool_t
+xdr_am_PATHCONF3args(XDR *xdrs, am_PATHCONF3args *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_PATHCONF3args:");
+
+  if (!xdr_am_nfs_fh3(xdrs, &objp->object))
+    return FALSE;
+  return TRUE;
+}
+
+bool_t
+xdr_am_PATHCONF3resok(XDR *xdrs, am_PATHCONF3resok *objp)
+{
+  register int32_t *buf;
+
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_PATHCONF3resok:");
+
+  if (xdrs->x_op == XDR_ENCODE) {
+    if (!xdr_am_post_op_attr(xdrs, &objp->obj_attributes))
+      return FALSE;
+    buf = XDR_INLINE(xdrs, 6 * BYTES_PER_XDR_UNIT);
+    if (buf == NULL) {
+      if (!xdr_u_int(xdrs, &objp->linkmax))
+        return FALSE;
+      if (!xdr_u_int(xdrs, &objp->name_max))
+        return FALSE;
+      if (!xdr_bool(xdrs, &objp->no_trunc))
+        return FALSE;
+      if (!xdr_bool(xdrs, &objp->chown_restricted))
+        return FALSE;
+      if (!xdr_bool(xdrs, &objp->case_insensitive))
+        return FALSE;
+      if (!xdr_bool(xdrs, &objp->case_preserving))
+        return FALSE;
+    } else {
+      IXDR_PUT_U_LONG(buf, objp->linkmax);
+      IXDR_PUT_U_LONG(buf, objp->name_max);
+      IXDR_PUT_BOOL(buf, objp->no_trunc);
+      IXDR_PUT_BOOL(buf, objp->chown_restricted);
+      IXDR_PUT_BOOL(buf, objp->case_insensitive);
+      IXDR_PUT_BOOL(buf, objp->case_preserving);
+    }
+    return TRUE;
+  } else if (xdrs->x_op == XDR_DECODE) {
+    if (!xdr_am_post_op_attr(xdrs, &objp->obj_attributes))
+      return FALSE;
+    buf = XDR_INLINE(xdrs, 6 * BYTES_PER_XDR_UNIT);
+    if (buf == NULL) {
+      if (!xdr_u_int(xdrs, &objp->linkmax))
+        return FALSE;
+      if (!xdr_u_int(xdrs, &objp->name_max))
+        return FALSE;
+      if (!xdr_bool(xdrs, &objp->no_trunc))
+        return FALSE;
+      if (!xdr_bool(xdrs, &objp->chown_restricted))
+        return FALSE;
+      if (!xdr_bool(xdrs, &objp->case_insensitive))
+        return FALSE;
+      if (!xdr_bool(xdrs, &objp->case_preserving))
+        return FALSE;
+    } else {
+      objp->linkmax = IXDR_GET_U_LONG(buf);
+      objp->name_max = IXDR_GET_U_LONG(buf);
+      objp->no_trunc = IXDR_GET_BOOL(buf);
+      objp->chown_restricted = IXDR_GET_BOOL(buf);
+      objp->case_insensitive = IXDR_GET_BOOL(buf);
+      objp->case_preserving = IXDR_GET_BOOL(buf);
+    }
+    return TRUE;
+  }
+
+  if (!xdr_am_post_op_attr(xdrs, &objp->obj_attributes))
+    return FALSE;
+  if (!xdr_u_int(xdrs, &objp->linkmax))
+    return FALSE;
+  if (!xdr_u_int(xdrs, &objp->name_max))
+    return FALSE;
+  if (!xdr_bool(xdrs, &objp->no_trunc))
+    return FALSE;
+  if (!xdr_bool(xdrs, &objp->chown_restricted))
+    return FALSE;
+  if (!xdr_bool(xdrs, &objp->case_insensitive))
+    return FALSE;
+  if (!xdr_bool(xdrs, &objp->case_preserving))
+    return FALSE;
+  return TRUE;
+}
+
+bool_t
+xdr_am_PATHCONF3resfail(XDR *xdrs, am_PATHCONF3resfail *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_PATHCONF3resfail:");
+
+  if (!xdr_am_post_op_attr(xdrs, &objp->obj_attributes))
+    return FALSE;
+  return TRUE;
+}
+
+bool_t
+xdr_am_PATHCONF3res(XDR *xdrs, am_PATHCONF3res *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_PATHCONF3res:");
+
+  if (!xdr_am_nfsstat3(xdrs, &objp->status))
+    return FALSE;
+  switch (objp->status) {
+  case AM_NFS3_OK:
+    if (!xdr_am_PATHCONF3resok(xdrs, &objp->res_u.ok))
+      return FALSE;
+    break;
+  default:
+    if (!xdr_am_PATHCONF3resfail(xdrs, &objp->res_u.fail))
+      return FALSE;
+    break;
+  }
+  return TRUE;
+}
+
+bool_t
+xdr_am_nfspath3(XDR *xdrs, am_nfspath3 *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_nfspath3:");
+
+  if (!xdr_string(xdrs, objp, ~0))
+    return FALSE;
+  return TRUE;
+}
+
+bool_t
+xdr_am_symlinkdata3(XDR *xdrs, am_symlinkdata3 *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_symlinkdata3:");
+
+  if (!xdr_am_sattr3(xdrs, &objp->symlink_attributes))
+    return FALSE;
+  if (!xdr_am_nfspath3(xdrs, &objp->symlink_data))
+    return FALSE;
+  return TRUE;
+}
+
+bool_t
+xdr_am_SYMLINK3args(XDR *xdrs, am_SYMLINK3args *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_SYMLINK3args:");
+
+  if (!xdr_am_diropargs3(xdrs, &objp->where))
+    return FALSE;
+  if (!xdr_am_symlinkdata3(xdrs, &objp->symlink))
+    return FALSE;
+  return TRUE;
+}
+
+bool_t
+xdr_am_SYMLINK3resok(XDR *xdrs, am_SYMLINK3resok *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_SYMLINK3resok:");
+
+  if (!xdr_am_post_op_fh3(xdrs, &objp->obj))
+    return FALSE;
+  if (!xdr_am_post_op_attr(xdrs, &objp->obj_attributes))
+    return FALSE;
+  if (!xdr_am_wcc_data(xdrs, &objp->dir_wcc))
+    return FALSE;
+  return TRUE;
+}
+
+bool_t
+xdr_am_SYMLINK3resfail(XDR *xdrs, am_SYMLINK3resfail *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_SYMLINK3resfail:");
+
+  if (!xdr_am_wcc_data(xdrs, &objp->dir_wcc))
+    return FALSE;
+  return TRUE;
+}
+
+bool_t
+xdr_am_SYMLINK3res(XDR *xdrs, am_SYMLINK3res *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_SYMLINK3res:");
+
+  if (!xdr_am_nfsstat3(xdrs, &objp->status))
+    return FALSE;
+  switch (objp->status) {
+  case AM_NFS3_OK:
+    if (!xdr_am_SYMLINK3resok(xdrs, &objp->res_u.ok))
+      return FALSE;
+    break;
+  default:
+    if (!xdr_am_SYMLINK3resfail(xdrs, &objp->res_u.fail))
+      return FALSE;
+    break;
+  }
+  return TRUE;
+}
+
+bool_t
+xdr_am_READLINK3args(XDR *xdrs, am_READLINK3args *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_READLINK3args:");
+
+  if (!xdr_am_nfs_fh3(xdrs, &objp->symlink))
+    return FALSE;
+  return TRUE;
+}
+
+bool_t
+xdr_am_READLINK3resok(XDR *xdrs, am_READLINK3resok *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_READLINK3resok:");
+
+  if (!xdr_am_post_op_attr(xdrs, &objp->symlink_attributes))
+    return FALSE;
+  if (!xdr_am_nfspath3(xdrs, &objp->data))
+    return FALSE;
+  return TRUE;
+}
+
+bool_t
+xdr_am_READLINK3resfail(XDR *xdrs, am_READLINK3resfail *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_READLINK3resfail:");
+
+  if (!xdr_am_post_op_attr(xdrs, &objp->symlink_attributes))
+    return FALSE;
+  return TRUE;
+}
+
+bool_t
+xdr_am_READLINK3res(XDR *xdrs, am_READLINK3res *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_READLINK3res:");
+
+  if (!xdr_am_nfsstat3(xdrs, &objp->status))
+    return FALSE;
+  switch (objp->status) {
+  case AM_NFS3_OK:
+    if (!xdr_am_READLINK3resok(xdrs, &objp->res_u.ok))
+      return FALSE;
+    break;
+  default:
+    if (!xdr_am_READLINK3resfail(xdrs, &objp->res_u.fail))
+      return FALSE;
+    break;
+  }
+  return TRUE;
+}
+
+bool_t
+xdr_am_devicedata3(XDR *xdrs, am_devicedata3 *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_devicedata3:");
+
+  if (!xdr_am_sattr3(xdrs, &objp->dev_attributes))
+    return FALSE;
+  if (!xdr_am_specdata3(xdrs, &objp->spec))
+    return FALSE;
+  return TRUE;
+}
+
+bool_t
+xdr_am_mknoddata3(XDR *xdrs, am_mknoddata3 *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_mknoddata3:");
+
+  if (!xdr_am_ftype3(xdrs, &objp->type))
+    return FALSE;
+  switch (objp->type) {
+  case AM_NF3CHR:
+    if (!xdr_am_devicedata3(xdrs, &objp->am_mknoddata3_u.chr_device))
+      return FALSE;
+    break;
+  case AM_NF3BLK:
+    if (!xdr_am_devicedata3(xdrs, &objp->am_mknoddata3_u.blk_device))
+      return FALSE;
+    break;
+  case AM_NF3SOCK:
+    if (!xdr_am_sattr3(xdrs, &objp->am_mknoddata3_u.sock_attributes))
+      return FALSE;
+    break;
+  case AM_NF3FIFO:
+    if (!xdr_am_sattr3(xdrs, &objp->am_mknoddata3_u.pipe_attributes))
+      return FALSE;
+    break;
+  default:
+    break;
+  }
+  return TRUE;
+}
+
+bool_t
+xdr_am_MKNOD3args(XDR *xdrs, am_MKNOD3args *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_MKNOD3args:");
+
+  if (!xdr_am_diropargs3(xdrs, &objp->where))
+    return FALSE;
+  if (!xdr_am_mknoddata3(xdrs, &objp->what))
+    return FALSE;
+  return TRUE;
+}
+
+bool_t
+xdr_am_MKNOD3resok(XDR *xdrs, am_MKNOD3resok *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_MKNOD3resok:");
+
+  if (!xdr_am_post_op_fh3(xdrs, &objp->obj))
+    return FALSE;
+  if (!xdr_am_post_op_attr(xdrs, &objp->obj_attributes))
+    return FALSE;
+  if (!xdr_am_wcc_data(xdrs, &objp->dir_wcc))
+    return FALSE;
+  return TRUE;
+}
+
+bool_t
+xdr_am_MKNOD3resfail(XDR *xdrs, am_MKNOD3resfail *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_MKNOD3resfail:");
+
+  if (!xdr_am_wcc_data(xdrs, &objp->dir_wcc))
+    return FALSE;
+  return TRUE;
+}
+
+bool_t
+xdr_am_MKNOD3res(XDR *xdrs, am_MKNOD3res *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, ":");
+
+  if (!xdr_am_nfsstat3(xdrs, &objp->status))
+    return FALSE;
+  switch (objp->status) {
+  case AM_NFS3_OK:
+    if (!xdr_am_MKNOD3resok(xdrs, &objp->res_u.ok))
+      return FALSE;
+    break;
+  default:
+    if (!xdr_am_MKNOD3resfail(xdrs, &objp->res_u.fail))
+      return FALSE;
+    break;
+  }
+  return TRUE;
+}
+
+bool_t
+xdr_am_MKDIR3args(XDR *xdrs, am_MKDIR3args *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, ":");
+
+  if (!xdr_am_diropargs3(xdrs, &objp->where))
+    return FALSE;
+  if (!xdr_am_sattr3(xdrs, &objp->attributes))
+    return FALSE;
+  return TRUE;
+}
+
+bool_t
+xdr_am_MKDIR3resok(XDR *xdrs, am_MKDIR3resok *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_MKDIR3resok:");
+
+  if (!xdr_am_post_op_fh3(xdrs, &objp->obj))
+    return FALSE;
+  if (!xdr_am_post_op_attr(xdrs, &objp->obj_attributes))
+    return FALSE;
+  if (!xdr_am_wcc_data(xdrs, &objp->dir_wcc))
+    return FALSE;
+  return TRUE;
+}
+
+bool_t
+xdr_am_MKDIR3resfail(XDR *xdrs, am_MKDIR3resfail *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_MKDIR3resfail:");
+
+  if (!xdr_am_wcc_data(xdrs, &objp->dir_wcc))
+    return FALSE;
+  return TRUE;
+}
+
+bool_t
+xdr_am_MKDIR3res(XDR *xdrs, am_MKDIR3res *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_MKDIR3res:");
+
+  if (!xdr_am_nfsstat3(xdrs, &objp->status))
+    return FALSE;
+  switch (objp->status) {
+  case AM_NFS3_OK:
+    if (!xdr_am_MKDIR3resok(xdrs, &objp->res_u.ok))
+      return FALSE;
+    break;
+  default:
+    if (!xdr_am_MKDIR3resfail(xdrs, &objp->res_u.fail))
+      return FALSE;
+    break;
+  }
+  return TRUE;
+}
+
+bool_t
+xdr_am_RMDIR3args(XDR *xdrs, am_RMDIR3args *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_RMDIR3args:");
+
+  if (!xdr_am_diropargs3(xdrs, &objp->object))
+    return FALSE;
+  return TRUE;
+}
+
+bool_t
+xdr_am_RMDIR3resok(XDR *xdrs, am_RMDIR3resok *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_RMDIR3resok:");
+
+  if (!xdr_am_wcc_data(xdrs, &objp->dir_wcc))
+    return FALSE;
+  return TRUE;
+}
+
+bool_t
+xdr_am_RMDIR3resfail(XDR *xdrs, am_RMDIR3resfail *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_RMDIR3resfail:");
+
+  if (!xdr_am_wcc_data(xdrs, &objp->dir_wcc))
+    return FALSE;
+  return TRUE;
+}
+
+bool_t
+xdr_am_RMDIR3res(XDR *xdrs, am_RMDIR3res *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_RMDIR3res:");
+
+  if (!xdr_am_nfsstat3(xdrs, &objp->status))
+    return FALSE;
+  switch (objp->status) {
+  case AM_NFS3_OK:
+    if (!xdr_am_RMDIR3resok(xdrs, &objp->res_u.ok))
+      return FALSE;
+    break;
+  default:
+    if (!xdr_am_RMDIR3resfail(xdrs, &objp->res_u.fail))
+      return FALSE;
+    break;
+  }
+  return TRUE;
+}
+
+bool_t
+xdr_am_RENAME3args(XDR *xdrs, am_RENAME3args *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_RENAME3args:");
+
+  if (!xdr_am_diropargs3(xdrs, &objp->from))
+    return FALSE;
+  if (!xdr_am_diropargs3(xdrs, &objp->to))
+    return FALSE;
+  return TRUE;
+}
+
+bool_t
+xdr_am_RENAME3resok(XDR *xdrs, am_RENAME3resok *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_RENAME3resok:");
+
+  if (!xdr_am_wcc_data(xdrs, &objp->fromdir_wcc))
+    return FALSE;
+  if (!xdr_am_wcc_data(xdrs, &objp->todir_wcc))
+    return FALSE;
+  return TRUE;
+}
+
+bool_t
+xdr_am_RENAME3resfail(XDR *xdrs, am_RENAME3resfail *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_RENAME3resfail:");
+
+  if (!xdr_am_wcc_data(xdrs, &objp->fromdir_wcc))
+    return FALSE;
+  if (!xdr_am_wcc_data(xdrs, &objp->todir_wcc))
+    return FALSE;
+  return TRUE;
+}
+
+bool_t
+xdr_am_RENAME3res(XDR *xdrs, am_RENAME3res *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_RENAME3res:");
+
+  if (!xdr_am_nfsstat3(xdrs, &objp->status))
+    return FALSE;
+  switch (objp->status) {
+  case AM_NFS3_OK:
+    if (!xdr_am_RENAME3resok(xdrs, &objp->res_u.ok))
+      return FALSE;
+    break;
+  default:
+    if (!xdr_am_RENAME3resfail(xdrs, &objp->res_u.fail))
+      return FALSE;
+    break;
+  }
+  return TRUE;
+}
+
+bool_t
+xdr_am_READDIRPLUS3args(XDR *xdrs, am_READDIRPLUS3args *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_READDIRPLUS3args:");
+
+  if (!xdr_am_nfs_fh3(xdrs, &objp->dir))
+    return FALSE;
+  if (!xdr_am_cookie3(xdrs, &objp->cookie))
+    return FALSE;
+  if (!xdr_am_cookieverf3(xdrs, objp->cookieverf))
+    return FALSE;
+  if (!xdr_am_count3(xdrs, &objp->dircount))
+    return FALSE;
+  if (!xdr_am_count3(xdrs, &objp->maxcount))
+    return FALSE;
+  return TRUE;
+}
+
+bool_t
+xdr_am_entryplus3(XDR *xdrs, am_entryplus3 *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_entryplus3:");
+
+   if (!xdr_am_fileid3(xdrs, &objp->fileid))
+     return FALSE;
+   if (!xdr_am_filename3(xdrs, &objp->name))
+     return FALSE;
+   if (!xdr_am_cookie3(xdrs, &objp->cookie))
+     return FALSE;
+   if (!xdr_am_post_op_attr(xdrs, &objp->name_attributes))
+     return FALSE;
+   if (!xdr_am_post_op_fh3(xdrs, &objp->name_handle))
+     return FALSE;
+   if (!xdr_pointer(xdrs, (char **)&objp->nextentry,
+                   sizeof(am_entryplus3), (xdrproc_t) xdr_am_entryplus3))
+     return FALSE;
+  return TRUE;
+}
+
+bool_t
+xdr_am_dirlistplus3(XDR *xdrs, am_dirlistplus3 *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_dirlistplus3:");
+
+  if (!xdr_pointer(xdrs, (char **)&objp->entries,
+                   sizeof(am_entryplus3), (xdrproc_t) xdr_am_entryplus3))
+    return FALSE;
+  if (!xdr_bool(xdrs, &objp->eof))
+    return FALSE;
+  return TRUE;
+}
+
+bool_t
+xdr_am_READDIRPLUS3resok(XDR *xdrs, am_READDIRPLUS3resok *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_READDIRPLUS3resok:");
+
+  if (!xdr_am_post_op_attr(xdrs, &objp->dir_attributes))
+    return FALSE;
+  if (!xdr_am_cookieverf3(xdrs, objp->cookieverf))
+    return FALSE;
+  if (!xdr_am_dirlistplus3(xdrs, &objp->reply))
+    return FALSE;
+  return TRUE;
+}
+
+bool_t
+xdr_am_READDIRPLUS3resfail(XDR *xdrs, am_READDIRPLUS3resfail *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_READDIRPLUS3resfail:");
+
+  if (!xdr_am_post_op_attr(xdrs, &objp->dir_attributes))
+    return FALSE;
+  return TRUE;
+}
+
+bool_t
+xdr_am_READDIRPLUS3res(XDR *xdrs, am_READDIRPLUS3res *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_READDIRPLUS3res:");
+
+  if (!xdr_am_nfsstat3(xdrs, &objp->status))
+    return FALSE;
+  switch (objp->status) {
+  case AM_NFS3_OK:
+    if (!xdr_am_READDIRPLUS3resok(xdrs, &objp->res_u.ok))
+      return FALSE;
+    break;
+  default:
+    if (!xdr_am_READDIRPLUS3resfail(xdrs, &objp->res_u.fail))
+      return FALSE;
+    break;
+  }
+  return TRUE;
+}
+
+bool_t
+xdr_am_READDIR3args(XDR *xdrs, am_READDIR3args *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_READDIR3args:");
+
+  if (!xdr_am_nfs_fh3(xdrs, &objp->dir))
+    return FALSE;
+  if (!xdr_am_cookie3(xdrs, &objp->cookie))
+    return FALSE;
+  if (!xdr_am_cookieverf3(xdrs, objp->cookieverf))
+    return FALSE;
+  if (!xdr_am_count3(xdrs, &objp->count))
+    return FALSE;
+  return TRUE;
+}
+
+bool_t
+xdr_am_entry3(XDR *xdrs, am_entry3 *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_entry3:");
+
+  if (!xdr_am_fileid3(xdrs, &objp->fileid))
+    return FALSE;
+  if (!xdr_am_filename3(xdrs, &objp->name))
+    return FALSE;
+  if (!xdr_am_cookie3(xdrs, &objp->cookie))
+    return FALSE;
+  if (!xdr_pointer(xdrs, (char **)&objp->nextentry,
+                   sizeof(am_entry3), (xdrproc_t) xdr_am_entry3))
+    return FALSE;
+  return TRUE;
+}
+
+bool_t
+xdr_am_dirlist3(XDR *xdrs, am_dirlist3 *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_dirlist3:");
+
+  if (!xdr_pointer(xdrs, (char **)&objp->entries,
+                   sizeof(am_entry3), (xdrproc_t) xdr_am_entry3))
+    return FALSE;
+  if (!xdr_bool (xdrs, &objp->eof))
+    return FALSE;
+  return TRUE;
+}
+
+bool_t
+xdr_am_READDIR3resok(XDR *xdrs, am_READDIR3resok *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_READDIR3resok:");
+
+  if (!xdr_am_post_op_attr(xdrs, &objp->dir_attributes))
+    return FALSE;
+  if (!xdr_am_cookieverf3(xdrs, objp->cookieverf))
+    return FALSE;
+  if (!xdr_am_dirlist3(xdrs, &objp->reply))
+    return FALSE;
+  return TRUE;
+}
+
+bool_t
+xdr_am_READDIR3resfail(XDR *xdrs, am_READDIR3resfail *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_READDIR3resfail:");
+
+  if (!xdr_am_post_op_attr(xdrs, &objp->dir_attributes))
+    return FALSE;
+  return TRUE;
+}
+
+bool_t
+xdr_am_READDIR3res(XDR *xdrs, am_READDIR3res *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_READDIR3res:");
+
+  if (!xdr_am_nfsstat3(xdrs, &objp->status))
+    return FALSE;
+  switch (objp->status) {
+  case AM_NFS3_OK:
+    if (!xdr_am_READDIR3resok(xdrs, &objp->res_u.ok))
+      return FALSE;
+    break;
+  default:
+    if (!xdr_am_READDIR3resfail(xdrs, &objp->res_u.fail))
+      return FALSE;
+    break;
+  }
+  return TRUE;
+}
+
+bool_t
+xdr_am_LINK3args(XDR *xdrs, am_LINK3args *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_LINK3args:");
+
+  if (!xdr_am_nfs_fh3(xdrs, &objp->file))
+    return FALSE;
+  if (!xdr_am_diropargs3(xdrs, &objp->link))
+    return FALSE;
+  return TRUE;
+}
+
+bool_t
+xdr_am_LINK3resok(XDR *xdrs, am_LINK3resok *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_LINK3resok:");
+
+  if (!xdr_am_post_op_attr(xdrs, &objp->file_attributes))
+    return FALSE;
+  if (!xdr_am_wcc_data(xdrs, &objp->linkdir_wcc))
+    return FALSE;
+  return TRUE;
+}
+
+bool_t
+xdr_am_LINK3resfail(XDR *xdrs, am_LINK3resfail *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_LINK3resfail:");
+
+  if (!xdr_am_post_op_attr(xdrs, &objp->file_attributes))
+    return FALSE;
+  if (!xdr_am_wcc_data(xdrs, &objp->linkdir_wcc))
+    return FALSE;
+  return TRUE;
+}
+
+bool_t
+xdr_am_LINK3res(XDR *xdrs, am_LINK3res *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_LINK3res:");
+
+  if (!xdr_am_nfsstat3(xdrs, &objp->status))
+    return FALSE;
+  switch (objp->status) {
+  case AM_NFS3_OK:
+    if (!xdr_am_LINK3resok(xdrs, &objp->res_u.ok))
+      return FALSE;
+    break;
+  default:
+    if (!xdr_am_LINK3resfail(xdrs, &objp->res_u.fail))
+      return FALSE;
+    break;
+  }
+  return TRUE;
+}
+
+bool_t
+xdr_am_sattrguard3(XDR *xdrs, am_sattrguard3 *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_sattrguard3:");
+
+  if (!xdr_bool(xdrs, &objp->check))
+    return FALSE;
+  switch (objp->check) {
+  case TRUE:
+    if (!xdr_am_nfstime3(xdrs, &objp->am_sattrguard3_u.obj_ctime))
+      return FALSE;
+    break;
+  case FALSE:
+    break;
+  default:
+    return FALSE;
+  }
+  return TRUE;
+}
+
+bool_t
+xdr_am_SETATTR3args(XDR *xdrs, am_SETATTR3args *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_SETATTR3args:");
+
+  if (!xdr_am_nfs_fh3(xdrs, &objp->object))
+    return FALSE;
+  if (!xdr_am_sattr3(xdrs, &objp->new_attributes))
+    return FALSE;
+  if (!xdr_am_sattrguard3(xdrs, &objp->guard))
+    return FALSE;
+  return TRUE;
+}
+
+bool_t
+xdr_am_SETATTR3resok(XDR *xdrs, am_SETATTR3resok *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_SETATTR3resok:");
+
+  if (!xdr_am_wcc_data(xdrs, &objp->obj_wcc))
+    return FALSE;
+  return TRUE;
+}
+
+bool_t
+xdr_am_SETATTR3resfail(XDR *xdrs, am_SETATTR3resfail *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_SETATTR3resfail:");
+
+  if (!xdr_am_wcc_data(xdrs, &objp->obj_wcc))
+    return FALSE;
+  return TRUE;
+}
+
+bool_t
+xdr_am_SETATTR3res(XDR *xdrs, am_SETATTR3res *objp)
+{
+  if (amuDebug(D_XDRTRACE))
+    plog(XLOG_DEBUG, "xdr_am_SETATTR3res:");
+
+  if (!xdr_am_nfsstat3(xdrs, &objp->status))
+    return FALSE;
+  switch (objp->status) {
+  case AM_NFS3_OK:
+    if (!xdr_am_SETATTR3resok(xdrs, &objp->res_u.ok))
+      return FALSE;
+    break;
+  default:
+    if (!xdr_am_SETATTR3resfail(xdrs, &objp->res_u.fail))
+      return FALSE;
+    break;
+  }
+  return TRUE;
 }
-#endif /* not HAVE_FS_NFS3 */
+#endif /* HAVE_FS_NFS3 */