Imported Upstream version 1.9.4 upstream/1.9.4
authorRitesh Raj Sarraf <rrs@debian.org>
Mon, 30 Jun 2014 08:15:52 +0000 (13:45 +0530)
committerRitesh Raj Sarraf <rrs@debian.org>
Mon, 30 Jun 2014 08:15:52 +0000 (13:45 +0530)
53 files changed:
COPYING
Makefile.am
README
aros/aros_compat.h
configure.ac
doc/Makefile.am [new file with mode: 0644]
doc/nfs-ls.1 [new file with mode: 0644]
doc/nfs-ls.1.xml [new file with mode: 0644]
examples/Makefile.am
examples/nfsclient-bcast.c
examples/nfsclient-raw.c
examples/portmap-client.c [new file with mode: 0644]
include/Makefile.am
include/libnfs-private.h
include/nfsc/libnfs-raw.h
include/nfsc/libnfs.h
include/slist.h
lib/Makefile.am
lib/init.c
lib/libnfs-sync.c
lib/libnfs-win32.def
lib/libnfs.c
lib/pdu.c
lib/socket.c
mount/Makefile.am
mount/libnfs-raw-mount.c
mount/libnfs-raw-mount.h
mount/mount.x
nfs/Makefile.am
nfs/libnfs-raw-nfs.c
nfs/libnfs-raw-nfs.h
nfs/nfs.x
nlm/Makefile.am
nlm/libnfs-raw-nlm.c
nlm/libnfs-raw-nlm.h
nlm/nlm.x
nsm/Makefile.am
nsm/libnfs-raw-nsm.c
nsm/libnfs-raw-nsm.h
nsm/nsm.x
packaging/RPM/libnfs.spec.in
portmap/Makefile.am
portmap/libnfs-raw-portmap.c
portmap/libnfs-raw-portmap.h
portmap/portmap.c
portmap/portmap.x
rquota/Makefile.am
rquota/libnfs-raw-rquota.c
rquota/libnfs-raw-rquota.h
rquota/rquota.x
utils/Makefile.am [new file with mode: 0644]
utils/nfs-ls.c [moved from examples/nfs-ls.c with 87% similarity]
win32/win32_errnowrapper.h

diff --git a/COPYING b/COPYING
index 306c29dd94241505163fae1599fc417ce5f8aae8..17a553e9ac166971b374e1c2a15d98de623a4e07 100644 (file)
--- a/COPYING
+++ b/COPYING
@@ -1,13 +1,18 @@
 Libnfs components fall under two separate licences
 
 
 Libnfs components fall under two separate licences
 
 
-The lib and include directories
-===============================
+The library sources and include directories
+===========================================
 The nfs client library itself, i.e. the lib and include directories,
 is licenced under GNU Lesser General Public License as published by
 the Free Software Foundation; either version 2.1 of the License, or
 (at your option) any later version.
 
 The nfs client library itself, i.e. the lib and include directories,
 is licenced under GNU Lesser General Public License as published by
 the Free Software Foundation; either version 2.1 of the License, or
 (at your option) any later version.
 
+The protocol definition, .x, files
+==================================
+These are based on old RFCs and studying how wireshark dissects various packets.
+These are distributed under the simplified BSD licence.
+
 The examples directory
 ================================
 The utility and example applications using this library, i.e. the
 The examples directory
 ================================
 The utility and example applications using this library, i.e. the
index 4ffb68f9897a84e5b3503e4daf30b1b28505e07a..f01dba369c9fb32f34bdafcb343dd12ab4a0ee2d 100644 (file)
@@ -1,4 +1,4 @@
-SUBDIRS = mount nfs nlm nsm portmap rquota lib include . $(MAYBE_EXAMPLES)
+SUBDIRS = doc mount nfs nlm nsm portmap rquota lib include utils . $(MAYBE_EXAMPLES)
 
 pkgconfigdir = $(libdir)/pkgconfig
 pkgconfig_DATA = libnfs.pc
 
 pkgconfigdir = $(libdir)/pkgconfig
 pkgconfig_DATA = libnfs.pc
diff --git a/README b/README
index 4e312da9e70a8b65bf78da6c03dc8d21ddb7acca..b0655ea7ca37b4e441ea26d29b04b6d91c25986d 100644 (file)
--- a/README
+++ b/README
@@ -28,7 +28,7 @@ URL-FORMAT:
 Libnfs uses RFC2224 style URLs extended with libnfs specific url arguments some minor extensions.
 The basic syntax of these URLs is :
 
 Libnfs uses RFC2224 style URLs extended with libnfs specific url arguments some minor extensions.
 The basic syntax of these URLs is :
 
-nfs://<server|ipv4>/path[?arg=val[&arg=val]*]
+nfs://<server|ipv4|ipv6>/path[?arg=val[&arg=val]*]
 
 Arguments supported by libnfs are :
  tcp-syncnt=<int>  : Number of SYNs to send during the session establish
 
 Arguments supported by libnfs are :
  tcp-syncnt=<int>  : Number of SYNs to send during the session establish
@@ -62,6 +62,14 @@ This is highly non-portable so IF this works on your linux system, count
 yourself lucky.
 
 
 yourself lucky.
 
 
+DOCUMENTATION
+=============
+libnfs sources ship with prebuilt manpage(s) in the doc directory.
+If you change the manpage sources you need to manually regenerate the new
+manpages by running 
+  cd doc
+  make doc
+
 FUSE
 ====
 A simple FUSE filesystem built on libnfs can be found in
 FUSE
 ====
 A simple FUSE filesystem built on libnfs can be found in
index 76de2ac948f724daefc71df716b7a905d754b407..2089bc89a13dd1bdd4ff11aa6113fd9c5940c8fe 100644 (file)
@@ -1,3 +1,20 @@
+/*
+   Copyright (C) 2013 by Ronnie Sahlberg <ronniesahlberg@gmail.com>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation; either version 2.1 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
 #ifndef AROS_COMPAT_H
 #define AROS_COMPAT_H
 
 #ifndef AROS_COMPAT_H
 #define AROS_COMPAT_H
 
index c52a370c6ddef05837245506d84aaa3c2634bd8b..2cb979eb8a7dc4680689e86b3090821346f00c5b 100644 (file)
@@ -1,5 +1,5 @@
 AC_PREREQ(2.50)
 AC_PREREQ(2.50)
-AC_INIT([libnfs], [1.9.3], [ronniesahlberg@gmail.com])
+AC_INIT([libnfs], [1.9.4], [ronniesahlberg@gmail.com])
 AC_CONFIG_HEADERS([config.h])
 AM_INIT_AUTOMAKE([foreign])
 AC_CANONICAL_HOST
 AC_CONFIG_HEADERS([config.h])
 AM_INIT_AUTOMAKE([foreign])
 AC_CANONICAL_HOST
@@ -155,6 +155,7 @@ AC_CHECK_MEMBER([struct sockaddr_storage.ss_family],
 
 #output
 AC_CONFIG_FILES([Makefile]
 
 #output
 AC_CONFIG_FILES([Makefile]
+                [doc/Makefile]
                 [include/Makefile]
                 [lib/Makefile]
                 [mount/Makefile]
                 [include/Makefile]
                 [lib/Makefile]
                 [mount/Makefile]
@@ -163,6 +164,7 @@ AC_CONFIG_FILES([Makefile]
                 [nsm/Makefile]
                 [portmap/Makefile]
                 [rquota/Makefile]
                 [nsm/Makefile]
                 [portmap/Makefile]
                 [rquota/Makefile]
+                [utils/Makefile]
                 [examples/Makefile]
                )
 
                 [examples/Makefile]
                )
 
diff --git a/doc/Makefile.am b/doc/Makefile.am
new file mode 100644 (file)
index 0000000..8b9753c
--- /dev/null
@@ -0,0 +1,9 @@
+XSLTPROC = /usr/bin/xsltproc
+
+EXTRA_DIST = nfs-ls.1 nfs-ls.1.xml
+
+# Manpages
+man1_MANS = nfs-ls.1
+
+doc:
+       -test -z "$(XSLTPROC)" || $(XSLTPROC) -o nfs-ls.1 http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl nfs-ls.1.xml
diff --git a/doc/nfs-ls.1 b/doc/nfs-ls.1
new file mode 100644 (file)
index 0000000..1c09bfc
--- /dev/null
@@ -0,0 +1,120 @@
+'\" t
+.\"     Title: nfs-ls
+.\"    Author: [FIXME: author] [see http://docbook.sf.net/el/author]
+.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
+.\"      Date: 05/14/2014
+.\"    Manual: nfs-ls: list servers, exports and directories
+.\"    Source: nfs-ls
+.\"  Language: English
+.\"
+.TH "NFS\-LS" "1" "05/14/2014" "nfs\-ls" "nfs\-ls: list servers, exports"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el       .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nfs-ls \- Utility to list NFS servers, exports and directories
+.SH "SYNOPSIS"
+.HP \w'\fBnfs\-ls\ [\ OPTIONS\ ]\ <NFS\-URL>\fR\ 'u
+\fBnfs\-ls [ OPTIONS ] <NFS\-URL>\fR
+.HP \w'\fBnfs\-ls\fR\ 'u
+\fBnfs\-ls\fR [\-R\ \-\-recursive] [\-s\ \-\-summary] [\-D\ \-\-discovery] [\-?\ \-\-help] [\-\-usage]
+.SH "DESCRIPTION"
+.PP
+nfs\-ls is a utility to list NFS servers, exports or directories\&.
+.PP
+Example: List the content of a directory on the NFS server
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+$ nfs\-ls nfs://127\&.0\&.0\&.1/data/tmp
+\-rwxrwxr\-x  1  1000  1000      1190802 a\&.out
+\-rwxr\-xr\-x  1  1000  1000           13 foo123\&.copy
+\-rwxrwxrwx  1  1000  1000            8 foo123\&.writtenx
+      
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.SH "OPTIONS"
+.PP
+\-s \-\-summary
+.RS 4
+Print a summary line at the end of output\&.
+.RE
+.PP
+\-R \-\-recursive
+.RS 4
+Recursive listing of the specified URL\&.
+.RE
+.PP
+\-D \-\-discovery;
+.RS 4
+This option is used to discover local NFS servers and to list the exports for specific servers\&.
+.sp
+When used with the \*(Aqnfs://\*(Aq URL the command will try to detect all local NFS servers and will list their IPs\&.
+.sp
+When used with a \*(Aqnfs://server\*(Aq the command will list all the exports on the specified server\&.
+.sp
+Example: Discover and list all local NFS servers
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+$ nfs\-ls \-D nfs://
+nfs://10\&.10\&.10\&.10
+nfs://10\&.0\&.0\&.10
+           
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Example: List the exports for a server
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+$ nfs\-ls \-D nfs://10\&.10\&.10\&.10
+nfs://10\&.10\&.10\&.10/foo
+nfs://10\&.10\&.10\&.10/bar
+           
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.RE
+.PP
+\-? \-\-help
+.RS 4
+Display basic help text\&.
+.RE
+.PP
+\-\-usage
+.RS 4
+Display basic usage text\&.
+.RE
+.SH "SEE ALSO"
+.PP
+\m[blue]\fB\%http://github.com/sahlberg/libnfs\fR\m[]
diff --git a/doc/nfs-ls.1.xml b/doc/nfs-ls.1.xml
new file mode 100644 (file)
index 0000000..9329369
--- /dev/null
@@ -0,0 +1,126 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<refentry id="nfs-ls.1">
+
+<refmeta>
+       <refentrytitle>nfs-ls</refentrytitle>
+       <manvolnum>1</manvolnum>
+       <refmiscinfo class="source">nfs-ls</refmiscinfo>
+       <refmiscinfo class="manual">nfs-ls: list servers, exports and directories</refmiscinfo>
+</refmeta>
+
+
+<refnamediv>
+       <refname>nfs-ls</refname>
+        <refpurpose>Utility to list NFS servers, exports and directories</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+       <cmdsynopsis>
+               <command>nfs-ls [ OPTIONS ] &lt;NFS-URL&gt;</command>
+       </cmdsynopsis>
+       
+       <cmdsynopsis>
+               <command>nfs-ls</command>
+               <arg choice="opt">-R --recursive</arg>
+               <arg choice="opt">-s --summary</arg>
+               <arg choice="opt">-D --discovery</arg>
+               <arg choice="opt">-? --help</arg>
+               <arg choice="opt">--usage</arg>
+       </cmdsynopsis>
+       
+</refsynopsisdiv>
+
+  <refsect1><title>DESCRIPTION</title>
+    <para>
+      nfs-ls is a utility to list NFS servers, exports or directories.
+    </para>
+    <para>
+      Example: List the content of a directory on the NFS server
+      <screen format="linespecific">
+$ nfs-ls nfs://127.0.0.1/data/tmp
+-rwxrwxr-x  1  1000  1000      1190802 a.out
+-rwxr-xr-x  1  1000  1000           13 foo123.copy
+-rwxrwxrwx  1  1000  1000            8 foo123.writtenx
+      </screen>
+    </para>
+  </refsect1>
+
+  <refsect1>
+    <title>OPTIONS</title>
+
+    <variablelist>
+
+      <varlistentry><term>-s --summary</term>
+        <listitem>
+          <para>
+           Print a summary line at the end of output.
+         </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry><term>-R --recursive</term>
+        <listitem>
+          <para>
+           Recursive listing of the specified URL.
+         </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry><term>-D --discovery;</term>
+        <listitem>
+          <para>
+           This option is used to discover local NFS servers and to list
+           the exports for specific servers.
+          </para>
+          <para>
+           When used with the 'nfs://' URL the command will try to
+           detect all local NFS servers and will list their IPs.
+          </para>
+          <para>
+           When used with a 'nfs://server' the command will
+           list all the exports on the specified server.
+          </para>
+          <para>
+           Example: Discover and list all local NFS servers
+           <screen format="linespecific">
+$ nfs-ls -D nfs://
+nfs://10.10.10.10
+nfs://10.0.0.10
+           </screen>
+
+           Example: List the exports for a server
+           <screen format="linespecific">
+$ nfs-ls -D nfs://10.10.10.10
+nfs://10.10.10.10/foo
+nfs://10.10.10.10/bar
+           </screen>
+         </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry><term>-? --help</term>
+        <listitem>
+          <para>
+           Display basic help text.
+         </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry><term>--usage</term>
+        <listitem>
+          <para>
+           Display basic usage text.
+         </para>
+        </listitem>
+      </varlistentry>
+
+    </variablelist>
+  </refsect1>
+
+  <refsect1><title>SEE ALSO</title>
+    <para>
+      <ulink url="http://github.com/sahlberg/libnfs"/>
+    </para>
+  </refsect1>
+
+</refentry>
index 10fd9ea737635c83ae3b0d490127378330af2bf3..fdf9fbd8da34ff8894488c5eaef3d9faba40d830 100644 (file)
@@ -1,4 +1,4 @@
-noinst_PROGRAMS = nfsclient-async nfsclient-raw nfsclient-sync nfsclient-bcast nfsclient-listservers nfs-ls nfs-cp nfs-io
+noinst_PROGRAMS = nfsclient-async nfsclient-raw nfsclient-sync nfsclient-bcast nfsclient-listservers nfs-cp nfs-io portmap-client
 
 AM_CPPFLAGS = \
        -I$(abs_top_srcdir)/include \
 
 AM_CPPFLAGS = \
        -I$(abs_top_srcdir)/include \
@@ -10,20 +10,3 @@ AM_CPPFLAGS = \
        "-D_U_=__attribute__((unused))"
 
 AM_LDFLAGS = ../lib/.libs/libnfs.la -lpopt
        "-D_U_=__attribute__((unused))"
 
 AM_LDFLAGS = ../lib/.libs/libnfs.la -lpopt
-
-nfs_ls_SOURCES = nfs-ls.c
-
-nfs_cp_SOURCES = nfs-cp.c
-
-nfs_io_SOURCES = nfs-io.c
-
-nfsclient_async_SOURCES = nfsclient-async.c
-
-nfsclient_raw_SOURCES = nfsclient-raw.c
-
-nfsclient_sync_SOURCES = nfsclient-sync.c
-
-nfsclient_bcast_SOURCES = nfsclient-bcast.c
-
-nfsclient_listservers_SOURCES = nfsclient-listservers.c
-
index 62ea6549d29ba295003feeb82932565545c0aa44..45a638532e786a809851e48a4f49d7f7b3eedcc7 100644 (file)
@@ -212,7 +212,7 @@ int main(int argc _U_, char *argv[] _U_)
                        exit(10);
                }
 
                        exit(10);
                }
 
-               if (rpc_pmap_callit_async(rpc, MOUNT_PROGRAM, 2, 0, NULL, 0, pm_cb, &data) < 0) {
+               if (rpc_pmap2_callit_async(rpc, MOUNT_PROGRAM, 2, 0, NULL, 0, pm_cb, &data) < 0) {
                        printf("Failed to set up callit function\n");
                        exit(10);
                }
                        printf("Failed to set up callit function\n");
                        exit(10);
                }
index fd6575f21fac787d3e0330d9216073bf126861a9..8b7d727781c3265c3124df4e875ac3c6a4907253 100644 (file)
@@ -340,7 +340,7 @@ void pmap_getport1_cb(struct rpc_context *rpc, int status, void *data, void *pri
        }               
 
        printf("Send getport request asking for MOUNT port\n");
        }               
 
        printf("Send getport request asking for MOUNT port\n");
-       if (rpc_pmap_getport_async(rpc, MOUNT_PROGRAM, MOUNT_V3, IPPROTO_TCP, pmap_getport2_cb, client) != 0) {
+       if (rpc_pmap2_getport_async(rpc, MOUNT_PROGRAM, MOUNT_V3, IPPROTO_TCP, pmap_getport2_cb, client) != 0) {
                printf("Failed to send getport request\n");
                exit(10);
        }
                printf("Failed to send getport request\n");
                exit(10);
        }
@@ -349,8 +349,8 @@ void pmap_getport1_cb(struct rpc_context *rpc, int status, void *data, void *pri
 void pmap_dump_cb(struct rpc_context *rpc, int status, void *data, void *private_data)
 {
        struct client *client = private_data;
 void pmap_dump_cb(struct rpc_context *rpc, int status, void *data, void *private_data)
 {
        struct client *client = private_data;
-       struct pmap_dump_result *dr = data;
-       struct pmap_mapping_list *list = dr->list;
+       struct pmap2_dump_result *dr = data;
+       struct pmap2_mapping_list *list = dr->list;
 
        if (status == RPC_STATUS_ERROR) {
                printf("portmapper null call failed with \"%s\"\n", (char *)data);
 
        if (status == RPC_STATUS_ERROR) {
                printf("portmapper null call failed with \"%s\"\n", (char *)data);
@@ -372,7 +372,7 @@ void pmap_dump_cb(struct rpc_context *rpc, int status, void *data, void *private
        }
 
        printf("Send getport request asking for MOUNT port\n");
        }
 
        printf("Send getport request asking for MOUNT port\n");
-       if (rpc_pmap_getport_async(rpc, RQUOTA_PROGRAM, RQUOTA_V1, IPPROTO_TCP, pmap_getport1_cb, client) != 0) {
+       if (rpc_pmap2_getport_async(rpc, RQUOTA_PROGRAM, RQUOTA_V1, IPPROTO_TCP, pmap_getport1_cb, client) != 0) {
                printf("Failed to send getport request\n");
                exit(10);
        }
                printf("Failed to send getport request\n");
                exit(10);
        }
@@ -393,7 +393,7 @@ void pmap_null_cb(struct rpc_context *rpc, int status, void *data, void *private
 
        printf("Got reply from server for PORTMAP/NULL procedure.\n");
        printf("Send PMAP/DUMP command\n");
 
        printf("Got reply from server for PORTMAP/NULL procedure.\n");
        printf("Send PMAP/DUMP command\n");
-       if (rpc_pmap_dump_async(rpc, pmap_dump_cb, client) != 0) {
+       if (rpc_pmap2_dump_async(rpc, pmap_dump_cb, client) != 0) {
                printf("Failed to send getport request\n");
                exit(10);
        }
                printf("Failed to send getport request\n");
                exit(10);
        }
@@ -410,7 +410,7 @@ void pmap_connect_cb(struct rpc_context *rpc, int status, void *data _U_, void *
        }
 
        printf("Send NULL request to check if portmapper is actually running\n");
        }
 
        printf("Send NULL request to check if portmapper is actually running\n");
-       if (rpc_pmap_null_async(rpc, pmap_null_cb, client) != 0) {
+       if (rpc_pmap2_null_async(rpc, pmap_null_cb, client) != 0) {
                printf("Failed to send null request\n");
                exit(10);
        }
                printf("Failed to send null request\n");
                exit(10);
        }
diff --git a/examples/portmap-client.c b/examples/portmap-client.c
new file mode 100644 (file)
index 0000000..526e348
--- /dev/null
@@ -0,0 +1,493 @@
+/* 
+   Copyright (C) by Ronnie Sahlberg <ronniesahlberg@gmail.com> 2014
+   
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* Example program using the lowlevel raw interface.
+ * This allow accurate control of the exact commands that are being used.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef WIN32
+#include "win32_compat.h"
+#endif
+
+#ifdef HAVE_POLL_H
+#include <poll.h>
+#endif
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <time.h>
+#include "libnfs-zdr.h"
+#include "libnfs.h"
+#include "libnfs-raw.h"
+#include "libnfs-raw-mount.h"
+#include "libnfs-raw-nfs.h"
+#include "libnfs-raw-portmap.h"
+#include "libnfs-raw-rquota.h"
+
+struct client {
+       int is_finished;
+};
+
+void pmap2_dump_cb(struct rpc_context *rpc, int status, void *data, void *private_data)
+{
+       struct client *client = private_data;
+       struct pmap2_dump_result *dr = data;
+       struct pmap2_mapping_list *list = dr->list;
+
+       if (status == RPC_STATUS_ERROR) {
+               printf("PORTMAP2/DUMP call failed with \"%s\"\n", (char *)data);
+               exit(10);
+       }
+       if (status != RPC_STATUS_SUCCESS) {
+               printf("PORTMAP2/DUMP call failed, status:%d\n", status);
+               exit(10);
+       }
+
+       printf("PORTMAP2/DUMP:\n");
+       while (list) {
+               printf("        Prog:%d Vers:%d Protocol:%d Port:%d\n",
+                       list->map.prog,
+                       list->map.vers,
+                       list->map.prot,
+                       list->map.port);
+               list = list->next;
+       }
+       client->is_finished = 1;
+}
+
+void pmap3_dump_cb(struct rpc_context *rpc, int status, void *data, void *private_data)
+{
+       struct client *client = private_data;
+       struct pmap3_dump_result *dr = data;
+       struct pmap3_mapping_list *list = dr->list;
+
+       if (status == RPC_STATUS_ERROR) {
+               printf("PORTMAP3/DUMP call failed with \"%s\"\n", (char *)data);
+               exit(10);
+       }
+       if (status != RPC_STATUS_SUCCESS) {
+               printf("PORTMAP3/DUMP call failed, status:%d\n", status);
+               exit(10);
+       }
+
+       printf("PORTMAP3/DUMP:\n");
+       while (list) {
+               printf("        Prog:%d Vers:%d Netid:%s Addr:%s Owner:%s\n",
+                       list->map.prog,
+                       list->map.vers,
+                       list->map.netid,
+                       list->map.addr,
+                       list->map.owner);
+               list = list->next;
+       }
+       client->is_finished = 1;
+}
+
+void pmap3_getaddr_cb(struct rpc_context *rpc, int status, void *data, void *private_data)
+{
+       struct client *client = private_data;
+       struct pmap3_string_result *gar = data;
+
+       if (status == RPC_STATUS_ERROR) {
+               printf("PORTMAP3/GETADDR call failed with \"%s\"\n", (char *)data);
+               exit(10);
+       }
+       if (status != RPC_STATUS_SUCCESS) {
+               printf("PORTMAP3/GETADDR call failed, status:%d\n", status);
+               exit(10);
+       }
+
+       printf("PORTMAP3/GETADDR:\n");
+       printf("        Addr:%s\n", gar->addr);
+
+       client->is_finished = 1;
+}
+
+void pmap3_set_cb(struct rpc_context *rpc, int status, void *data, void *private_data)
+{
+       struct client *client = private_data;
+       uint32_t res = *(uint32_t *)data;
+
+       if (status == RPC_STATUS_ERROR) {
+               printf("PORTMAP3/SET call failed with \"%s\"\n", (char *)data);
+               exit(10);
+       }
+       if (status != RPC_STATUS_SUCCESS) {
+               printf("PORTMAP3/SET call failed, status:%d\n", status);
+               exit(10);
+       }
+
+       printf("PORTMAP3/SET:\n");
+       printf("        Res:%d\n", res);
+
+       client->is_finished = 1;
+}
+
+void pmap3_unset_cb(struct rpc_context *rpc, int status, void *data, void *private_data)
+{
+       struct client *client = private_data;
+       uint32_t res = *(uint32_t *)data;
+
+       if (status == RPC_STATUS_ERROR) {
+               printf("PORTMAP3/UNSET call failed with \"%s\"\n", (char *)data);
+               exit(10);
+       }
+       if (status != RPC_STATUS_SUCCESS) {
+               printf("PORTMAP3/UNSET call failed, status:%d\n", status);
+               exit(10);
+       }
+
+       printf("PORTMAP3/UNSET:\n");
+       printf("        Res:%d\n", res);
+
+       client->is_finished = 1;
+}
+
+void pmap3_gettime_cb(struct rpc_context *rpc, int status, void *data, void *private_data)
+{
+       struct client *client = private_data;
+       time_t t = *(uint32_t *)data;
+
+       if (status == RPC_STATUS_ERROR) {
+               printf("PORTMAP3/GETTIME call failed with \"%s\"\n", (char *)data);
+               exit(10);
+       }
+       if (status != RPC_STATUS_SUCCESS) {
+               printf("PORTMAP3/GETTIME call failed, status:%d\n", status);
+               exit(10);
+       }
+
+       printf("PORTMAP3/GETTIME:\n");
+       printf("        Time:%d %s\n", (int)t, ctime(&t));
+
+       client->is_finished = 1;
+}
+
+void pmap3_uaddr2taddr_cb(struct rpc_context *rpc, int status, void *data, void *private_data)
+{
+       struct client *client = private_data;
+       struct pmap3_netbuf *nb = data;
+       struct sockaddr_storage *ss;
+       char host[256], port[6];
+       int i;
+
+       if (status == RPC_STATUS_ERROR) {
+               printf("PORTMAP3/UADDR2TADDR call failed with \"%s\"\n", (char *)data);
+               exit(10);
+       }
+       if (status != RPC_STATUS_SUCCESS) {
+               printf("PORTMAP3/UADDR2TADDR call failed, status:%d\n", status);
+               exit(10);
+       }
+
+       printf("PORTMAP3/UADDR2TADDR:\n");
+       printf("        MaxLen:%d\n", nb->maxlen);
+       printf("        ");
+       for (i = 0; i < nb->maxlen; i++) {
+               printf("%02x ", nb->buf.buf_val[i]);
+               if (i %16 == 15) {
+                       printf("\n        ");
+               }
+       }
+       printf("\n");
+       printf("        ---\n");
+       ss = (struct sockaddr_storage *)&nb->buf.buf_val[0];
+       getnameinfo((struct sockaddr *)ss, sizeof(struct sockaddr_storage),
+               &host[0], sizeof(host), &port[0], sizeof(port),
+               NI_NUMERICHOST|NI_NUMERICSERV);
+       switch (ss->ss_family) {
+       case AF_INET:
+               printf("        IPv4: %s:%s\n", &host[0], &port[0]);
+               break;
+       case AF_INET6:
+               printf("        IPv6: %s:%s\n", &host[0], &port[0]);
+               break;
+       }
+       client->is_finished = 1;
+}
+
+void pmap2_null_cb(struct rpc_context *rpc, int status, void *data, void *private_data)
+{
+       struct client *client = private_data;
+
+       if (status == RPC_STATUS_ERROR) {
+               printf("PORTMAP2/NULL call failed with \"%s\"\n", (char *)data);
+               exit(10);
+       }
+       if (status != RPC_STATUS_SUCCESS) {
+               printf("PORTMAP2/NULL call failed, status:%d\n", status);
+               exit(10);
+       }
+
+       printf("PORTMAP2/NULL responded and server is alive\n");
+       client->is_finished = 1;
+}
+
+void pmap3_null_cb(struct rpc_context *rpc, int status, void *data, void *private_data)
+{
+       struct client *client = private_data;
+
+       if (status == RPC_STATUS_ERROR) {
+               printf("PORTMAP3/NULL call failed with \"%s\"\n", (char *)data);
+               exit(10);
+       }
+       if (status != RPC_STATUS_SUCCESS) {
+               printf("PORTMAP3/NULL call failed, status:%d\n", status);
+               exit(10);
+       }
+
+       printf("PORTMAP3/NULL responded and server is alive\n");
+       client->is_finished = 1;
+}
+
+void pmap_null_cb(struct rpc_context *rpc, int status, void *data, void *private_data)
+{
+       struct client *client = private_data;
+
+       if (status == RPC_STATUS_ERROR) {
+               printf("PORTMAP/NULL call failed with \"%s\"\n", (char *)data);
+               exit(10);
+       }
+       if (status != RPC_STATUS_SUCCESS) {
+               printf("PORTMAP/NULL call failed, status:%d\n", status);
+               exit(10);
+       }
+
+       client->is_finished = 1;
+}
+
+void pmap_connect_cb(struct rpc_context *rpc, int status, void *data _U_, void *private_data)
+{
+       struct client *client = private_data;
+
+       if (status != RPC_STATUS_SUCCESS) {
+               printf("connection to portmapper failed\n");
+               exit(10);
+       }
+
+       if (rpc_pmap2_null_async(rpc, pmap_null_cb, client) != 0) {
+               printf("Failed to send null request\n");
+               exit(10);
+       }
+}
+
+
+static void wait_until_finished(struct rpc_context *rpc, struct client *client)
+{
+       struct pollfd pfd;
+
+       client->is_finished = 0;
+       for (;;) {
+               pfd.fd = rpc_get_fd(rpc);
+               pfd.events = rpc_which_events(rpc);
+
+               if (poll(&pfd, 1, -1) < 0) {
+                       printf("Poll failed");
+                       exit(10);
+               }
+               if (rpc_service(rpc, pfd.revents) < 0) {
+                       printf("rpc_service failed\n");
+                       break;
+               }
+               if (client->is_finished) {
+                       break;
+               }
+       }
+}
+
+int main(int argc _U_, char *argv[] _U_)
+{
+       struct rpc_context *rpc;
+       struct client client;
+       char *server = NULL;
+       int i;
+       int null2 = 0;
+       int dump2 = 0;
+       int null3 = 0;
+       int set3 = 0;
+       int unset3 = 0;
+       int getaddr3 = 0;
+       int dump3 = 0;
+       int gettime3 = 0;
+       int u2t3 = 0;
+       int command_found = 0;
+
+       int set3prog, set3vers;
+       char *set3netid, *set3addr, *set3owner;
+       int unset3prog, unset3vers;
+       char *unset3netid, *unset3addr, *unset3owner;
+       int getaddr3prog, getaddr3vers;
+       char *getaddr3netid, *getaddr3addr, *getaddr3owner;
+       char *u2t3string;
+
+       rpc = rpc_init_context();
+       if (rpc == NULL) {
+               printf("failed to init context\n");
+               exit(10);
+       }
+
+       for (i = 1; i < argc; i++) {
+               if (!strcmp(argv[i], "dump2")) {
+                       dump2 = 1;
+                       command_found++;
+               } else if (!strcmp(argv[i], "null2")) {
+                       null2 = 1;
+                       command_found++;
+               } else if (!strcmp(argv[i], "dump3")) {
+                       dump3 = 1;
+                       command_found++;
+               } else if (!strcmp(argv[i], "gettime3")) {
+                       gettime3 = 1;
+                       command_found++;
+               } else if (!strcmp(argv[i], "u2t3")) {
+                       u2t3 = 1;
+                       u2t3string = argv[++i];
+                       command_found++;
+               } else if (!strcmp(argv[i], "getaddr3")) {
+                       getaddr3 = 1;
+                       getaddr3prog = atoi(argv[++i]);
+                       getaddr3vers = atoi(argv[++i]);
+                       getaddr3netid = argv[++i];
+                       getaddr3addr  = argv[++i];
+                       getaddr3owner = argv[++i];
+                       command_found++;
+               } else if (!strcmp(argv[i], "set3")) {
+                       set3 = 1;
+                       set3prog = atoi(argv[++i]);
+                       set3vers = atoi(argv[++i]);
+                       set3netid = argv[++i];
+                       set3addr  = argv[++i];
+                       set3owner = argv[++i];
+                       command_found++;
+               } else if (!strcmp(argv[i], "null3")) {
+                       null3 = 1;
+                       command_found++;
+               } else {
+                       server = argv[i];
+               }
+       }
+       if (command_found == 0 || server == NULL) {
+               fprintf(stderr, "Usage: portmap-client <command*> <server>\n");
+               exit(10);
+       }
+
+       if (rpc_connect_async(rpc, server, 111, pmap_connect_cb, &client) != 0) {
+               printf("Failed to start connection\n");
+               exit(10);
+       }
+       wait_until_finished(rpc, &client);
+
+       if (null2) {
+               if (rpc_pmap2_null_async(rpc, pmap2_null_cb, &client) != 0) {
+                       printf("Failed to send NULL2 request\n");
+                       exit(10);
+               }
+               wait_until_finished(rpc, &client);
+       }
+       if (dump2) {
+               if (rpc_pmap2_dump_async(rpc, pmap2_dump_cb, &client) != 0) {
+                       printf("Failed to send DUMP2 request\n");
+                       exit(10);
+               }
+               wait_until_finished(rpc, &client);
+       }
+       if (null3) {
+               if (rpc_pmap3_null_async(rpc, pmap3_null_cb, &client) != 0) {
+                       printf("Failed to send NULL3 request\n");
+                       exit(10);
+               }
+               wait_until_finished(rpc, &client);
+       }
+       if (dump3) {
+               if (rpc_pmap3_dump_async(rpc, pmap3_dump_cb, &client) != 0) {
+                       printf("Failed to send DUMP3 request\n");
+                       exit(10);
+               }
+               wait_until_finished(rpc, &client);
+       }
+       if (gettime3) {
+               if (rpc_pmap3_gettime_async(rpc, pmap3_gettime_cb, &client) != 0) {
+                       printf("Failed to send GETTIME3 request\n");
+                       exit(10);
+               }
+               wait_until_finished(rpc, &client);
+       }
+       if (u2t3) {
+               if (rpc_pmap3_uaddr2taddr_async(rpc, u2t3string, pmap3_uaddr2taddr_cb, &client) != 0) {
+                       printf("Failed to send UADDR2TADDR3 request\n");
+                       exit(10);
+               }
+               wait_until_finished(rpc, &client);
+       }
+       if (getaddr3) {
+               struct pmap3_mapping map;
+
+               map.prog  = getaddr3prog;
+               map.vers  = getaddr3vers;
+               map.netid = getaddr3netid;
+               map.addr  = getaddr3addr;
+               map.owner = getaddr3owner;
+               if (rpc_pmap3_getaddr_async(rpc, &map, pmap3_getaddr_cb, &client) != 0) {
+                       printf("Failed to send GETADDR3 request\n");
+                       exit(10);
+               }
+               wait_until_finished(rpc, &client);
+       }
+       if (set3) {
+               struct pmap3_mapping map;
+
+               map.prog  = set3prog;
+               map.vers  = set3vers;
+               map.netid = set3netid;
+               map.addr  = set3addr;
+               map.owner = set3owner;
+               if (rpc_pmap3_set_async(rpc, &map, pmap3_set_cb, &client) != 0) {
+                       printf("Failed to send SET3 request\n");
+                       exit(10);
+               }
+               wait_until_finished(rpc, &client);
+       }
+       if (unset3) {
+               struct pmap3_mapping map;
+
+               map.prog  = unset3prog;
+               map.vers  = unset3vers;
+               map.netid = unset3netid;
+               map.addr  = unset3addr;
+               map.owner = unset3owner;
+               if (rpc_pmap3_unset_async(rpc, &map, pmap3_unset_cb, &client) != 0) {
+                       printf("Failed to send UNSET3 request\n");
+                       exit(10);
+               }
+               wait_until_finished(rpc, &client);
+       }
+
+       
+       rpc_destroy_context(rpc);
+       rpc=NULL;
+       return 0;
+}
index 27810e05109055b587cfd5189826809ae96b7616..98ab2cfdefc64af9ce74391739456a7a888e10a0 100644 (file)
@@ -1,7 +1,5 @@
 nfscdir = $(includedir)/nfsc
 dist_nfsc_HEADERS = \
 nfscdir = $(includedir)/nfsc
 dist_nfsc_HEADERS = \
-       libnfs-private.h \
-       slist.h \
        nfsc/libnfs.h \
        nfsc/libnfs-raw.h \
        nfsc/libnfs-zdr.h \
        nfsc/libnfs.h \
        nfsc/libnfs-raw.h \
        nfsc/libnfs-zdr.h \
@@ -11,3 +9,7 @@ dist_nfsc_HEADERS = \
        ../nlm/libnfs-raw-nlm.h \
        ../nsm/libnfs-raw-nsm.h \
        ../rquota/libnfs-raw-rquota.h
        ../nlm/libnfs-raw-nlm.h \
        ../nsm/libnfs-raw-nsm.h \
        ../rquota/libnfs-raw-rquota.h
+
+dist_noinst_HEADERS = \
+        libnfs-private.h \
+        slist.h
index 07ce9a8f96b2b9d3edf355cbbc56cb0a4994cee5..ef3b9de3cd9789a52912a249498700bdaa162068 100644 (file)
@@ -65,6 +65,16 @@ struct rpc_fragment {
 #define RPC_CONTEXT_MAGIC 0xc6e46435
 #define RPC_PARAM_UNDEFINED -1
 
 #define RPC_CONTEXT_MAGIC 0xc6e46435
 #define RPC_PARAM_UNDEFINED -1
 
+/*
+ * Queue is singly-linked but we hold on to the tail
+ */
+struct rpc_queue {
+       struct rpc_pdu *head, *tail;
+};
+
+#define HASHES 1024
+#define NFS_RA_TIMEOUT 5
+
 struct rpc_context {
        uint32_t magic;
        int fd;
 struct rpc_context {
        uint32_t magic;
        int fd;
@@ -82,9 +92,9 @@ struct rpc_context {
        char *encodebuf;
        int encodebuflen;
 
        char *encodebuf;
        int encodebuflen;
 
-       struct rpc_pdu *outqueue;
+       struct rpc_queue outqueue;
        struct sockaddr_storage udp_src;
        struct sockaddr_storage udp_src;
-       struct rpc_pdu *waitpdu;
+       struct rpc_queue waitpdu[HASHES];
 
        uint32_t inpos;
        uint32_t insize;
 
        uint32_t inpos;
        uint32_t insize;
@@ -106,6 +116,7 @@ struct rpc_context {
        int tcp_syncnt;
        int uid;
        int gid;
        int tcp_syncnt;
        int uid;
        int gid;
+       uint32_t readahead;
 };
 
 struct rpc_pdu {
 };
 
 struct rpc_pdu {
@@ -126,6 +137,11 @@ struct rpc_pdu {
        uint32_t zdr_decode_bufsize;
 };
 
        uint32_t zdr_decode_bufsize;
 };
 
+void rpc_reset_queue(struct rpc_queue *q);
+void rpc_enqueue(struct rpc_queue *q, struct rpc_pdu *pdu);
+void rpc_return_to_queue(struct rpc_queue *q, struct rpc_pdu *pdu);
+unsigned int rpc_hash_xid(uint32_t xid);
+
 struct rpc_pdu *rpc_allocate_pdu(struct rpc_context *rpc, int program, int version, int procedure, rpc_cb cb, void *private_data, zdrproc_t zdr_decode_fn, int zdr_bufsize);
 void rpc_free_pdu(struct rpc_context *rpc, struct rpc_pdu *pdu);
 int rpc_queue_pdu(struct rpc_context *rpc, struct rpc_pdu *pdu);
 struct rpc_pdu *rpc_allocate_pdu(struct rpc_context *rpc, int program, int version, int procedure, rpc_cb cb, void *private_data, zdrproc_t zdr_decode_fn, int zdr_bufsize);
 void rpc_free_pdu(struct rpc_context *rpc, struct rpc_pdu *pdu);
 int rpc_queue_pdu(struct rpc_context *rpc, struct rpc_pdu *pdu);
@@ -160,6 +176,7 @@ void rpc_unset_autoreconnect(struct rpc_context *rpc);
 void rpc_set_tcp_syncnt(struct rpc_context *rpc, int v);
 void rpc_set_uid(struct rpc_context *rpc, int uid);
 void rpc_set_gid(struct rpc_context *rpc, int gid);
 void rpc_set_tcp_syncnt(struct rpc_context *rpc, int v);
 void rpc_set_uid(struct rpc_context *rpc, int uid);
 void rpc_set_gid(struct rpc_context *rpc, int gid);
+void rpc_set_readahead(struct rpc_context *rpc, uint32_t v);
 
 int rpc_add_fragment(struct rpc_context *rpc, char *data, uint64_t size);
 void rpc_free_all_fragments(struct rpc_context *rpc);
 
 int rpc_add_fragment(struct rpc_context *rpc, char *data, uint64_t size);
 void rpc_free_all_fragments(struct rpc_context *rpc);
index 9d6b0ec099e2245fb3c3fcd215a306f91b925eda..3ba9de3b0aed865ff4c423bde673a52efd1bad7b 100644 (file)
@@ -110,7 +110,7 @@ int rpc_connect_async(struct rpc_context *rpc, const char *server, int port, rpc
  * RPC_STATUS_CANCEL  : The connection attempt was aborted before it could complete.
  *                    : data is NULL.
  */
  * RPC_STATUS_CANCEL  : The connection attempt was aborted before it could complete.
  *                    : data is NULL.
  */
-int rpc_connect_program_async(struct rpc_context *rpc, char *server, int program, int version, rpc_cb cb, void *private_data);
+int rpc_connect_program_async(struct rpc_context *rpc, const char *server, int program, int version, rpc_cb cb, void *private_data);
 /*
  * When disconnecting a connection in flight. All commands in flight will be called with the callback
  * and status RPC_STATUS_ERROR. Data will be the error string for the disconnection.
 /*
  * When disconnecting a connection in flight. All commands in flight will be called with the callback
  * and status RPC_STATUS_ERROR. Data will be the error string for the disconnection.
@@ -119,11 +119,11 @@ int rpc_disconnect(struct rpc_context *rpc, char *error);
 
 
 /*
 
 
 /*
- * PORTMAP FUNCTIONS
+ * PORTMAP v2 FUNCTIONS
  */
 
 /*
  */
 
 /*
- * Call PORTMAPPER/NULL
+ * Call PORTMAPPER2/NULL
  * Function returns
  *  0 : The connection was initiated. Once the connection establish finishes, the callback will be invoked.
  * <0 : An error occured when trying to set up the connection. The callback will not be invoked.
  * Function returns
  *  0 : The connection was initiated. Once the connection establish finishes, the callback will be invoked.
  * <0 : An error occured when trying to set up the connection. The callback will not be invoked.
@@ -136,11 +136,11 @@ int rpc_disconnect(struct rpc_context *rpc, char *error);
  * RPC_STATUS_CANCEL : The connection attempt was aborted before it could complete.
  *                     data is NULL.
  */
  * RPC_STATUS_CANCEL : The connection attempt was aborted before it could complete.
  *                     data is NULL.
  */
-EXTERN int rpc_pmap_null_async(struct rpc_context *rpc, rpc_cb cb, void *private_data);
+EXTERN int rpc_pmap2_null_async(struct rpc_context *rpc, rpc_cb cb, void *private_data);
 
 
 /*
 
 
 /*
- * Call PORTMAPPER/GETPORT.
+ * Call PORTMAPPER2/GETPORT.
  * Function returns
  *  0 : The connection was initiated. Once the connection establish finishes, the callback will be invoked.
  * <0 : An error occured when trying to set up the connection. The callback will not be invoked.
  * Function returns
  *  0 : The connection was initiated. Once the connection establish finishes, the callback will be invoked.
  * <0 : An error occured when trying to set up the connection. The callback will not be invoked.
@@ -153,10 +153,10 @@ EXTERN int rpc_pmap_null_async(struct rpc_context *rpc, rpc_cb cb, void *private
  * RPC_STATUS_CANCEL : The connection attempt was aborted before it could complete.
  *                     data is NULL.
  */
  * RPC_STATUS_CANCEL : The connection attempt was aborted before it could complete.
  *                     data is NULL.
  */
-EXTERN int rpc_pmap_getport_async(struct rpc_context *rpc, int program, int version, int protocol, rpc_cb cb, void *private_data);
+EXTERN int rpc_pmap2_getport_async(struct rpc_context *rpc, int program, int version, int protocol, rpc_cb cb, void *private_data);
 
 /*
 
 /*
- * Call PORTMAPPER/SET
+ * Call PORTMAPPER2/SET
  * Function returns
  *  0 : The connection was initiated. Once the connection establish finishes, the callback will be invoked.
  * <0 : An error occured when trying to set up the connection. The callback will not be invoked.
  * Function returns
  *  0 : The connection was initiated. Once the connection establish finishes, the callback will be invoked.
  * <0 : An error occured when trying to set up the connection. The callback will not be invoked.
@@ -169,10 +169,10 @@ EXTERN int rpc_pmap_getport_async(struct rpc_context *rpc, int program, int vers
  * RPC_STATUS_CANCEL : The connection attempt was aborted before it could complete.
  *                     data is NULL.
  */
  * RPC_STATUS_CANCEL : The connection attempt was aborted before it could complete.
  *                     data is NULL.
  */
-EXTERN int rpc_pmap_set_async(struct rpc_context *rpc, int program, int version, int protocol, int port, rpc_cb cb, void *private_data);
+EXTERN int rpc_pmap2_set_async(struct rpc_context *rpc, int program, int version, int protocol, int port, rpc_cb cb, void *private_data);
 
 /*
 
 /*
- * Call PORTMAPPER/UNSET
+ * Call PORTMAPPER2/UNSET
  * Function returns
  *  0 : The connection was initiated. Once the connection establish finishes, the callback will be invoked.
  * <0 : An error occured when trying to set up the connection. The callback will not be invoked.
  * Function returns
  *  0 : The connection was initiated. Once the connection establish finishes, the callback will be invoked.
  * <0 : An error occured when trying to set up the connection. The callback will not be invoked.
@@ -185,39 +185,189 @@ EXTERN int rpc_pmap_set_async(struct rpc_context *rpc, int program, int version,
  * RPC_STATUS_CANCEL : The connection attempt was aborted before it could complete.
  *                     data is NULL.
  */
  * RPC_STATUS_CANCEL : The connection attempt was aborted before it could complete.
  *                     data is NULL.
  */
-EXTERN int rpc_pmap_unset_async(struct rpc_context *rpc, int program, int version, int protocol, int port, rpc_cb cb, void *private_data);
+EXTERN int rpc_pmap2_unset_async(struct rpc_context *rpc, int program, int version, int protocol, int port, rpc_cb cb, void *private_data);
 
 /*
 
 /*
- * Call PORTMAPPER/DUMP.
+ * Call PORTMAPPER2/DUMP.
  * Function returns
  *  0 : The connection was initiated. Once the connection establish finishes, the callback will be invoked.
  * <0 : An error occured when trying to set up the connection. The callback will not be invoked.
  *
  * When the callback is invoked, status indicates the result:
  * RPC_STATUS_SUCCESS : We got a successful response from the portmapper daemon.
  * Function returns
  *  0 : The connection was initiated. Once the connection establish finishes, the callback will be invoked.
  * <0 : An error occured when trying to set up the connection. The callback will not be invoked.
  *
  * When the callback is invoked, status indicates the result:
  * RPC_STATUS_SUCCESS : We got a successful response from the portmapper daemon.
- *                      data is struct *pmap_mapping_list.
+ *                      data is struct pmap2_dump_result.
  * RPC_STATUS_ERROR   : An error occured when trying to contact the portmapper.
  *                      data is the error string.
  * RPC_STATUS_CANCEL : The connection attempt was aborted before it could complete.
  *                     data is NULL.
  */
  * RPC_STATUS_ERROR   : An error occured when trying to contact the portmapper.
  *                      data is the error string.
  * RPC_STATUS_CANCEL : The connection attempt was aborted before it could complete.
  *                     data is NULL.
  */
-EXTERN int rpc_pmap_dump_async(struct rpc_context *rpc, rpc_cb cb, void *private_data);
+EXTERN int rpc_pmap2_dump_async(struct rpc_context *rpc, rpc_cb cb, void *private_data);
 
 /*
 
 /*
- * Call PORTMAPPER/CALLIT.
+ * Call PORTMAPPER2/CALLIT.
  * Function returns
  *  0 : The connection was initiated. Once the connection establish finishes, the callback will be invoked.
  * <0 : An error occured when trying to set up the connection. The callback will not be invoked.
  *
  * When the callback is invoked, status indicates the result:
  * RPC_STATUS_SUCCESS : We got a successful response from the portmapper daemon
  * Function returns
  *  0 : The connection was initiated. Once the connection establish finishes, the callback will be invoked.
  * <0 : An error occured when trying to set up the connection. The callback will not be invoked.
  *
  * When the callback is invoked, status indicates the result:
  * RPC_STATUS_SUCCESS : We got a successful response from the portmapper daemon
- *                      data is a 'pmap_call_result' pointer.
+ *                      data is a 'pmap2_call_result' pointer.
  * RPC_STATUS_ERROR   : An error occured when trying to contact the portmapper.
  *                      data is the error string.
  * RPC_STATUS_CANCEL : The connection attempt was aborted before it could complete.
  *                     data is NULL.
  */
  * RPC_STATUS_ERROR   : An error occured when trying to contact the portmapper.
  *                      data is the error string.
  * RPC_STATUS_CANCEL : The connection attempt was aborted before it could complete.
  *                     data is NULL.
  */
-EXTERN int rpc_pmap_callit_async(struct rpc_context *rpc, int program, int version, int procedure, char *data, int datalen, rpc_cb cb, void *private_data);
+EXTERN int rpc_pmap2_callit_async(struct rpc_context *rpc, int program, int version, int procedure, char *data, int datalen, rpc_cb cb, void *private_data);
+
+/*
+ * PORTMAP v3 FUNCTIONS
+ */
+
+/*
+ * Call PORTMAPPER3/NULL
+ * Function returns
+ *  0 : The connection was initiated. Once the connection establish finishes, the callback will be invoked.
+ * <0 : An error occured when trying to set up the connection. The callback will not be invoked.
+ *
+ * When the callback is invoked, status indicates the result:
+ * RPC_STATUS_SUCCESS : We got a successful response from the portmapper daemon.
+ *                      data is NULL.
+ * RPC_STATUS_ERROR   : An error occured when trying to contact the portmapper.
+ *                      data is the error string.
+ * RPC_STATUS_CANCEL : The connection attempt was aborted before it could complete.
+ *                     data is NULL.
+ */
+EXTERN int rpc_pmap3_null_async(struct rpc_context *rpc, rpc_cb cb, void *private_data);
+
+/*
+ * Call PORTMAPPER3/SET.
+ * Function returns
+ *  0 : The connection was initiated. Once the connection establish finishes, the callback will be invoked.
+ * <0 : An error occured when trying to set up the connection. The callback will not be invoked.
+ *
+ * When the callback is invoked, status indicates the result:
+ * RPC_STATUS_SUCCESS : We got a successful response from the portmapper daemon.
+ *                      data is uint32_t *
+ * RPC_STATUS_ERROR   : An error occured when trying to contact the portmapper.
+ *                      data is the error string.
+ * RPC_STATUS_CANCEL : The connection attempt was aborted before it could complete.
+ *                     data is NULL.
+ */
+struct pmap3_mapping;
+EXTERN int rpc_pmap3_set_async(struct rpc_context *rpc, struct pmap3_mapping *map, rpc_cb cb, void *private_data);
+
+/*
+ * Call PORTMAPPER3/UNSET.
+ * Function returns
+ *  0 : The connection was initiated. Once the connection establish finishes, the callback will be invoked.
+ * <0 : An error occured when trying to set up the connection. The callback will not be invoked.
+ *
+ * When the callback is invoked, status indicates the result:
+ * RPC_STATUS_SUCCESS : We got a successful response from the portmapper daemon.
+ *                      data is uint32_t *
+ * RPC_STATUS_ERROR   : An error occured when trying to contact the portmapper.
+ *                      data is the error string.
+ * RPC_STATUS_CANCEL : The connection attempt was aborted before it could complete.
+ *                     data is NULL.
+ */
+EXTERN int rpc_pmap3_unset_async(struct rpc_context *rpc, struct pmap3_mapping *map, rpc_cb cb, void *private_data);
+
+/*
+ * Call PORTMAPPER3/GETADDR.
+ * Function returns
+ *  0 : The connection was initiated. Once the connection establish finishes, the callback will be invoked.
+ * <0 : An error occured when trying to set up the connection. The callback will not be invoked.
+ *
+ * When the callback is invoked, status indicates the result:
+ * RPC_STATUS_SUCCESS : We got a successful response from the portmapper daemon.
+ *                      data is struct pmap3_string_result.
+ * RPC_STATUS_ERROR   : An error occured when trying to contact the portmapper.
+ *                      data is the error string.
+ * RPC_STATUS_CANCEL : The connection attempt was aborted before it could complete.
+ *                     data is NULL.
+ */
+EXTERN int rpc_pmap3_getaddr_async(struct rpc_context *rpc, struct pmap3_mapping *map, rpc_cb cb, void *private_data);
+
+/*
+ * Call PORTMAPPER3/DUMP.
+ * Function returns
+ *  0 : The connection was initiated. Once the connection establish finishes, the callback will be invoked.
+ * <0 : An error occured when trying to set up the connection. The callback will not be invoked.
+ *
+ * When the callback is invoked, status indicates the result:
+ * RPC_STATUS_SUCCESS : We got a successful response from the portmapper daemon.
+ *                      data is struct pmap3_dump_result.
+ * RPC_STATUS_ERROR   : An error occured when trying to contact the portmapper.
+ *                      data is the error string.
+ * RPC_STATUS_CANCEL : The connection attempt was aborted before it could complete.
+ *                     data is NULL.
+ */
+EXTERN int rpc_pmap3_dump_async(struct rpc_context *rpc, rpc_cb cb, void *private_data);
+
+/*
+ * Call PORTMAPPER3/CALLIT.
+ * Function returns
+ *  0 : The connection was initiated. Once the connection establish finishes, the callback will be invoked.
+ * <0 : An error occured when trying to set up the connection. The callback will not be invoked.
+ *
+ * When the callback is invoked, status indicates the result:
+ * RPC_STATUS_SUCCESS : We got a successful response from the portmapper daemon
+ *                      data is a 'pmap3_call_result' pointer.
+ * RPC_STATUS_ERROR   : An error occured when trying to contact the portmapper.
+ *                      data is the error string.
+ * RPC_STATUS_CANCEL : The connection attempt was aborted before it could complete.
+ *                     data is NULL.
+ */
+EXTERN int rpc_pmap3_callit_async(struct rpc_context *rpc, int program, int version, int procedure, char *data, int datalen, rpc_cb cb, void *private_data);
+
+/*
+ * Call PORTMAPPER3/GETTIME.
+ * Function returns
+ *  0 : The connection was initiated. Once the connection establish finishes, the callback will be invoked.
+ * <0 : An error occured when trying to set up the connection. The callback will not be invoked.
+ *
+ * When the callback is invoked, status indicates the result:
+ * RPC_STATUS_SUCCESS : We got a successful response from the portmapper daemon.
+ *                      data is a uint32_t *.
+ * RPC_STATUS_ERROR   : An error occured when trying to contact the portmapper.
+ *                      data is the error string.
+ * RPC_STATUS_CANCEL : The connection attempt was aborted before it could complete.
+ *                     data is NULL.
+ */
+EXTERN int rpc_pmap3_gettime_async(struct rpc_context *rpc, rpc_cb cb, void *private_data);
+
+/*
+ * Call PORTMAPPER3/UADDR2TADDR.
+ * Function returns
+ *  0 : The connection was initiated. Once the connection establish finishes, the callback will be invoked.
+ * <0 : An error occured when trying to set up the connection. The callback will not be invoked.
+ *
+ * When the callback is invoked, status indicates the result:
+ * RPC_STATUS_SUCCESS : We got a successful response from the portmapper daemon.
+ *                      data is a struct pmap3_netbuf *.
+ * RPC_STATUS_ERROR   : An error occured when trying to contact the portmapper.
+ *                      data is the error string.
+ * RPC_STATUS_CANCEL : The connection attempt was aborted before it could complete.
+ *                     data is NULL.
+ */
+EXTERN int rpc_pmap3_uaddr2taddr_async(struct rpc_context *rpc, char *uaddr, rpc_cb cb, void *private_data);
+
+/*
+ * Call PORTMAPPER3/TADDR2UADDR.
+ * Function returns
+ *  0 : The connection was initiated. Once the connection establish finishes, the callback will be invoked.
+ * <0 : An error occured when trying to set up the connection. The callback will not be invoked.
+ *
+ * When the callback is invoked, status indicates the result:
+ * RPC_STATUS_SUCCESS : We got a successful response from the portmapper daemon.
+ *                      data is a struct pmap3_string_result *.
+ * RPC_STATUS_ERROR   : An error occured when trying to contact the portmapper.
+ *                      data is the error string.
+ * RPC_STATUS_CANCEL : The connection attempt was aborted before it could complete.
+ *                     data is NULL.
+ */
+struct pmap3_netbuf;
+EXTERN int rpc_pmap3_taddr2uaddr_async(struct rpc_context *rpc, struct pmap3_netbuf *netbuf, rpc_cb cb, void *private_data);
 
 /*
  * MOUNT v3 FUNCTIONS
 
 /*
  * MOUNT v3 FUNCTIONS
index 406fcdfa0b4525bab3e582f5cdc0f6a903634cd6..dfa2185a06b57854be7f3aea6a9df5291065fbde 100644 (file)
 #if defined(AROS)
 #include <sys/time.h>
 #endif
 #if defined(AROS)
 #include <sys/time.h>
 #endif
+#if defined(__APPLE__) && defined(__MACH__)
+#include <sys/time.h>
+#endif
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
+#define LIBNFS_FEATURE_READAHEAD
+#define NFS_BLKSIZE 4096
+
 struct nfs_context;
 struct rpc_context;
 
 struct nfs_context;
 struct rpc_context;
 
@@ -181,6 +187,7 @@ EXTERN uint64_t nfs_get_writemax(struct nfs_context *nfs);
 EXTERN void nfs_set_tcp_syncnt(struct nfs_context *nfs, int v);
 EXTERN void nfs_set_uid(struct nfs_context *nfs, int uid);
 EXTERN void nfs_set_gid(struct nfs_context *nfs, int gid);
 EXTERN void nfs_set_tcp_syncnt(struct nfs_context *nfs, int v);
 EXTERN void nfs_set_uid(struct nfs_context *nfs, int uid);
 EXTERN void nfs_set_gid(struct nfs_context *nfs, int gid);
+EXTERN void nfs_set_readahead(struct nfs_context *nfs, uint32_t v);
 
 /*
  * MOUNT THE EXPORT
 
 /*
  * MOUNT THE EXPORT
@@ -322,13 +329,15 @@ EXTERN int nfs_fstat(struct nfs_context *nfs, struct nfsfh *nfsfh, struct stat *
 /*
  * Async open(<filename>)
  *
 /*
  * Async open(<filename>)
  *
- * mode is a combination of the flags : O_RDOLNY, O_WRONLY, O_RDWR , O_SYNC
+ * mode is a combination of the flags :
+ * O_RDOLNY, O_WRONLY, O_RDWR , O_SYNC, O_APPEND
  *
  * Function returns
  *  0 : The operation was initiated. Once the operation finishes, the callback will be invoked.
  * <0 : An error occured when trying to set up the operation. The callback will not be invoked.
  *
  * Supported flags are
  *
  * Function returns
  *  0 : The operation was initiated. Once the operation finishes, the callback will be invoked.
  * <0 : An error occured when trying to set up the operation. The callback will not be invoked.
  *
  * Supported flags are
+ * O_APPEND
  * O_RDONLY
  * O_WRONLY
  * O_RDWR
  * O_RDONLY
  * O_WRONLY
  * O_RDWR
@@ -504,14 +513,14 @@ EXTERN int nfs_write(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t coun
  * -errno : An error occured.
  *          data is the error string.
  */
  * -errno : An error occured.
  *          data is the error string.
  */
-EXTERN int nfs_lseek_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offset, int whence, nfs_cb cb, void *private_data);
+EXTERN int nfs_lseek_async(struct nfs_context *nfs, struct nfsfh *nfsfh, int64_t offset, int whence, nfs_cb cb, void *private_data);
 /*
  * Sync lseek()
  * Function returns
  *    >=0 : numer of bytes read.
  * -errno : An error occured.
  */
 /*
  * Sync lseek()
  * Function returns
  *    >=0 : numer of bytes read.
  * -errno : An error occured.
  */
-EXTERN int nfs_lseek(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offset, int whence, uint64_t *current_offset);
+EXTERN int nfs_lseek(struct nfs_context *nfs, struct nfsfh *nfsfh, int64_t offset, int whence, uint64_t *current_offset);
 
 
 /*
 
 
 /*
@@ -776,6 +785,7 @@ struct nfsdirent  {
        struct timeval ctime;
        uint32_t uid;
        uint32_t gid;
        struct timeval ctime;
        uint32_t uid;
        uint32_t gid;
+       uint32_t nlink;
 };
 /*
  * nfs_readdir() never blocks, so no special sync/async versions are available
 };
 /*
  * nfs_readdir() never blocks, so no special sync/async versions are available
index 8bb6ca480cdf2740115510fd8e0e100604714b80..5755ca14e3b6edef9b4488329a417c6bfa3a03a8 100644 (file)
 #ifndef _LIBNFS_SLIST_H_
 #define _LIBNFS_SLIST_H_
 
 #ifndef _LIBNFS_SLIST_H_
 #define _LIBNFS_SLIST_H_
 
-#define SLIST_ADD(list, item) \
+#define LIBNFS_LIST_ADD(list, item) \
        do {                                                    \
                (item)->next = (*list);                         \
                (*list) = (item);                               \
        } while (0);
 
        do {                                                    \
                (item)->next = (*list);                         \
                (*list) = (item);                               \
        } while (0);
 
-#define SLIST_ADD_END(list, item)                              \
+#define LIBNFS_LIST_ADD_END(list, item)                                \
        if ((*list) == NULL) {                                  \
        if ((*list) == NULL) {                                  \
-          SLIST_ADD((list), (item));                           \
+          LIBNFS_LIST_ADD((list), (item));                             \
        } else {                                                \
           void *head = (*list);                                \
           while ((*list)->next)                                \
        } else {                                                \
           void *head = (*list);                                \
           while ((*list)->next)                                \
@@ -36,7 +36,7 @@
           (*list) = head;                                      \
        }
 
           (*list) = head;                                      \
        }
 
-#define SLIST_REMOVE(list, item) \
+#define LIBNFS_LIST_REMOVE(list, item) \
        if ((*list) == (item)) {                                \
           (*list) = (item)->next;                              \
        } else {                                                \
        if ((*list) == (item)) {                                \
           (*list) = (item)->next;                              \
        } else {                                                \
index aa0855f76c5e3b34b7cb0505bc072c4e89e5c75f..1f9a55a7d0e55515730d1c214ff24c162ab1612a 100644 (file)
@@ -18,9 +18,9 @@ libnfs_la_SOURCES = \
        pdu.c \
        socket.c
 
        pdu.c \
        socket.c
 
-SOCURRENT=4
+SOCURRENT=5
 SOREVISION=0
 SOREVISION=0
-SOAGE=0
+SOAGE=1
 libnfs_la_LDFLAGS = -version-info $(SOCURRENT):$(SOREVISION):$(SOAGE)
 libnfs_la_LIBADD = \
        ../mount/libmount.la \
 libnfs_la_LDFLAGS = -version-info $(SOCURRENT):$(SOREVISION):$(SOAGE)
 libnfs_la_LIBADD = \
        ../mount/libmount.la \
index 36d4880006d9f244b804fdf0a8b2631c2a220924..d41c4f8186acdc02261a473ae53c9b8c0288918d 100644 (file)
@@ -1,7 +1,10 @@
 /*
    Copyright (C) 2010 by Ronnie Sahlberg <ronniesahlberg@gmail.com>
 
 /*
    Copyright (C) 2010 by Ronnie Sahlberg <ronniesahlberg@gmail.com>
 
-
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation; either version 2.1 of the License, or
+   (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
 
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -49,6 +52,7 @@ struct rpc_context *rpc_init_context(void)
 {
        struct rpc_context *rpc;
        static uint32_t salt = 0;
 {
        struct rpc_context *rpc;
        static uint32_t salt = 0;
+       unsigned int i;
 
        rpc = malloc(sizeof(struct rpc_context));
        if (rpc == NULL) {
 
        rpc = malloc(sizeof(struct rpc_context));
        if (rpc == NULL) {
@@ -83,10 +87,19 @@ struct rpc_context *rpc_init_context(void)
        rpc->uid = getuid();
        rpc->gid = getgid();
 #endif
        rpc->uid = getuid();
        rpc->gid = getgid();
 #endif
+       rpc_reset_queue(&rpc->outqueue);
+       for (i = 0; i < HASHES; i++)
+               rpc_reset_queue(&rpc->waitpdu[i]);
 
        return rpc;
 }
 
 
        return rpc;
 }
 
+void rpc_set_readahead(struct rpc_context *rpc, uint32_t v)
+{
+       assert(rpc->magic == RPC_CONTEXT_MAGIC);
+
+       rpc->readahead = v;
+}
 
 struct rpc_context *rpc_init_udp_context(void)
 {
 
 struct rpc_context *rpc_init_udp_context(void)
 {
@@ -155,19 +168,27 @@ char *rpc_get_error(struct rpc_context *rpc)
 
 void rpc_error_all_pdus(struct rpc_context *rpc, char *error)
 {
 
 void rpc_error_all_pdus(struct rpc_context *rpc, char *error)
 {
-       struct rpc_pdu *pdu;
+       struct rpc_pdu *pdu, *next;
+       unsigned int i;
 
        assert(rpc->magic == RPC_CONTEXT_MAGIC);
 
 
        assert(rpc->magic == RPC_CONTEXT_MAGIC);
 
-       while((pdu = rpc->outqueue) != NULL) {
+       while ((pdu = rpc->outqueue.head) != NULL) {
                pdu->cb(rpc, RPC_STATUS_ERROR, error, pdu->private_data);
                pdu->cb(rpc, RPC_STATUS_ERROR, error, pdu->private_data);
-               SLIST_REMOVE(&rpc->outqueue, pdu);
+               rpc->outqueue.head = pdu->next;
                rpc_free_pdu(rpc, pdu);
        }
                rpc_free_pdu(rpc, pdu);
        }
-       while((pdu = rpc->waitpdu) != NULL) {
-               pdu->cb(rpc, RPC_STATUS_ERROR, error, pdu->private_data);
-               SLIST_REMOVE(&rpc->waitpdu, pdu);
-               rpc_free_pdu(rpc, pdu);
+       rpc->outqueue.tail = NULL;
+
+       for (i = 0; i < HASHES; i++) {
+               struct rpc_queue *q = &rpc->waitpdu[i];
+
+               while((pdu = q->head) != NULL) {
+                       pdu->cb(rpc, RPC_STATUS_ERROR, error, pdu->private_data);
+                       q->head = pdu->next;
+                       rpc_free_pdu(rpc, pdu);
+               }
+               q->tail = NULL;
        }
 }
 
        }
 }
 
@@ -186,7 +207,7 @@ void rpc_free_all_fragments(struct rpc_context *rpc)
        while (rpc->fragments != NULL) {
              struct rpc_fragment *fragment = rpc->fragments;
 
        while (rpc->fragments != NULL) {
              struct rpc_fragment *fragment = rpc->fragments;
 
-             SLIST_REMOVE(&rpc->fragments, fragment);
+             rpc->fragments = fragment->next;
              rpc_free_fragment(fragment);
        }
 }
              rpc_free_fragment(fragment);
        }
 }
@@ -210,25 +231,31 @@ int rpc_add_fragment(struct rpc_context *rpc, char *data, uint64_t size)
        }
 
        memcpy(fragment->data, data, fragment->size);
        }
 
        memcpy(fragment->data, data, fragment->size);
-       SLIST_ADD_END(&rpc->fragments, fragment);
+       LIBNFS_LIST_ADD_END(&rpc->fragments, fragment);
        return 0;
 }
 
 void rpc_destroy_context(struct rpc_context *rpc)
 {
        struct rpc_pdu *pdu;
        return 0;
 }
 
 void rpc_destroy_context(struct rpc_context *rpc)
 {
        struct rpc_pdu *pdu;
+       unsigned int i;
 
        assert(rpc->magic == RPC_CONTEXT_MAGIC);
 
 
        assert(rpc->magic == RPC_CONTEXT_MAGIC);
 
-       while((pdu = rpc->outqueue) != NULL) {
+       while((pdu = rpc->outqueue.head) != NULL) {
                pdu->cb(rpc, RPC_STATUS_CANCEL, NULL, pdu->private_data);
                pdu->cb(rpc, RPC_STATUS_CANCEL, NULL, pdu->private_data);
-               SLIST_REMOVE(&rpc->outqueue, pdu);
+               LIBNFS_LIST_REMOVE(&rpc->outqueue.head, pdu);
                rpc_free_pdu(rpc, pdu);
        }
                rpc_free_pdu(rpc, pdu);
        }
-       while((pdu = rpc->waitpdu) != NULL) {
-               pdu->cb(rpc, RPC_STATUS_CANCEL, NULL, pdu->private_data);
-               SLIST_REMOVE(&rpc->waitpdu, pdu);
-               rpc_free_pdu(rpc, pdu);
+
+       for (i = 0; i < HASHES; i++) {
+               struct rpc_queue *q = &rpc->waitpdu[i];
+
+               while((pdu = q->head) != NULL) {
+                       pdu->cb(rpc, RPC_STATUS_CANCEL, NULL, pdu->private_data);
+                       LIBNFS_LIST_REMOVE(&q->head, pdu);
+                       rpc_free_pdu(rpc, pdu);
+               }
        }
 
        rpc_free_all_fragments(rpc);
        }
 
        rpc_free_all_fragments(rpc);
index 7ba52225395fcfc10f715181030882240c672640..d4a54513f2647df3e3020bea932971223f3d8d70 100644 (file)
 #include "win32_compat.h"
 #endif
 
 #include "win32_compat.h"
 #endif
 
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+
 #ifdef HAVE_NET_IF_H
 #include <net/if.h>
 #endif
 #ifdef HAVE_NET_IF_H
 #include <net/if.h>
 #endif
 #include <sys/ioctl.h>
 #endif
 
 #include <sys/ioctl.h>
 #endif
 
-#ifdef HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
-
 #ifdef HAVE_POLL_H
 #include <poll.h>
 #endif
 #ifdef HAVE_POLL_H
 #include <poll.h>
 #endif
 #include "libnfs-private.h"
 
 struct sync_cb_data {
 #include "libnfs-private.h"
 
 struct sync_cb_data {
-       int is_finished;
-       int status;
-       uint64_t offset;
-       void *return_data;
-       int return_int;
+       int is_finished;
+       int status;
+       uint64_t offset;
+       void *return_data;
+       int return_int;
+       const char *call;
 };
 
 
 };
 
 
@@ -351,7 +352,7 @@ static void pread_cb(int status, struct nfs_context *nfs, void *data, void *priv
        cb_data->status = status;
 
        if (status < 0) {
        cb_data->status = status;
 
        if (status < 0) {
-               nfs_set_error(nfs, "pread call failed with \"%s\"", (char *)data);
+               nfs_set_error(nfs, "%s call failed with \"%s\"", cb_data->call, (char *)data);
                return;
        }
 
                return;
        }
 
@@ -365,6 +366,7 @@ int nfs_pread(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offset, uin
 
        cb_data.is_finished = 0;
        cb_data.return_data = buffer;
 
        cb_data.is_finished = 0;
        cb_data.return_data = buffer;
+       cb_data.call = "pread";
 
        if (nfs_pread_async(nfs, nfsfh, offset, count, pread_cb, &cb_data) != 0) {
                nfs_set_error(nfs, "nfs_pread_async failed");
 
        if (nfs_pread_async(nfs, nfsfh, offset, count, pread_cb, &cb_data) != 0) {
                nfs_set_error(nfs, "nfs_pread_async failed");
@@ -381,7 +383,20 @@ int nfs_pread(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offset, uin
  */
 int nfs_read(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t count, char *buffer)
 {
  */
 int nfs_read(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t count, char *buffer)
 {
-       return nfs_pread(nfs, nfsfh, nfs_get_current_offset(nfsfh), count, buffer);
+       struct sync_cb_data cb_data;
+
+       cb_data.is_finished = 0;
+       cb_data.return_data = buffer;
+       cb_data.call = "read";
+
+       if (nfs_read_async(nfs, nfsfh, count, pread_cb, &cb_data) != 0) {
+               nfs_set_error(nfs, "nfs_read_async failed");
+               return -1;
+       }
+
+       wait_for_nfs_reply(nfs, &cb_data);
+
+       return cb_data.status;
 }
 
 /*
 }
 
 /*
@@ -448,10 +463,8 @@ static void pwrite_cb(int status, struct nfs_context *nfs, void *data, void *pri
        cb_data->is_finished = 1;
        cb_data->status = status;
 
        cb_data->is_finished = 1;
        cb_data->status = status;
 
-       if (status < 0) {
-               nfs_set_error(nfs, "pwrite call failed with \"%s\"", (char *)data);
-               return;
-       }
+       if (status < 0)
+               nfs_set_error(nfs, "%s call failed with \"%s\"", cb_data->call, (char *)data);
 }
 
 int nfs_pwrite(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offset, uint64_t count, char *buf)
 }
 
 int nfs_pwrite(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offset, uint64_t count, char *buf)
@@ -459,6 +472,7 @@ int nfs_pwrite(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offset, ui
        struct sync_cb_data cb_data;
 
        cb_data.is_finished = 0;
        struct sync_cb_data cb_data;
 
        cb_data.is_finished = 0;
+       cb_data.call = "pwrite";
 
        if (nfs_pwrite_async(nfs, nfsfh, offset, count, buf, pwrite_cb, &cb_data) != 0) {
                nfs_set_error(nfs, "nfs_pwrite_async failed");
 
        if (nfs_pwrite_async(nfs, nfsfh, offset, count, buf, pwrite_cb, &cb_data) != 0) {
                nfs_set_error(nfs, "nfs_pwrite_async failed");
@@ -475,7 +489,19 @@ int nfs_pwrite(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offset, ui
  */
 int nfs_write(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t count, char *buf)
 {
  */
 int nfs_write(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t count, char *buf)
 {
-       return nfs_pwrite(nfs, nfsfh, nfs_get_current_offset(nfsfh), count, buf);
+       struct sync_cb_data cb_data;
+
+       cb_data.is_finished = 0;
+       cb_data.call = "write";
+
+       if (nfs_write_async(nfs, nfsfh, count, buf, pwrite_cb, &cb_data) != 0) {
+               nfs_set_error(nfs, "nfs_write_async failed");
+               return -1;
+       }
+
+       wait_for_nfs_reply(nfs, &cb_data);
+
+       return cb_data.status;
 }
 
 
 }
 
 
@@ -813,7 +839,7 @@ static void lseek_cb(int status, struct nfs_context *nfs, void *data, void *priv
        }
 }
 
        }
 }
 
-int nfs_lseek(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offset, int whence, uint64_t *current_offset)
+int nfs_lseek(struct nfs_context *nfs, struct nfsfh *nfsfh, int64_t offset, int whence, uint64_t *current_offset)
 {
        struct sync_cb_data cb_data;
 
 {
        struct sync_cb_data cb_data;
 
@@ -1328,7 +1354,7 @@ void free_nfs_srvr_list(struct nfs_server_list *srv)
                free(srv);
                srv = next;
        }
                free(srv);
                srv = next;
        }
-}           
+}
 
 struct nfs_list_data {
        int status;
 
 struct nfs_list_data {
        int status;
@@ -1364,7 +1390,7 @@ void callit_cb(struct rpc_context *rpc, int status, void *data _U_, void *privat
                srv_data->status = -1;
                return;
        }
                srv_data->status = -1;
                return;
        }
-       
+
        /* check for dupes */
        for (srvr = srv_data->srvrs; srvr; srvr = srvr->next) {
                if (!strcmp(hostdd, srvr->addr)) {
        /* check for dupes */
        for (srvr = srv_data->srvrs; srvr; srvr = srvr->next) {
                if (!strcmp(hostdd, srvr->addr)) {
@@ -1374,7 +1400,7 @@ void callit_cb(struct rpc_context *rpc, int status, void *data _U_, void *privat
 
        srvr = malloc(sizeof(struct nfs_server_list));
        if (srvr == NULL) {
 
        srvr = malloc(sizeof(struct nfs_server_list));
        if (srvr == NULL) {
-               rpc_set_error(rpc, "Malloc failed when allocating server structure");   
+               rpc_set_error(rpc, "Malloc failed when allocating server structure");
                srv_data->status = -1;
                return;
        }
                srv_data->status = -1;
                return;
        }
@@ -1399,7 +1425,7 @@ static int send_nfsd_probes(struct rpc_context *rpc, INTERFACE_INFO *InterfaceLi
 
   assert(rpc->magic == RPC_CONTEXT_MAGIC);
 
 
   assert(rpc->magic == RPC_CONTEXT_MAGIC);
 
-  for(i = 0; i < numIfs; i++) 
+  for(i = 0; i < numIfs; i++)
   {
     SOCKADDR *pAddress;
     char bcdd[16];
   {
     SOCKADDR *pAddress;
     char bcdd[16];
@@ -1409,35 +1435,35 @@ static int send_nfsd_probes(struct rpc_context *rpc, INTERFACE_INFO *InterfaceLi
 
     if(pAddress->sa_family != AF_INET)
       continue;
 
     if(pAddress->sa_family != AF_INET)
       continue;
-               
+
     nFlags = InterfaceList[i].iiFlags;
 
     nFlags = InterfaceList[i].iiFlags;
 
-    if (!(nFlags & IFF_UP)) 
+    if (!(nFlags & IFF_UP))
     {
       continue;
     }
 
     {
       continue;
     }
 
-    if (nFlags & IFF_LOOPBACK) 
+    if (nFlags & IFF_LOOPBACK)
     {
       continue;
     }
 
     {
       continue;
     }
 
-    if (!(nFlags & IFF_BROADCAST)) 
+    if (!(nFlags & IFF_BROADCAST))
     {
       continue;
     }
 
     {
       continue;
     }
 
-    if (getnameinfo(pAddress, sizeof(struct sockaddr_in), &bcdd[0], sizeof(bcdd), NULL, 0, NI_NUMERICHOST) < 0) 
+    if (getnameinfo(pAddress, sizeof(struct sockaddr_in), &bcdd[0], sizeof(bcdd), NULL, 0, NI_NUMERICHOST) < 0)
     {
       continue;
     }
 
     {
       continue;
     }
 
-    if (rpc_set_udp_destination(rpc, bcdd, 111, 1) < 0) 
+    if (rpc_set_udp_destination(rpc, bcdd, 111, 1) < 0)
     {
       return -1;
     }
 
     {
       return -1;
     }
 
-    if (rpc_pmap_callit_async(rpc, MOUNT_PROGRAM, 2, 0, NULL, 0, callit_cb, data) < 0) 
+    if (rpc_pmap2_callit_async(rpc, MOUNT_PROGRAM, 2, 0, NULL, 0, callit_cb, data) < 0)
     {
       return -1;
     }
     {
       return -1;
     }
@@ -1457,34 +1483,34 @@ struct nfs_server_list *nfs_find_local_servers(void)
   int nNumInterfaces = 0;
 
   rpc = rpc_init_udp_context();
   int nNumInterfaces = 0;
 
   rpc = rpc_init_udp_context();
-  if (rpc == NULL) 
+  if (rpc == NULL)
   {
     return NULL;
   }
 
   {
     return NULL;
   }
 
-  if (rpc_bind_udp(rpc, "0.0.0.0", 0) < 0) 
+  if (rpc_bind_udp(rpc, "0.0.0.0", 0) < 0)
   {
     rpc_destroy_context(rpc);
     return NULL;
   }
 
   {
     rpc_destroy_context(rpc);
     return NULL;
   }
 
-  if (WSAIoctl(rpc_get_fd(rpc), SIO_GET_INTERFACE_LIST, 0, 0, &InterfaceList, sizeof(InterfaceList), &nBytesReturned, 0, 0) == SOCKET_ERROR) 
+  if (WSAIoctl(rpc_get_fd(rpc), SIO_GET_INTERFACE_LIST, 0, 0, &InterfaceList, sizeof(InterfaceList), &nBytesReturned, 0, 0) == SOCKET_ERROR)
   {
     return NULL;
   }
 
   nNumInterfaces = nBytesReturned / sizeof(INTERFACE_INFO);
 
   {
     return NULL;
   }
 
   nNumInterfaces = nBytesReturned / sizeof(INTERFACE_INFO);
 
-  for (loop=0; loop<3; loop++) 
+  for (loop=0; loop<3; loop++)
   {
   {
-    if (send_nfsd_probes(rpc, InterfaceList, nNumInterfaces, &data) != 0) 
+    if (send_nfsd_probes(rpc, InterfaceList, nNumInterfaces, &data) != 0)
     {
       rpc_destroy_context(rpc);
       return NULL;
     }
 
     win32_gettimeofday(&tv_start, NULL);
     {
       rpc_destroy_context(rpc);
       return NULL;
     }
 
     win32_gettimeofday(&tv_start, NULL);
-    for(;;) 
+    for(;;)
     {
       int mpt;
 
     {
       int mpt;
 
@@ -1496,18 +1522,18 @@ struct nfs_server_list *nfs_find_local_servers(void)
       -    (tv_current.tv_sec *1000 + tv_current.tv_usec / 1000)
       +    (tv_start.tv_sec *1000 + tv_start.tv_usec / 1000);
 
       -    (tv_current.tv_sec *1000 + tv_current.tv_usec / 1000)
       +    (tv_start.tv_sec *1000 + tv_start.tv_usec / 1000);
 
-      if (poll(&pfd, 1, mpt) < 0) 
+      if (poll(&pfd, 1, mpt) < 0)
       {
         free_nfs_srvr_list(data.srvrs);
         rpc_destroy_context(rpc);
         return NULL;
       }
       {
         free_nfs_srvr_list(data.srvrs);
         rpc_destroy_context(rpc);
         return NULL;
       }
-      if (pfd.revents == 0) 
+      if (pfd.revents == 0)
       {
         break;
       }
       {
         break;
       }
-               
-      if (rpc_service(rpc, pfd.revents) < 0) 
+
+      if (rpc_service(rpc, pfd.revents) < 0)
       {
         break;
       }
       {
         break;
       }
@@ -1516,7 +1542,7 @@ struct nfs_server_list *nfs_find_local_servers(void)
 
   rpc_destroy_context(rpc);
 
 
   rpc_destroy_context(rpc);
 
-  if (data.status != 0) 
+  if (data.status != 0)
   {
     free_nfs_srvr_list(data.srvrs);
     return NULL;
   {
     free_nfs_srvr_list(data.srvrs);
     return NULL;
@@ -1571,7 +1597,7 @@ static int send_nfsd_probes(struct rpc_context *rpc, struct ifconf *ifc, struct
                        return -1;
                }
 
                        return -1;
                }
 
-               if (rpc_pmap_callit_async(rpc, MOUNT_PROGRAM, 2, 0, NULL, 0, callit_cb, data) < 0) {
+               if (rpc_pmap2_callit_async(rpc, MOUNT_PROGRAM, 2, 0, NULL, 0, callit_cb, data) < 0) {
                        return -1;
                }
        }
                        return -1;
                }
        }
@@ -1607,21 +1633,21 @@ struct nfs_server_list *nfs_find_local_servers(void)
        while(ifc.ifc_len > (size - sizeof(struct ifreq))) {
                size *= 2;
 
        while(ifc.ifc_len > (size - sizeof(struct ifreq))) {
                size *= 2;
 
-               free(ifc.ifc_buf);      
+               free(ifc.ifc_buf);
                ifc.ifc_len = size;
                ifc.ifc_buf = malloc(size);
                memset(ifc.ifc_buf, 0, size);
                if (ioctl(rpc_get_fd(rpc), SIOCGIFCONF, (caddr_t)&ifc) < 0) {
                        rpc_destroy_context(rpc);
                ifc.ifc_len = size;
                ifc.ifc_buf = malloc(size);
                memset(ifc.ifc_buf, 0, size);
                if (ioctl(rpc_get_fd(rpc), SIOCGIFCONF, (caddr_t)&ifc) < 0) {
                        rpc_destroy_context(rpc);
-                       free(ifc.ifc_buf);      
+                       free(ifc.ifc_buf);
                        return NULL;
                }
                        return NULL;
                }
-       }       
+       }
 
        for (loop=0; loop<3; loop++) {
                if (send_nfsd_probes(rpc, &ifc, &data) != 0) {
                        rpc_destroy_context(rpc);
 
        for (loop=0; loop<3; loop++) {
                if (send_nfsd_probes(rpc, &ifc, &data) != 0) {
                        rpc_destroy_context(rpc);
-                       free(ifc.ifc_buf);      
+                       free(ifc.ifc_buf);
                        return NULL;
                }
 
                        return NULL;
                }
 
@@ -1645,14 +1671,14 @@ struct nfs_server_list *nfs_find_local_servers(void)
                        if (pfd.revents == 0) {
                                break;
                        }
                        if (pfd.revents == 0) {
                                break;
                        }
-               
+
                        if (rpc_service(rpc, pfd.revents) < 0) {
                                break;
                        }
                }
        }
 
                        if (rpc_service(rpc, pfd.revents) < 0) {
                                break;
                        }
                }
        }
 
-       free(ifc.ifc_buf);      
+       free(ifc.ifc_buf);
        rpc_destroy_context(rpc);
 
        if (data.status != 0) {
        rpc_destroy_context(rpc);
 
        if (data.status != 0) {
index 7eae9520c9a85d4b47d8267b3300364e4bf0acaa..5a0df03018c64bfd58665841a66a9a27c6a8de12 100644 (file)
@@ -70,6 +70,7 @@ nfs_set_auth
 nfs_set_gid
 nfs_set_tcp_syncnt
 nfs_set_uid
 nfs_set_gid
 nfs_set_tcp_syncnt
 nfs_set_uid
+nfs_set_readahead
 nfs_stat
 nfs_stat_async
 nfs_stat64
 nfs_stat
 nfs_stat_async
 nfs_stat64
@@ -96,12 +97,21 @@ rpc_disconnect
 rpc_get_error
 rpc_get_fd
 rpc_init_context
 rpc_get_error
 rpc_get_fd
 rpc_init_context
-rpc_pmap_null_async
-rpc_pmap_getport_async
-rpc_pmap_set_async
-rpc_pmap_unset_async
-rpc_pmap_dump_async
-rpc_pmap_callit_async
+rpc_pmap2_null_async
+rpc_pmap2_getport_async
+rpc_pmap2_set_async
+rpc_pmap2_unset_async
+rpc_pmap2_dump_async
+rpc_pmap2_callit_async
+rpc_pmap3_null_async
+rpc_pmap3_set_async
+rpc_pmap3_unset_async
+rpc_pmap3_getaddr_async
+rpc_pmap3_dump_async
+rpc_pmap3_callit_async
+rpc_pmap3_gettime_async
+rpc_pmap3_uaddr2taddr_async
+rpc_pmap3_taddr2uaddr_async
 rpc_mount_null_async
 rpc_mount_mnt_async
 rpc_mount_dump_async
 rpc_mount_null_async
 rpc_mount_mnt_async
 rpc_mount_dump_async
index bb89d4a8c10bb34fd541801af242d7d3704ce1f6..94f03cb520455600f5d27c93301e8fecc1122dfb 100644 (file)
 #include <sys/stat.h>
 #include <fcntl.h>
 #include "libnfs-zdr.h"
 #include <sys/stat.h>
 #include <fcntl.h>
 #include "libnfs-zdr.h"
+#include "slist.h"
 #include "libnfs.h"
 #include "libnfs-raw.h"
 #include "libnfs-raw-mount.h"
 #include "libnfs-raw-nfs.h"
 #include "libnfs.h"
 #include "libnfs-raw.h"
 #include "libnfs-raw-mount.h"
 #include "libnfs-raw-nfs.h"
+#include "libnfs-raw-portmap.h"
 #include "libnfs-private.h"
 
 #include "libnfs-private.h"
 
+#define MAX_DIR_CACHE 128
+
 struct nfsdir {
 struct nfsdir {
+       struct nfs_fh3 fh;
+       fattr3 attr;
+       struct nfsdir *next;
+
        struct nfsdirent *entries;
        struct nfsdirent *current;
 };
 
        struct nfsdirent *entries;
        struct nfsdirent *current;
 };
 
+struct nfs_readahead {
+       uint64_t fh_offset;
+       uint64_t last_offset;
+       uint64_t buf_offset;
+       uint64_t buf_count;
+       time_t buf_ts;
+       void *buf;
+       uint32_t cur_ra;
+};
+
 struct nfsfh {
        struct nfs_fh3 fh;
        int is_sync;
 struct nfsfh {
        struct nfs_fh3 fh;
        int is_sync;
+       int is_append;
        uint64_t offset;
        uint64_t offset;
+       struct nfs_readahead ra;
 };
 
 struct nfs_context {
 };
 
 struct nfs_context {
@@ -94,6 +114,7 @@ struct nfs_context {
        uint64_t readmax;
        uint64_t writemax;
        char *cwd;
        uint64_t readmax;
        uint64_t writemax;
        char *cwd;
+       struct nfsdir *dircache;
 };
 
 void nfs_free_nfsdir(struct nfsdir *nfsdir)
 };
 
 void nfs_free_nfsdir(struct nfsdir *nfsdir)
@@ -106,11 +127,42 @@ void nfs_free_nfsdir(struct nfsdir *nfsdir)
                free(nfsdir->entries);
                nfsdir->entries = dirent;
        }
                free(nfsdir->entries);
                nfsdir->entries = dirent;
        }
+       free(nfsdir->fh.data.data_val);
        free(nfsdir);
 }
 
        free(nfsdir);
 }
 
+static void nfs_dircache_add(struct nfs_context *nfs, struct nfsdir *nfsdir)
+{
+       int i;
+       LIBNFS_LIST_ADD(&nfs->dircache, nfsdir);
+
+       for (nfsdir = nfs->dircache, i = 0; nfsdir; nfsdir = nfsdir->next, i++) {
+               if (i > MAX_DIR_CACHE) {
+                       LIBNFS_LIST_REMOVE(&nfs->dircache, nfsdir);
+                       nfs_free_nfsdir(nfsdir);
+                       break;
+               }
+       }
+}
+
+static struct nfsdir *nfs_dircache_find(struct nfs_context *nfs, struct nfs_fh3 *fh)
+{
+       struct nfsdir *nfsdir;
+
+       for (nfsdir = nfs->dircache; nfsdir; nfsdir = nfsdir->next) {
+               if (nfsdir->fh.data.data_len == fh->data.data_len &&
+                   !memcmp(nfsdir->fh.data.data_val, fh->data.data_val, fh->data.data_len)) {
+                       LIBNFS_LIST_REMOVE(&nfs->dircache, nfsdir);
+                       return nfsdir;
+               }
+       }
+
+       return NULL;
+}
+
 struct nfs_cb_data;
 struct nfs_cb_data;
-typedef int (*continue_func)(struct nfs_context *nfs, struct nfs_cb_data *data);
+typedef int (*continue_func)(struct nfs_context *nfs, fattr3 *attr,
+                            struct nfs_cb_data *data);
 
 struct nfs_cb_data {
        struct nfs_context *nfs;
 
 struct nfs_cb_data {
        struct nfs_context *nfs;
@@ -132,9 +184,8 @@ struct nfs_cb_data {
        int cancel;
        int oom;
        int num_calls;
        int cancel;
        int oom;
        int num_calls;
-       uint64_t start_offset, max_offset;
+       uint64_t offset, count, max_offset, org_offset, org_count;
        char *buffer;
        char *buffer;
-       size_t request_size;
        char *usrbuf;
 };
 
        char *usrbuf;
 };
 
@@ -142,9 +193,10 @@ struct nfs_mcb_data {
        struct nfs_cb_data *data;
        uint64_t offset;
        uint64_t count;
        struct nfs_cb_data *data;
        uint64_t offset;
        uint64_t count;
+       int update_pos;
 };
 
 };
 
-static int nfs_lookup_path_async_internal(struct nfs_context *nfs, struct nfs_cb_data *data, struct nfs_fh3 *fh);
+static int nfs_lookup_path_async_internal(struct nfs_context *nfs, fattr3 *attr, struct nfs_cb_data *data, struct nfs_fh3 *fh);
 
 void nfs_set_auth(struct nfs_context *nfs, struct AUTH *auth)
 {
 
 void nfs_set_auth(struct nfs_context *nfs, struct AUTH *auth)
 {
@@ -178,12 +230,14 @@ char *nfs_get_error(struct nfs_context *nfs)
 
 static int nfs_set_context_args(struct nfs_context *nfs, char *arg, char *val)
 {
 
 static int nfs_set_context_args(struct nfs_context *nfs, char *arg, char *val)
 {
-       if (!strncmp(arg, "tcp-syncnt", 10)) {
+       if (!strcmp(arg, "tcp-syncnt")) {
                rpc_set_tcp_syncnt(nfs_get_rpc_context(nfs), atoi(val));
                rpc_set_tcp_syncnt(nfs_get_rpc_context(nfs), atoi(val));
-       } else if (!strncmp(arg, "uid", 3)) {
+       } else if (!strcmp(arg, "uid")) {
                rpc_set_uid(nfs_get_rpc_context(nfs), atoi(val));
                rpc_set_uid(nfs_get_rpc_context(nfs), atoi(val));
-       } else if (!strncmp(arg, "gid", 3)) {
+       } else if (!strcmp(arg, "gid")) {
                rpc_set_gid(nfs_get_rpc_context(nfs), atoi(val));
                rpc_set_gid(nfs_get_rpc_context(nfs), atoi(val));
+       } else if (!strcmp(arg, "readahaed")) {
+               rpc_set_readahead(nfs_get_rpc_context(nfs), atoi(val));
        }
        return 0;
 }
        }
        return 0;
 }
@@ -375,6 +429,12 @@ void nfs_destroy_context(struct nfs_context *nfs)
                nfs->rootfh.data.data_val = NULL;
        }
 
                nfs->rootfh.data.data_val = NULL;
        }
 
+       while (nfs->dircache) {
+               struct nfsdir *nfsdir = nfs->dircache;
+               LIBNFS_LIST_REMOVE(&nfs->dircache, nfsdir);
+               nfs_free_nfsdir(nfsdir);
+       }
+
        free(nfs);
 }
 
        free(nfs);
 }
 
@@ -394,6 +454,30 @@ void free_rpc_cb_data(struct rpc_cb_data *data)
        free(data);
 }
 
        free(data);
 }
 
+static void rpc_connect_program_5_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
+{
+       struct rpc_cb_data *data = private_data;
+
+       assert(rpc->magic == RPC_CONTEXT_MAGIC);
+
+       /* Dont want any more callbacks even if the socket is closed */
+       rpc->connect_cb = NULL;
+
+       if (status == RPC_STATUS_ERROR) {
+               data->cb(rpc, status, command_data, data->private_data);
+               free_rpc_cb_data(data);
+               return;
+       }
+       if (status == RPC_STATUS_CANCEL) {
+               data->cb(rpc, status, "Command was cancelled", data->private_data);
+               free_rpc_cb_data(data);
+               return;
+       }
+
+       data->cb(rpc, status, NULL, data->private_data);
+       free_rpc_cb_data(data);
+}
+
 static void rpc_connect_program_4_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
 {
        struct rpc_cb_data *data = private_data;
 static void rpc_connect_program_4_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
 {
        struct rpc_cb_data *data = private_data;
@@ -414,6 +498,25 @@ static void rpc_connect_program_4_cb(struct rpc_context *rpc, int status, void *
                return;
        }
 
                return;
        }
 
+       switch (data->program) {
+       case MOUNT_PROGRAM:
+               if (rpc_mount3_null_async(rpc, rpc_connect_program_5_cb,
+                                       data) != 0) {
+                       data->cb(rpc, status, command_data, data->private_data);
+                       free_rpc_cb_data(data);
+                       return;
+               }
+               return;
+       case NFS_PROGRAM:
+               if (rpc_nfs3_null_async(rpc, rpc_connect_program_5_cb,
+                                       data) != 0) {
+                       data->cb(rpc, status, command_data, data->private_data);
+                       free_rpc_cb_data(data);
+                       return;
+               }
+               return;
+       }
+
        data->cb(rpc, status, NULL, data->private_data);
        free_rpc_cb_data(data);
 }
        data->cb(rpc, status, NULL, data->private_data);
        free_rpc_cb_data(data);
 }
@@ -421,7 +524,9 @@ static void rpc_connect_program_4_cb(struct rpc_context *rpc, int status, void *
 static void rpc_connect_program_3_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
 {
        struct rpc_cb_data *data = private_data;
 static void rpc_connect_program_3_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
 {
        struct rpc_cb_data *data = private_data;
-       uint32_t rpc_port;
+       struct pmap3_string_result *gar;
+       uint32_t rpc_port = 0;
+       unsigned char *ptr;
 
        assert(rpc->magic == RPC_CONTEXT_MAGIC);
 
 
        assert(rpc->magic == RPC_CONTEXT_MAGIC);
 
@@ -436,7 +541,29 @@ static void rpc_connect_program_3_cb(struct rpc_context *rpc, int status, void *
                return;
        }
 
                return;
        }
 
-       rpc_port = *(uint32_t *)command_data;
+       switch (rpc->s.ss_family) {
+       case AF_INET:
+               rpc_port = *(uint32_t *)command_data;
+               break;
+       case AF_INET6:
+               /* ouch. portmapper and ipv6 are not great */
+               gar = command_data;
+               if (gar->addr == NULL) {
+                       break;
+               }
+               ptr = strrchr(gar->addr, '.');
+               if (ptr == NULL) {
+                       break;
+               }
+               rpc_port = atoi(ptr + 1);
+               *ptr = 0;
+               ptr = strrchr(gar->addr, '.');
+               if (ptr == NULL) {
+                       break;
+               }
+               rpc_port += 256 * atoi(ptr + 1);
+               break;
+       }
        if (rpc_port == 0) {
                rpc_set_error(rpc, "RPC error. Program is not available on %s", data->server);
                data->cb(rpc, RPC_STATUS_ERROR, rpc_get_error(rpc), data->private_data);
        if (rpc_port == 0) {
                rpc_set_error(rpc, "RPC error. Program is not available on %s", data->server);
                data->cb(rpc, RPC_STATUS_ERROR, rpc_get_error(rpc), data->private_data);
@@ -455,6 +582,7 @@ static void rpc_connect_program_3_cb(struct rpc_context *rpc, int status, void *
 static void rpc_connect_program_2_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
 {
        struct rpc_cb_data *data = private_data;
 static void rpc_connect_program_2_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
 {
        struct rpc_cb_data *data = private_data;
+       struct pmap3_mapping map;
 
        assert(rpc->magic == RPC_CONTEXT_MAGIC);
 
 
        assert(rpc->magic == RPC_CONTEXT_MAGIC);
 
@@ -469,10 +597,26 @@ static void rpc_connect_program_2_cb(struct rpc_context *rpc, int status, void *
                return;
        }
 
                return;
        }
 
-       if (rpc_pmap_getport_async(rpc, data->program, data->version, IPPROTO_TCP, rpc_connect_program_3_cb, private_data) != 0) {
-               data->cb(rpc, status, command_data, data->private_data);
-               free_rpc_cb_data(data);
-               return;
+       switch (rpc->s.ss_family) {
+       case AF_INET:
+               if (rpc_pmap2_getport_async(rpc, data->program, data->version, IPPROTO_TCP, rpc_connect_program_3_cb, private_data) != 0) {
+                       data->cb(rpc, status, command_data, data->private_data);
+                       free_rpc_cb_data(data);
+                       return;
+               }
+               break;
+       case AF_INET6:
+               map.prog=data->program;
+               map.vers=data->version;
+               map.netid="";
+               map.addr="";
+               map.owner="";
+               if (rpc_pmap3_getaddr_async(rpc, &map, rpc_connect_program_3_cb, private_data) != 0) {
+                       data->cb(rpc, status, command_data, data->private_data);
+                       free_rpc_cb_data(data);
+                       return;
+               }
+               break;
        }
 }
 
        }
 }
 
@@ -496,14 +640,25 @@ static void rpc_connect_program_1_cb(struct rpc_context *rpc, int status, void *
                return;
        }
 
                return;
        }
 
-       if (rpc_pmap_null_async(rpc, rpc_connect_program_2_cb, data) != 0) {
-               data->cb(rpc, status, command_data, data->private_data);
-               free_rpc_cb_data(data);
-               return;
+       switch (rpc->s.ss_family) {
+       case AF_INET:
+               if (rpc_pmap2_null_async(rpc, rpc_connect_program_2_cb, data) != 0) {
+                       data->cb(rpc, status, command_data, data->private_data);
+                       free_rpc_cb_data(data);
+                       return;
+               }
+               break;
+       case AF_INET6:
+               if (rpc_pmap3_null_async(rpc, rpc_connect_program_2_cb, data) != 0) {
+                       data->cb(rpc, status, command_data, data->private_data);
+                       free_rpc_cb_data(data);
+                       return;
+               }
+               break;
        }
 }
 
        }
 }
 
-int rpc_connect_program_async(struct rpc_context *rpc, char *server, int program, int version, rpc_cb cb, void *private_data)
+int rpc_connect_program_async(struct rpc_context *rpc, const char *server, int program, int version, rpc_cb cb, void *private_data)
 {
        struct rpc_cb_data *data;
 
 {
        struct rpc_cb_data *data;
 
@@ -542,9 +697,6 @@ static void free_nfs_cb_data(struct nfs_cb_data *data)
 }
 
 
 }
 
 
-
-
-
 static void nfs_mount_10_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
 {
        struct nfs_cb_data *data = private_data;
 static void nfs_mount_10_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
 {
        struct nfs_cb_data *data = private_data;
@@ -627,36 +779,6 @@ static void nfs_mount_8_cb(struct rpc_context *rpc, int status, void *command_da
        }
 }
 
        }
 }
 
-
-static void nfs_mount_7_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
-{
-       struct nfs_cb_data *data = private_data;
-       struct nfs_context *nfs = data->nfs;
-
-       assert(rpc->magic == RPC_CONTEXT_MAGIC);
-
-       /* Dont want any more callbacks even if the socket is closed */
-       rpc->connect_cb = NULL;
-
-       if (status == RPC_STATUS_ERROR) {
-               data->cb(-EFAULT, nfs, command_data, data->private_data);
-               free_nfs_cb_data(data);
-               return;
-       }
-       if (status == RPC_STATUS_CANCEL) {
-               data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
-               free_nfs_cb_data(data);
-               return;
-       }
-
-       if (rpc_nfs3_null_async(rpc, nfs_mount_8_cb, data) != 0) {
-               data->cb(-ENOMEM, nfs, command_data, data->private_data);
-               free_nfs_cb_data(data);
-               return;
-       }
-}
-
-
 static void nfs_mount_6_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
 {
        struct nfs_cb_data *data = private_data;
 static void nfs_mount_6_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
 {
        struct nfs_cb_data *data = private_data;
@@ -695,11 +817,13 @@ static void nfs_mount_6_cb(struct rpc_context *rpc, int status, void *command_da
        memcpy(nfs->rootfh.data.data_val, res->mountres3_u.mountinfo.fhandle.fhandle3_val, nfs->rootfh.data.data_len);
 
        rpc_disconnect(rpc, "normal disconnect");
        memcpy(nfs->rootfh.data.data_val, res->mountres3_u.mountinfo.fhandle.fhandle3_val, nfs->rootfh.data.data_len);
 
        rpc_disconnect(rpc, "normal disconnect");
-       if (rpc_connect_async(rpc, nfs->server, 2049, nfs_mount_7_cb, data) != 0) {
+
+       if (rpc_connect_program_async(nfs->rpc, nfs->server, NFS_PROGRAM, NFS_V3, nfs_mount_8_cb, data) != 0) {
                data->cb(-ENOMEM, nfs, command_data, data->private_data);
                free_nfs_cb_data(data);
                return;
        }
                data->cb(-ENOMEM, nfs, command_data, data->private_data);
                free_nfs_cb_data(data);
                return;
        }
+
        /* NFS TCP connections we want to autoreconnect after sessions are torn down (due to inactivity or error) */
        rpc_set_autoreconnect(rpc);
 }
        /* NFS TCP connections we want to autoreconnect after sessions are torn down (due to inactivity or error) */
        rpc_set_autoreconnect(rpc);
 }
@@ -730,123 +854,6 @@ static void nfs_mount_5_cb(struct rpc_context *rpc, int status, void *command_da
        }
 }
 
        }
 }
 
-static void nfs_mount_4_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
-{
-       struct nfs_cb_data *data = private_data;
-       struct nfs_context *nfs = data->nfs;
-
-       assert(rpc->magic == RPC_CONTEXT_MAGIC);
-
-       /* Dont want any more callbacks even if the socket is closed */
-       rpc->connect_cb = NULL;
-
-       if (status == RPC_STATUS_ERROR) {
-               data->cb(-EFAULT, nfs, command_data, data->private_data);
-               free_nfs_cb_data(data);
-               return;
-       }
-       if (status == RPC_STATUS_CANCEL) {
-               data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
-               free_nfs_cb_data(data);
-               return;
-       }
-
-       if (rpc_mount3_null_async(rpc, nfs_mount_5_cb, data) != 0) {
-               data->cb(-ENOMEM, nfs, command_data, data->private_data);
-               free_nfs_cb_data(data);
-               return;
-       }
-}
-
-static void nfs_mount_3_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
-{
-       struct nfs_cb_data *data = private_data;
-       struct nfs_context *nfs = data->nfs;
-       uint32_t mount_port;
-
-       assert(rpc->magic == RPC_CONTEXT_MAGIC);
-
-       if (status == RPC_STATUS_ERROR) {
-               data->cb(-EFAULT, nfs, command_data, data->private_data);
-               free_nfs_cb_data(data);
-               return;
-       }
-       if (status == RPC_STATUS_CANCEL) {
-               data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
-               free_nfs_cb_data(data);
-               return;
-       }
-
-       mount_port = *(uint32_t *)command_data;
-       if (mount_port == 0) {
-               rpc_set_error(rpc, "RPC error. Mount program is not available on %s", nfs->server);
-               data->cb(-ENOENT, nfs, command_data, data->private_data);
-               free_nfs_cb_data(data);
-               return;
-       }
-
-       rpc_disconnect(rpc, "normal disconnect");
-       if (rpc_connect_async(rpc, nfs->server, mount_port, nfs_mount_4_cb, data) != 0) {
-               data->cb(-ENOMEM, nfs, command_data, data->private_data);
-               free_nfs_cb_data(data);
-               return;
-       }
-}
-
-
-static void nfs_mount_2_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
-{
-       struct nfs_cb_data *data = private_data;
-       struct nfs_context *nfs = data->nfs;
-
-       assert(rpc->magic == RPC_CONTEXT_MAGIC);
-
-       if (status == RPC_STATUS_ERROR) {
-               data->cb(-EFAULT, nfs, command_data, data->private_data);
-               free_nfs_cb_data(data);
-               return;
-       }
-       if (status == RPC_STATUS_CANCEL) {
-               data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
-               free_nfs_cb_data(data);
-               return;
-       }
-
-       if (rpc_pmap_getport_async(rpc, MOUNT_PROGRAM, MOUNT_V3, IPPROTO_TCP, nfs_mount_3_cb, private_data) != 0) {
-               data->cb(-ENOMEM, nfs, command_data, data->private_data);
-               free_nfs_cb_data(data);
-               return;
-       }
-}
-
-static void nfs_mount_1_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
-{
-       struct nfs_cb_data *data = private_data;
-       struct nfs_context *nfs = data->nfs;
-
-       assert(rpc->magic == RPC_CONTEXT_MAGIC);
-
-       /* Dont want any more callbacks even if the socket is closed */
-       rpc->connect_cb = NULL;
-
-       if (status == RPC_STATUS_ERROR) {
-               data->cb(-EFAULT, nfs, command_data, data->private_data);
-               free_nfs_cb_data(data);
-               return;
-       }
-       if (status == RPC_STATUS_CANCEL) {
-               data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
-               free_nfs_cb_data(data);
-               return;
-       }
-
-       if (rpc_pmap_null_async(rpc, nfs_mount_2_cb, data) != 0) {
-               data->cb(-ENOMEM, nfs, command_data, data->private_data);
-               free_nfs_cb_data(data);
-               return;
-       }
-}
-
 /*
  * Async call for mounting an nfs share and geting the root filehandle
  */
 /*
  * Async call for mounting an nfs share and geting the root filehandle
  */
@@ -875,7 +882,7 @@ int nfs_mount_async(struct nfs_context *nfs, const char *server, const char *exp
        data->cb           = cb;
        data->private_data = private_data;
 
        data->cb           = cb;
        data->private_data = private_data;
 
-       if (rpc_connect_async(nfs->rpc, server, 111, nfs_mount_1_cb, data) != 0) {
+       if (rpc_connect_program_async(nfs->rpc, server, MOUNT_PROGRAM, MOUNT_V3, nfs_mount_5_cb, data) != 0) {
                rpc_set_error(nfs->rpc, "Failed to start connection");
                free_nfs_cb_data(data);
                return -1;
                rpc_set_error(nfs->rpc, "Failed to start connection");
                free_nfs_cb_data(data);
                return -1;
@@ -895,6 +902,7 @@ static void nfs_lookup_path_1_cb(struct rpc_context *rpc, int status, void *comm
        struct nfs_cb_data *data = private_data;
        struct nfs_context *nfs = data->nfs;
        LOOKUP3res *res;
        struct nfs_cb_data *data = private_data;
        struct nfs_context *nfs = data->nfs;
        LOOKUP3res *res;
+       fattr3 *attr;
 
        assert(rpc->magic == RPC_CONTEXT_MAGIC);
 
 
        assert(rpc->magic == RPC_CONTEXT_MAGIC);
 
@@ -917,15 +925,17 @@ static void nfs_lookup_path_1_cb(struct rpc_context *rpc, int status, void *comm
                return;
        }
 
                return;
        }
 
-       if (nfs_lookup_path_async_internal(nfs, data, &res->LOOKUP3res_u.resok.object) != 0) {
-               rpc_set_error(nfs->rpc, "Failed to create lookup pdu");
-               data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
-               free_nfs_cb_data(data);
-               return;
-       }
+       attr = res->LOOKUP3res_u.resok.obj_attributes.attributes_follow ?
+         &res->LOOKUP3res_u.resok.obj_attributes.post_op_attr_u.attributes :
+         NULL;
+
+       /* This function will always invoke the callback and cleanup
+        * for failures. So no need to check the return value.
+        */
+       nfs_lookup_path_async_internal(nfs, attr, data, &res->LOOKUP3res_u.resok.object);
 }
 
 }
 
-static int nfs_lookup_path_async_internal(struct nfs_context *nfs, struct nfs_cb_data *data, struct nfs_fh3 *fh)
+static int nfs_lookup_path_async_internal(struct nfs_context *nfs, fattr3 *attr _U_, struct nfs_cb_data *data, struct nfs_fh3 *fh)
 {
        char *path, *slash;
        LOOKUP3args args;
 {
        char *path, *slash;
        LOOKUP3args args;
@@ -964,11 +974,10 @@ static int nfs_lookup_path_async_internal(struct nfs_context *nfs, struct nfs_cb
                if (slash != NULL) {
                        *slash = '/';
                }
                if (slash != NULL) {
                        *slash = '/';
                }
-               data->continue_cb(nfs, data);
+               data->continue_cb(nfs, attr, data);
                return 0;
        }
 
                return 0;
        }
 
-
        memset(&args, 0, sizeof(LOOKUP3args));
        args.what.dir = *fh;
        args.what.name = path;
        memset(&args, 0, sizeof(LOOKUP3args));
        args.what.dir = *fh;
        args.what.name = path;
@@ -1043,7 +1052,7 @@ static int nfs_normalize_path(struct nfs_context *nfs, char *path)
 
        /* /$ -> \0 */
        len = strlen(path);
 
        /* /$ -> \0 */
        len = strlen(path);
-       if (len >= 1) {
+       if (len > 1) {
                if (path[len - 1] == '/') {
                        path[len - 1] = '\0';
                        len--;
                if (path[len - 1] == '/') {
                        path[len - 1] = '\0';
                        len--;
@@ -1085,9 +1094,45 @@ static int nfs_normalize_path(struct nfs_context *nfs, char *path)
        return 0;
 }
 
        return 0;
 }
 
+static void nfs_lookup_path_getattr_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
+{
+       struct nfs_cb_data *data = private_data;
+       struct nfs_context *nfs = data->nfs;
+       GETATTR3res *res;
+       fattr3 *attr;
+
+       assert(rpc->magic == RPC_CONTEXT_MAGIC);
+
+       if (status == RPC_STATUS_ERROR) {
+               data->cb(-EFAULT, nfs, command_data, data->private_data);
+               free_nfs_cb_data(data);
+               return;
+       }
+       if (status == RPC_STATUS_CANCEL) {
+               data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
+               free_nfs_cb_data(data);
+               return;
+       }
+
+       res = command_data;
+       if (res->status != NFS3_OK) {
+               rpc_set_error(nfs->rpc, "NFS: GETATTR of %s failed with %s(%d)", data->saved_path, nfsstat3_to_str(res->status), nfsstat3_to_errno(res->status));
+               data->cb(nfsstat3_to_errno(res->status), nfs, rpc_get_error(nfs->rpc), data->private_data);
+               free_nfs_cb_data(data);
+               return;
+       }
+
+       attr = &res->GETATTR3res_u.resok.obj_attributes;
+       /* This function will always invoke the callback and cleanup
+        * for failures. So no need to check the return value.
+        */
+       nfs_lookup_path_async_internal(nfs, attr, data, &nfs->rootfh);
+}
+
 static int nfs_lookuppath_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void *private_data, continue_func continue_cb, void *continue_data, void (*free_continue_data)(void *), int continue_int)
 {
        struct nfs_cb_data *data;
 static int nfs_lookuppath_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void *private_data, continue_func continue_cb, void *continue_data, void (*free_continue_data)(void *), int continue_int)
 {
        struct nfs_cb_data *data;
+       struct GETATTR3args args;
 
        if (path[0] == '\0') {
                path = ".";
 
        if (path[0] == '\0') {
                path = ".";
@@ -1133,18 +1178,27 @@ static int nfs_lookuppath_async(struct nfs_context *nfs, const char *path, nfs_c
        }
 
        data->path = data->saved_path;
        }
 
        data->path = data->saved_path;
-
-       if (nfs_lookup_path_async_internal(nfs, data, &nfs->rootfh) != 0) {
-               /* return 0 here since the callback will be invoked if there is a failure */
+       if (data->path[0]) {
+               /* This function will always invoke the callback and cleanup
+                * for failures. So no need to check the return value.
+                */
+               nfs_lookup_path_async_internal(nfs, NULL, data, &nfs->rootfh);
                return 0;
        }
                return 0;
        }
+
+       /* We have a request for "", so just perform a GETATTR3 so we can
+        * return the attributes to the caller.
+        */
+       memset(&args, 0, sizeof(GETATTR3args));
+       args.object = nfs->rootfh;
+       if (rpc_nfs3_getattr_async(nfs->rpc, nfs_lookup_path_getattr_cb, &args, data) != 0) {
+               free_nfs_cb_data(data);
+               return -1;
+       }
        return 0;
 }
 
 
        return 0;
 }
 
 
-
-
-
 /*
  * Async stat()
  */
 /*
  * Async stat()
  */
@@ -1195,8 +1249,8 @@ static void nfs_stat_1_cb(struct rpc_context *rpc, int status, void *command_dat
         st.st_rdev    = 0;
         st.st_size    = res->GETATTR3res_u.resok.obj_attributes.size;
 #ifndef WIN32
         st.st_rdev    = 0;
         st.st_size    = res->GETATTR3res_u.resok.obj_attributes.size;
 #ifndef WIN32
-        st.st_blksize = 4096;
-        st.st_blocks  = res->GETATTR3res_u.resok.obj_attributes.size / 4096;
+        st.st_blksize = NFS_BLKSIZE;
+        st.st_blocks  = res->GETATTR3res_u.resok.obj_attributes.size / NFS_BLKSIZE;
 #endif//WIN32
         st.st_atime   = res->GETATTR3res_u.resok.obj_attributes.atime.seconds;
         st.st_mtime   = res->GETATTR3res_u.resok.obj_attributes.mtime.seconds;
 #endif//WIN32
         st.st_atime   = res->GETATTR3res_u.resok.obj_attributes.atime.seconds;
         st.st_mtime   = res->GETATTR3res_u.resok.obj_attributes.mtime.seconds;
@@ -1206,7 +1260,7 @@ static void nfs_stat_1_cb(struct rpc_context *rpc, int status, void *command_dat
        free_nfs_cb_data(data);
 }
 
        free_nfs_cb_data(data);
 }
 
-static int nfs_stat_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
+static int nfs_stat_continue_internal(struct nfs_context *nfs, fattr3 *attr _U_, struct nfs_cb_data *data)
 {
        struct GETATTR3args args;
 
 {
        struct GETATTR3args args;
 
@@ -1286,7 +1340,7 @@ static void nfs_stat64_1_cb(struct rpc_context *rpc, int status, void *command_d
        free_nfs_cb_data(data);
 }
 
        free_nfs_cb_data(data);
 }
 
-static int nfs_stat64_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
+static int nfs_stat64_continue_internal(struct nfs_context *nfs, fattr3 *attr _U_, struct nfs_cb_data *data)
 {
        struct GETATTR3args args;
 
 {
        struct GETATTR3args args;
 
@@ -1355,6 +1409,9 @@ static void nfs_open_trunc_cb(struct rpc_context *rpc, int status, void *command
        if (data->continue_int & O_SYNC) {
                nfsfh->is_sync = 1;
        }
        if (data->continue_int & O_SYNC) {
                nfsfh->is_sync = 1;
        }
+       if (data->continue_int & O_APPEND) {
+               nfsfh->is_append = 1;
+       }
 
        /* steal the filehandle */
        nfsfh->fh = data->fh;
 
        /* steal the filehandle */
        nfsfh->fh = data->fh;
@@ -1451,6 +1508,9 @@ static void nfs_open_cb(struct rpc_context *rpc, int status, void *command_data,
        if (data->continue_int & O_SYNC) {
                nfsfh->is_sync = 1;
        }
        if (data->continue_int & O_SYNC) {
                nfsfh->is_sync = 1;
        }
+       if (data->continue_int & O_APPEND) {
+               nfsfh->is_append = 1;
+       }
 
        /* steal the filehandle */
        nfsfh->fh = data->fh;
 
        /* steal the filehandle */
        nfsfh->fh = data->fh;
@@ -1460,7 +1520,7 @@ static void nfs_open_cb(struct rpc_context *rpc, int status, void *command_data,
        free_nfs_cb_data(data);
 }
 
        free_nfs_cb_data(data);
 }
 
-static int nfs_open_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
+static int nfs_open_continue_internal(struct nfs_context *nfs, fattr3 *attr _U_, struct nfs_cb_data *data)
 {
        int nfsmode = 0;
        ACCESS3args args;
 {
        int nfsmode = 0;
        ACCESS3args args;
@@ -1504,7 +1564,7 @@ int nfs_open_async(struct nfs_context *nfs, const char *path, int flags, nfs_cb
 /*
  * Async chdir()
  */
 /*
  * Async chdir()
  */
-static int nfs_chdir_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
+static int nfs_chdir_continue_internal(struct nfs_context *nfs, fattr3 *attr _U_, struct nfs_cb_data *data)
 {
        /* steal saved_path */
        free(nfs->cwd);
 {
        /* steal saved_path */
        free(nfs->cwd);
@@ -1564,25 +1624,30 @@ static void nfs_pread_mcb(struct rpc_context *rpc, int status, void *command_dat
                if (res->status != NFS3_OK) {
                        rpc_set_error(nfs->rpc, "NFS: Read failed with %s(%d)", nfsstat3_to_str(res->status), nfsstat3_to_errno(res->status));
                        data->error = 1;
                if (res->status != NFS3_OK) {
                        rpc_set_error(nfs->rpc, "NFS: Read failed with %s(%d)", nfsstat3_to_str(res->status), nfsstat3_to_errno(res->status));
                        data->error = 1;
-               } else  {
+               } else {
+                       uint64_t count = res->READ3res_u.resok.count;
+
+                       if (mdata->update_pos)
+                               data->nfsfh->offset += count;
+
                        /* if we have more than one call or we have received a short read we need a reassembly buffer */
                        /* if we have more than one call or we have received a short read we need a reassembly buffer */
-                       if (data->num_calls || (res->READ3res_u.resok.count < mdata->count && !res->READ3res_u.resok.eof)) {
+                       if (data->num_calls || (count < mdata->count && !res->READ3res_u.resok.eof)) {
                                if (data->buffer == NULL) {
                                if (data->buffer == NULL) {
-                                       data->buffer =  malloc(data->request_size);
+                                       data->buffer =  malloc(data->count);
                                        if (data->buffer == NULL) {
                                        if (data->buffer == NULL) {
-                                               rpc_set_error(nfs->rpc, "Out-Of-Memory: Failed to allocate reassembly buffer for %d bytes", (int)data->request_size);
+                                               rpc_set_error(nfs->rpc, "Out-Of-Memory: Failed to allocate reassembly buffer for %d bytes", (int)data->count);
                                                data->oom = 1;
                                        }
                                }
                        }
                                                data->oom = 1;
                                        }
                                }
                        }
-                       if (res->READ3res_u.resok.count > 0) {
-                               if (res->READ3res_u.resok.count <= mdata->count) {
+                       if (count > 0) {
+                               if (count <= mdata->count) {
                                        /* copy data into reassembly buffer if we have one */
                                        if (data->buffer != NULL) {
                                        /* copy data into reassembly buffer if we have one */
                                        if (data->buffer != NULL) {
-                                               memcpy(&data->buffer[mdata->offset - data->start_offset], res->READ3res_u.resok.data.data_val, res->READ3res_u.resok.count);
+                                               memcpy(&data->buffer[mdata->offset - data->offset], res->READ3res_u.resok.data.data_val, count);
                                        }
                                        }
-                                       if (data->max_offset < mdata->offset + res->READ3res_u.resok.count) {
-                                               data->max_offset = mdata->offset + res->READ3res_u.resok.count;
+                                       if (data->max_offset < mdata->offset + count) {
+                                               data->max_offset = mdata->offset + count;
                                        }
                                } else {
                                        rpc_set_error(nfs->rpc, "NFS: Read overflow. Server has sent more data than requested!");
                                        }
                                } else {
                                        rpc_set_error(nfs->rpc, "NFS: Read overflow. Server has sent more data than requested!");
@@ -1590,15 +1655,15 @@ static void nfs_pread_mcb(struct rpc_context *rpc, int status, void *command_dat
                                }
                        }
                        /* check if we have received a short read */
                                }
                        }
                        /* check if we have received a short read */
-                       if (res->READ3res_u.resok.count < mdata->count && !res->READ3res_u.resok.eof) {
-                               if (res->READ3res_u.resok.count == 0) {
+                       if (count < mdata->count && !res->READ3res_u.resok.eof) {
+                               if (count == 0) {
                                        rpc_set_error(nfs->rpc, "NFS: Read failed. No bytes read and not at EOF!");
                                        data->error = 1;
                                } else {
                                        /* reissue reminder of this read request */
                                        READ3args args;
                                        rpc_set_error(nfs->rpc, "NFS: Read failed. No bytes read and not at EOF!");
                                        data->error = 1;
                                } else {
                                        /* reissue reminder of this read request */
                                        READ3args args;
-                                       mdata->offset += res->READ3res_u.resok.count;
-                                       mdata->count -= res->READ3res_u.resok.count;
+                                       mdata->offset += count;
+                                       mdata->count -= count;
                                        nfs_fill_READ3args(&args, data->nfsfh, mdata->offset, mdata->count);
                                        if (rpc_nfs3_read_async(nfs->rpc, nfs_pread_mcb, &args, mdata) == 0) {
                                                data->num_calls++;
                                        nfs_fill_READ3args(&args, data->nfsfh, mdata->offset, mdata->count);
                                        if (rpc_nfs3_read_async(nfs->rpc, nfs_pread_mcb, &args, mdata) == 0) {
                                                data->num_calls++;
@@ -1634,17 +1699,37 @@ static void nfs_pread_mcb(struct rpc_context *rpc, int status, void *command_dat
                return;
        }
 
                return;
        }
 
-       data->nfsfh->offset = data->max_offset;
        if (data->buffer) {
        if (data->buffer) {
-               data->cb(data->max_offset - data->start_offset, nfs, data->buffer, data->private_data);
+               if (data->max_offset > data->org_offset + data->org_count) {
+                       data->max_offset = data->org_offset + data->org_count;
+               }
+               data->cb(data->max_offset - data->org_offset, nfs, data->buffer + (data->org_offset - data->offset), data->private_data);
        } else {
                data->cb(res->READ3res_u.resok.count, nfs, res->READ3res_u.resok.data.data_val, data->private_data);
        }
 
        } else {
                data->cb(res->READ3res_u.resok.count, nfs, res->READ3res_u.resok.data.data_val, data->private_data);
        }
 
+       data->nfsfh->ra.fh_offset = data->max_offset;
+       if (data->nfsfh->ra.cur_ra) {
+               free(data->nfsfh->ra.buf);
+               data->nfsfh->ra.buf = data->buffer;
+               data->nfsfh->ra.buf_offset = data->offset;
+               data->nfsfh->ra.buf_count = data->count;
+               data->nfsfh->ra.buf_ts = time(NULL);
+               data->buffer = NULL;
+       }
        free_nfs_cb_data(data);
 }
 
        free_nfs_cb_data(data);
 }
 
-int nfs_pread_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offset, uint64_t count, nfs_cb cb, void *private_data)
+static void nfs_ra_invalidate(struct nfsfh *nfsfh) {
+       free(nfsfh->ra.buf);
+       nfsfh->ra.buf = NULL;
+       nfsfh->ra.buf_offset = 0;
+       nfsfh->ra.buf_count = 0;
+       nfsfh->ra.buf_ts = time(NULL);
+       nfsfh->ra.cur_ra = NFS_BLKSIZE;
+}
+
+static int nfs_pread_async_internal(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offset, uint64_t count, nfs_cb cb, void *private_data, int update_pos)
 {
        struct nfs_cb_data *data;
 
 {
        struct nfs_cb_data *data;
 
@@ -1658,18 +1743,78 @@ int nfs_pread_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offse
        data->cb           = cb;
        data->private_data = private_data;
        data->nfsfh        = nfsfh;
        data->cb           = cb;
        data->private_data = private_data;
        data->nfsfh        = nfsfh;
-       data->request_size = count;
-
-       nfsfh->offset = offset;
+       data->org_offset   = offset;
+       data->org_count    = count;
 
        assert(data->num_calls == 0);
 
 
        assert(data->num_calls == 0);
 
+       if (nfs->rpc->readahead && time(NULL) - nfsfh->ra.buf_ts > NFS_RA_TIMEOUT) {
+               /* readahead cache timeout */
+               nfs_ra_invalidate(nfsfh);
+       }
+
+       if (nfs->rpc->readahead) {
+               if (offset >= nfsfh->ra.last_offset &&
+                       offset - NFS_BLKSIZE <= nfsfh->ra.fh_offset + nfsfh->ra.cur_ra) {
+                       if (nfs->rpc->readahead > nfsfh->ra.cur_ra) {
+                               nfsfh->ra.cur_ra <<= 1;
+                       }
+               } else {
+                       nfsfh->ra.cur_ra = NFS_BLKSIZE;
+               }
+
+               nfsfh->ra.last_offset = offset;
+
+               if (nfsfh->ra.buf_offset <= offset &&
+                       nfsfh->ra.buf_offset + nfsfh->ra.buf_count >= offset + count) {
+                       /* serve request completely from cache */
+                       data->buffer = malloc(count);
+                       if (data->buffer == NULL) {
+                               free_nfs_cb_data(data);
+                               return -ENOMEM;
+                       }
+                       memcpy(data->buffer, nfsfh->ra.buf + (offset - nfsfh->ra.buf_offset), count);
+                       data->cb(count, nfs, data->buffer, data->private_data);
+                       nfsfh->ra.fh_offset = offset + count;
+                       free_nfs_cb_data(data);
+                       return 0;
+               }
+
+               /* align start offset to blocksize */
+               count += offset & (NFS_BLKSIZE - 1);
+               offset &= ~(NFS_BLKSIZE - 1);
+
+               /* align end offset to blocksize and add readahead */
+               count += nfsfh->ra.cur_ra - 1;
+               count &= ~(NFS_BLKSIZE - 1);
+
+               data->buffer = malloc(count);
+               if (data->buffer == NULL) {
+                       free_nfs_cb_data(data);
+                       return -ENOMEM;
+               }
+               data->offset = offset;
+               data->count = count;
+
+               if (nfsfh->ra.buf_count && nfsfh->ra.buf_offset <= offset &&
+                       nfsfh->ra.buf_offset + nfsfh->ra.buf_count >= offset) {
+                       /* serve request partially from cache */
+                       size_t overlap = (nfsfh->ra.buf_offset + nfsfh->ra.buf_count) - offset;
+                       if (overlap > count) count = overlap;
+                       memcpy(data->buffer, nfsfh->ra.buf + (offset - nfsfh->ra.buf_offset), overlap);
+                       offset += overlap;
+                       count -= overlap;
+               }
+       } else {
+               data->offset = offset;
+               data->count = count;
+       }
+
+       data->max_offset = offset;
+
        /* chop requests into chunks of at most READMAX bytes if necessary.
         * we send all reads in parallel so that performance is still good.
         */
        /* chop requests into chunks of at most READMAX bytes if necessary.
         * we send all reads in parallel so that performance is still good.
         */
-       data->max_offset = offset;
-       data->start_offset = offset;
-
        do {
                uint64_t readcount = count;
                struct nfs_mcb_data *mdata;
        do {
                uint64_t readcount = count;
                struct nfs_mcb_data *mdata;
@@ -1693,6 +1838,7 @@ int nfs_pread_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offse
                mdata->data   = data;
                mdata->offset = offset;
                mdata->count  = readcount;
                mdata->data   = data;
                mdata->offset = offset;
                mdata->count  = readcount;
+               mdata->update_pos = update_pos;
 
                nfs_fill_READ3args(&args, nfsfh, offset, readcount);
 
 
                nfs_fill_READ3args(&args, nfsfh, offset, readcount);
 
@@ -1715,12 +1861,17 @@ int nfs_pread_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offse
         return 0;
 }
 
         return 0;
 }
 
+int nfs_pread_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offset, uint64_t count, nfs_cb cb, void *private_data)
+{
+       return nfs_pread_async_internal(nfs, nfsfh, offset, count, cb, private_data, 0);
+}
+
 /*
  * Async read()
  */
 int nfs_read_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t count, nfs_cb cb, void *private_data)
 {
 /*
  * Async read()
  */
 int nfs_read_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t count, nfs_cb cb, void *private_data)
 {
-       return nfs_pread_async(nfs, nfsfh, nfsfh->offset, count, cb, private_data);
+       return nfs_pread_async_internal(nfs, nfsfh, nfsfh->offset, count, cb, private_data, 1);
 }
 
 
 }
 
 
@@ -1735,7 +1886,7 @@ static void nfs_fill_WRITE3args (WRITE3args *args, struct nfsfh *fh, uint64_t of
        args->file = fh->fh;
        args->offset = offset;
        args->count  = count;
        args->file = fh->fh;
        args->offset = offset;
        args->count  = count;
-       args->stable = fh->is_sync?FILE_SYNC:UNSTABLE;
+       args->stable = fh->is_sync ? FILE_SYNC : UNSTABLE;
        args->data.data_len = count;
        args->data.data_val = buf;
 }
        args->data.data_len = count;
        args->data.data_val = buf;
 }
@@ -1766,17 +1917,23 @@ static void nfs_pwrite_mcb(struct rpc_context *rpc, int status, void *command_da
                        rpc_set_error(nfs->rpc, "NFS: Write failed with %s(%d)", nfsstat3_to_str(res->status), nfsstat3_to_errno(res->status));
                        data->error = 1;
                } else  {
                        rpc_set_error(nfs->rpc, "NFS: Write failed with %s(%d)", nfsstat3_to_str(res->status), nfsstat3_to_errno(res->status));
                        data->error = 1;
                } else  {
-                       if (res->WRITE3res_u.resok.count < mdata->count) {
-                               if (res->WRITE3res_u.resok.count == 0) {
+                       uint64_t count = res->WRITE3res_u.resok.count;
+
+                       if (mdata->update_pos)
+                               data->nfsfh->offset += count;
+
+                       if (count < mdata->count) {
+                               if (count == 0) {
                                        rpc_set_error(nfs->rpc, "NFS: Write failed. No bytes written!");
                                        data->error = 1;
                                } else {
                                        /* reissue reminder of this write request */
                                        WRITE3args args;
                                        rpc_set_error(nfs->rpc, "NFS: Write failed. No bytes written!");
                                        data->error = 1;
                                } else {
                                        /* reissue reminder of this write request */
                                        WRITE3args args;
-                                       mdata->offset += res->WRITE3res_u.resok.count;
-                                       mdata->count -= res->WRITE3res_u.resok.count;
+                                       mdata->offset += count;
+                                       mdata->count -= count;
+
                                        nfs_fill_WRITE3args(&args, data->nfsfh, mdata->offset, mdata->count,
                                        nfs_fill_WRITE3args(&args, data->nfsfh, mdata->offset, mdata->count,
-                                                                               &data->usrbuf[mdata->offset - data->start_offset]);
+                                                                               &data->usrbuf[mdata->offset - data->offset]);
                                        if (rpc_nfs3_write_async(nfs->rpc, nfs_pwrite_mcb, &args, mdata) == 0) {
                                                data->num_calls++;
                                                return;
                                        if (rpc_nfs3_write_async(nfs->rpc, nfs_pwrite_mcb, &args, mdata) == 0) {
                                                data->num_calls++;
                                                return;
@@ -1786,9 +1943,9 @@ static void nfs_pwrite_mcb(struct rpc_context *rpc, int status, void *command_da
                                        }
                                }
                        }
                                        }
                                }
                        }
-                       if (res->WRITE3res_u.resok.count > 0) {
-                               if (data->max_offset < mdata->offset + res->WRITE3res_u.resok.count) {
-                                       data->max_offset = mdata->offset + res->WRITE3res_u.resok.count;
+                       if (count > 0) {
+                               if (data->max_offset < mdata->offset + count) {
+                                       data->max_offset = mdata->offset + count;
                                }
                        }
                }
                                }
                        }
                }
@@ -1816,14 +1973,13 @@ static void nfs_pwrite_mcb(struct rpc_context *rpc, int status, void *command_da
                return;
        }
 
                return;
        }
 
-       data->nfsfh->offset = data->max_offset;
-       data->cb(data->max_offset - data->start_offset, nfs, NULL, data->private_data);
+       data->cb(data->max_offset - data->offset, nfs, NULL, data->private_data);
 
        free_nfs_cb_data(data);
 }
 
 
 
        free_nfs_cb_data(data);
 }
 
 
-int nfs_pwrite_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offset, uint64_t count, char *buf, nfs_cb cb, void *private_data)
+static int nfs_pwrite_async_internal(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offset, uint64_t count, char *buf, nfs_cb cb, void *private_data, int update_pos)
 {
        struct nfs_cb_data *data;
 
 {
        struct nfs_cb_data *data;
 
@@ -1839,8 +1995,6 @@ int nfs_pwrite_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offs
        data->nfsfh        = nfsfh;
        data->usrbuf       = buf;
 
        data->nfsfh        = nfsfh;
        data->usrbuf       = buf;
 
-       nfsfh->offset = offset;
-
        /* hello, clang-analyzer */
        assert(data->num_calls == 0);
 
        /* hello, clang-analyzer */
        assert(data->num_calls == 0);
 
@@ -1848,7 +2002,7 @@ int nfs_pwrite_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offs
         * we send all writes in parallel so that performance is still good.
         */
        data->max_offset = offset;
         * we send all writes in parallel so that performance is still good.
         */
        data->max_offset = offset;
-       data->start_offset = offset;
+       data->offset = offset;
 
        do {
                uint64_t writecount = count;
 
        do {
                uint64_t writecount = count;
@@ -1873,8 +2027,9 @@ int nfs_pwrite_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offs
                mdata->data   = data;
                mdata->offset = offset;
                mdata->count  = writecount;
                mdata->data   = data;
                mdata->offset = offset;
                mdata->count  = writecount;
+               mdata->update_pos = update_pos;
 
 
-               nfs_fill_WRITE3args(&args, nfsfh, offset, writecount, &buf[offset - data->start_offset]);
+               nfs_fill_WRITE3args(&args, nfsfh, offset, writecount, &buf[offset - data->offset]);
 
                if (rpc_nfs3_write_async(nfs->rpc, nfs_pwrite_mcb, &args, mdata) != 0) {
                        rpc_set_error(nfs->rpc, "RPC error: Failed to send WRITE call for %s", data->path);
 
                if (rpc_nfs3_write_async(nfs->rpc, nfs_pwrite_mcb, &args, mdata) != 0) {
                        rpc_set_error(nfs->rpc, "RPC error: Failed to send WRITE call for %s", data->path);
@@ -1895,12 +2050,80 @@ int nfs_pwrite_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offs
        return 0;
 }
 
        return 0;
 }
 
+int nfs_pwrite_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offset, uint64_t count, char *buf, nfs_cb cb, void *private_data)
+{
+       return nfs_pwrite_async_internal(nfs, nfsfh, offset, count, buf, cb, private_data, 0);
+}
+
 /*
  * Async write()
  */
 /*
  * Async write()
  */
+static void nfs_write_append_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
+{
+       struct nfs_cb_data *data = private_data;
+       struct nfs_context *nfs = data->nfs;
+       GETATTR3res *res;
+
+       assert(rpc->magic == RPC_CONTEXT_MAGIC);
+
+       if (status == RPC_STATUS_ERROR) {
+               data->cb(-EFAULT, nfs, command_data, data->private_data);
+               free_nfs_cb_data(data);
+               return;
+       }
+       if (status == RPC_STATUS_CANCEL) {
+               data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
+               free_nfs_cb_data(data);
+               return;
+       }
+
+       res = command_data;
+       if (res->status != NFS3_OK) {
+               rpc_set_error(nfs->rpc, "NFS: GETATTR failed with %s(%d)", nfsstat3_to_str(res->status), nfsstat3_to_errno(res->status));
+               data->cb(nfsstat3_to_errno(res->status), nfs, rpc_get_error(nfs->rpc), data->private_data);
+               free_nfs_cb_data(data);
+               return;
+       }
+
+       if (nfs_pwrite_async_internal(nfs, data->nfsfh, res->GETATTR3res_u.resok.obj_attributes.size, data->count, data->usrbuf, data->cb, data->private_data, 1) != 0) {
+               data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
+               free_nfs_cb_data(data);
+               return;
+       }
+       free_nfs_cb_data(data);
+}
+
 int nfs_write_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t count, char *buf, nfs_cb cb, void *private_data)
 {
 int nfs_write_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t count, char *buf, nfs_cb cb, void *private_data)
 {
-       return nfs_pwrite_async(nfs, nfsfh, nfsfh->offset, count, buf, cb, private_data);
+       nfs_ra_invalidate(nfsfh);
+       if (nfsfh->is_append) {
+               struct GETATTR3args args;
+               struct nfs_cb_data *data;
+
+               data = malloc(sizeof(struct nfs_cb_data));
+               if (data == NULL) {
+                       rpc_set_error(nfs->rpc, "out of memory: failed to allocate nfs_cb_data structure");
+                       return -1;
+               }
+               memset(data, 0, sizeof(struct nfs_cb_data));
+               data->nfs           = nfs;
+               data->cb            = cb;
+               data->private_data  = private_data;
+               data->nfsfh         = nfsfh;
+               data->usrbuf        = buf;
+               data->count         = count;
+
+               memset(&args, 0, sizeof(GETATTR3args));
+               args.object = nfsfh->fh;
+
+               if (rpc_nfs3_getattr_async(nfs->rpc, nfs_write_append_cb, &args, data) != 0) {
+                       rpc_set_error(nfs->rpc, "out of memory: failed to send GETATTR");
+                       free_nfs_cb_data(data);
+                       return -1;
+               }
+               return 0;
+       }
+       return nfs_pwrite_async_internal(nfs, nfsfh, nfsfh->offset, count, buf, cb, private_data, 1);
 }
 
 
 }
 
 
@@ -1916,6 +2139,7 @@ int nfs_close_async(struct nfs_context *nfs, struct nfsfh *nfsfh, nfs_cb cb, voi
                free(nfsfh->fh.data.data_val);
                nfsfh->fh.data.data_val = NULL;
        }
                free(nfsfh->fh.data.data_val);
                nfsfh->fh.data.data_val = NULL;
        }
+       free(nfsfh->ra.buf);
        free(nfsfh);
 
        cb(0, nfs, NULL, private_data);
        free(nfsfh);
 
        cb(0, nfs, NULL, private_data);
@@ -2089,7 +2313,7 @@ int nfs_ftruncate_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t l
 /*
  * Async truncate()
  */
 /*
  * Async truncate()
  */
-static int nfs_truncate_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
+static int nfs_truncate_continue_internal(struct nfs_context *nfs, fattr3 *attr _U_, struct nfs_cb_data *data)
 {
        uint64_t offset = data->continue_int;
        struct nfsfh nfsfh;
 {
        uint64_t offset = data->continue_int;
        struct nfsfh nfsfh;
@@ -2160,7 +2384,7 @@ static void nfs_mkdir_cb(struct rpc_context *rpc, int status, void *command_data
        free_nfs_cb_data(data);
 }
 
        free_nfs_cb_data(data);
 }
 
-static int nfs_mkdir_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
+static int nfs_mkdir_continue_internal(struct nfs_context *nfs, fattr3 *attr _U_, struct nfs_cb_data *data)
 {
        char *str = data->continue_data;
        MKDIR3args args;
 {
        char *str = data->continue_data;
        MKDIR3args args;
@@ -2251,7 +2475,7 @@ static void nfs_rmdir_cb(struct rpc_context *rpc, int status, void *command_data
        free_nfs_cb_data(data);
 }
 
        free_nfs_cb_data(data);
 }
 
-static int nfs_rmdir_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
+static int nfs_rmdir_continue_internal(struct nfs_context *nfs, fattr3 *attr _U_, struct nfs_cb_data *data)
 {
        char *str = data->continue_data;
        RMDIR3args args;
 {
        char *str = data->continue_data;
        RMDIR3args args;
@@ -2396,7 +2620,7 @@ static void nfs_creat_1_cb(struct rpc_context *rpc, int status, void *command_da
        return;
 }
 
        return;
 }
 
-static int nfs_creat_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
+static int nfs_creat_continue_internal(struct nfs_context *nfs, fattr3 *attr _U_, struct nfs_cb_data *data)
 {
        char *str = data->continue_data;
        CREATE3args args;
 {
        char *str = data->continue_data;
        CREATE3args args;
@@ -2487,7 +2711,7 @@ static void nfs_unlink_cb(struct rpc_context *rpc, int status, void *command_dat
        free_nfs_cb_data(data);
 }
 
        free_nfs_cb_data(data);
 }
 
-static int nfs_unlink_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
+static int nfs_unlink_continue_internal(struct nfs_context *nfs, fattr3 *attr _U_, struct nfs_cb_data *data)
 {
        char *str = data->continue_data;
        struct REMOVE3args args;
 {
        char *str = data->continue_data;
        struct REMOVE3args args;
@@ -2586,7 +2810,7 @@ static void nfs_mknod_cb(struct rpc_context *rpc, int status, void *command_data
        free_nfs_cb_data(data);
 }
 
        free_nfs_cb_data(data);
 }
 
-static int nfs_mknod_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
+static int nfs_mknod_continue_internal(struct nfs_context *nfs, fattr3 *attr _U_, struct nfs_cb_data *data)
 {
        struct mknod_cb_data *cb_data = data->continue_data;
        char *str = cb_data->path;
 {
        struct mknod_cb_data *cb_data = data->continue_data;
        char *str = cb_data->path;
@@ -2734,6 +2958,7 @@ static void nfs_opendir3_cb(struct rpc_context *rpc, int status, void *command_d
                        nfsdirent->ctime.tv_usec = attributes->ctime.nseconds/1000;
                        nfsdirent->uid = attributes->uid;
                        nfsdirent->gid = attributes->gid;
                        nfsdirent->ctime.tv_usec = attributes->ctime.nseconds/1000;
                        nfsdirent->uid = attributes->uid;
                        nfsdirent->gid = attributes->gid;
+                       nfsdirent->nlink = attributes->nlink;
                }
        }
 
                }
        }
 
@@ -2840,49 +3065,54 @@ static void nfs_opendir2_cb(struct rpc_context *rpc, int status, void *command_d
                return;
        }
 
                return;
        }
 
+       if (res->READDIR3res_u.resok.dir_attributes.attributes_follow)
+               nfsdir->attr = res->READDIR3res_u.resok.dir_attributes.post_op_attr_u.attributes;
+
        /* steal the dirhandle */
        nfsdir->current = nfsdir->entries;
 
        /* steal the dirhandle */
        nfsdir->current = nfsdir->entries;
 
-       rdpe_cb_data = malloc(sizeof(struct rdpe_cb_data));
-       rdpe_cb_data->getattrcount = 0;
-       rdpe_cb_data->status = RPC_STATUS_SUCCESS;
-       rdpe_cb_data->data = data;
-       for (nfsdirent = nfsdir->entries; nfsdirent; nfsdirent = nfsdirent->next) {
-               struct rdpe_lookup_cb_data *rdpe_lookup_cb_data;
-               LOOKUP3args args;
-
-               rdpe_lookup_cb_data = malloc(sizeof(struct rdpe_lookup_cb_data));
-               rdpe_lookup_cb_data->rdpe_cb_data = rdpe_cb_data;
-               rdpe_lookup_cb_data->nfsdirent = nfsdirent;
-
-               memset(&args, 0, sizeof(LOOKUP3args));
-               args.what.dir = data->fh;
-               args.what.name = nfsdirent->name;
-
-               if (rpc_nfs3_lookup_async(nfs->rpc, nfs_opendir3_cb, &args, rdpe_lookup_cb_data) != 0) {
-                       rpc_set_error(nfs->rpc, "RPC error: Failed to send READDIR LOOKUP call");
-
-                       /* if we have already commands in flight, we cant just stop, we have to wait for the
-                        * commands in flight to complete
-                        */
-                       if (rdpe_cb_data->getattrcount > 0) {
+       if (nfsdir->entries) {
+               rdpe_cb_data = malloc(sizeof(struct rdpe_cb_data));
+               rdpe_cb_data->getattrcount = 0;
+               rdpe_cb_data->status = RPC_STATUS_SUCCESS;
+               rdpe_cb_data->data = data;
+               for (nfsdirent = nfsdir->entries; nfsdirent; nfsdirent = nfsdirent->next) {
+                       struct rdpe_lookup_cb_data *rdpe_lookup_cb_data;
+                       LOOKUP3args args;
+
+                       rdpe_lookup_cb_data = malloc(sizeof(struct rdpe_lookup_cb_data));
+                       rdpe_lookup_cb_data->rdpe_cb_data = rdpe_cb_data;
+                       rdpe_lookup_cb_data->nfsdirent = nfsdirent;
+
+                       memset(&args, 0, sizeof(LOOKUP3args));
+                       args.what.dir = data->fh;
+                       args.what.name = nfsdirent->name;
+
+                       if (rpc_nfs3_lookup_async(nfs->rpc, nfs_opendir3_cb, &args, rdpe_lookup_cb_data) != 0) {
+                               rpc_set_error(nfs->rpc, "RPC error: Failed to send READDIR LOOKUP call");
+
+                               /* if we have already commands in flight, we cant just stop, we have to wait for the
+                                * commands in flight to complete
+                                */
+                               if (rdpe_cb_data->getattrcount > 0) {
+                                       nfs_free_nfsdir(nfsdir);
+                                       data->continue_data = NULL;
+                                       free_nfs_cb_data(data);
+                                       rdpe_cb_data->status = RPC_STATUS_ERROR;
+                                       free(rdpe_lookup_cb_data);
+                                       return;
+                               }
+
+                               data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
                                nfs_free_nfsdir(nfsdir);
                                data->continue_data = NULL;
                                free_nfs_cb_data(data);
                                nfs_free_nfsdir(nfsdir);
                                data->continue_data = NULL;
                                free_nfs_cb_data(data);
-                               rdpe_cb_data->status = RPC_STATUS_ERROR;
                                free(rdpe_lookup_cb_data);
                                free(rdpe_lookup_cb_data);
+                               free(rdpe_cb_data);
                                return;
                        }
                                return;
                        }
-
-                       data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
-                       nfs_free_nfsdir(nfsdir);
-                       data->continue_data = NULL;
-                       free_nfs_cb_data(data);
-                       free(rdpe_lookup_cb_data);
-                       free(rdpe_cb_data);
-                       return;
+                       rdpe_cb_data->getattrcount++;
                }
                }
-               rdpe_cb_data->getattrcount++;
        }
 }
 
        }
 }
 
@@ -2969,6 +3199,7 @@ static void nfs_opendir_cb(struct rpc_context *rpc, int status, void *command_da
                        nfsdirent->ctime.tv_usec = entry->name_attributes.post_op_attr_u.attributes.ctime.nseconds/1000;
                        nfsdirent->uid = entry->name_attributes.post_op_attr_u.attributes.uid;
                        nfsdirent->gid = entry->name_attributes.post_op_attr_u.attributes.gid;
                        nfsdirent->ctime.tv_usec = entry->name_attributes.post_op_attr_u.attributes.ctime.nseconds/1000;
                        nfsdirent->uid = entry->name_attributes.post_op_attr_u.attributes.uid;
                        nfsdirent->gid = entry->name_attributes.post_op_attr_u.attributes.gid;
+                       nfsdirent->nlink = entry->name_attributes.post_op_attr_u.attributes.nlink;
                }
 
                nfsdirent->next  = nfsdir->entries;
                }
 
                nfsdirent->next  = nfsdir->entries;
@@ -2998,6 +3229,9 @@ static void nfs_opendir_cb(struct rpc_context *rpc, int status, void *command_da
                return;
        }
 
                return;
        }
 
+       if (res->READDIRPLUS3res_u.resok.dir_attributes.attributes_follow)
+               nfsdir->attr = res->READDIRPLUS3res_u.resok.dir_attributes.post_op_attr_u.attributes;
+
        /* steal the dirhandle */
        data->continue_data = NULL;
        nfsdir->current = nfsdir->entries;
        /* steal the dirhandle */
        data->continue_data = NULL;
        nfsdir->current = nfsdir->entries;
@@ -3006,9 +3240,34 @@ static void nfs_opendir_cb(struct rpc_context *rpc, int status, void *command_da
        free_nfs_cb_data(data);
 }
 
        free_nfs_cb_data(data);
 }
 
-static int nfs_opendir_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
+static int nfs_opendir_continue_internal(struct nfs_context *nfs, fattr3 *attr _U_, struct nfs_cb_data *data)
 {
        READDIRPLUS3args args;
 {
        READDIRPLUS3args args;
+       struct nfsdir *nfsdir = data->continue_data;;
+       struct nfsdir *cached;
+
+       cached = nfs_dircache_find(nfs, &data->fh);
+       if (cached) {
+               if (attr && attr->mtime.seconds == cached->attr.mtime.seconds) {
+                       cached->current = cached->entries;
+                       data->cb(0, nfs, cached, data->private_data);
+                       free_nfs_cb_data(data);
+                       return 0;
+               } else {
+                       /* cache must be stale */
+                       nfs_free_nfsdir(cached);
+               }
+       }
+
+       nfsdir->fh.data.data_len  = data->fh.data.data_len;
+       nfsdir->fh.data.data_val = malloc(nfsdir->fh.data.data_len);
+       if (nfsdir->fh.data.data_val == NULL) {
+               rpc_set_error(nfs->rpc, "OOM when allocating fh for nfsdir");
+               data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
+               free_nfs_cb_data(data);
+               return -1;
+       }
+       memcpy(nfsdir->fh.data.data_val, data->fh.data.data_val, data->fh.data.data_len);
 
        args.dir = data->fh;
        args.cookie = 0;
 
        args.dir = data->fh;
        args.cookie = 0;
@@ -3058,9 +3317,9 @@ struct nfsdirent *nfs_readdir(struct nfs_context *nfs _U_, struct nfsdir *nfsdir
 /*
  * closedir()
  */
 /*
  * closedir()
  */
-void nfs_closedir(struct nfs_context *nfs _U_, struct nfsdir *nfsdir)
+void nfs_closedir(struct nfs_context *nfs, struct nfsdir *nfsdir)
 {
 {
-       nfs_free_nfsdir(nfsdir);
+       nfs_dircache_add(nfs, nfsdir);
 }
 
 
 }
 
 
@@ -3081,7 +3340,7 @@ void nfs_getcwd(struct nfs_context *nfs, const char **cwd)
 struct lseek_cb_data {
        struct nfs_context *nfs;
        struct nfsfh *nfsfh;
 struct lseek_cb_data {
        struct nfs_context *nfs;
        struct nfsfh *nfsfh;
-       uint64_t offset;
+       int64_t offset;
        nfs_cb cb;
        void *private_data;
 };
        nfs_cb cb;
        void *private_data;
 };
@@ -3091,6 +3350,7 @@ static void nfs_lseek_1_cb(struct rpc_context *rpc, int status, void *command_da
        GETATTR3res *res;
        struct lseek_cb_data *data = private_data;
        struct nfs_context *nfs = data->nfs;
        GETATTR3res *res;
        struct lseek_cb_data *data = private_data;
        struct nfs_context *nfs = data->nfs;
+       uint64_t size = 0;
 
        assert(rpc->magic == RPC_CONTEXT_MAGIC);
 
 
        assert(rpc->magic == RPC_CONTEXT_MAGIC);
 
@@ -3113,24 +3373,41 @@ static void nfs_lseek_1_cb(struct rpc_context *rpc, int status, void *command_da
                return;
        }
 
                return;
        }
 
-       data->nfsfh->offset = data->offset + res->GETATTR3res_u.resok.obj_attributes.size;
-       data->cb(0, nfs, &data->nfsfh->offset, data->private_data);
+       size = res->GETATTR3res_u.resok.obj_attributes.size;
+
+       if (data->offset < 0 &&
+           (uint64_t)(-data->offset) > size) {
+               data->cb(-EINVAL, nfs, &data->nfsfh->offset, data->private_data);
+       } else {
+               data->nfsfh->offset = data->offset + size;
+               data->cb(0, nfs, &data->nfsfh->offset, data->private_data);
+       }
+
        free(data);
 }
 
        free(data);
 }
 
-int nfs_lseek_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offset, int whence, nfs_cb cb, void *private_data)
+int nfs_lseek_async(struct nfs_context *nfs, struct nfsfh *nfsfh, int64_t offset, int whence, nfs_cb cb, void *private_data)
 {
        struct lseek_cb_data *data;
        struct GETATTR3args args;
 
        if (whence == SEEK_SET) {
 {
        struct lseek_cb_data *data;
        struct GETATTR3args args;
 
        if (whence == SEEK_SET) {
-               nfsfh->offset = offset;
-               cb(0, nfs, &nfsfh->offset, private_data);
+               if (offset < 0) {
+                       cb(-EINVAL, nfs, &nfsfh->offset, private_data);
+               } else {
+                       nfsfh->offset = offset;
+                       cb(0, nfs, &nfsfh->offset, private_data);
+               }
                return 0;
        }
        if (whence == SEEK_CUR) {
                return 0;
        }
        if (whence == SEEK_CUR) {
-               nfsfh->offset += offset;
-               cb(0, nfs, &nfsfh->offset, private_data);
+               if (offset < 0 &&
+                   nfsfh->offset < (uint64_t)(-offset)) {
+                       cb(-EINVAL, nfs, &nfsfh->offset, private_data);
+               } else {
+                       nfsfh->offset += offset;
+                       cb(0, nfs, &nfsfh->offset, private_data);
+               }
                return 0;
        }
 
                return 0;
        }
 
@@ -3191,11 +3468,11 @@ static void nfs_statvfs_1_cb(struct rpc_context *rpc, int status, void *command_
                return;
        }
 
                return;
        }
 
-       svfs.f_bsize   = 4096;
-       svfs.f_frsize  = 4096;
-       svfs.f_blocks  = res->FSSTAT3res_u.resok.tbytes/4096;
-       svfs.f_bfree   = res->FSSTAT3res_u.resok.fbytes/4096;
-       svfs.f_bavail  = res->FSSTAT3res_u.resok.abytes/4096;
+       svfs.f_bsize   = NFS_BLKSIZE;
+       svfs.f_frsize  = NFS_BLKSIZE;
+       svfs.f_blocks  = res->FSSTAT3res_u.resok.tbytes/NFS_BLKSIZE;
+       svfs.f_bfree   = res->FSSTAT3res_u.resok.fbytes/NFS_BLKSIZE;
+       svfs.f_bavail  = res->FSSTAT3res_u.resok.abytes/NFS_BLKSIZE;
        svfs.f_files   = res->FSSTAT3res_u.resok.tfiles;
        svfs.f_ffree   = res->FSSTAT3res_u.resok.ffiles;
 #if !defined(ANDROID)
        svfs.f_files   = res->FSSTAT3res_u.resok.tfiles;
        svfs.f_ffree   = res->FSSTAT3res_u.resok.ffiles;
 #if !defined(ANDROID)
@@ -3209,7 +3486,7 @@ static void nfs_statvfs_1_cb(struct rpc_context *rpc, int status, void *command_
        free_nfs_cb_data(data);
 }
 
        free_nfs_cb_data(data);
 }
 
-static int nfs_statvfs_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
+static int nfs_statvfs_continue_internal(struct nfs_context *nfs, fattr3 *attr _U_, struct nfs_cb_data *data)
 {
        FSSTAT3args args;
 
 {
        FSSTAT3args args;
 
@@ -3271,7 +3548,7 @@ static void nfs_readlink_1_cb(struct rpc_context *rpc, int status, void *command
        free_nfs_cb_data(data);
 }
 
        free_nfs_cb_data(data);
 }
 
-static int nfs_readlink_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
+static int nfs_readlink_continue_internal(struct nfs_context *nfs, fattr3 *attr _U_, struct nfs_cb_data *data)
 {
        READLINK3args args;
 
 {
        READLINK3args args;
 
@@ -3333,7 +3610,7 @@ static void nfs_chmod_cb(struct rpc_context *rpc, int status, void *command_data
        free_nfs_cb_data(data);
 }
 
        free_nfs_cb_data(data);
 }
 
-static int nfs_chmod_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
+static int nfs_chmod_continue_internal(struct nfs_context *nfs, fattr3 *attr _U_, struct nfs_cb_data *data)
 {
        SETATTR3args args;
 
 {
        SETATTR3args args;
 
@@ -3388,7 +3665,7 @@ int nfs_fchmod_async(struct nfs_context *nfs, struct nfsfh *nfsfh, int mode, nfs
        }
        memcpy(data->fh.data.data_val, nfsfh->fh.data.data_val, data->fh.data.data_len);
 
        }
        memcpy(data->fh.data.data_val, nfsfh->fh.data.data_val, data->fh.data.data_len);
 
-       if (nfs_chmod_continue_internal(nfs, data) != 0) {
+       if (nfs_chmod_continue_internal(nfs, NULL, data) != 0) {
                return -1;
        }
 
                return -1;
        }
 
@@ -3436,7 +3713,7 @@ struct nfs_chown_data {
        gid_t gid;
 };
 
        gid_t gid;
 };
 
-static int nfs_chown_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
+static int nfs_chown_continue_internal(struct nfs_context *nfs, fattr3 *attr _U_, struct nfs_cb_data *data)
 {
        SETATTR3args args;
        struct nfs_chown_data *chown_data = data->continue_data;
 {
        SETATTR3args args;
        struct nfs_chown_data *chown_data = data->continue_data;
@@ -3522,7 +3799,7 @@ int nfs_fchown_async(struct nfs_context *nfs, struct nfsfh *nfsfh, int uid, int
        }
        memcpy(data->fh.data.data_val, nfsfh->fh.data.data_val, data->fh.data.data_len);
 
        }
        memcpy(data->fh.data.data_val, nfsfh->fh.data.data_val, data->fh.data.data_len);
 
-       if (nfs_chown_continue_internal(nfs, data) != 0) {
+       if (nfs_chown_continue_internal(nfs, NULL, data) != 0) {
                return -1;
        }
 
                return -1;
        }
 
@@ -3567,7 +3844,7 @@ static void nfs_utimes_cb(struct rpc_context *rpc, int status, void *command_dat
        free_nfs_cb_data(data);
 }
 
        free_nfs_cb_data(data);
 }
 
-static int nfs_utimes_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
+static int nfs_utimes_continue_internal(struct nfs_context *nfs, fattr3 *attr _U_, struct nfs_cb_data *data)
 {
        SETATTR3args args;
        struct timeval *utimes_data = data->continue_data;
 {
        SETATTR3args args;
        struct timeval *utimes_data = data->continue_data;
@@ -3705,7 +3982,7 @@ static void nfs_access_cb(struct rpc_context *rpc, int status, void *command_dat
        free_nfs_cb_data(data);
 }
 
        free_nfs_cb_data(data);
 }
 
-static int nfs_access_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
+static int nfs_access_continue_internal(struct nfs_context *nfs, fattr3 *attr _U_, struct nfs_cb_data *data)
 {
        int nfsmode = 0;
        ACCESS3args args;
 {
        int nfsmode = 0;
        ACCESS3args args;
@@ -3802,7 +4079,7 @@ static void nfs_symlink_cb(struct rpc_context *rpc, int status, void *command_da
        free_nfs_cb_data(data);
 }
 
        free_nfs_cb_data(data);
 }
 
-static int nfs_symlink_continue_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
+static int nfs_symlink_continue_internal(struct nfs_context *nfs, fattr3 *attr _U_, struct nfs_cb_data *data)
 {
        struct nfs_symlink_data *symlink_data = data->continue_data;
        SYMLINK3args args;
 {
        struct nfs_symlink_data *symlink_data = data->continue_data;
        SYMLINK3args args;
@@ -3938,7 +4215,7 @@ static void nfs_rename_cb(struct rpc_context *rpc, int status, void *command_dat
        free_nfs_cb_data(data);
 }
 
        free_nfs_cb_data(data);
 }
 
-static int nfs_rename_continue_2_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
+static int nfs_rename_continue_2_internal(struct nfs_context *nfs, fattr3 *attr _U_, struct nfs_cb_data *data)
 {
        struct nfs_rename_data *rename_data = data->continue_data;
        RENAME3args args;
 {
        struct nfs_rename_data *rename_data = data->continue_data;
        RENAME3args args;
@@ -3961,7 +4238,7 @@ static int nfs_rename_continue_2_internal(struct nfs_context *nfs, struct nfs_cb
 }
 
 
 }
 
 
-static int nfs_rename_continue_1_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
+static int nfs_rename_continue_1_internal(struct nfs_context *nfs, fattr3 *attr _U_, struct nfs_cb_data *data)
 {
        struct nfs_rename_data *rename_data = data->continue_data;
        char* newpath = strdup(rename_data->newpath);
 {
        struct nfs_rename_data *rename_data = data->continue_data;
        char* newpath = strdup(rename_data->newpath);
@@ -4108,7 +4385,7 @@ static void nfs_link_cb(struct rpc_context *rpc, int status, void *command_data,
        free_nfs_cb_data(data);
 }
 
        free_nfs_cb_data(data);
 }
 
-static int nfs_link_continue_2_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
+static int nfs_link_continue_2_internal(struct nfs_context *nfs, fattr3 *attr _U_, struct nfs_cb_data *data)
 {
        struct nfs_link_data *link_data = data->continue_data;
        LINK3args args;
 {
        struct nfs_link_data *link_data = data->continue_data;
        LINK3args args;
@@ -4131,7 +4408,7 @@ static int nfs_link_continue_2_internal(struct nfs_context *nfs, struct nfs_cb_d
 }
 
 
 }
 
 
-static int nfs_link_continue_1_internal(struct nfs_context *nfs, struct nfs_cb_data *data)
+static int nfs_link_continue_1_internal(struct nfs_context *nfs, fattr3 *attr _U_, struct nfs_cb_data *data)
 {
        struct nfs_link_data *link_data = data->continue_data;
 
 {
        struct nfs_link_data *link_data = data->continue_data;
 
@@ -4233,6 +4510,10 @@ void nfs_set_gid(struct nfs_context *nfs, int gid) {
        rpc_set_gid(nfs->rpc, gid);
 }
 
        rpc_set_gid(nfs->rpc, gid);
 }
 
+void nfs_set_readahead(struct nfs_context *nfs, uint32_t v) {
+       rpc_set_readahead(nfs->rpc, v);
+}
+
 void nfs_set_error(struct nfs_context *nfs, char *error_string, ...)
 {
         va_list ap;
 void nfs_set_error(struct nfs_context *nfs, char *error_string, ...)
 {
         va_list ap;
@@ -4317,91 +4598,6 @@ static void mount_export_4_cb(struct rpc_context *rpc, int status, void *command
        }
 }
 
        }
 }
 
-static void mount_export_3_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
-{
-       struct mount_cb_data *data = private_data;
-       uint32_t mount_port;
-
-       assert(rpc->magic == RPC_CONTEXT_MAGIC);
-
-       if (status == RPC_STATUS_ERROR) {
-               data->cb(rpc, -EFAULT, command_data, data->private_data);
-               free_mount_cb_data(data);
-               return;
-       }
-       if (status == RPC_STATUS_CANCEL) {
-               data->cb(rpc, -EINTR, "Command was cancelled", data->private_data);
-               free_mount_cb_data(data);
-               return;
-       }
-
-       mount_port = *(uint32_t *)command_data;
-       if (mount_port == 0) {
-               rpc_set_error(rpc, "RPC error. Mount program is not available");
-               data->cb(rpc, -ENOENT, command_data, data->private_data);
-               free_mount_cb_data(data);
-               return;
-       }
-
-       rpc_disconnect(rpc, "normal disconnect");
-       if (rpc_connect_async(rpc, data->server, mount_port, mount_export_4_cb, data) != 0) {
-               data->cb(rpc, -ENOMEM, command_data, data->private_data);
-               free_mount_cb_data(data);
-               return;
-       }
-}
-
-static void mount_export_2_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
-{
-       struct mount_cb_data *data = private_data;
-
-       assert(rpc->magic == RPC_CONTEXT_MAGIC);
-
-       if (status == RPC_STATUS_ERROR) {
-               data->cb(rpc, -EFAULT, command_data, data->private_data);
-               free_mount_cb_data(data);
-               return;
-       }
-       if (status == RPC_STATUS_CANCEL) {
-               data->cb(rpc, -EINTR, "Command was cancelled", data->private_data);
-               free_mount_cb_data(data);
-               return;
-       }
-
-       if (rpc_pmap_getport_async(rpc, MOUNT_PROGRAM, MOUNT_V3, IPPROTO_TCP, mount_export_3_cb, private_data) != 0) {
-               data->cb(rpc, -ENOMEM, command_data, data->private_data);
-               free_mount_cb_data(data);
-               return;
-       }
-}
-
-static void mount_export_1_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
-{
-       struct mount_cb_data *data = private_data;
-
-       assert(rpc->magic == RPC_CONTEXT_MAGIC);
-
-       /* Dont want any more callbacks even if the socket is closed */
-       rpc->connect_cb = NULL;
-
-       if (status == RPC_STATUS_ERROR) {
-               data->cb(rpc, -EFAULT, command_data, data->private_data);
-               free_mount_cb_data(data);
-               return;
-       }
-       if (status == RPC_STATUS_CANCEL) {
-               data->cb(rpc, -EINTR, "Command was cancelled", data->private_data);
-               free_mount_cb_data(data);
-               return;
-       }
-
-       if (rpc_pmap_null_async(rpc, mount_export_2_cb, data) != 0) {
-               data->cb(rpc, -ENOMEM, command_data, data->private_data);
-               free_mount_cb_data(data);
-               return;
-       }
-}
-
 int mount_getexports_async(struct rpc_context *rpc, const char *server, rpc_cb cb, void *private_data)
 {
        struct mount_cb_data *data;
 int mount_getexports_async(struct rpc_context *rpc, const char *server, rpc_cb cb, void *private_data)
 {
        struct mount_cb_data *data;
@@ -4420,7 +4616,8 @@ int mount_getexports_async(struct rpc_context *rpc, const char *server, rpc_cb c
                free_mount_cb_data(data);
                return -1;
        }
                free_mount_cb_data(data);
                return -1;
        }
-       if (rpc_connect_async(rpc, data->server, 111, mount_export_1_cb, data) != 0) {
+       if (rpc_connect_program_async(rpc, data->server, MOUNT_PROGRAM, MOUNT_V3, mount_export_4_cb, data) != 0) {
+               rpc_set_error(rpc, "Failed to start connection");
                free_mount_cb_data(data);
                return -1;
        }
                free_mount_cb_data(data);
                return -1;
        }
index 5def0bc5d9041363b2bc833b5f50677750e5c517..4d487b71b0c692408dd606881294eaa229dde9b0 100644 (file)
--- a/lib/pdu.c
+++ b/lib/pdu.c
 #include "libnfs-raw.h"
 #include "libnfs-private.h"
 
 #include "libnfs-raw.h"
 #include "libnfs-private.h"
 
+void rpc_reset_queue(struct rpc_queue *q)
+{
+       q->head = NULL;
+       q->tail = NULL;
+}
+
+/*
+ * Push to the tail end of the queue
+ */
+void rpc_enqueue(struct rpc_queue *q, struct rpc_pdu *pdu)
+{
+       if (q->head == NULL)
+               q->head = pdu;
+       else
+               q->tail->next = pdu;
+       q->tail = pdu;
+       pdu->next = NULL;
+}
+
+/*
+ * Push to the front/head of the queue
+ */
+void rpc_return_to_queue(struct rpc_queue *q, struct rpc_pdu *pdu)
+{
+       pdu->next = q->head;
+       q->head = pdu;
+       if (q->tail == NULL)
+               q->tail = pdu;
+}
+
+unsigned int rpc_hash_xid(uint32_t xid)
+{
+       return (xid * 7919) % HASHES;
+}
+
 struct rpc_pdu *rpc_allocate_pdu(struct rpc_context *rpc, int program, int version, int procedure, rpc_cb cb, void *private_data, zdrproc_t zdr_decode_fn, int zdr_decode_bufsize)
 {
        struct rpc_pdu *pdu;
 struct rpc_pdu *rpc_allocate_pdu(struct rpc_context *rpc, int program, int version, int procedure, rpc_cb cb, void *private_data, zdrproc_t zdr_decode_fn, int zdr_decode_bufsize)
 {
        struct rpc_pdu *pdu;
@@ -129,13 +164,17 @@ int rpc_queue_pdu(struct rpc_context *rpc, struct rpc_pdu *pdu)
 
        /* for udp we dont queue, we just send it straight away */
        if (rpc->is_udp != 0) {
 
        /* for udp we dont queue, we just send it straight away */
        if (rpc->is_udp != 0) {
+               unsigned int hash;
+
 // XXX add a rpc->udp_dest_sock_size  and get rid of sys/socket.h and netinet/in.h
                if (sendto(rpc->fd, rpc->encodebuf, size, MSG_DONTWAIT, rpc->udp_dest, sizeof(struct sockaddr_in)) < 0) {
                        rpc_set_error(rpc, "Sendto failed with errno %s", strerror(errno));
                        rpc_free_pdu(rpc, pdu);
                        return -1;
                }
 // XXX add a rpc->udp_dest_sock_size  and get rid of sys/socket.h and netinet/in.h
                if (sendto(rpc->fd, rpc->encodebuf, size, MSG_DONTWAIT, rpc->udp_dest, sizeof(struct sockaddr_in)) < 0) {
                        rpc_set_error(rpc, "Sendto failed with errno %s", strerror(errno));
                        rpc_free_pdu(rpc, pdu);
                        return -1;
                }
-               SLIST_ADD_END(&rpc->waitpdu, pdu);
+
+               hash = rpc_hash_xid(pdu->xid);
+               rpc_enqueue(&rpc->waitpdu[hash], pdu);
                return 0;
        }
 
                return 0;
        }
 
@@ -153,7 +192,7 @@ int rpc_queue_pdu(struct rpc_context *rpc, struct rpc_pdu *pdu)
        }
 
        memcpy(pdu->outdata.data, rpc->encodebuf, pdu->outdata.size);
        }
 
        memcpy(pdu->outdata.data, rpc->encodebuf, pdu->outdata.size);
-       SLIST_ADD_END(&rpc->outqueue, pdu);
+       rpc_enqueue(&rpc->outqueue, pdu);
 
        return 0;
 }
 
        return 0;
 }
@@ -237,9 +276,11 @@ static int rpc_process_reply(struct rpc_context *rpc, struct rpc_pdu *pdu, ZDR *
 
 int rpc_process_pdu(struct rpc_context *rpc, char *buf, int size)
 {
 
 int rpc_process_pdu(struct rpc_context *rpc, char *buf, int size)
 {
-       struct rpc_pdu *pdu;
+       struct rpc_pdu *pdu, *prev_pdu;
+       struct rpc_queue *q;
        ZDR zdr;
        int pos, recordmarker = 0;
        ZDR zdr;
        int pos, recordmarker = 0;
+       unsigned int hash;
        uint32_t xid;
        char *reasbuf = NULL;
 
        uint32_t xid;
        char *reasbuf = NULL;
 
@@ -302,12 +343,26 @@ int rpc_process_pdu(struct rpc_context *rpc, char *buf, int size)
        }
        zdr_setpos(&zdr, pos);
 
        }
        zdr_setpos(&zdr, pos);
 
-       for (pdu=rpc->waitpdu; pdu; pdu=pdu->next) {
+       /* Look up the transaction in a hash table of our requests */
+       hash = rpc_hash_xid(xid);
+       q = &rpc->waitpdu[hash];
+
+       /* Follow the hash chain.  Linear traverse singly-linked list,
+        * but track previous entry for optimised removal */
+       prev_pdu = NULL;
+       for (pdu=q->head; pdu; pdu=pdu->next) {
                if (pdu->xid != xid) {
                if (pdu->xid != xid) {
+                       prev_pdu = pdu;
                        continue;
                }
                if (rpc->is_udp == 0 || rpc->is_broadcast == 0) {
                        continue;
                }
                if (rpc->is_udp == 0 || rpc->is_broadcast == 0) {
-                       SLIST_REMOVE(&rpc->waitpdu, pdu);
+                       /* Singly-linked but we track head and tail */
+                       if (pdu == q->head)
+                               q->head = pdu->next;
+                       if (pdu == q->tail)
+                               q->tail = prev_pdu;
+                       if (prev_pdu != NULL)
+                               prev_pdu->next = pdu->next;
                }
                if (rpc_process_reply(rpc, pdu, &zdr) != 0) {
                        rpc_set_error(rpc, "rpc_procdess_reply failed");
                }
                if (rpc_process_reply(rpc, pdu, &zdr) != 0) {
                        rpc_set_error(rpc, "rpc_procdess_reply failed");
index 055109a73c9f7b4be1f69d73f0552feb5c2d51ff..f973f0178b923a0dab3f369fea14a04b076e85ab 100644 (file)
@@ -80,7 +80,6 @@
 #include "win32_errnowrapper.h"
 #endif
 
 #include "win32_errnowrapper.h"
 #endif
 
-
 static int rpc_reconnect_requeue(struct rpc_context *rpc);
 static int rpc_connect_sockaddr_async(struct rpc_context *rpc, struct sockaddr_storage *s);
 
 static int rpc_reconnect_requeue(struct rpc_context *rpc);
 static int rpc_connect_sockaddr_async(struct rpc_context *rpc, struct sockaddr_storage *s);
 
@@ -96,6 +95,14 @@ static void set_nonblocking(int fd)
 #endif //FIXME
 }
 
 #endif //FIXME
 }
 
+static void set_nolinger(int fd)
+{
+       struct linger lng;
+       lng.l_onoff = 1;
+       lng.l_linger = 0;
+       setsockopt(fd, SOL_SOCKET, SO_LINGER, &lng, sizeof(lng));
+}
+
 #ifdef HAVE_NETINET_TCP_H
 int set_tcp_sockopt(int sockfd, int optname, int value)
 {
 #ifdef HAVE_NETINET_TCP_H
 int set_tcp_sockopt(int sockfd, int optname, int value)
 {
@@ -123,6 +130,11 @@ int rpc_get_fd(struct rpc_context *rpc)
        return rpc->fd;
 }
 
        return rpc->fd;
 }
 
+static int rpc_has_queue(struct rpc_queue *q)
+{
+       return q->head != NULL;
+}
+
 int rpc_which_events(struct rpc_context *rpc)
 {
        int events;
 int rpc_which_events(struct rpc_context *rpc)
 {
        int events;
@@ -136,7 +148,7 @@ int rpc_which_events(struct rpc_context *rpc)
                return POLLIN;
        }
 
                return POLLIN;
        }
 
-       if (rpc->outqueue) {
+       if (rpc_has_queue(&rpc->outqueue)) {
                events |= POLLOUT;
        }
        return events;
                events |= POLLOUT;
        }
        return events;
@@ -145,6 +157,7 @@ int rpc_which_events(struct rpc_context *rpc)
 static int rpc_write_to_socket(struct rpc_context *rpc)
 {
        int32_t count;
 static int rpc_write_to_socket(struct rpc_context *rpc)
 {
        int32_t count;
+       struct rpc_pdu *pdu;
 
        assert(rpc->magic == RPC_CONTEXT_MAGIC);
 
 
        assert(rpc->magic == RPC_CONTEXT_MAGIC);
 
@@ -153,12 +166,12 @@ static int rpc_write_to_socket(struct rpc_context *rpc)
                return -1;
        }
 
                return -1;
        }
 
-       while (rpc->outqueue != NULL) {
+       while ((pdu = rpc->outqueue.head) != NULL) {
                int64_t total;
 
                int64_t total;
 
-               total = rpc->outqueue->outdata.size;
+               total = pdu->outdata.size;
 
 
-               count = send(rpc->fd, rpc->outqueue->outdata.data + rpc->outqueue->written, total - rpc->outqueue->written, 0);
+               count = send(rpc->fd, pdu->outdata.data + pdu->written, total - pdu->written, 0);
                if (count == -1) {
                        if (errno == EAGAIN || errno == EWOULDBLOCK) {
                                return 0;
                if (count == -1) {
                        if (errno == EAGAIN || errno == EWOULDBLOCK) {
                                return 0;
@@ -167,12 +180,16 @@ static int rpc_write_to_socket(struct rpc_context *rpc)
                        return -1;
                }
 
                        return -1;
                }
 
-               rpc->outqueue->written += count;
-               if (rpc->outqueue->written == total) {
-                       struct rpc_pdu *pdu = rpc->outqueue;
+               pdu->written += count;
+               if (pdu->written == total) {
+                       unsigned int hash;
 
 
-                       SLIST_REMOVE(&rpc->outqueue, pdu);
-                       SLIST_ADD_END(&rpc->waitpdu, pdu);
+                       rpc->outqueue.head = pdu->next;
+                       if (pdu->next == NULL)
+                               rpc->outqueue.tail = NULL;
+
+                       hash = rpc_hash_xid(pdu->xid);
+                       rpc_enqueue(&rpc->waitpdu[hash], pdu);
                }
        }
        return 0;
                }
        }
        return 0;
@@ -369,7 +386,7 @@ int rpc_service(struct rpc_context *rpc, int revents)
                }
        }
 
                }
        }
 
-       if (revents & POLLOUT && rpc->outqueue != NULL) {
+       if (revents & POLLOUT && rpc_has_queue(&rpc->outqueue)) {
                if (rpc_write_to_socket(rpc) != 0) {
                        rpc_set_error(rpc, "write to socket failed");
                        return -1;
                if (rpc_write_to_socket(rpc) != 0) {
                        rpc_set_error(rpc, "write to socket failed");
                        return -1;
@@ -418,6 +435,15 @@ static int rpc_connect_sockaddr_async(struct rpc_context *rpc, struct sockaddr_s
                if (rpc->tcp_syncnt != RPC_PARAM_UNDEFINED) {
                        set_tcp_sockopt(rpc->fd, TCP_SYNCNT, rpc->tcp_syncnt);
                }
                if (rpc->tcp_syncnt != RPC_PARAM_UNDEFINED) {
                        set_tcp_sockopt(rpc->fd, TCP_SYNCNT, rpc->tcp_syncnt);
                }
+#endif
+               break;
+       case AF_INET6:
+               socksize = sizeof(struct sockaddr_in6);
+               rpc->fd = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
+#ifdef HAVE_NETINET_TCP_H
+               if (rpc->tcp_syncnt != RPC_PARAM_UNDEFINED) {
+                       set_tcp_sockopt(rpc->fd, TCP_SYNCNT, rpc->tcp_syncnt);
+               }
 #endif
                break;
        default:
 #endif
                break;
        default:
@@ -449,7 +475,7 @@ static int rpc_connect_sockaddr_async(struct rpc_context *rpc, struct sockaddr_s
         * binding will usually succeed.
         */
        {
         * binding will usually succeed.
         */
        {
-               struct sockaddr_in sin;
+               struct sockaddr_storage ss;
                static int portOfs = 0;
                const int firstPort = 512;      /* >= 512 according to Sun docs */
                const int portCount = IPPORT_RESERVED - firstPort;
                static int portOfs = 0;
                const int firstPort = 512;      /* >= 512 according to Sun docs */
                const int portCount = IPPORT_RESERVED - firstPort;
@@ -466,12 +492,26 @@ static int rpc_connect_sockaddr_async(struct rpc_context *rpc, struct sockaddr_s
 
                        /* skip well-known ports */
                        if (!getservbyport(port, "tcp")) {
 
                        /* skip well-known ports */
                        if (!getservbyport(port, "tcp")) {
-                               memset(&sin, 0, sizeof(sin));
-                               sin.sin_port        = port;
-                               sin.sin_family      = AF_INET;
-                               sin.sin_addr.s_addr = 0;
+                               memset(&ss, 0, sizeof(ss));
 
 
-                               rc = bind(rpc->fd, (struct sockaddr *)&sin, sizeof(struct sockaddr_in));
+                               switch (s->ss_family) {
+                               case AF_INET:
+                                       ((struct sockaddr_in *)&ss)->sin_port = port;
+                                       ((struct sockaddr_in *)&ss)->sin_family      = AF_INET;
+#ifdef HAVE_SOCKADDR_LEN
+                                       ((struct sockaddr_in *)&ss)->sin_len = sizeof(struct sockaddr_in);
+#endif
+                                       break;
+                               case AF_INET6:
+                                       ((struct sockaddr_in6 *)&ss)->sin6_port = port;
+                                       ((struct sockaddr_in6 *)&ss)->sin6_family      = AF_INET6;
+#ifdef HAVE_SOCKADDR_LEN
+                                       ((struct sockaddr_in6 *)&ss)->sin6_len = sizeof(struct sockaddr6_in);
+#endif
+                                       break;
+                               }
+
+                               rc = bind(rpc->fd, (struct sockaddr *)&ss, socksize);
 #if !defined(WIN32)
                                /* we got EACCES, so don't try again */
                                if (rc != 0 && errno == EACCES)
 #if !defined(WIN32)
                                /* we got EACCES, so don't try again */
                                if (rc != 0 && errno == EACCES)
@@ -482,6 +522,7 @@ static int rpc_connect_sockaddr_async(struct rpc_context *rpc, struct sockaddr_s
        }
 
        set_nonblocking(rpc->fd);
        }
 
        set_nonblocking(rpc->fd);
+       set_nolinger(rpc->fd);
 
        if (connect(rpc->fd, (struct sockaddr *)s, socksize) != 0 && errno != EINPROGRESS) {
                rpc_set_error(rpc, "connect() to server failed. %s(%d)", strerror(errno), errno);
 
        if (connect(rpc->fd, (struct sockaddr *)s, socksize) != 0 && errno != EINPROGRESS) {
                rpc_set_error(rpc, "connect() to server failed. %s(%d)", strerror(errno), errno);
@@ -493,7 +534,7 @@ static int rpc_connect_sockaddr_async(struct rpc_context *rpc, struct sockaddr_s
 
 int rpc_connect_async(struct rpc_context *rpc, const char *server, int port, rpc_cb cb, void *private_data)
 {
 
 int rpc_connect_async(struct rpc_context *rpc, const char *server, int port, rpc_cb cb, void *private_data)
 {
-       struct sockaddr_in *sin = (struct sockaddr_in *)&rpc->s;
+       struct addrinfo *ai = NULL;
 
        assert(rpc->magic == RPC_CONTEXT_MAGIC);
 
 
        assert(rpc->magic == RPC_CONTEXT_MAGIC);
 
@@ -509,18 +550,27 @@ int rpc_connect_async(struct rpc_context *rpc, const char *server, int port, rpc
 
        rpc->auto_reconnect = 0;
 
 
        rpc->auto_reconnect = 0;
 
-       sin->sin_family = AF_INET;
-       sin->sin_port   = htons(port);
-       if (inet_pton(AF_INET, server, &sin->sin_addr) != 1) {
-               rpc_set_error(rpc, "Not a valid server ip address");
+       if (getaddrinfo(server, NULL, NULL, &ai) != 0) {
+               rpc_set_error(rpc, "Invalid address:%s. "
+                             "Can not resolv into IPv4/v6 structure.", server);
                return -1;
                return -1;
-       }
-
+       }
 
 
-       switch (rpc->s.ss_family) {
+       switch (ai->ai_family) {
        case AF_INET:
        case AF_INET:
+               ((struct sockaddr_in *)&rpc->s)->sin_family = ai->ai_family;
+               ((struct sockaddr_in *)&rpc->s)->sin_port   = htons(port);
+               ((struct sockaddr_in *)&rpc->s)->sin_addr   = ((struct sockaddr_in *)(ai->ai_addr))->sin_addr;
+#ifdef HAVE_SOCKADDR_LEN
+               ((struct sockaddr_in *)&rpc->s)->sin_len = sizeof(struct sockaddr_in);
+#endif
+               break;
+       case AF_INET6:
+               ((struct sockaddr_in6 *)&rpc->s)->sin6_family = ai->ai_family;
+               ((struct sockaddr_in6 *)&rpc->s)->sin6_port   = htons(port);
+               ((struct sockaddr_in6 *)&rpc->s)->sin6_addr   = ((struct sockaddr_in6 *)(ai->ai_addr))->sin6_addr;
 #ifdef HAVE_SOCKADDR_LEN
 #ifdef HAVE_SOCKADDR_LEN
-               sin->sin_len = sizeof(struct sockaddr_in);
+               ((struct sockaddr_in6 *)&rpc->s)->sin6_len = sizeof(struct sockaddr_in6);
 #endif
                break;
        }
 #endif
                break;
        }
@@ -528,6 +578,8 @@ int rpc_connect_async(struct rpc_context *rpc, const char *server, int port, rpc
        rpc->connect_cb  = cb;
        rpc->connect_data = private_data;
 
        rpc->connect_cb  = cb;
        rpc->connect_data = private_data;
 
+       freeaddrinfo(ai);
+
        if (rpc_connect_sockaddr_async(rpc, &rpc->s) != 0) {
                return -1;
        }
        if (rpc_connect_sockaddr_async(rpc, &rpc->s) != 0) {
                return -1;
        }
@@ -570,6 +622,7 @@ static void reconnect_cb(struct rpc_context *rpc, int status, void *data _U_, vo
 static int rpc_reconnect_requeue(struct rpc_context *rpc)
 {
        struct rpc_pdu *pdu;
 static int rpc_reconnect_requeue(struct rpc_context *rpc)
 {
        struct rpc_pdu *pdu;
+       unsigned int i;
 
        assert(rpc->magic == RPC_CONTEXT_MAGIC);
 
 
        assert(rpc->magic == RPC_CONTEXT_MAGIC);
 
@@ -583,11 +636,15 @@ static int rpc_reconnect_requeue(struct rpc_context *rpc)
        /* socket is closed so we will not get any replies to any commands
         * in flight. Move them all over from the waitpdu queue back to the out queue
         */
        /* socket is closed so we will not get any replies to any commands
         * in flight. Move them all over from the waitpdu queue back to the out queue
         */
-       for (pdu=rpc->waitpdu; pdu; pdu=pdu->next) {
-               SLIST_REMOVE(&rpc->waitpdu, pdu);
-               SLIST_ADD(&rpc->outqueue, pdu);
-               /* we have to re-send the whole pdu again */
-               pdu->written = 0;
+       for (i = 0; i < HASHES; i++) {
+               struct rpc_queue *q = &rpc->waitpdu[i];
+
+               for (pdu=q->head; pdu; pdu=pdu->next) {
+                       rpc_return_to_queue(&rpc->outqueue, pdu);
+                       /* we have to re-send the whole pdu again */
+                       pdu->written = 0;
+               }
+               rpc_reset_queue(q);
        }
 
        if (rpc->auto_reconnect != 0) {
        }
 
        if (rpc->auto_reconnect != 0) {
@@ -697,14 +754,19 @@ int rpc_queue_length(struct rpc_context *rpc)
 {
        int i=0;
        struct rpc_pdu *pdu;
 {
        int i=0;
        struct rpc_pdu *pdu;
+       unsigned int n;
 
        assert(rpc->magic == RPC_CONTEXT_MAGIC);
 
 
        assert(rpc->magic == RPC_CONTEXT_MAGIC);
 
-       for(pdu = rpc->outqueue; pdu; pdu = pdu->next) {
+       for(pdu = rpc->outqueue.head; pdu; pdu = pdu->next) {
                i++;
        }
                i++;
        }
-       for(pdu = rpc->waitpdu; pdu; pdu = pdu->next) {
-               i++;
+
+       for (n = 0; n < HASHES; n++) {
+               struct rpc_queue *q = &rpc->waitpdu[n];
+
+               for(pdu = q->head; pdu; pdu = pdu->next)
+                       i++;
        }
        return i;
 }
        }
        return i;
 }
index 138d031b8e444cb630eae020d689f91ed3acb1fc..de7fdbdeb0fb28bb7f2ab996e36a9edfb960f598 100644 (file)
@@ -17,6 +17,8 @@ mount-stamp : mount.x
        rm -f $(mount_GENERATED)
        touch mount-stamp
 
        rm -f $(mount_GENERATED)
        touch mount-stamp
 
-compile_rpc:   
-       rpcgen -h mount.x | sed -e "s/#include <rpc\/rpc.h>//" | sed -e "s/xdr/zdr/g" -e "s/XDR/ZDR/g" > libnfs-raw-mount.h
-       rpcgen -c mount.x | sed -e "s/#include \".*mount.h\"/#include \"libnfs-xdr.h\"\n#include \"libnfs-raw-mount.h\"/" -e "s/xdr/zdr/g" -e "s/XDR/ZDR/g" -e "s/register int32_t \*buf;/register int32_t *buf;\n      buf = NULL;/" > libnfs-raw-mount.c
+compile_rpc:
+       cat mount.x | head -29 >libnfs-raw-mount.h
+       rpcgen -h mount.x | sed -e "s/#include <rpc\/rpc.h>//" | sed -e "s/xdr/zdr/g" -e "s/XDR/ZDR/g" >> libnfs-raw-mount.h
+       cat mount.x | head -29 >libnfs-raw-mount.c
+       rpcgen -c mount.x | sed -e "s/#include \".*mount.h\"/#include \"libnfs-xdr.h\"\n#include \"libnfs-raw-mount.h\"/" -e "s/xdr/zdr/g" -e "s/XDR/ZDR/g" -e "s/register int32_t \*buf;/register int32_t *buf;\n      buf = NULL;/" >> libnfs-raw-mount.c
index 81fae00d39f6e31dda9ec7c2f8279188b8ef2fab..0a70d43e0fd6762803aff9c1d7482f8d8c216c5c 100644 (file)
@@ -1,3 +1,32 @@
+/*
+Copyright (c) 2014, Ronnie Sahlberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+   list of conditions and the following disclaimer. 
+2. Redistributions in binary form must reproduce the above copyright notice,
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+The views and conclusions contained in the software and documentation are those
+of the authors and should not be interpreted as representing official policies, 
+either expressed or implied, of the FreeBSD Project.
+*/
+
 /*
  * Please do not edit this file.
  * It was generated using rpcgen.
 /*
  * Please do not edit this file.
  * It was generated using rpcgen.
index 1cb2775c5b5d598e6372dd9ea5e5f25b502fbe49..9f07d31a38c4b9d2d537edd00c3d36bad934671b 100644 (file)
@@ -1,3 +1,32 @@
+/*
+Copyright (c) 2014, Ronnie Sahlberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+   list of conditions and the following disclaimer. 
+2. Redistributions in binary form must reproduce the above copyright notice,
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+The views and conclusions contained in the software and documentation are those
+of the authors and should not be interpreted as representing official policies, 
+either expressed or implied, of the FreeBSD Project.
+*/
+
 /*
  * Please do not edit this file.
  * It was generated using rpcgen.
 /*
  * Please do not edit this file.
  * It was generated using rpcgen.
@@ -6,7 +35,8 @@
 #ifndef _MOUNT_H_RPCGEN
 #define _MOUNT_H_RPCGEN
 
 #ifndef _MOUNT_H_RPCGEN
 #define _MOUNT_H_RPCGEN
 
-#include <nfsc/libnfs-zdr.h>
+
+
 
 #ifdef __cplusplus
 extern "C" {
 
 #ifdef __cplusplus
 extern "C" {
index 10e6a1fdd94d775fa041f1f0752b888b48b8bc5f..62b4e3984c72bcf349d3f83a9604ba8798b877a4 100644 (file)
@@ -1,4 +1,31 @@
-/* copied from RFC1813 and RFC1094 */
+/*
+Copyright (c) 2014, Ronnie Sahlberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+   list of conditions and the following disclaimer. 
+2. Redistributions in binary form must reproduce the above copyright notice,
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+The views and conclusions contained in the software and documentation are those
+of the authors and should not be interpreted as representing official policies, 
+either expressed or implied, of the FreeBSD Project.
+*/
 
 const MNTPATHLEN = 1024;  /* Maximum bytes in a path name */
 const MNTNAMLEN  = 255;   /* Maximum bytes in a name */
 
 const MNTPATHLEN = 1024;  /* Maximum bytes in a path name */
 const MNTNAMLEN  = 255;   /* Maximum bytes in a name */
index aad66ce60957ed87e0ffdea7afc945c16b467a47..2177519c8b71576ee5ec72e2a74bb7dd93258e7f 100644 (file)
@@ -18,5 +18,7 @@ nfs-stamp : nfs.x
        touch nfs-stamp
 
 compile_rpc:   
        touch nfs-stamp
 
 compile_rpc:   
-       rpcgen -h nfs.x | sed -e "s/#include <rpc\/rpc.h>//" -e "s/xdr/zdr/g" -e "s/XDR/ZDR/g" -e "s/#define _NFS_H_RPCGEN/#define _NFS_H_RPCGEN\n#include <nfsc\/libnfs-zdr.h>/g" -e "s/#define NFS3_COOKIEVERFSIZE 8/#define NFS3_COOKIEVERFSIZE 8\n\n#if defined(ANDROID)\ntypedef long long int quad_t;\ntypedef long long unsigned u_quad_t;\n#endif\n#if defined(WIN32)\ntypedef long long int quad_t;\ntypedef long long unsigned u_quad_t;\n#endif/g" > libnfs-raw-nfs.h
-       rpcgen -c nfs.x | sed -e "s/#include \".*nfs.h\"/#include \"libnfs-xdr.h\"\n#include \"libnfs-raw-nfs.h\"/" -e "s/xdr/zdr/g" -e "s/XDR/ZDR/g" -e "s/register int32_t \*buf;/register int32_t *buf;\n    buf = NULL;/" > libnfs-raw-nfs.c
+       cat nfs.x | head -29 >libnfs-raw-nfs.h
+       rpcgen -h nfs.x | sed -e "s/#include <rpc\/rpc.h>//" -e "s/xdr/zdr/g" -e "s/XDR/ZDR/g" -e "s/#define _NFS_H_RPCGEN/#define _NFS_H_RPCGEN\n#include <nfsc\/libnfs-zdr.h>/g" -e "s/#define NFS3_COOKIEVERFSIZE 8/#define NFS3_COOKIEVERFSIZE 8\n\n#if defined(ANDROID)\ntypedef long long int quad_t;\ntypedef long long unsigned u_quad_t;\n#endif\n#if defined(WIN32)\ntypedef long long int quad_t;\ntypedef long long unsigned u_quad_t;\n#endif/g" >> libnfs-raw-nfs.h
+       cat nfs.x | head -29 >libnfs-raw-nfs.c
+       rpcgen -c nfs.x | sed -e "s/#include \".*nfs.h\"/#include \"libnfs-xdr.h\"\n#include \"libnfs-raw-nfs.h\"/" -e "s/xdr/zdr/g" -e "s/XDR/ZDR/g" -e "s/register int32_t \*buf;/register int32_t *buf;\n    buf = NULL;/" >> libnfs-raw-nfs.c
index 04e914d74e3b24411cdaa92c6ecc43ef2817636e..30d05a584be7fad86771cd427d4d5e999f7b9389 100644 (file)
@@ -1,3 +1,32 @@
+/*
+Copyright (c) 2014, Ronnie Sahlberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+   list of conditions and the following disclaimer. 
+2. Redistributions in binary form must reproduce the above copyright notice,
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+The views and conclusions contained in the software and documentation are those
+of the authors and should not be interpreted as representing official policies, 
+either expressed or implied, of the FreeBSD Project.
+*/
+
 /*
  * Please do not edit this file.
  * It was generated using rpcgen.
 /*
  * Please do not edit this file.
  * It was generated using rpcgen.
@@ -17,24 +46,13 @@ zdr_cookieverf3 (ZDR *zdrs, cookieverf3 objp)
        return TRUE;
 }
 
        return TRUE;
 }
 
-bool_t
-zdr_uint64 (ZDR *zdrs, uint64 *objp)
-{
-       register int32_t *buf;
-       buf = NULL;
-
-        if (!zdr_u_quad_t (zdrs, objp))
-                return FALSE;
-       return TRUE;
-}
-
 bool_t
 zdr_cookie3 (ZDR *zdrs, cookie3 *objp)
 {
        register int32_t *buf;
        buf = NULL;
 
 bool_t
 zdr_cookie3 (ZDR *zdrs, cookie3 *objp)
 {
        register int32_t *buf;
        buf = NULL;
 
-        if (!zdr_uint64 (zdrs, objp))
+        if (!zdr_u_quad_t (zdrs, objp))
                 return FALSE;
        return TRUE;
 }
                 return FALSE;
        return TRUE;
 }
@@ -124,7 +142,7 @@ zdr_size3 (ZDR *zdrs, size3 *objp)
        register int32_t *buf;
        buf = NULL;
 
        register int32_t *buf;
        buf = NULL;
 
-        if (!zdr_uint64 (zdrs, objp))
+        if (!zdr_u_quad_t (zdrs, objp))
                 return FALSE;
        return TRUE;
 }
                 return FALSE;
        return TRUE;
 }
@@ -135,7 +153,7 @@ zdr_fileid3 (ZDR *zdrs, fileid3 *objp)
        register int32_t *buf;
        buf = NULL;
 
        register int32_t *buf;
        buf = NULL;
 
-        if (!zdr_uint64 (zdrs, objp))
+        if (!zdr_u_quad_t (zdrs, objp))
                 return FALSE;
        return TRUE;
 }
                 return FALSE;
        return TRUE;
 }
@@ -188,7 +206,7 @@ zdr_fattr3 (ZDR *zdrs, fattr3 *objp)
                 return FALSE;
         if (!zdr_specdata3 (zdrs, &objp->rdev))
                 return FALSE;
                 return FALSE;
         if (!zdr_specdata3 (zdrs, &objp->rdev))
                 return FALSE;
-        if (!zdr_uint64 (zdrs, &objp->fsid))
+        if (!zdr_u_quad_t (zdrs, &objp->fsid))
                 return FALSE;
         if (!zdr_fileid3 (zdrs, &objp->fileid))
                 return FALSE;
                 return FALSE;
         if (!zdr_fileid3 (zdrs, &objp->fileid))
                 return FALSE;
@@ -250,7 +268,7 @@ zdr_offset3 (ZDR *zdrs, offset3 *objp)
        register int32_t *buf;
        buf = NULL;
 
        register int32_t *buf;
        buf = NULL;
 
-        if (!zdr_uint64 (zdrs, objp))
+        if (!zdr_u_quad_t (zdrs, objp))
                 return FALSE;
        return TRUE;
 }
                 return FALSE;
        return TRUE;
 }
index 8eb3b2e21fea18701caace016262e6758fcf3867..4b4c87406f4b6b4cb4cb31bc68b833b9eeacc10f 100644 (file)
@@ -1,3 +1,32 @@
+/*
+Copyright (c) 2014, Ronnie Sahlberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+   list of conditions and the following disclaimer. 
+2. Redistributions in binary form must reproduce the above copyright notice,
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+The views and conclusions contained in the software and documentation are those
+of the authors and should not be interpreted as representing official policies, 
+either expressed or implied, of the FreeBSD Project.
+*/
+
 /*
  * Please do not edit this file.
  * It was generated using rpcgen.
 /*
  * Please do not edit this file.
  * It was generated using rpcgen.
@@ -30,9 +59,7 @@ typedef long long unsigned u_quad_t;
 
 typedef char cookieverf3[NFS3_COOKIEVERFSIZE];
 
 
 typedef char cookieverf3[NFS3_COOKIEVERFSIZE];
 
-typedef u_quad_t uint64;
-
-typedef uint64 cookie3;
+typedef u_quad_t cookie3;
 
 struct nfs_fh3 {
        struct {
 
 struct nfs_fh3 {
        struct {
@@ -67,9 +94,9 @@ typedef u_int uid3;
 
 typedef u_int gid3;
 
 
 typedef u_int gid3;
 
-typedef uint64 size3;
+typedef u_quad_t size3;
 
 
-typedef uint64 fileid3;
+typedef u_quad_t fileid3;
 
 struct specdata3 {
        u_int specdata1;
 
 struct specdata3 {
        u_int specdata1;
@@ -92,7 +119,7 @@ struct fattr3 {
        size3 size;
        size3 used;
        specdata3 rdev;
        size3 size;
        size3 used;
        specdata3 rdev;
-       uint64 fsid;
+       u_quad_t fsid;
        fileid3 fileid;
        nfstime3 atime;
        nfstime3 mtime;
        fileid3 fileid;
        nfstime3 atime;
        nfstime3 mtime;
@@ -148,7 +175,7 @@ enum stable_how {
 };
 typedef enum stable_how stable_how;
 
 };
 typedef enum stable_how stable_how;
 
-typedef uint64 offset3;
+typedef u_quad_t offset3;
 
 typedef u_int count3;
 
 
 typedef u_int count3;
 
@@ -1611,7 +1638,6 @@ extern int nfsacl_program_3_freeresult ();
 
 #if defined(__STDC__) || defined(__cplusplus)
 extern  bool_t zdr_cookieverf3 (ZDR *, cookieverf3);
 
 #if defined(__STDC__) || defined(__cplusplus)
 extern  bool_t zdr_cookieverf3 (ZDR *, cookieverf3);
-extern  bool_t zdr_uint64 (ZDR *, uint64*);
 extern  bool_t zdr_cookie3 (ZDR *, cookie3*);
 extern  bool_t zdr_nfs_fh3 (ZDR *, nfs_fh3*);
 extern  bool_t zdr_filename3 (ZDR *, filename3*);
 extern  bool_t zdr_cookie3 (ZDR *, cookie3*);
 extern  bool_t zdr_nfs_fh3 (ZDR *, nfs_fh3*);
 extern  bool_t zdr_filename3 (ZDR *, filename3*);
@@ -1799,7 +1825,6 @@ extern  bool_t zdr_SETACL3res (ZDR *, SETACL3res*);
 
 #else /* K&R C */
 extern bool_t zdr_cookieverf3 ();
 
 #else /* K&R C */
 extern bool_t zdr_cookieverf3 ();
-extern bool_t zdr_uint64 ();
 extern bool_t zdr_cookie3 ();
 extern bool_t zdr_nfs_fh3 ();
 extern bool_t zdr_filename3 ();
 extern bool_t zdr_cookie3 ();
 extern bool_t zdr_nfs_fh3 ();
 extern bool_t zdr_filename3 ();
index cc19757ea607ede75d79d47517a068050eb01123..ca48c0305886d7cbf6ab25fccc5c59a52eee2fca 100644 (file)
--- a/nfs/nfs.x
+++ b/nfs/nfs.x
@@ -1,4 +1,31 @@
-/* NFS part from rfc 1813, NFSACL part is from wireshark sources */
+/*
+Copyright (c) 2014, Ronnie Sahlberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+   list of conditions and the following disclaimer. 
+2. Redistributions in binary form must reproduce the above copyright notice,
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+The views and conclusions contained in the software and documentation are those
+of the authors and should not be interpreted as representing official policies, 
+either expressed or implied, of the FreeBSD Project.
+*/
 
 /*
  * NFS v3 Definitions
 
 /*
  * NFS v3 Definitions
@@ -10,16 +37,7 @@ const NFS3_COOKIEVERFSIZE = 8;
 
 typedef opaque cookieverf3[NFS3_COOKIEVERFSIZE];
 
 
 typedef opaque cookieverf3[NFS3_COOKIEVERFSIZE];
 
-/*unsigned hyper can be overridden by giving rpcgen -DU_INT64_PLATTFORM_TYPE="
-  where rpcgen doesn't know anything about hyper
-  default to unsigned hyper as of rfc 1813 */
-#ifndef U_INT64_PLATTFORM_TYPE
-#define U_INT64_PLATTFORM_TYPE unsigned hyper
-#endif/*U_INT64_PLATTFORM_TYPE*/
-
-typedef U_INT64_PLATTFORM_TYPE uint64;
-
-typedef uint64 cookie3;
+typedef u_quad_t cookie3;
 
 struct nfs_fh3 {
        opaque       data<NFS3_FHSIZE>;
 
 struct nfs_fh3 {
        opaque       data<NFS3_FHSIZE>;
@@ -48,9 +66,9 @@ typedef unsigned int uid3;
 
 typedef unsigned int gid3;
 
 
 typedef unsigned int gid3;
 
-typedef uint64 size3;
+typedef u_quad_t size3;
 
 
-typedef uint64 fileid3;
+typedef u_quad_t fileid3;
 
 struct specdata3 {
        unsigned int specdata1;
 
 struct specdata3 {
        unsigned int specdata1;
@@ -71,7 +89,7 @@ struct fattr3 {
        size3        size;
        size3        used;
        specdata3    rdev;
        size3        size;
        size3        used;
        specdata3    rdev;
-       uint64       fsid;
+       u_quad_t       fsid;
        fileid3      fileid;
        nfstime3     atime;
        nfstime3     mtime;
        fileid3      fileid;
        nfstime3     atime;
        nfstime3     mtime;
@@ -124,7 +142,7 @@ enum stable_how {
        FILE_SYNC = 2
 };
 
        FILE_SYNC = 2
 };
 
-typedef uint64 offset3;
+typedef u_quad_t offset3;
 
 typedef unsigned int count3;
 
 
 typedef unsigned int count3;
 
index 5b6d02fbc0d81a7c5b3a15ed40fff8d58154616e..0cc563dbf5b327c92010b6adace537c80ed5ded8 100644 (file)
@@ -18,5 +18,7 @@ nlm-stamp : nlm.x
        touch nlm-stamp
 
 compile_rpc:   
        touch nlm-stamp
 
 compile_rpc:   
-       rpcgen -h nlm.x | sed -e "s/#include <rpc\/rpc.h>//" | sed -e "s/xdr/zdr/g" -e "s/XDR/ZDR/g" > libnfs-raw-nlm.h
-       rpcgen -c nlm.x | sed -e "s/#include \".*nlm.h\"/#include \"libnfs-xdr.h\"\n#include \"libnfs-raw-nlm.h\"/" -e "s/xdr/zdr/g" -e "s/XDR/ZDR/g" -e "s/register int32_t \*buf;/register int32_t *buf;\n    buf = NULL;/" > libnfs-raw-nlm.c
+       cat nlm.x | head -29 >libnfs-raw-nlm.h
+       rpcgen -h nlm.x | sed -e "s/#include <rpc\/rpc.h>//" | sed -e "s/xdr/zdr/g" -e "s/XDR/ZDR/g" >> libnfs-raw-nlm.h
+       cat nlm.x | head -29 >libnfs-raw-nlm.c
+       rpcgen -c nlm.x | sed -e "s/#include \".*nlm.h\"/#include \"libnfs-xdr.h\"\n#include \"libnfs-raw-nlm.h\"/" -e "s/xdr/zdr/g" -e "s/XDR/ZDR/g" -e "s/register int32_t \*buf;/register int32_t *buf;\n    buf = NULL;/" >> libnfs-raw-nlm.c
index 808924af6063c9806b9c9eb15cae610f51b97cd3..79302615eafc4d31b1f06283cc47bb1ca4fa7976 100644 (file)
@@ -1,3 +1,32 @@
+/*
+Copyright (c) 2014, Ronnie Sahlberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+   list of conditions and the following disclaimer. 
+2. Redistributions in binary form must reproduce the above copyright notice,
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+The views and conclusions contained in the software and documentation are those
+of the authors and should not be interpreted as representing official policies, 
+either expressed or implied, of the FreeBSD Project.
+*/
+
 /*
  * Please do not edit this file.
  * It was generated using rpcgen.
 /*
  * Please do not edit this file.
  * It was generated using rpcgen.
index 6437aa4ddbbacde76f7606c466d867cce9c187d7..eb73c1ac99bb3712bc4d5166336828c14feb58c0 100644 (file)
@@ -1,3 +1,32 @@
+/*
+Copyright (c) 2014, Ronnie Sahlberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+   list of conditions and the following disclaimer. 
+2. Redistributions in binary form must reproduce the above copyright notice,
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+The views and conclusions contained in the software and documentation are those
+of the authors and should not be interpreted as representing official policies, 
+either expressed or implied, of the FreeBSD Project.
+*/
+
 /*
  * Please do not edit this file.
  * It was generated using rpcgen.
 /*
  * Please do not edit this file.
  * It was generated using rpcgen.
 #ifndef _NLM_H_RPCGEN
 #define _NLM_H_RPCGEN
 
 #ifndef _NLM_H_RPCGEN
 #define _NLM_H_RPCGEN
 
-#include <nfsc/libnfs-zdr.h>
+
+
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-#if defined(ANDROID)
-typedef long long int quad_t;
-typedef long long unsigned u_quad_t;
-#endif
-#if defined(WIN32)
-typedef long long int quad_t;
-typedef long long unsigned u_quad_t;
-#endif
 
 struct nlm_fh4 {
        struct {
 
 struct nlm_fh4 {
        struct {
index 8ec6614ddb8ac714d8580b2235d1b7a0175504fc..6cd39c2b6c8d29c0364dbbe624c92021e6b2cb80 100644 (file)
--- a/nlm/nlm.x
+++ b/nlm/nlm.x
@@ -1,6 +1,31 @@
-/* based on rfc1813 and wireshark */
-
-typedef unsigned hyper uint64;
+/*
+Copyright (c) 2014, Ronnie Sahlberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+   list of conditions and the following disclaimer. 
+2. Redistributions in binary form must reproduce the above copyright notice,
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+The views and conclusions contained in the software and documentation are those
+of the authors and should not be interpreted as representing official policies, 
+either expressed or implied, of the FreeBSD Project.
+*/
 
 struct nlm_fh4 {
        opaque       data<>;
 
 struct nlm_fh4 {
        opaque       data<>;
@@ -29,8 +54,8 @@ struct nlm4_holder {
        bool           exclusive;
        unsigned int   svid;
        nlm4_oh        oh;
        bool           exclusive;
        unsigned int   svid;
        nlm4_oh        oh;
-       uint64         l_offset;
-       uint64         l_len;
+       u_quad_t       l_offset;
+       u_quad_t       l_len;
 };
 
 const NLM_MAXNAME = 256;
 };
 
 const NLM_MAXNAME = 256;
@@ -39,8 +64,8 @@ struct nlm4_lock {
        struct nlm_fh4 fh;
        nlm4_oh        oh;
        unsigned int   svid;
        struct nlm_fh4 fh;
        nlm4_oh        oh;
        unsigned int   svid;
-       uint64         l_offset;
-       uint64         l_len;
+       u_quad_t       l_offset;
+       u_quad_t       l_len;
 };
 
 struct nlm4_share {
 };
 
 struct nlm4_share {
index 6362ddb938a14918327f245123fe83a6ef38617b..3bf06a84ed83051b931fbedd2f269eb9bba5d3bf 100644 (file)
@@ -18,5 +18,7 @@ nsm-stamp : nsm.x
        touch nsm-stamp
 
 compile_rpc:   
        touch nsm-stamp
 
 compile_rpc:   
-       rpcgen -h nsm.x | sed -e "s/#include <rpc\/rpc.h>//" | sed -e "s/xdr/zdr/g" -e "s/XDR/ZDR/g" > libnfs-raw-nsm.h
-       rpcgen -c nsm.x | sed -e "s/#include \".*nsm.h\"/#include \"libnfs-xdr.h\"\n#include \"libnfs-raw-nsm.h\"/" -e "s/xdr/zdr/g" -e "s/XDR/ZDR/g" -e "s/register int32_t \*buf;/register int32_t *buf;\n    buf = NULL;/" > libnfs-raw-nsm.c
+       cat nsm.x | head -29 >libnfs-raw-nsm.h
+       rpcgen -h nsm.x | sed -e "s/#include <rpc\/rpc.h>//" | sed -e "s/xdr/zdr/g" -e "s/XDR/ZDR/g" >> libnfs-raw-nsm.h
+       cat nsm.x | head -29 >libnfs-raw-nsm.c
+       rpcgen -c nsm.x | sed -e "s/#include \".*nsm.h\"/#include \"libnfs-xdr.h\"\n#include \"libnfs-raw-nsm.h\"/" -e "s/xdr/zdr/g" -e "s/XDR/ZDR/g" -e "s/register int32_t \*buf;/register int32_t *buf;\n    buf = NULL;/" >> libnfs-raw-nsm.c
index cee4d8910ee41ed702b4ce683e3d267fb8a0a679..d3be8328abcbab3a46f73fc5a81d32b041319185 100644 (file)
@@ -1,3 +1,32 @@
+/*
+Copyright (c) 2014, Ronnie Sahlberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+   list of conditions and the following disclaimer. 
+2. Redistributions in binary form must reproduce the above copyright notice,
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+The views and conclusions contained in the software and documentation are those
+of the authors and should not be interpreted as representing official policies, 
+either expressed or implied, of the FreeBSD Project.
+*/
+
 /*
  * Please do not edit this file.
  * It was generated using rpcgen.
 /*
  * Please do not edit this file.
  * It was generated using rpcgen.
@@ -90,6 +119,7 @@ zdr_NSM1_MONargs (ZDR *zdrs, NSM1_MONargs *objp)
        register int32_t *buf;
        buf = NULL;
 
        register int32_t *buf;
        buf = NULL;
 
+       int i;
         if (!zdr_nsm_mon_id (zdrs, &objp->mon_id))
                 return FALSE;
         if (!zdr_opaque (zdrs, objp->priv, 16))
         if (!zdr_nsm_mon_id (zdrs, &objp->mon_id))
                 return FALSE;
         if (!zdr_opaque (zdrs, objp->priv, 16))
index b68a1bd11832123cdfe35e40f65d1f3cf1beb79b..d656f3f560817c9e22c5163c90996de960dabbcc 100644 (file)
@@ -1,3 +1,32 @@
+/*
+Copyright (c) 2014, Ronnie Sahlberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+   list of conditions and the following disclaimer. 
+2. Redistributions in binary form must reproduce the above copyright notice,
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+The views and conclusions contained in the software and documentation are those
+of the authors and should not be interpreted as representing official policies, 
+either expressed or implied, of the FreeBSD Project.
+*/
+
 /*
  * Please do not edit this file.
  * It was generated using rpcgen.
 /*
  * Please do not edit this file.
  * It was generated using rpcgen.
index 43fbc1407320719128f11513e0571d460ab59e39..430a5e44a7175eaca826ad4c5c907e4a669cf311 100644 (file)
--- a/nsm/nsm.x
+++ b/nsm/nsm.x
@@ -1,11 +1,31 @@
 /*
 /*
- * NSM definitions from:
- * Protocols for Interworking: XNFS, Version 3W
- * http://pubs.opengroup.org/onlinepubs/9629799/chap11.htm
- *
- * Symbols then massaged to avoid too much namespace pollution
- * and to bring more inline with convention in nlm.
- */
+Copyright (c) 2014, Ronnie Sahlberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+   list of conditions and the following disclaimer. 
+2. Redistributions in binary form must reproduce the above copyright notice,
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+The views and conclusions contained in the software and documentation are those
+of the authors and should not be interpreted as representing official policies, 
+either expressed or implied, of the FreeBSD Project.
+*/
 
 /*
  * This defines the maximum length of the string
 
 /*
  * This defines the maximum length of the string
index 98acdbc4d1df71eaf01bd508fd5c9c0aca15773f..8b34636f30ce38d0146e1efc4d4144f5c56e43a5 100644 (file)
@@ -95,8 +95,20 @@ development libraries for LibNFS
 %{_libdir}/libnfs.la
 %{_libdir}/pkgconfig/libnfs.pc
 
 %{_libdir}/libnfs.la
 %{_libdir}/pkgconfig/libnfs.pc
 
+%package utils
+Summary: Utility programs for LibNFS
+Group: Applications/System
+
+%description utils
+Utility programs for LibNFS
+
+%files utils
+%defattr(-,root,root)
+%{_bindir}/nfs-ls
+%{_mandir}/man1/nfs-ls.1.gz
+
 %changelog
 %changelog
-* Wed Mar 19 2014: Version 1.9.3
+* Wed Mar 19 2014 : Version 1.9.3
  - Add O_TRUNC support to nfs_open()
  - Add a simple but incomplete LD_PRELOAD tool
  - Fixes for some memory leaks and C++ compile support
  - Add O_TRUNC support to nfs_open()
  - Add a simple but incomplete LD_PRELOAD tool
  - Fixes for some memory leaks and C++ compile support
@@ -120,7 +132,7 @@ development libraries for LibNFS
  - RPC layer support for NSM
  - Add example FUSE filesystem.
  - Minor fixes.
  - RPC layer support for NSM
  - Add example FUSE filesystem.
  - Minor fixes.
-* Sun Oct 30 2013 : Version 1.8
+* Wed Oct 30 2013 : Version 1.8
  - Fix nasty memory leak in read_from_socket
  - minor updates
 * Sun Oct 20 2013 : Version 1.7
  - Fix nasty memory leak in read_from_socket
  - minor updates
 * Sun Oct 20 2013 : Version 1.7
index 4d486fc3f79d451eade9ac3d829a7ca6065efdd3..682ca2ac5a6695fbe6a0aae59f5b567c2e365880 100644 (file)
@@ -18,5 +18,7 @@ portmap-stamp : portmap.x
        touch portmap-stamp
 
 compile_rpc:   
        touch portmap-stamp
 
 compile_rpc:   
-       rpcgen -h portmap.x | sed -e "s/#include <rpc\/rpc.h>//" | sed -e "s/xdr/zdr/g" -e "s/XDR/ZDR/g" > libnfs-raw-portmap.h
-       rpcgen -c portmap.x | sed -e "s/#include \".*portmap.h\"/#include \"libnfs-zdr.h\"\n#include \"libnfs-raw-portmap.h\"/" -e "s/xdr/zdr/g" -e "s/XDR/ZDR/g" -e "s/register int32_t \*buf;/register int32_t *buf;\n        buf = NULL;/" > libnfs-raw-portmap.c
+       cat portmap.x | head -29 >libnfs-raw-portmap.h
+       rpcgen -h portmap.x | sed -e "s/#include <rpc\/rpc.h>//" | sed -e "s/xdr/zdr/g" -e "s/XDR/ZDR/g" >> libnfs-raw-portmap.h
+       cat portmap.x | head -29 >libnfs-raw-portmap.c
+       rpcgen -c portmap.x | sed -e "s/#include \".*portmap.h\"/#include \"libnfs-zdr.h\"\n#include \"libnfs-raw-portmap.h\"/" -e "s/xdr/zdr/g" -e "s/XDR/ZDR/g" -e "s/register int32_t \*buf;/register int32_t *buf;\n        buf = NULL;/" >> libnfs-raw-portmap.c
index a07a1e62e025374b5d70b8d07a19d00853332ac1..12b919d33a709c86369177f1ab1d3f9971c80fc0 100644 (file)
@@ -1,3 +1,32 @@
+/*
+Copyright (c) 2014, Ronnie Sahlberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+   list of conditions and the following disclaimer. 
+2. Redistributions in binary form must reproduce the above copyright notice,
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+The views and conclusions contained in the software and documentation are those
+of the authors and should not be interpreted as representing official policies, 
+either expressed or implied, of the FreeBSD Project.
+*/
+
 /*
  * Please do not edit this file.
  * It was generated using rpcgen.
 /*
  * Please do not edit this file.
  * It was generated using rpcgen.
@@ -7,7 +36,7 @@
 #include "libnfs-raw-portmap.h"
 
 bool_t
 #include "libnfs-raw-portmap.h"
 
 bool_t
-zdr_pmap_mapping (ZDR *zdrs, pmap_mapping *objp)
+zdr_pmap2_mapping (ZDR *zdrs, pmap2_mapping *objp)
 {
        register int32_t *buf;
        buf = NULL;
 {
        register int32_t *buf;
        buf = NULL;
@@ -63,7 +92,7 @@ zdr_pmap_mapping (ZDR *zdrs, pmap_mapping *objp)
 }
 
 bool_t
 }
 
 bool_t
-zdr_pmap_call_args (ZDR *zdrs, pmap_call_args *objp)
+zdr_pmap2_call_args (ZDR *zdrs, pmap2_call_args *objp)
 {
        register int32_t *buf;
        buf = NULL;
 {
        register int32_t *buf;
        buf = NULL;
@@ -119,7 +148,7 @@ zdr_pmap_call_args (ZDR *zdrs, pmap_call_args *objp)
 }
 
 bool_t
 }
 
 bool_t
-zdr_pmap_call_result (ZDR *zdrs, pmap_call_result *objp)
+zdr_pmap2_call_result (ZDR *zdrs, pmap2_call_result *objp)
 {
        register int32_t *buf;
        buf = NULL;
 {
        register int32_t *buf;
        buf = NULL;
@@ -132,25 +161,161 @@ zdr_pmap_call_result (ZDR *zdrs, pmap_call_result *objp)
 }
 
 bool_t
 }
 
 bool_t
-zdr_pmap_mapping_list (ZDR *zdrs, pmap_mapping_list *objp)
+zdr_pmap2_mapping_list (ZDR *zdrs, pmap2_mapping_list *objp)
+{
+       register int32_t *buf;
+       buf = NULL;
+
+        if (!zdr_pmap2_mapping (zdrs, &objp->map))
+                return FALSE;
+        if (!zdr_pointer (zdrs, (char **)&objp->next, sizeof (pmap2_mapping_list), (zdrproc_t) zdr_pmap2_mapping_list))
+                return FALSE;
+       return TRUE;
+}
+
+bool_t
+zdr_pmap2_dump_result (ZDR *zdrs, pmap2_dump_result *objp)
+{
+       register int32_t *buf;
+       buf = NULL;
+
+        if (!zdr_pointer (zdrs, (char **)&objp->list, sizeof (pmap2_mapping_list), (zdrproc_t) zdr_pmap2_mapping_list))
+                return FALSE;
+       return TRUE;
+}
+
+bool_t
+zdr_pmap3_string_result (ZDR *zdrs, pmap3_string_result *objp)
+{
+       register int32_t *buf;
+       buf = NULL;
+
+        if (!zdr_string (zdrs, &objp->addr, ~0))
+                return FALSE;
+       return TRUE;
+}
+
+bool_t
+zdr_pmap3_mapping (ZDR *zdrs, pmap3_mapping *objp)
+{
+       register int32_t *buf;
+       buf = NULL;
+
+        if (!zdr_u_int (zdrs, &objp->prog))
+                return FALSE;
+        if (!zdr_u_int (zdrs, &objp->vers))
+                return FALSE;
+        if (!zdr_string (zdrs, &objp->netid, ~0))
+                return FALSE;
+        if (!zdr_string (zdrs, &objp->addr, ~0))
+                return FALSE;
+        if (!zdr_string (zdrs, &objp->owner, ~0))
+                return FALSE;
+       return TRUE;
+}
+
+bool_t
+zdr_pmap3_mapping_list (ZDR *zdrs, pmap3_mapping_list *objp)
+{
+       register int32_t *buf;
+       buf = NULL;
+
+        if (!zdr_pmap3_mapping (zdrs, &objp->map))
+                return FALSE;
+        if (!zdr_pointer (zdrs, (char **)&objp->next, sizeof (pmap3_mapping_list), (zdrproc_t) zdr_pmap3_mapping_list))
+                return FALSE;
+       return TRUE;
+}
+
+bool_t
+zdr_pmap3_dump_result (ZDR *zdrs, pmap3_dump_result *objp)
+{
+       register int32_t *buf;
+       buf = NULL;
+
+        if (!zdr_pointer (zdrs, (char **)&objp->list, sizeof (pmap3_mapping_list), (zdrproc_t) zdr_pmap3_mapping_list))
+                return FALSE;
+       return TRUE;
+}
+
+bool_t
+zdr_pmap3_call_args (ZDR *zdrs, pmap3_call_args *objp)
 {
        register int32_t *buf;
        buf = NULL;
 
 {
        register int32_t *buf;
        buf = NULL;
 
-        if (!zdr_pmap_mapping (zdrs, &objp->map))
+
+       if (zdrs->x_op == ZDR_ENCODE) {
+               buf = ZDR_INLINE (zdrs, 3 * BYTES_PER_ZDR_UNIT);
+               if (buf == NULL) {
+                        if (!zdr_u_int (zdrs, &objp->prog))
+                                return FALSE;
+                        if (!zdr_u_int (zdrs, &objp->vers))
+                                return FALSE;
+                        if (!zdr_u_int (zdrs, &objp->proc))
+                                return FALSE;
+
+               } else {
+               IZDR_PUT_U_LONG(buf, objp->prog);
+               IZDR_PUT_U_LONG(buf, objp->vers);
+               IZDR_PUT_U_LONG(buf, objp->proc);
+               }
+                if (!zdr_bytes (zdrs, (char **)&objp->args.args_val, (u_int *) &objp->args.args_len, ~0))
+                        return FALSE;
+               return TRUE;
+       } else if (zdrs->x_op == ZDR_DECODE) {
+               buf = ZDR_INLINE (zdrs, 3 * BYTES_PER_ZDR_UNIT);
+               if (buf == NULL) {
+                        if (!zdr_u_int (zdrs, &objp->prog))
+                                return FALSE;
+                        if (!zdr_u_int (zdrs, &objp->vers))
+                                return FALSE;
+                        if (!zdr_u_int (zdrs, &objp->proc))
+                                return FALSE;
+
+               } else {
+               objp->prog = IZDR_GET_U_LONG(buf);
+               objp->vers = IZDR_GET_U_LONG(buf);
+               objp->proc = IZDR_GET_U_LONG(buf);
+               }
+                if (!zdr_bytes (zdrs, (char **)&objp->args.args_val, (u_int *) &objp->args.args_len, ~0))
+                        return FALSE;
+        return TRUE;
+       }
+
+        if (!zdr_u_int (zdrs, &objp->prog))
+                return FALSE;
+        if (!zdr_u_int (zdrs, &objp->vers))
                 return FALSE;
                 return FALSE;
-        if (!zdr_pointer (zdrs, (char **)&objp->next, sizeof (pmap_mapping_list), (zdrproc_t) zdr_pmap_mapping_list))
+        if (!zdr_u_int (zdrs, &objp->proc))
+                return FALSE;
+        if (!zdr_bytes (zdrs, (char **)&objp->args.args_val, (u_int *) &objp->args.args_len, ~0))
                 return FALSE;
        return TRUE;
 }
 
 bool_t
                 return FALSE;
        return TRUE;
 }
 
 bool_t
-zdr_pmap_dump_result (ZDR *zdrs, pmap_dump_result *objp)
+zdr_pmap3_call_result (ZDR *zdrs, pmap3_call_result *objp)
 {
        register int32_t *buf;
        buf = NULL;
 
 {
        register int32_t *buf;
        buf = NULL;
 
-        if (!zdr_pointer (zdrs, (char **)&objp->list, sizeof (pmap_mapping_list), (zdrproc_t) zdr_pmap_mapping_list))
+        if (!zdr_u_int (zdrs, &objp->port))
+                return FALSE;
+        if (!zdr_bytes (zdrs, (char **)&objp->res.res_val, (u_int *) &objp->res.res_len, ~0))
+                return FALSE;
+       return TRUE;
+}
+
+bool_t
+zdr_pmap3_netbuf (ZDR *zdrs, pmap3_netbuf *objp)
+{
+       register int32_t *buf;
+       buf = NULL;
+
+        if (!zdr_u_int (zdrs, &objp->maxlen))
+                return FALSE;
+        if (!zdr_bytes (zdrs, (char **)&objp->buf.buf_val, (u_int *) &objp->buf.buf_len, ~0))
                 return FALSE;
        return TRUE;
 }
                 return FALSE;
        return TRUE;
 }
index f8d9a45b613fdcf0cc22a71c37614b1ac9b6791a..676be5e8d4d08932630464fc8463eaf11577a546 100644 (file)
@@ -1,3 +1,32 @@
+/*
+Copyright (c) 2014, Ronnie Sahlberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+   list of conditions and the following disclaimer. 
+2. Redistributions in binary form must reproduce the above copyright notice,
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+The views and conclusions contained in the software and documentation are those
+of the authors and should not be interpreted as representing official policies, 
+either expressed or implied, of the FreeBSD Project.
+*/
+
 /*
  * Please do not edit this file.
  * It was generated using rpcgen.
 /*
  * Please do not edit this file.
  * It was generated using rpcgen.
@@ -15,15 +44,15 @@ extern "C" {
 
 #define PMAP_PORT 111
 
 
 #define PMAP_PORT 111
 
-struct pmap_mapping {
+struct pmap2_mapping {
        u_int prog;
        u_int vers;
        u_int prot;
        u_int port;
 };
        u_int prog;
        u_int vers;
        u_int prot;
        u_int port;
 };
-typedef struct pmap_mapping pmap_mapping;
+typedef struct pmap2_mapping pmap2_mapping;
 
 
-struct pmap_call_args {
+struct pmap2_call_args {
        u_int prog;
        u_int vers;
        u_int proc;
        u_int prog;
        u_int vers;
        u_int proc;
@@ -32,89 +61,219 @@ struct pmap_call_args {
                char *args_val;
        } args;
 };
                char *args_val;
        } args;
 };
-typedef struct pmap_call_args pmap_call_args;
+typedef struct pmap2_call_args pmap2_call_args;
 
 
-struct pmap_call_result {
+struct pmap2_call_result {
        u_int port;
        struct {
                u_int res_len;
                char *res_val;
        } res;
 };
        u_int port;
        struct {
                u_int res_len;
                char *res_val;
        } res;
 };
-typedef struct pmap_call_result pmap_call_result;
+typedef struct pmap2_call_result pmap2_call_result;
+
+struct pmap2_mapping_list {
+       pmap2_mapping map;
+       struct pmap2_mapping_list *next;
+};
+typedef struct pmap2_mapping_list pmap2_mapping_list;
+
+struct pmap2_dump_result {
+       struct pmap2_mapping_list *list;
+};
+typedef struct pmap2_dump_result pmap2_dump_result;
+
+struct pmap3_string_result {
+       char *addr;
+};
+typedef struct pmap3_string_result pmap3_string_result;
+
+struct pmap3_mapping {
+       u_int prog;
+       u_int vers;
+       char *netid;
+       char *addr;
+       char *owner;
+};
+typedef struct pmap3_mapping pmap3_mapping;
+
+struct pmap3_mapping_list {
+       pmap3_mapping map;
+       struct pmap3_mapping_list *next;
+};
+typedef struct pmap3_mapping_list pmap3_mapping_list;
+
+struct pmap3_dump_result {
+       struct pmap3_mapping_list *list;
+};
+typedef struct pmap3_dump_result pmap3_dump_result;
 
 
-struct pmap_mapping_list {
-       pmap_mapping map;
-       struct pmap_mapping_list *next;
+struct pmap3_call_args {
+       u_int prog;
+       u_int vers;
+       u_int proc;
+       struct {
+               u_int args_len;
+               char *args_val;
+       } args;
+};
+typedef struct pmap3_call_args pmap3_call_args;
+
+struct pmap3_call_result {
+       u_int port;
+       struct {
+               u_int res_len;
+               char *res_val;
+       } res;
 };
 };
-typedef struct pmap_mapping_list pmap_mapping_list;
+typedef struct pmap3_call_result pmap3_call_result;
 
 
-struct pmap_dump_result {
-       struct pmap_mapping_list *list;
+struct pmap3_netbuf {
+       u_int maxlen;
+       struct {
+               u_int buf_len;
+               char *buf_val;
+       } buf;
 };
 };
-typedef struct pmap_dump_result pmap_dump_result;
+typedef struct pmap3_netbuf pmap3_netbuf;
 
 #define PMAP_PROGRAM 100000
 #define PMAP_V2 2
 
 #if defined(__STDC__) || defined(__cplusplus)
 
 #define PMAP_PROGRAM 100000
 #define PMAP_V2 2
 
 #if defined(__STDC__) || defined(__cplusplus)
-#define PMAP_NULL 0
-extern  void * pmap_null_2(void *, CLIENT *);
-extern  void * pmap_null_2_svc(void *, struct svc_req *);
-#define PMAP_SET 1
-extern  bool_t * pmap_set_2(pmap_mapping *, CLIENT *);
-extern  bool_t * pmap_set_2_svc(pmap_mapping *, struct svc_req *);
-#define PMAP_UNSET 2
-extern  bool_t * pmap_unset_2(pmap_mapping *, CLIENT *);
-extern  bool_t * pmap_unset_2_svc(pmap_mapping *, struct svc_req *);
-#define PMAP_GETPORT 3
-extern  u_int * pmap_getport_2(pmap_mapping *, CLIENT *);
-extern  u_int * pmap_getport_2_svc(pmap_mapping *, struct svc_req *);
-#define PMAP_DUMP 4
-extern  pmap_mapping_list * pmap_dump_2(void *, CLIENT *);
-extern  pmap_mapping_list * pmap_dump_2_svc(void *, struct svc_req *);
-#define PMAP_CALLIT 5
-extern  pmap_call_result * pmap_callit_2(pmap_call_args *, CLIENT *);
-extern  pmap_call_result * pmap_callit_2_svc(pmap_call_args *, struct svc_req *);
+#define PMAP2_NULL 0
+extern  void * pmap2_null_2(void *, CLIENT *);
+extern  void * pmap2_null_2_svc(void *, struct svc_req *);
+#define PMAP2_SET 1
+extern  bool_t * pmap2_set_2(pmap2_mapping *, CLIENT *);
+extern  bool_t * pmap2_set_2_svc(pmap2_mapping *, struct svc_req *);
+#define PMAP2_UNSET 2
+extern  bool_t * pmap2_unset_2(pmap2_mapping *, CLIENT *);
+extern  bool_t * pmap2_unset_2_svc(pmap2_mapping *, struct svc_req *);
+#define PMAP2_GETPORT 3
+extern  u_int * pmap2_getport_2(pmap2_mapping *, CLIENT *);
+extern  u_int * pmap2_getport_2_svc(pmap2_mapping *, struct svc_req *);
+#define PMAP2_DUMP 4
+extern  pmap2_dump_result * pmap2_dump_2(void *, CLIENT *);
+extern  pmap2_dump_result * pmap2_dump_2_svc(void *, struct svc_req *);
+#define PMAP2_CALLIT 5
+extern  pmap2_call_result * pmap2_callit_2(pmap2_call_args *, CLIENT *);
+extern  pmap2_call_result * pmap2_callit_2_svc(pmap2_call_args *, struct svc_req *);
 extern int pmap_program_2_freeresult (SVCXPRT *, zdrproc_t, caddr_t);
 
 #else /* K&R C */
 extern int pmap_program_2_freeresult (SVCXPRT *, zdrproc_t, caddr_t);
 
 #else /* K&R C */
-#define PMAP_NULL 0
-extern  void * pmap_null_2();
-extern  void * pmap_null_2_svc();
-#define PMAP_SET 1
-extern  bool_t * pmap_set_2();
-extern  bool_t * pmap_set_2_svc();
-#define PMAP_UNSET 2
-extern  bool_t * pmap_unset_2();
-extern  bool_t * pmap_unset_2_svc();
-#define PMAP_GETPORT 3
-extern  u_int * pmap_getport_2();
-extern  u_int * pmap_getport_2_svc();
-#define PMAP_DUMP 4
-extern  pmap_mapping_list * pmap_dump_2();
-extern  pmap_mapping_list * pmap_dump_2_svc();
-#define PMAP_CALLIT 5
-extern  pmap_call_result * pmap_callit_2();
-extern  pmap_call_result * pmap_callit_2_svc();
+#define PMAP2_NULL 0
+extern  void * pmap2_null_2();
+extern  void * pmap2_null_2_svc();
+#define PMAP2_SET 1
+extern  bool_t * pmap2_set_2();
+extern  bool_t * pmap2_set_2_svc();
+#define PMAP2_UNSET 2
+extern  bool_t * pmap2_unset_2();
+extern  bool_t * pmap2_unset_2_svc();
+#define PMAP2_GETPORT 3
+extern  u_int * pmap2_getport_2();
+extern  u_int * pmap2_getport_2_svc();
+#define PMAP2_DUMP 4
+extern  pmap2_dump_result * pmap2_dump_2();
+extern  pmap2_dump_result * pmap2_dump_2_svc();
+#define PMAP2_CALLIT 5
+extern  pmap2_call_result * pmap2_callit_2();
+extern  pmap2_call_result * pmap2_callit_2_svc();
 extern int pmap_program_2_freeresult ();
 #endif /* K&R C */
 extern int pmap_program_2_freeresult ();
 #endif /* K&R C */
+#define PMAP_V3 3
+
+#if defined(__STDC__) || defined(__cplusplus)
+#define PMAP3_NULL 0
+extern  void * pmap3_null_3(void *, CLIENT *);
+extern  void * pmap3_null_3_svc(void *, struct svc_req *);
+#define PMAP3_SET 1
+extern  bool_t * pmap3_set_3(pmap3_mapping *, CLIENT *);
+extern  bool_t * pmap3_set_3_svc(pmap3_mapping *, struct svc_req *);
+#define PMAP3_UNSET 2
+extern  bool_t * pmap3_unset_3(pmap3_mapping *, CLIENT *);
+extern  bool_t * pmap3_unset_3_svc(pmap3_mapping *, struct svc_req *);
+#define PMAP3_GETADDR 3
+extern  pmap3_string_result * pmap3_getaddr_3(pmap3_mapping *, CLIENT *);
+extern  pmap3_string_result * pmap3_getaddr_3_svc(pmap3_mapping *, struct svc_req *);
+#define PMAP3_DUMP 4
+extern  pmap3_dump_result * pmap3_dump_3(void *, CLIENT *);
+extern  pmap3_dump_result * pmap3_dump_3_svc(void *, struct svc_req *);
+#define PMAP3_CALLIT 5
+extern  pmap3_call_result * pmap3_callit_3(pmap3_call_args *, CLIENT *);
+extern  pmap3_call_result * pmap3_callit_3_svc(pmap3_call_args *, struct svc_req *);
+#define PMAP3_GETTIME 6
+extern  u_int * pmap3_gettime_3(void *, CLIENT *);
+extern  u_int * pmap3_gettime_3_svc(void *, struct svc_req *);
+#define PMAP3_UADDR2TADDR 7
+extern  pmap3_netbuf * pmap3_uaddr2taddr_3(char **, CLIENT *);
+extern  pmap3_netbuf * pmap3_uaddr2taddr_3_svc(char **, struct svc_req *);
+#define PMAP3_TADDR2UADDR 8
+extern  struct pmap3_string_result * pmap3_taddr2uaddr_3(pmap3_netbuf *, CLIENT *);
+extern  struct pmap3_string_result * pmap3_taddr2uaddr_3_svc(pmap3_netbuf *, struct svc_req *);
+extern int pmap_program_3_freeresult (SVCXPRT *, zdrproc_t, caddr_t);
+
+#else /* K&R C */
+#define PMAP3_NULL 0
+extern  void * pmap3_null_3();
+extern  void * pmap3_null_3_svc();
+#define PMAP3_SET 1
+extern  bool_t * pmap3_set_3();
+extern  bool_t * pmap3_set_3_svc();
+#define PMAP3_UNSET 2
+extern  bool_t * pmap3_unset_3();
+extern  bool_t * pmap3_unset_3_svc();
+#define PMAP3_GETADDR 3
+extern  pmap3_string_result * pmap3_getaddr_3();
+extern  pmap3_string_result * pmap3_getaddr_3_svc();
+#define PMAP3_DUMP 4
+extern  pmap3_dump_result * pmap3_dump_3();
+extern  pmap3_dump_result * pmap3_dump_3_svc();
+#define PMAP3_CALLIT 5
+extern  pmap3_call_result * pmap3_callit_3();
+extern  pmap3_call_result * pmap3_callit_3_svc();
+#define PMAP3_GETTIME 6
+extern  u_int * pmap3_gettime_3();
+extern  u_int * pmap3_gettime_3_svc();
+#define PMAP3_UADDR2TADDR 7
+extern  pmap3_netbuf * pmap3_uaddr2taddr_3();
+extern  pmap3_netbuf * pmap3_uaddr2taddr_3_svc();
+#define PMAP3_TADDR2UADDR 8
+extern  struct pmap3_string_result * pmap3_taddr2uaddr_3();
+extern  struct pmap3_string_result * pmap3_taddr2uaddr_3_svc();
+extern int pmap_program_3_freeresult ();
+#endif /* K&R C */
 
 /* the zdr functions */
 
 #if defined(__STDC__) || defined(__cplusplus)
 
 /* the zdr functions */
 
 #if defined(__STDC__) || defined(__cplusplus)
-extern  bool_t zdr_pmap_mapping (ZDR *, pmap_mapping*);
-extern  bool_t zdr_pmap_call_args (ZDR *, pmap_call_args*);
-extern  bool_t zdr_pmap_call_result (ZDR *, pmap_call_result*);
-extern  bool_t zdr_pmap_mapping_list (ZDR *, pmap_mapping_list*);
-extern  bool_t zdr_pmap_dump_result (ZDR *, pmap_dump_result*);
+extern  bool_t zdr_pmap2_mapping (ZDR *, pmap2_mapping*);
+extern  bool_t zdr_pmap2_call_args (ZDR *, pmap2_call_args*);
+extern  bool_t zdr_pmap2_call_result (ZDR *, pmap2_call_result*);
+extern  bool_t zdr_pmap2_mapping_list (ZDR *, pmap2_mapping_list*);
+extern  bool_t zdr_pmap2_dump_result (ZDR *, pmap2_dump_result*);
+extern  bool_t zdr_pmap3_string_result (ZDR *, pmap3_string_result*);
+extern  bool_t zdr_pmap3_mapping (ZDR *, pmap3_mapping*);
+extern  bool_t zdr_pmap3_mapping_list (ZDR *, pmap3_mapping_list*);
+extern  bool_t zdr_pmap3_dump_result (ZDR *, pmap3_dump_result*);
+extern  bool_t zdr_pmap3_call_args (ZDR *, pmap3_call_args*);
+extern  bool_t zdr_pmap3_call_result (ZDR *, pmap3_call_result*);
+extern  bool_t zdr_pmap3_netbuf (ZDR *, pmap3_netbuf*);
 
 #else /* K&R C */
 
 #else /* K&R C */
-extern bool_t zdr_pmap_mapping ();
-extern bool_t zdr_pmap_call_args ();
-extern bool_t zdr_pmap_call_result ();
-extern bool_t zdr_pmap_mapping_list ();
-extern bool_t zdr_pmap_dump_result ();
+extern bool_t zdr_pmap2_mapping ();
+extern bool_t zdr_pmap2_call_args ();
+extern bool_t zdr_pmap2_call_result ();
+extern bool_t zdr_pmap2_mapping_list ();
+extern bool_t zdr_pmap2_dump_result ();
+extern bool_t zdr_pmap3_string_result ();
+extern bool_t zdr_pmap3_mapping ();
+extern bool_t zdr_pmap3_mapping_list ();
+extern bool_t zdr_pmap3_dump_result ();
+extern bool_t zdr_pmap3_call_args ();
+extern bool_t zdr_pmap3_call_result ();
+extern bool_t zdr_pmap3_netbuf ();
 
 #endif /* K&R C */
 
 
 #endif /* K&R C */
 
index 5042e8c19b0eb6bc7fb724953ee28c87d8a53b87..9b0e0f64cf35c3cc79edd9207ffc34d32dd3ac3a 100644 (file)
 #include "libnfs-private.h"
 #include "libnfs-raw-portmap.h"
 
 #include "libnfs-private.h"
 #include "libnfs-raw-portmap.h"
 
-
-int rpc_pmap_null_async(struct rpc_context *rpc, rpc_cb cb, void *private_data)
+/*
+ * PORTMAP v2
+ */
+int rpc_pmap2_null_async(struct rpc_context *rpc, rpc_cb cb, void *private_data)
 {
        struct rpc_pdu *pdu;
 
 {
        struct rpc_pdu *pdu;
 
-       pdu = rpc_allocate_pdu(rpc, PMAP_PROGRAM, PMAP_V2, PMAP_NULL, cb, private_data, (zdrproc_t)zdr_void, 0);
+       pdu = rpc_allocate_pdu(rpc, PMAP_PROGRAM, PMAP_V2, PMAP2_NULL, cb, private_data, (zdrproc_t)zdr_void, 0);
        if (pdu == NULL) {
        if (pdu == NULL) {
-               rpc_set_error(rpc, "Out of memory. Failed to allocate pdu for portmap/null call");
+               rpc_set_error(rpc, "Out of memory. Failed to allocate pdu for PORTMAP2/NULL call");
                return -1;
        }
 
        if (rpc_queue_pdu(rpc, pdu) != 0) {
                return -1;
        }
 
        if (rpc_queue_pdu(rpc, pdu) != 0) {
-               rpc_set_error(rpc, "Out of memory. Failed to queue pdu for portmap/null call");
+               rpc_set_error(rpc, "Out of memory. Failed to queue pdu for PORTMAP2/NULL call");
                rpc_free_pdu(rpc, pdu);
                return -1;
        }
                rpc_free_pdu(rpc, pdu);
                return -1;
        }
@@ -45,14 +47,14 @@ int rpc_pmap_null_async(struct rpc_context *rpc, rpc_cb cb, void *private_data)
        return 0;
 }
 
        return 0;
 }
 
-int rpc_pmap_getport_async(struct rpc_context *rpc, int program, int version, int protocol, rpc_cb cb, void *private_data)
+int rpc_pmap2_getport_async(struct rpc_context *rpc, int program, int version, int protocol, rpc_cb cb, void *private_data)
 {
        struct rpc_pdu *pdu;
 {
        struct rpc_pdu *pdu;
-       struct pmap_mapping m;
+       struct pmap2_mapping m;
 
 
-       pdu = rpc_allocate_pdu(rpc, PMAP_PROGRAM, PMAP_V2, PMAP_GETPORT, cb, private_data, (zdrproc_t)zdr_int, sizeof(uint32_t));
+       pdu = rpc_allocate_pdu(rpc, PMAP_PROGRAM, PMAP_V2, PMAP2_GETPORT, cb, private_data, (zdrproc_t)zdr_int, sizeof(uint32_t));
        if (pdu == NULL) {
        if (pdu == NULL) {
-               rpc_set_error(rpc, "Out of memory. Failed to allocate pdu for portmap/getport call");
+               rpc_set_error(rpc, "Out of memory. Failed to allocate pdu for PORTMAP2/GETPORT call");
                return -1;
        }
 
                return -1;
        }
 
@@ -60,14 +62,14 @@ int rpc_pmap_getport_async(struct rpc_context *rpc, int program, int version, in
        m.vers = version;
        m.prot = protocol;
        m.port = 0;
        m.vers = version;
        m.prot = protocol;
        m.port = 0;
-       if (zdr_pmap_mapping(&pdu->zdr, &m) == 0) {
-               rpc_set_error(rpc, "ZDR error: Failed to encode data for portmap/getport call");
+       if (zdr_pmap2_mapping(&pdu->zdr, &m) == 0) {
+               rpc_set_error(rpc, "ZDR error: Failed to encode data for PORTMAP2/GETPORT call");
                rpc_free_pdu(rpc, pdu);
                return -1;
        }
 
        if (rpc_queue_pdu(rpc, pdu) != 0) {
                rpc_free_pdu(rpc, pdu);
                return -1;
        }
 
        if (rpc_queue_pdu(rpc, pdu) != 0) {
-               rpc_set_error(rpc, "Failed to queue portmap/getport pdu");
+               rpc_set_error(rpc, "Failed to queue PORTMAP2/GETPORT pdu");
                rpc_free_pdu(rpc, pdu);
                return -1;
        }
                rpc_free_pdu(rpc, pdu);
                return -1;
        }
@@ -75,14 +77,14 @@ int rpc_pmap_getport_async(struct rpc_context *rpc, int program, int version, in
        return 0;
 }
 
        return 0;
 }
 
-int rpc_pmap_set_async(struct rpc_context *rpc, int program, int version, int protocol, int port, rpc_cb cb, void *private_data)
+int rpc_pmap2_set_async(struct rpc_context *rpc, int program, int version, int protocol, int port, rpc_cb cb, void *private_data)
 {
        struct rpc_pdu *pdu;
 {
        struct rpc_pdu *pdu;
-       struct pmap_mapping m;
+       struct pmap2_mapping m;
 
 
-       pdu = rpc_allocate_pdu(rpc, PMAP_PROGRAM, PMAP_V2, PMAP_SET, cb, private_data, (zdrproc_t)zdr_int, sizeof(uint32_t));
+       pdu = rpc_allocate_pdu(rpc, PMAP_PROGRAM, PMAP_V2, PMAP2_SET, cb, private_data, (zdrproc_t)zdr_int, sizeof(uint32_t));
        if (pdu == NULL) {
        if (pdu == NULL) {
-               rpc_set_error(rpc, "Out of memory. Failed to allocate pdu for portmap/set call");
+               rpc_set_error(rpc, "Out of memory. Failed to allocate pdu for PORTMAP2/SET call");
                return -1;
        }
 
                return -1;
        }
 
@@ -90,14 +92,14 @@ int rpc_pmap_set_async(struct rpc_context *rpc, int program, int version, int pr
        m.vers = version;
        m.prot = protocol;
        m.port = port;
        m.vers = version;
        m.prot = protocol;
        m.port = port;
-       if (zdr_pmap_mapping(&pdu->zdr, &m) == 0) {
-               rpc_set_error(rpc, "ZDR error: Failed to encode data for portmap/set call");
+       if (zdr_pmap2_mapping(&pdu->zdr, &m) == 0) {
+               rpc_set_error(rpc, "ZDR error: Failed to encode data for PORTMAP2/SET call");
                rpc_free_pdu(rpc, pdu);
                return -1;
        }
 
        if (rpc_queue_pdu(rpc, pdu) != 0) {
                rpc_free_pdu(rpc, pdu);
                return -1;
        }
 
        if (rpc_queue_pdu(rpc, pdu) != 0) {
-               rpc_set_error(rpc, "Failed to queue portmap/set pdu");
+               rpc_set_error(rpc, "Failed to queue PORTMAP2/SET pdu");
                rpc_free_pdu(rpc, pdu);
                return -1;
        }
                rpc_free_pdu(rpc, pdu);
                return -1;
        }
@@ -105,14 +107,14 @@ int rpc_pmap_set_async(struct rpc_context *rpc, int program, int version, int pr
        return 0;
 }
 
        return 0;
 }
 
-int rpc_pmap_unset_async(struct rpc_context *rpc, int program, int version, int protocol, int port, rpc_cb cb, void *private_data)
+int rpc_pmap2_unset_async(struct rpc_context *rpc, int program, int version, int protocol, int port, rpc_cb cb, void *private_data)
 {
        struct rpc_pdu *pdu;
 {
        struct rpc_pdu *pdu;
-       struct pmap_mapping m;
+       struct pmap2_mapping m;
 
 
-       pdu = rpc_allocate_pdu(rpc, PMAP_PROGRAM, PMAP_V2, PMAP_UNSET, cb, private_data, (zdrproc_t)zdr_int, sizeof(uint32_t));
+       pdu = rpc_allocate_pdu(rpc, PMAP_PROGRAM, PMAP_V2, PMAP2_UNSET, cb, private_data, (zdrproc_t)zdr_int, sizeof(uint32_t));
        if (pdu == NULL) {
        if (pdu == NULL) {
-               rpc_set_error(rpc, "Out of memory. Failed to allocate pdu for portmap/unset call");
+               rpc_set_error(rpc, "Out of memory. Failed to allocate pdu for PORTMAP2/UNSET call");
                return -1;
        }
 
                return -1;
        }
 
@@ -120,14 +122,14 @@ int rpc_pmap_unset_async(struct rpc_context *rpc, int program, int version, int
        m.vers = version;
        m.prot = protocol;
        m.port = port;
        m.vers = version;
        m.prot = protocol;
        m.port = port;
-       if (zdr_pmap_mapping(&pdu->zdr, &m) == 0) {
-               rpc_set_error(rpc, "ZDR error: Failed to encode data for portmap/unset call");
+       if (zdr_pmap2_mapping(&pdu->zdr, &m) == 0) {
+               rpc_set_error(rpc, "ZDR error: Failed to encode data for PORTMAP2/UNSET call");
                rpc_free_pdu(rpc, pdu);
                return -1;
        }
 
        if (rpc_queue_pdu(rpc, pdu) != 0) {
                rpc_free_pdu(rpc, pdu);
                return -1;
        }
 
        if (rpc_queue_pdu(rpc, pdu) != 0) {
-               rpc_set_error(rpc, "Failed to queue portmap/unset pdu");
+               rpc_set_error(rpc, "Failed to queue PORTMAP2/UNSET pdu");
                rpc_free_pdu(rpc, pdu);
                return -1;
        }
                rpc_free_pdu(rpc, pdu);
                return -1;
        }
@@ -135,18 +137,18 @@ int rpc_pmap_unset_async(struct rpc_context *rpc, int program, int version, int
        return 0;
 }
 
        return 0;
 }
 
-int rpc_pmap_dump_async(struct rpc_context *rpc, rpc_cb cb, void *private_data)
+int rpc_pmap2_dump_async(struct rpc_context *rpc, rpc_cb cb, void *private_data)
 {
        struct rpc_pdu *pdu;
 
 {
        struct rpc_pdu *pdu;
 
-       pdu = rpc_allocate_pdu(rpc, PMAP_PROGRAM, PMAP_V2, PMAP_DUMP, cb, private_data, (zdrproc_t)zdr_pmap_dump_result, sizeof(pmap_dump_result));
+       pdu = rpc_allocate_pdu(rpc, PMAP_PROGRAM, PMAP_V2, PMAP2_DUMP, cb, private_data, (zdrproc_t)zdr_pmap2_dump_result, sizeof(pmap2_dump_result));
        if (pdu == NULL) {
        if (pdu == NULL) {
-               rpc_set_error(rpc, "Out of memory. Failed to allocate pdu for portmap/dump call");
+               rpc_set_error(rpc, "Out of memory. Failed to allocate pdu for PORTMAP2/DUMP call");
                return -1;
        }
 
        if (rpc_queue_pdu(rpc, pdu) != 0) {
                return -1;
        }
 
        if (rpc_queue_pdu(rpc, pdu) != 0) {
-               rpc_set_error(rpc, "Failed to queue portmap/dump pdu");
+               rpc_set_error(rpc, "Failed to queue PORTMAP2/DUMP pdu");
                rpc_free_pdu(rpc, pdu);
                return -1;
        }
                rpc_free_pdu(rpc, pdu);
                return -1;
        }
@@ -154,14 +156,14 @@ int rpc_pmap_dump_async(struct rpc_context *rpc, rpc_cb cb, void *private_data)
        return 0;
 }
 
        return 0;
 }
 
-int rpc_pmap_callit_async(struct rpc_context *rpc, int program, int version, int procedure, char *data, int datalen, rpc_cb cb, void *private_data)
+int rpc_pmap2_callit_async(struct rpc_context *rpc, int program, int version, int procedure, char *data, int datalen, rpc_cb cb, void *private_data)
 {
        struct rpc_pdu *pdu;
 {
        struct rpc_pdu *pdu;
-       struct pmap_call_args ca;
+       struct pmap2_call_args ca;
 
 
-       pdu = rpc_allocate_pdu(rpc, PMAP_PROGRAM, PMAP_V2, PMAP_CALLIT, cb, private_data, (zdrproc_t)zdr_pmap_call_result, sizeof(pmap_call_result));
+       pdu = rpc_allocate_pdu(rpc, PMAP_PROGRAM, PMAP_V2, PMAP2_CALLIT, cb, private_data, (zdrproc_t)zdr_pmap2_call_result, sizeof(pmap2_call_result));
        if (pdu == NULL) {
        if (pdu == NULL) {
-               rpc_set_error(rpc, "Out of memory. Failed to allocate pdu for portmap/callit call");
+               rpc_set_error(rpc, "Out of memory. Failed to allocate pdu for PORTMAP2/CALLIT call");
                return -1;
        }
 
                return -1;
        }
 
@@ -171,14 +173,228 @@ int rpc_pmap_callit_async(struct rpc_context *rpc, int program, int version, int
        ca.args.args_len = datalen;
        ca.args.args_val = data;
 
        ca.args.args_len = datalen;
        ca.args.args_val = data;
 
-       if (zdr_pmap_call_args(&pdu->zdr, &ca) == 0) {
-               rpc_set_error(rpc, "ZDR error: Failed to encode data for portmap/callit call");
+       if (zdr_pmap2_call_args(&pdu->zdr, &ca) == 0) {
+               rpc_set_error(rpc, "ZDR error: Failed to encode data for PORTMAP2/CALLIT call");
+               rpc_free_pdu(rpc, pdu);
+               return -1;
+       }
+
+       if (rpc_queue_pdu(rpc, pdu) != 0) {
+               rpc_set_error(rpc, "Failed to queue PORTMAP2/CALLIT pdu: %s", rpc_get_error(rpc));
+               return -1;
+       }
+
+       return 0;
+}
+
+/*
+ * PORTMAP v3
+ */
+int rpc_pmap3_null_async(struct rpc_context *rpc, rpc_cb cb, void *private_data)
+{
+       struct rpc_pdu *pdu;
+
+       pdu = rpc_allocate_pdu(rpc, PMAP_PROGRAM, PMAP_V3, PMAP3_NULL, cb, private_data, (zdrproc_t)zdr_void, 0);
+       if (pdu == NULL) {
+               rpc_set_error(rpc, "Out of memory. Failed to allocate pdu for PORTMAP3/NULL call");
+               return -1;
+       }
+
+       if (rpc_queue_pdu(rpc, pdu) != 0) {
+               rpc_set_error(rpc, "Out of memory. Failed to queue pdu for PORTMAP3/NULL call");
+               rpc_free_pdu(rpc, pdu);
+               return -1;
+       }
+
+       return 0;
+}
+
+int rpc_pmap3_set_async(struct rpc_context *rpc, struct pmap3_mapping *map, rpc_cb cb, void *private_data)
+{
+       struct rpc_pdu *pdu;
+
+       pdu = rpc_allocate_pdu(rpc, PMAP_PROGRAM, PMAP_V3, PMAP3_SET, cb, private_data, (zdrproc_t)zdr_int, sizeof(uint32_t));
+       if (pdu == NULL) {
+               rpc_set_error(rpc, "Out of memory. Failed to allocate pdu for PORTMAP3/SET call");
+               return -1;
+       }
+
+       if (zdr_pmap3_mapping(&pdu->zdr, map) == 0) {
+               rpc_set_error(rpc, "ZDR error: Failed to encode data for PORTMAP3/SET call");
+               rpc_free_pdu(rpc, pdu);
+               return -1;
+       }
+
+       if (rpc_queue_pdu(rpc, pdu) != 0) {
+               rpc_set_error(rpc, "Failed to queue PORTMAP3/SET pdu");
+               rpc_free_pdu(rpc, pdu);
+               return -1;
+       }
+
+       return 0;
+}
+
+int rpc_pmap3_unset_async(struct rpc_context *rpc, struct pmap3_mapping *map, rpc_cb cb, void *private_data)
+{
+       struct rpc_pdu *pdu;
+
+       pdu = rpc_allocate_pdu(rpc, PMAP_PROGRAM, PMAP_V3, PMAP3_UNSET, cb, private_data, (zdrproc_t)zdr_int, sizeof(uint32_t));
+       if (pdu == NULL) {
+               rpc_set_error(rpc, "Out of memory. Failed to allocate pdu for PORTMAP3/UNSET call");
+               return -1;
+       }
+
+       if (zdr_pmap3_mapping(&pdu->zdr, map) == 0) {
+               rpc_set_error(rpc, "ZDR error: Failed to encode data for PORTMAP3/UNSET call");
+               rpc_free_pdu(rpc, pdu);
+               return -1;
+       }
+
+       if (rpc_queue_pdu(rpc, pdu) != 0) {
+               rpc_set_error(rpc, "Failed to queue PORTMAP3/UNSET pdu");
+               rpc_free_pdu(rpc, pdu);
+               return -1;
+       }
+
+       return 0;
+}
+
+int rpc_pmap3_getaddr_async(struct rpc_context *rpc, struct pmap3_mapping *map, rpc_cb cb, void *private_data)
+{
+       struct rpc_pdu *pdu;
+
+       pdu = rpc_allocate_pdu(rpc, PMAP_PROGRAM, PMAP_V3, PMAP3_GETADDR, cb, private_data, (zdrproc_t)zdr_pmap3_string_result, sizeof(pmap3_string_result));
+       if (pdu == NULL) {
+               rpc_set_error(rpc, "Out of memory. Failed to allocate pdu for PORTMAP3/GETADDR call");
+               return -1;
+       }
+
+       if (zdr_pmap3_mapping(&pdu->zdr, map) == 0) {
+               rpc_set_error(rpc, "ZDR error: Failed to encode data for PORTMAP3/GETADDR call");
+               rpc_free_pdu(rpc, pdu);
+               return -1;
+       }
+
+       if (rpc_queue_pdu(rpc, pdu) != 0) {
+               rpc_set_error(rpc, "Failed to queue PORTMAP3/GETADDR pdu");
+               rpc_free_pdu(rpc, pdu);
+               return -1;
+       }
+
+       return 0;
+}
+
+int rpc_pmap3_dump_async(struct rpc_context *rpc, rpc_cb cb, void *private_data)
+{
+       struct rpc_pdu *pdu;
+
+       pdu = rpc_allocate_pdu(rpc, PMAP_PROGRAM, PMAP_V3, PMAP3_DUMP, cb, private_data, (zdrproc_t)zdr_pmap3_dump_result, sizeof(pmap3_dump_result));
+       if (pdu == NULL) {
+               rpc_set_error(rpc, "Out of memory. Failed to allocate pdu for PORTMAP3/DUMP call");
+               return -1;
+       }
+
+       if (rpc_queue_pdu(rpc, pdu) != 0) {
+               rpc_set_error(rpc, "Failed to queue PORTMAP3/DUMP pdu");
+               rpc_free_pdu(rpc, pdu);
+               return -1;
+       }
+
+       return 0;
+}
+
+int rpc_pmap3_gettime_async(struct rpc_context *rpc, rpc_cb cb, void *private_data)
+{
+       struct rpc_pdu *pdu;
+
+       pdu = rpc_allocate_pdu(rpc, PMAP_PROGRAM, PMAP_V3, PMAP3_GETTIME, cb, private_data, (zdrproc_t)zdr_int, sizeof(uint32_t));
+       if (pdu == NULL) {
+               rpc_set_error(rpc, "Out of memory. Failed to allocate pdu for PORTMAP3/GETTIME call");
+               return -1;
+       }
+
+       if (rpc_queue_pdu(rpc, pdu) != 0) {
+               rpc_set_error(rpc, "Failed to queue PORTMAP3/GETTIME pdu");
+               rpc_free_pdu(rpc, pdu);
+               return -1;
+       }
+
+       return 0;
+}
+
+int rpc_pmap3_callit_async(struct rpc_context *rpc, int program, int version, int procedure, char *data, int datalen, rpc_cb cb, void *private_data)
+{
+       struct rpc_pdu *pdu;
+       struct pmap3_call_args ca;
+
+       pdu = rpc_allocate_pdu(rpc, PMAP_PROGRAM, PMAP_V3, PMAP3_CALLIT, cb, private_data, (zdrproc_t)zdr_pmap3_call_result, sizeof(pmap3_call_result));
+       if (pdu == NULL) {
+               rpc_set_error(rpc, "Out of memory. Failed to allocate pdu for PORTMAP3/CALLIT call");
+               return -1;
+       }
+
+       ca.prog = program;
+       ca.vers = version;
+       ca.proc = procedure;
+       ca.args.args_len = datalen;
+       ca.args.args_val = data;
+
+       if (zdr_pmap3_call_args(&pdu->zdr, &ca) == 0) {
+               rpc_set_error(rpc, "ZDR error: Failed to encode data for PORTMAP3/CALLIT call");
+               rpc_free_pdu(rpc, pdu);
+               return -1;
+       }
+
+       if (rpc_queue_pdu(rpc, pdu) != 0) {
+               rpc_set_error(rpc, "Failed to queue PORTMAP3/CALLIT pdu: %s", rpc_get_error(rpc));
+               return -1;
+       }
+
+       return 0;
+}
+
+int rpc_pmap3_uaddr2taddr_async(struct rpc_context *rpc, char *uaddr, rpc_cb cb, void *private_data)
+{
+       struct rpc_pdu *pdu;
+
+       pdu = rpc_allocate_pdu(rpc, PMAP_PROGRAM, PMAP_V3, PMAP3_UADDR2TADDR, cb, private_data, (zdrproc_t)zdr_pmap3_netbuf, sizeof(pmap3_netbuf));
+       if (pdu == NULL) {
+               rpc_set_error(rpc, "Out of memory. Failed to allocate pdu for PORTMAP3/UADDR2TADDR call");
+               return -1;
+       }
+
+       if (zdr_string(&pdu->zdr, &uaddr, 255) == 0) {
+               rpc_set_error(rpc, "ZDR error: Failed to encode data for PORTMAP3/UADDR2TADDR call");
+               rpc_free_pdu(rpc, pdu);
+               return -1;
+       }
+
+       if (rpc_queue_pdu(rpc, pdu) != 0) {
+               rpc_set_error(rpc, "Failed to queue PORTMAP3/UADDR2TADDR pdu: %s", rpc_get_error(rpc));
+               return -1;
+       }
+
+       return 0;
+}
+
+int rpc_pmap3_taddr2uaddr_async(struct rpc_context *rpc, struct pmap3_netbuf *nb, rpc_cb cb, void *private_data)
+{
+       struct rpc_pdu *pdu;
+
+       pdu = rpc_allocate_pdu(rpc, PMAP_PROGRAM, PMAP_V3, PMAP3_TADDR2UADDR, cb, private_data, (zdrproc_t)zdr_pmap3_string_result, sizeof(pmap3_string_result));
+       if (pdu == NULL) {
+               rpc_set_error(rpc, "Out of memory. Failed to allocate pdu for PORTMAP3/TADDR2UADDR call");
+               return -1;
+       }
+
+       if (zdr_pmap3_netbuf(&pdu->zdr, nb) == 0) {
+               rpc_set_error(rpc, "ZDR error: Failed to encode data for PORTMAP3/TADDR2UADDR call");
                rpc_free_pdu(rpc, pdu);
                return -1;
        }
 
        if (rpc_queue_pdu(rpc, pdu) != 0) {
                rpc_free_pdu(rpc, pdu);
                return -1;
        }
 
        if (rpc_queue_pdu(rpc, pdu) != 0) {
-               rpc_set_error(rpc, "Failed to queue portmap/callit pdu: %s", rpc_get_error(rpc));
+               rpc_set_error(rpc, "Failed to queue PORTMAP3/TADDR2UADDR pdu: %s", rpc_get_error(rpc));
                return -1;
        }
 
                return -1;
        }
 
index 17fd980455449cff57bde695be42296d1b28ff4e..5ceb4367f2365a398bf384daa8221b05222019b4 100644 (file)
 /*
 /*
- * From RFC1833
- */
+Copyright (c) 2014, Ronnie Sahlberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+   list of conditions and the following disclaimer. 
+2. Redistributions in binary form must reproduce the above copyright notice,
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+The views and conclusions contained in the software and documentation are those
+of the authors and should not be interpreted as representing official policies, 
+either expressed or implied, of the FreeBSD Project.
+*/
 
 const PMAP_PORT = 111;      /* portmapper port number */
 
 
 const PMAP_PORT = 111;      /* portmapper port number */
 
-struct pmap_mapping {
+struct pmap2_mapping {
        unsigned int prog;
        unsigned int vers;
        unsigned int prot;
        unsigned int port;
 };
 
        unsigned int prog;
        unsigned int vers;
        unsigned int prot;
        unsigned int port;
 };
 
-struct pmap_call_args {
+struct pmap2_call_args {
        unsigned int prog;
        unsigned int vers;
        unsigned int proc;
        opaque args<>;
 };
 
        unsigned int prog;
        unsigned int vers;
        unsigned int proc;
        opaque args<>;
 };
 
-struct pmap_call_result {
+struct pmap2_call_result {
        unsigned int port;
        opaque res<>;
 };
 
        unsigned int port;
        opaque res<>;
 };
 
-struct pmap_mapping_list {
-       pmap_mapping map;
-       pmap_mapping_list *next;
+struct pmap2_mapping_list {
+       pmap2_mapping map;
+       pmap2_mapping_list *next;
+};
+
+struct pmap2_dump_result {
+       struct pmap2_mapping_list *list;
+};
+
+struct pmap3_string_result {
+       string addr<>;
 };
 
 };
 
-struct pmap_dump_result {
-       struct pmap_mapping_list *list;
+struct pmap3_mapping {
+       unsigned int prog;
+       unsigned int vers;
+       string netid<>;
+       string addr<>;
+       string owner<>;
+};
+
+struct pmap3_mapping_list {
+       pmap3_mapping map;
+       pmap3_mapping_list *next;
+};
+
+struct pmap3_dump_result {
+       struct pmap3_mapping_list *list;
+};
+
+struct pmap3_call_args {
+       unsigned int prog;
+       unsigned int vers;
+       unsigned int proc;
+       opaque args<>;
+};
+
+struct pmap3_call_result {
+       unsigned int port;
+       opaque res<>;
+};
+
+struct pmap3_netbuf {
+       unsigned int maxlen;
+       /* This pretty much contains a sockaddr_storage.
+        * Beware differences in endianess for ss_family
+        * and whether or not ss_len exists.
+        */
+       opaque buf<>;
 };
 
 program PMAP_PROGRAM {
        version PMAP_V2 {
                void
 };
 
 program PMAP_PROGRAM {
        version PMAP_V2 {
                void
-               PMAP_NULL(void)              = 0;
+               PMAP2_NULL(void)              = 0;
 
                bool
 
                bool
-               PMAP_SET(pmap_mapping)       = 1;
+               PMAP2_SET(pmap2_mapping)       = 1;
 
                bool
 
                bool
-               PMAP_UNSET(pmap_mapping)     = 2;
+               PMAP2_UNSET(pmap2_mapping)     = 2;
 
                unsigned int
 
                unsigned int
-               PMAP_GETPORT(pmap_mapping)   = 3;
+               PMAP2_GETPORT(pmap2_mapping)   = 3;
 
 
-               pmap_mapping_list
-               PMAP_DUMP(void)              = 4;
+               pmap2_dump_result
+               PMAP2_DUMP(void)               = 4;
 
 
-               pmap_call_result
-               PMAP_CALLIT(pmap_call_args)  = 5;
+               pmap2_call_result
+               PMAP2_CALLIT(pmap2_call_args)  = 5;
        } = 2;
        } = 2;
+       version PMAP_V3 {
+               void
+               PMAP3_NULL(void)              = 0;
+
+               bool
+               PMAP3_SET(pmap3_mapping)      = 1;
+
+               bool
+               PMAP3_UNSET(pmap3_mapping)    = 2;
+
+               pmap3_string_result
+               PMAP3_GETADDR(pmap3_mapping)  = 3;
+
+               pmap3_dump_result
+               PMAP3_DUMP(void)              = 4;
+
+               pmap3_call_result
+               PMAP3_CALLIT(pmap3_call_args) = 5;
+
+               unsigned int
+               PMAP3_GETTIME(void)           = 6;
+
+               pmap3_netbuf
+               PMAP3_UADDR2TADDR(string)     = 7;
+
+               struct pmap3_string_result
+               PMAP3_TADDR2UADDR(pmap3_netbuf) = 8;
+       } = 3;
 } = 100000;
 
 } = 100000;
 
index 02f86f7f42bfd69834340ee0545304d5d121442b..5a604a8cc2ae9656ec388a65c4c99193a03e8449 100644 (file)
@@ -16,7 +16,9 @@ $(rquota_GENERATED) : rquota-stamp
 rquota-stamp : rquota.x
        rm -f $(rquota_GENERATED)
        touch rquota-stamp
 rquota-stamp : rquota.x
        rm -f $(rquota_GENERATED)
        touch rquota-stamp
-       
+
 compile_rpc:
 compile_rpc:
-       rpcgen -h rquota.x | sed -e "s/#include <rpc\/rpc.h>//" | sed -e "s/xdr/zdr/g" -e "s/XDR/ZDR/g" > libnfs-raw-rquota.h
-       rpcgen -c rquota.x | sed -e "s/#include \".*rquota.h\"/#include \"libnfs-xdr.h\"\n#include \"libnfs-raw-rquota.h\"/" -e "s/xdr/zdr/g" -e "s/XDR/ZDR/g" -e "s/register int32_t \*buf;/register int32_t *buf;\n   buf = NULL;/" > libnfs-raw-rquota.c
+       cat rquota.x | head -29 >libnfs-raw-rquota.h
+       rpcgen -h rquota.x | sed -e "s/#include <rpc\/rpc.h>//" | sed -e "s/xdr/zdr/g" -e "s/XDR/ZDR/g" >> libnfs-raw-rquota.h
+       cat rquota.x | head -29 >libnfs-raw-rquota.c
+       rpcgen -c rquota.x | sed -e "s/#include \".*rquota.h\"/#include \"libnfs-xdr.h\"\n#include \"libnfs-raw-rquota.h\"/" -e "s/xdr/zdr/g" -e "s/XDR/ZDR/g" -e "s/register int32_t \*buf;/register int32_t *buf;\n   buf = NULL;/" >> libnfs-raw-rquota.c
index 4b0e33019bf9127032f5c63e7a0c1bcdf6614797..482645f2dc3f51541e2fc182fa6c1e076994a21f 100644 (file)
@@ -1,3 +1,32 @@
+/*
+Copyright (c) 2014, Ronnie Sahlberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+   list of conditions and the following disclaimer. 
+2. Redistributions in binary form must reproduce the above copyright notice,
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+The views and conclusions contained in the software and documentation are those
+of the authors and should not be interpreted as representing official policies, 
+either expressed or implied, of the FreeBSD Project.
+*/
+
 /*
  * Please do not edit this file.
  * It was generated using rpcgen.
 /*
  * Please do not edit this file.
  * It was generated using rpcgen.
index 4690da6b035dd879f475734dbeea147178c23f32..ed5fcb9c9712f5ea10292032d4a0a478df3297f7 100644 (file)
@@ -1,3 +1,32 @@
+/*
+Copyright (c) 2014, Ronnie Sahlberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+   list of conditions and the following disclaimer. 
+2. Redistributions in binary form must reproduce the above copyright notice,
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+The views and conclusions contained in the software and documentation are those
+of the authors and should not be interpreted as representing official policies, 
+either expressed or implied, of the FreeBSD Project.
+*/
+
 /*
  * Please do not edit this file.
  * It was generated using rpcgen.
 /*
  * Please do not edit this file.
  * It was generated using rpcgen.
@@ -6,7 +35,8 @@
 #ifndef _RQUOTA_H_RPCGEN
 #define _RQUOTA_H_RPCGEN
 
 #ifndef _RQUOTA_H_RPCGEN
 #define _RQUOTA_H_RPCGEN
 
-#include <nfsc/libnfs-zdr.h>
+
+
 
 #ifdef __cplusplus
 extern "C" {
 
 #ifdef __cplusplus
 extern "C" {
index fb8bc0eb256f329971430d4540e20c525c4d8c2a..e0a764f718410849d98c3ea2ac9820a447d8cbec 100644 (file)
@@ -1,4 +1,31 @@
-/* implementation based on wireshark c-code */
+/*
+Copyright (c) 2014, Ronnie Sahlberg
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+   list of conditions and the following disclaimer. 
+2. Redistributions in binary form must reproduce the above copyright notice,
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+The views and conclusions contained in the software and documentation are those
+of the authors and should not be interpreted as representing official policies, 
+either expressed or implied, of the FreeBSD Project.
+*/
 
 const RQUOTAPATHLEN = 1024; /* Guess this is max. It is max for mount so probably rquota too */
 
 
 const RQUOTAPATHLEN = 1024; /* Guess this is max. It is max for mount so probably rquota too */
 
diff --git a/utils/Makefile.am b/utils/Makefile.am
new file mode 100644 (file)
index 0000000..e8bb94e
--- /dev/null
@@ -0,0 +1,9 @@
+bin_PROGRAMS = nfs-ls
+
+AM_CPPFLAGS = \
+       -I$(abs_top_srcdir)/include \
+       -I$(abs_top_srcdir)/include/nfsc \
+       -I$(abs_top_srcdir)/mount \
+       "-D_U_=__attribute__((unused))"
+
+AM_LDFLAGS = ../lib/.libs/libnfs.la
similarity index 87%
rename from examples/nfs-ls.c
rename to utils/nfs-ls.c
index c680617effc5e1ee640b96cea114f1c56f70e2dd..7653f56d9b6439981c8e1d4a6cdc5ed2e2e63d49 100644 (file)
@@ -91,7 +91,6 @@ void process_dir(struct nfs_context *nfs, char *dir, int level) {
        struct nfsdirent *nfsdirent;
        struct statvfs svfs;
        struct nfsdir *nfsdir;
        struct nfsdirent *nfsdirent;
        struct statvfs svfs;
        struct nfsdir *nfsdir;
-       struct nfs_stat_64 st;
        
        if (!level) {
                printf("Recursion detected!\n");
        
        if (!level) {
                printf("Recursion detected!\n");
@@ -109,15 +108,9 @@ void process_dir(struct nfs_context *nfs, char *dir, int level) {
                if (!strcmp(nfsdirent->name, ".") || !strcmp(nfsdirent->name, "..")) {
                        continue;
                }
                if (!strcmp(nfsdirent->name, ".") || !strcmp(nfsdirent->name, "..")) {
                        continue;
                }
-
                snprintf(path, 1024, "%s/%s", dir, nfsdirent->name);
                snprintf(path, 1024, "%s/%s", dir, nfsdirent->name);
-               ret = nfs_stat64(nfs, path, &st);
-               if (ret != 0) {
-                       fprintf(stderr, "Failed to stat(%s) %s\n", path, nfs_get_error(nfs));
-                       continue;
-               }
 
 
-               switch (st.nfs_mode & S_IFMT) {
+               switch (nfsdirent->mode & S_IFMT) {
 #ifndef WIN32
                case S_IFLNK:
                        printf("l");
 #ifndef WIN32
                case S_IFLNK:
                        printf("l");
@@ -137,28 +130,28 @@ void process_dir(struct nfs_context *nfs, char *dir, int level) {
                        break;
                }
                printf("%c%c%c",
                        break;
                }
                printf("%c%c%c",
-                       "-r"[!!(st.nfs_mode & S_IRUSR)],
-                       "-w"[!!(st.nfs_mode & S_IWUSR)],
-                       "-x"[!!(st.nfs_mode & S_IXUSR)]
+                       "-r"[!!(nfsdirent->mode & S_IRUSR)],
+                       "-w"[!!(nfsdirent->mode & S_IWUSR)],
+                       "-x"[!!(nfsdirent->mode & S_IXUSR)]
                );
                printf("%c%c%c",
                );
                printf("%c%c%c",
-                       "-r"[!!(st.nfs_mode & S_IRGRP)],
-                       "-w"[!!(st.nfs_mode & S_IWGRP)],
-                       "-x"[!!(st.nfs_mode & S_IXGRP)]
+                       "-r"[!!(nfsdirent->mode & S_IRGRP)],
+                       "-w"[!!(nfsdirent->mode & S_IWGRP)],
+                       "-x"[!!(nfsdirent->mode & S_IXGRP)]
                );
                printf("%c%c%c",
                );
                printf("%c%c%c",
-                       "-r"[!!(st.nfs_mode & S_IROTH)],
-                       "-w"[!!(st.nfs_mode & S_IWOTH)],
-                       "-x"[!!(st.nfs_mode & S_IXOTH)]
+                       "-r"[!!(nfsdirent->mode & S_IROTH)],
+                       "-w"[!!(nfsdirent->mode & S_IWOTH)],
+                       "-x"[!!(nfsdirent->mode & S_IXOTH)]
                );
                );
-               printf(" %2d", (int)st.nfs_nlink);
-               printf(" %5d", (int)st.nfs_uid);
-               printf(" %5d", (int)st.nfs_gid);
-               printf(" %12" PRId64, st.nfs_size);
+               printf(" %2d", (int)nfsdirent->nlink);
+               printf(" %5d", (int)nfsdirent->uid);
+               printf(" %5d", (int)nfsdirent->gid);
+               printf(" %12" PRId64, nfsdirent->size);
 
                printf(" %s\n", path + 1);
                
 
                printf(" %s\n", path + 1);
                
-               if (recursive && (st.nfs_mode & S_IFMT) == S_IFDIR) {
+               if (recursive && (nfsdirent->mode & S_IFMT) == S_IFDIR) {
                        process_dir(nfs, path, level - 1);
                }
        }
                        process_dir(nfs, path, level - 1);
                }
        }
@@ -172,7 +165,7 @@ int main(int argc, char *argv[])
        uint64_t offset;
        struct client client;
        struct statvfs stvfs;
        uint64_t offset;
        struct client client;
        struct statvfs stvfs;
-       struct nfs_url *url;
+       struct nfs_url *url = NULL;
        exports export, tmp;
 
 #ifdef WIN32
        exports export, tmp;
 
 #ifdef WIN32
index ebed01c35eed8a00a8f56a14895f0bbbd7983925..1699d5e1f33496cc202970f79e39307d226719bc 100644 (file)
@@ -1,3 +1,24 @@
+/*
+Copyright (c) 2014, Ronnie Sahlberg
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
 #ifndef WIN32_ERRNOWRAPPER_H_
 #define WIN32_ERRNOWRAPPER_H_
 
 #ifndef WIN32_ERRNOWRAPPER_H_
 #define WIN32_ERRNOWRAPPER_H_